2020-10-26 20:09:47 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020, Linaro Limited
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/of_device.h>
# include <sound/soc.h>
# include <sound/soc-dapm.h>
# include <sound/pcm.h>
# include <linux/soundwire/sdw.h>
2021-10-06 20:27:45 +03:00
# include <sound/jack.h>
# include <linux/input-event-codes.h>
2020-10-26 20:09:47 +03:00
# include "qdsp6/q6afe.h"
# include "common.h"
# define DRIVER_NAME "sm8250"
# define MI2S_BCLK_RATE 1536000
struct sm8250_snd_data {
2020-10-28 17:20:01 +03:00
bool stream_prepared [ AFE_PORT_MAX ] ;
2020-10-26 20:09:47 +03:00
struct snd_soc_card * card ;
2020-10-28 17:20:01 +03:00
struct sdw_stream_runtime * sruntime [ AFE_PORT_MAX ] ;
2021-10-06 20:27:45 +03:00
struct snd_soc_jack jack ;
bool jack_setup ;
2020-10-26 20:09:47 +03:00
} ;
2021-10-06 20:27:45 +03:00
static int sm8250_snd_init ( struct snd_soc_pcm_runtime * rtd )
{
struct sm8250_snd_data * data = snd_soc_card_get_drvdata ( rtd - > card ) ;
2022-09-16 16:24:26 +03:00
return qcom_snd_wcd_jack_setup ( rtd , & data - > jack , & data - > jack_setup ) ;
2021-10-06 20:27:45 +03:00
}
2020-10-26 20:09:47 +03:00
static int sm8250_be_hw_params_fixup ( struct snd_soc_pcm_runtime * rtd ,
struct snd_pcm_hw_params * params )
{
struct snd_interval * rate = hw_param_interval ( params ,
SNDRV_PCM_HW_PARAM_RATE ) ;
struct snd_interval * channels = hw_param_interval ( params ,
SNDRV_PCM_HW_PARAM_CHANNELS ) ;
rate - > min = rate - > max = 48000 ;
channels - > min = channels - > max = 2 ;
return 0 ;
}
static int sm8250_snd_startup ( struct snd_pcm_substream * substream )
{
2022-05-19 18:42:39 +03:00
unsigned int fmt = SND_SOC_DAIFMT_BP_FP ;
unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC ;
2020-10-26 20:09:47 +03:00
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
switch ( cpu_dai - > id ) {
case TERTIARY_MI2S_RX :
2020-11-19 15:31:45 +03:00
codec_dai_fmt | = SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S ;
2020-10-26 20:09:47 +03:00
snd_soc_dai_set_sysclk ( cpu_dai ,
Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT ,
MI2S_BCLK_RATE , SNDRV_PCM_STREAM_PLAYBACK ) ;
2020-11-19 15:31:45 +03:00
snd_soc_dai_set_fmt ( cpu_dai , fmt ) ;
2020-10-26 20:09:47 +03:00
snd_soc_dai_set_fmt ( codec_dai , codec_dai_fmt ) ;
break ;
default :
break ;
}
return 0 ;
}
static int sm8250_snd_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
struct sm8250_snd_data * pdata = snd_soc_card_get_drvdata ( rtd - > card ) ;
2022-09-16 16:24:26 +03:00
return qcom_snd_sdw_hw_params ( substream , params , & pdata - > sruntime [ cpu_dai - > id ] ) ;
2020-10-26 20:09:47 +03:00
}
2022-09-16 16:24:26 +03:00
static int sm8250_snd_prepare ( struct snd_pcm_substream * substream )
2020-10-26 20:09:47 +03:00
{
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
struct sm8250_snd_data * data = snd_soc_card_get_drvdata ( rtd - > card ) ;
struct sdw_stream_runtime * sruntime = data - > sruntime [ cpu_dai - > id ] ;
2022-09-16 16:24:26 +03:00
return qcom_snd_sdw_prepare ( substream , sruntime ,
& data - > stream_prepared [ cpu_dai - > id ] ) ;
2020-10-26 20:09:47 +03:00
}
static int sm8250_snd_hw_free ( struct snd_pcm_substream * substream )
{
struct snd_soc_pcm_runtime * rtd = substream - > private_data ;
struct sm8250_snd_data * data = snd_soc_card_get_drvdata ( rtd - > card ) ;
struct snd_soc_dai * cpu_dai = asoc_rtd_to_cpu ( rtd , 0 ) ;
struct sdw_stream_runtime * sruntime = data - > sruntime [ cpu_dai - > id ] ;
2022-09-16 16:24:26 +03:00
return qcom_snd_sdw_hw_free ( substream , sruntime ,
& data - > stream_prepared [ cpu_dai - > id ] ) ;
2020-10-26 20:09:47 +03:00
}
static const struct snd_soc_ops sm8250_be_ops = {
. startup = sm8250_snd_startup ,
. hw_params = sm8250_snd_hw_params ,
. hw_free = sm8250_snd_hw_free ,
. prepare = sm8250_snd_prepare ,
} ;
static void sm8250_add_be_ops ( struct snd_soc_card * card )
{
struct snd_soc_dai_link * link ;
int i ;
for_each_card_prelinks ( card , i , link ) {
if ( link - > no_pcm = = 1 ) {
2021-10-06 20:27:45 +03:00
link - > init = sm8250_snd_init ;
2020-10-26 20:09:47 +03:00
link - > be_hw_params_fixup = sm8250_be_hw_params_fixup ;
link - > ops = & sm8250_be_ops ;
}
}
}
static int sm8250_platform_probe ( struct platform_device * pdev )
{
struct snd_soc_card * card ;
struct sm8250_snd_data * data ;
struct device * dev = & pdev - > dev ;
int ret ;
card = devm_kzalloc ( dev , sizeof ( * card ) , GFP_KERNEL ) ;
if ( ! card )
return - ENOMEM ;
2022-08-16 19:52:29 +03:00
card - > owner = THIS_MODULE ;
2020-10-26 20:09:47 +03:00
/* Allocate the private data */
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
card - > dev = dev ;
dev_set_drvdata ( dev , card ) ;
snd_soc_card_set_drvdata ( card , data ) ;
ret = qcom_snd_parse_of ( card ) ;
if ( ret )
return ret ;
card - > driver_name = DRIVER_NAME ;
sm8250_add_be_ops ( card ) ;
return devm_snd_soc_register_card ( dev , card ) ;
}
static const struct of_device_id snd_sm8250_dt_match [ ] = {
2020-10-29 13:15:50 +03:00
{ . compatible = " qcom,sm8250-sndcard " } ,
{ . compatible = " qcom,qrb5165-rb5-sndcard " } ,
2020-10-26 20:09:47 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , snd_sm8250_dt_match ) ;
static struct platform_driver snd_sm8250_driver = {
. probe = sm8250_platform_probe ,
. driver = {
. name = " snd-sm8250 " ,
. of_match_table = snd_sm8250_dt_match ,
} ,
} ;
module_platform_driver ( snd_sm8250_driver ) ;
MODULE_AUTHOR ( " Srinivas Kandagatla <srinivas.kandagatla@linaro.org " ) ;
MODULE_DESCRIPTION ( " SM8250 ASoC Machine Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;