From 7c27ba46792d3596a83f28243e235a92cba80d45 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 29 Dec 2014 23:52:35 -0200 Subject: [PATCH 01/32] ASoC: fsl_spdif: Use dev_name() for registering the irq The 'name' array is currently stored inside the fsl_spdif_priv private structure only for registering the interrupt name. This can be simplified by registering it with dev_name() instead. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index af0429421fc8..73da1f0f8786 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -90,7 +90,6 @@ struct spdif_mixer_control { * @sysclk: system clock for rx clock rate measurement * @dma_params_tx: DMA parameters for transmit channel * @dma_params_rx: DMA parameters for receive channel - * @name: driver name */ struct fsl_spdif_priv { struct spdif_mixer_control fsl_spdif_control; @@ -109,12 +108,8 @@ struct fsl_spdif_priv { struct clk *sysclk; struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_rx; - - /* The name space will be allocated dynamically */ - char name[0]; }; - /* DPLL locked and lock loss interrupt handler */ static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv) { @@ -1169,19 +1164,15 @@ static int fsl_spdif_probe(struct platform_device *pdev) if (!np) return -ENODEV; - spdif_priv = devm_kzalloc(&pdev->dev, - sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1, - GFP_KERNEL); + spdif_priv = devm_kzalloc(&pdev->dev, sizeof(*spdif_priv), GFP_KERNEL); if (!spdif_priv) return -ENOMEM; - strcpy(spdif_priv->name, np->name); - spdif_priv->pdev = pdev; /* Initialize this copy of the CPU DAI driver structure */ memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); - spdif_priv->cpu_dai_drv.name = spdif_priv->name; + spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev); /* Get the addresses and IRQ */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1203,7 +1194,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) } ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, - spdif_priv->name, spdif_priv); + dev_name(&pdev->dev), spdif_priv); if (ret) { dev_err(&pdev->dev, "could not claim irq %u\n", irq); return ret; From 544c55c810a55dcfd2febbc33105642923be9192 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 19:03:55 +0100 Subject: [PATCH 02/32] ASoC: Intel: Delete an unnecessary check before the function call "sst_dma_free" The sst_dma_free() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/intel/sst-dsp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index 86e410845670..64e94212d2d2 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c @@ -410,8 +410,7 @@ void sst_dsp_free(struct sst_dsp *sst) if (sst->ops->free) sst->ops->free(sst); - if (sst->dma) - sst_dma_free(sst->dma); + sst_dma_free(sst->dma); } EXPORT_SYMBOL_GPL(sst_dsp_free); From 4e3461d34f4cd632b403342ea1df33135e5e3ad3 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 3 Jan 2015 19:49:37 +0100 Subject: [PATCH 03/32] ASoC: Intel: Delete an unnecessary check before the function call "release_firmware" The release_firmware() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Mark Brown --- sound/soc/intel/sst/sst_loader.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c index b580f96e25e5..7888cd707853 100644 --- a/sound/soc/intel/sst/sst_loader.c +++ b/sound/soc/intel/sst/sst_loader.c @@ -324,8 +324,7 @@ void sst_firmware_load_cb(const struct firmware *fw, void *context) if (ctx->sst_state != SST_RESET || ctx->fw_in_mem != NULL) { - if (fw != NULL) - release_firmware(fw); + release_firmware(fw); mutex_unlock(&ctx->sst_lock); return; } From 057a1573fd1309a6b3a039f9cd75b4e90f7f6cf4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 11:30:35 +0100 Subject: [PATCH 04/32] ASoC: broadwell: Drop unnecessary snd_soc_dapm_enable() calls DAPM widgets are enabled by default, there is no need to enable them unless they have previously been explicitly disabled. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/intel/broadwell.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index 7cf95d5d5d80..9cf7d01479ad 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c @@ -140,8 +140,6 @@ static struct snd_soc_ops broadwell_rt286_ops = { static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); struct sst_hsw *broadwell = pdata->dsp; int ret; @@ -155,14 +153,6 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) return ret; } - /* always connected - check HP for jack detect */ - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Speaker"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - snd_soc_dapm_enable_pin(dapm, "Line Jack"); - snd_soc_dapm_enable_pin(dapm, "DMIC1"); - snd_soc_dapm_enable_pin(dapm, "DMIC2"); - return 0; } From 7a81140b0ead01fcb27e6167b1015b06c36acbd0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 11:23:44 +0100 Subject: [PATCH 05/32] ASoC: byt-rt5640: Fix snd_soc_dapm_ignore_suspend() calls To work properly snd_soc_dapm_ignore_suspend() needs to be called on endpoint widgets. In this case those are the board level Speaker and Headphone widgets and not the CODEC output widgets that are connected to them. Signed-off-by: Lars-Peter Clausen Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/byt-rt5640.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 0cba7830c5e9..a51856e91826 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -171,13 +171,8 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) return ret; } - snd_soc_dapm_ignore_suspend(dapm, "HPOL"); - snd_soc_dapm_ignore_suspend(dapm, "HPOR"); - - snd_soc_dapm_ignore_suspend(dapm, "SPOLP"); - snd_soc_dapm_ignore_suspend(dapm, "SPOLN"); - snd_soc_dapm_ignore_suspend(dapm, "SPORP"); - snd_soc_dapm_ignore_suspend(dapm, "SPORN"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); return ret; } From b93673be48cef887551d109683922bcc15f40d27 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 1 Jan 2015 11:23:45 +0100 Subject: [PATCH 06/32] ASoC: byt-rt5640: Register microphone routes with the card DAPM context Board level DAPM elements should be registered with the card's DAPM context rather than the CODEC's DAPM context. Signed-off-by: Lars-Peter Clausen Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/byt-rt5640.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index a51856e91826..354eaad886e1 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c @@ -132,7 +132,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) { int ret; struct snd_soc_codec *codec = runtime->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_card *card = runtime->card; const struct snd_soc_dapm_route *custom_map; int num_routes; @@ -161,7 +160,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); } - ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); if (ret) return ret; From 8686f251e4823a4196bae86f22dab8cfd3b454cc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 2 Jan 2015 13:56:09 +0100 Subject: [PATCH 07/32] ASoC: intel: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Lars-Peter Clausen Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/sst-baytrail-pcm.c | 6 ------ sound/soc/intel/sst-haswell-pcm.c | 6 ------ sound/soc/intel/sst-mfld-platform-pcm.c | 7 ------- 3 files changed, 19 deletions(-) diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c index 3bb6288d8b4d..224c49c9f135 100644 --- a/sound/soc/intel/sst-baytrail-pcm.c +++ b/sound/soc/intel/sst-baytrail-pcm.c @@ -320,11 +320,6 @@ static struct snd_pcm_ops sst_byt_pcm_ops = { .mmap = sst_byt_pcm_mmap, }; -static void sst_byt_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; @@ -403,7 +398,6 @@ static struct snd_soc_platform_driver byt_soc_platform = { .remove = sst_byt_pcm_remove, .ops = &sst_byt_pcm_ops, .pcm_new = sst_byt_pcm_new, - .pcm_free = sst_byt_pcm_free, }; static const struct snd_soc_component_driver byt_dai_component = { diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 619525200705..13f156b4a612 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -735,11 +735,6 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) } } -static void hsw_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_pcm *pcm = rtd->pcm; @@ -936,7 +931,6 @@ static struct snd_soc_platform_driver hsw_soc_platform = { .remove = hsw_pcm_remove, .ops = &hsw_pcm_ops, .pcm_new = hsw_pcm_new, - .pcm_free = hsw_pcm_free, }; static const struct snd_soc_component_driver hsw_dai_component = { diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index a1a8d9d91539..7523cbef8780 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c @@ -643,12 +643,6 @@ static struct snd_pcm_ops sst_platform_ops = { .pointer = sst_platform_pcm_pointer, }; -static void sst_pcm_free(struct snd_pcm *pcm) -{ - dev_dbg(pcm->dev, "sst_pcm_free called\n"); - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; @@ -679,7 +673,6 @@ static struct snd_soc_platform_driver sst_soc_platform_drv = { .ops = &sst_platform_ops, .compr_ops = &sst_platform_compr_ops, .pcm_new = sst_pcm_new, - .pcm_free = sst_pcm_free, }; static const struct snd_soc_component_driver sst_component = { From b7ed9f1d26f04272127a98248338177e5bac233e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 7 Jan 2015 10:19:06 +0800 Subject: [PATCH 08/32] ASoC: rt5670: redefine ASRC control registers 0x84 and 0x85 The previous definition of registers 0x84 and 0x85 doesn't match the datasheet. So this patch removes the wrong definition and writes a new one for the two registers. Signed-off-by: Bard Liao Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.h | 65 +++++++++++++++------------------------ 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index d11b9c207e26..ec38d8f173e7 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1023,50 +1023,33 @@ #define RT5670_DMIC_2_M_NOR (0x0 << 8) #define RT5670_DMIC_2_M_ASYN (0x1 << 8) +/* ASRC clock source selection (0x84, 0x85) */ +#define RT5670_CLK_SEL_SYS (0x0) +#define RT5670_CLK_SEL_I2S1_ASRC (0x1) +#define RT5670_CLK_SEL_I2S2_ASRC (0x2) +#define RT5670_CLK_SEL_I2S3_ASRC (0x3) +#define RT5670_CLK_SEL_SYS2 (0x5) +#define RT5670_CLK_SEL_SYS3 (0x6) + /* ASRC Control 2 (0x84) */ -#define RT5670_MDA_L_M_MASK (0x1 << 15) -#define RT5670_MDA_L_M_SFT 15 -#define RT5670_MDA_L_M_NOR (0x0 << 15) -#define RT5670_MDA_L_M_ASYN (0x1 << 15) -#define RT5670_MDA_R_M_MASK (0x1 << 14) -#define RT5670_MDA_R_M_SFT 14 -#define RT5670_MDA_R_M_NOR (0x0 << 14) -#define RT5670_MDA_R_M_ASYN (0x1 << 14) -#define RT5670_MAD_L_M_MASK (0x1 << 13) -#define RT5670_MAD_L_M_SFT 13 -#define RT5670_MAD_L_M_NOR (0x0 << 13) -#define RT5670_MAD_L_M_ASYN (0x1 << 13) -#define RT5670_MAD_R_M_MASK (0x1 << 12) -#define RT5670_MAD_R_M_SFT 12 -#define RT5670_MAD_R_M_NOR (0x0 << 12) -#define RT5670_MAD_R_M_ASYN (0x1 << 12) -#define RT5670_ADC_M_MASK (0x1 << 11) -#define RT5670_ADC_M_SFT 11 -#define RT5670_ADC_M_NOR (0x0 << 11) -#define RT5670_ADC_M_ASYN (0x1 << 11) -#define RT5670_STO_DAC_M_MASK (0x1 << 5) -#define RT5670_STO_DAC_M_SFT 5 -#define RT5670_STO_DAC_M_NOR (0x0 << 5) -#define RT5670_STO_DAC_M_ASYN (0x1 << 5) -#define RT5670_I2S1_R_D_MASK (0x1 << 4) -#define RT5670_I2S1_R_D_SFT 4 -#define RT5670_I2S1_R_D_DIS (0x0 << 4) -#define RT5670_I2S1_R_D_EN (0x1 << 4) -#define RT5670_I2S2_R_D_MASK (0x1 << 3) -#define RT5670_I2S2_R_D_SFT 3 -#define RT5670_I2S2_R_D_DIS (0x0 << 3) -#define RT5670_I2S2_R_D_EN (0x1 << 3) -#define RT5670_PRE_SCLK_MASK (0x3) -#define RT5670_PRE_SCLK_SFT 0 -#define RT5670_PRE_SCLK_512 (0x0) -#define RT5670_PRE_SCLK_1024 (0x1) -#define RT5670_PRE_SCLK_2048 (0x2) +#define RT5670_DA_STO_CLK_SEL_MASK (0xf << 12) +#define RT5670_DA_STO_CLK_SEL_SFT 12 +#define RT5670_DA_MONOL_CLK_SEL_MASK (0xf << 8) +#define RT5670_DA_MONOL_CLK_SEL_SFT 8 +#define RT5670_DA_MONOR_CLK_SEL_MASK (0xf << 4) +#define RT5670_DA_MONOR_CLK_SEL_SFT 4 +#define RT5670_AD_STO1_CLK_SEL_MASK (0xf << 0) +#define RT5670_AD_STO1_CLK_SEL_SFT 0 /* ASRC Control 3 (0x85) */ -#define RT5670_I2S1_RATE_MASK (0xf << 12) -#define RT5670_I2S1_RATE_SFT 12 -#define RT5670_I2S2_RATE_MASK (0xf << 8) -#define RT5670_I2S2_RATE_SFT 8 +#define RT5670_UP_CLK_SEL_MASK (0xf << 12) +#define RT5670_UP_CLK_SEL_SFT 12 +#define RT5670_DOWN_CLK_SEL_MASK (0xf << 8) +#define RT5670_DOWN_CLK_SEL_SFT 8 +#define RT5670_AD_MONOL_CLK_SEL_MASK (0xf << 4) +#define RT5670_AD_MONOL_CLK_SEL_SFT 4 +#define RT5670_AD_MONOR_CLK_SEL_MASK (0xf << 0) +#define RT5670_AD_MONOR_CLK_SEL_SFT 0 /* ASRC Control 4 (0x89) */ #define RT5670_I2S1_PD_MASK (0x7 << 12) From e8c47ba3cadcc3649f18e4710804bb6c3791eac2 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 7 Jan 2015 10:19:12 +0800 Subject: [PATCH 09/32] ASoC: rt5670: add API to select ASRC clock source When codec is in slave mode, ASRC can suppress noise for asynchronous MCLK and LRCLK or special I2S format. This patch defines an API to select the clock source for specified filters. And the codec driver will turn on ASRC for these filters if ASRC is selected as their clock source. Signed-off-by: Bard Liao Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 83 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5670.h | 15 +++++++ 2 files changed, 98 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 0a027bc94399..0632b7458a53 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -590,6 +590,89 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source, return 0; } + +/** + * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + unsigned int asrc2_mask = 0, asrc2_value = 0; + unsigned int asrc3_mask = 0, asrc3_value = 0; + + if (clk_src > RT5670_CLK_SEL_SYS3) + return -EINVAL; + + if (filter_mask & RT5670_DA_STEREO_FILTER) { + asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK) + | (clk_src << RT5670_DA_STO_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DA_MONO_L_FILTER) { + asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK) + | (clk_src << RT5670_DA_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DA_MONO_R_FILTER) { + asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK) + | (clk_src << RT5670_DA_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_STEREO_FILTER) { + asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK) + | (clk_src << RT5670_AD_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_MONO_L_FILTER) { + asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK) + | (clk_src << RT5670_AD_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_AD_MONO_R_FILTER) { + asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK) + | (clk_src << RT5670_AD_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_UP_RATE_FILTER) { + asrc3_mask |= RT5670_UP_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK) + | (clk_src << RT5670_UP_CLK_SEL_SFT); + } + + if (filter_mask & RT5670_DOWN_RATE_FILTER) { + asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK) + | (clk_src << RT5670_DOWN_CLK_SEL_SFT); + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5670_ASRC_2, + asrc2_mask, asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5670_ASRC_3, + asrc3_mask, asrc3_value); + return 0; +} +EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src); + /* Digital Mixer */ static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index ec38d8f173e7..21f8e18c13c4 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1966,6 +1966,21 @@ enum { RT5670_DMIC_DATA_GPIO5, }; +/* filter mask */ +enum { + RT5670_DA_STEREO_FILTER = 0x1, + RT5670_DA_MONO_L_FILTER = (0x1 << 1), + RT5670_DA_MONO_R_FILTER = (0x1 << 2), + RT5670_AD_STEREO_FILTER = (0x1 << 3), + RT5670_AD_MONO_L_FILTER = (0x1 << 4), + RT5670_AD_MONO_R_FILTER = (0x1 << 5), + RT5670_UP_RATE_FILTER = (0x1 << 6), + RT5670_DOWN_RATE_FILTER = (0x1 << 7), +}; + +int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); + struct rt5670_priv { struct snd_soc_codec *codec; struct rt5670_platform_data pdata; From eb55fab997c0bf1b1ddf0a7199da0ceb18432b96 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 7 Jan 2015 10:19:23 +0800 Subject: [PATCH 10/32] ASoC: Intel: Select RT5672 ASRC clock source on Cherrytrail and Braswell On Cherrytrail and Braswell, the I2S BCLK is 100FS which cannot be supported by RT5672 in slave mode and can cause noise. This patch selects codec ASRC clock source to track I2S1 clock so that codec ASRC can be enabled to suppress the noise. Signed-off-by: Mengdong Lin Reviewed-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/intel/cht_bsw_rt5672.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index a406c6104897..ff016621583a 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -140,6 +140,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) { int ret; struct snd_soc_dai *codec_dai = runtime->codec_dai; + struct snd_soc_codec *codec = codec_dai->codec; /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); @@ -148,6 +149,19 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) return ret; } + /* Select codec ASRC clock source to track I2S1 clock, because codec + * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot + * be supported by RT5672. Otherwise, ASRC will be disabled and cause + * noise. + */ + rt5670_sel_asrc_clk_src(codec, + RT5670_DA_STEREO_FILTER + | RT5670_DA_MONO_L_FILTER + | RT5670_DA_MONO_R_FILTER + | RT5670_AD_STEREO_FILTER + | RT5670_AD_MONO_L_FILTER + | RT5670_AD_MONO_R_FILTER, + RT5670_CLK_SEL_I2S1_ASRC); return 0; } From 69067f9d52aa325baa0d113c1f35eb98fe486bfc Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Thu, 8 Jan 2015 20:12:52 +0800 Subject: [PATCH 11/32] ASoC: Intel: Always enable DRAM block for FW dump The first 512 bytes of data DRAM memory is used for FW dump, and this first data SRAM block should be never power gated (always on), here always enable the block(DSRAM[0]) for D0 stage. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-dsp.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index 57039b00efc2..c42ffae5fe9f 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c @@ -306,7 +306,7 @@ static void hsw_reset(struct sst_dsp *sst) static int hsw_set_dsp_D0(struct sst_dsp *sst) { int tries = 10; - u32 reg; + u32 reg, fw_dump_bit; /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); @@ -368,7 +368,9 @@ finish: can't be accessed, please enable each block before accessing. */ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK; - writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0); + /* for D0, always enable the block(DSRAM[0]) used for FW dump */ + fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT; + writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0); /* disable DMA finish function for SSP0 & SSP1 */ @@ -491,6 +493,7 @@ static const struct sst_sram_shift sram_shift[] = { {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */ {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */ }; + static u32 hsw_block_get_bit(struct sst_mem_block *block) { u32 bit = 0, shift = 0, index; @@ -587,7 +590,9 @@ static int hsw_block_disable(struct sst_mem_block *block) val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); bit = hsw_block_get_bit(block); - writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); + /* don't disable DSRAM[0], keep it always enable for FW dump*/ + if (bit != (1 << SST_VDRTCL0_DSRAMPGE_SHIFT)) + writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); /* wait 18 DSP clock ticks */ udelay(10); @@ -612,7 +617,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) const struct sst_adsp_memregion *region; struct device *dev; int ret = -ENODEV, i, j, region_count; - u32 offset, size; + u32 offset, size, fw_dump_bit; dev = sst->dma_dev; @@ -669,9 +674,11 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) } } + /* always enable the block(DSRAM[0]) used for FW dump */ + fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT; /* set default power gating control, enable power gating control for all blocks. that is, can't be accessed, please enable each block before accessing. */ - writel(0xffffffff, sst->addr.pci_cfg + SST_VDRTCTL0); + writel(0xffffffff & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0); return 0; } From 98b9c1d2ce59d98d5921bbdca5a6d7fe40b4a384 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Thu, 8 Jan 2015 14:32:20 +0800 Subject: [PATCH 12/32] ASoC: Intel: Add stream direction for pcm-module map A DAI may have 2 streams(playback/capture) and different modules may be needed for them respectively, so we need add a stream direction here, the combination(dai_id + stream) can tell us which module we really need here. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-pcm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 13f156b4a612..5448f79283b7 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -78,7 +78,6 @@ static const u32 volume_map[] = { #define HSW_PCM_DAI_ID_OFFLOAD0 1 #define HSW_PCM_DAI_ID_OFFLOAD1 2 #define HSW_PCM_DAI_ID_LOOPBACK 3 -#define HSW_PCM_DAI_ID_CAPTURE 4 static const struct snd_pcm_hardware hsw_pcm_hardware = { @@ -99,6 +98,7 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = { struct hsw_pcm_module_map { int dai_id; + int stream; enum sst_hsw_module_id mod_id; }; @@ -687,11 +687,11 @@ static struct snd_pcm_ops hsw_pcm_ops = { /* static mappings between PCMs and modules - may be dynamic in future */ static struct hsw_pcm_module_map mod_map[] = { - {HSW_PCM_DAI_ID_SYSTEM, SST_HSW_MODULE_PCM_SYSTEM}, - {HSW_PCM_DAI_ID_OFFLOAD0, SST_HSW_MODULE_PCM}, - {HSW_PCM_DAI_ID_OFFLOAD1, SST_HSW_MODULE_PCM}, - {HSW_PCM_DAI_ID_LOOPBACK, SST_HSW_MODULE_PCM_REFERENCE}, - {HSW_PCM_DAI_ID_CAPTURE, SST_HSW_MODULE_PCM_CAPTURE}, + {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM}, + {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM}, + {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM}, + {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE}, + {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE}, }; static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) @@ -1075,7 +1075,7 @@ static void hsw_pcm_complete(struct device *dev) return; } - for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { + for (i = 0; i < ARRAY_SIZE(mod_map); i++) { pcm_data = &pdata->pcm[i]; if (!pcm_data->substream) @@ -1109,7 +1109,7 @@ static int hsw_pcm_prepare(struct device *dev) if (pdata->pm_state == HSW_PM_STATE_D3) return 0; /* suspend all active streams */ - for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { + for (i = 0; i < ARRAY_SIZE(mod_map); i++) { pcm_data = &pdata->pcm[i]; if (!pcm_data->substream) @@ -1128,7 +1128,7 @@ static int hsw_pcm_prepare(struct device *dev) sst_hsw_dsp_runtime_suspend(hsw); /* preserve persistent memory */ - for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { + for (i = 0; i < ARRAY_SIZE(mod_map); i++) { pcm_data = &pdata->pcm[i]; if (!pcm_data->substream) From 7ff9d6714a5c97fb448c53aae801af3d529ecb56 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Fri, 9 Jan 2015 14:36:36 +0800 Subject: [PATCH 13/32] ASoC: Intel: Split hsw_pcm_data for playback and capture There may be 2 pcm streams for a same DAI at most, and these 2 streams should have different hsw_pcm_data, e.g. they have different persistent data, so here we need split hsw_pcm_data for playback and capture, to make sure they won't be mixed and keep cleaned. Signed-off-by: Jie Yang Reviewed-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-pcm.c | 91 +++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 5448f79283b7..ad7f4a51e138 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -135,7 +135,17 @@ struct hsw_priv_data { struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; /* DAI data */ - struct hsw_pcm_data pcm[HSW_PCM_COUNT]; + struct hsw_pcm_data pcm[HSW_PCM_COUNT][2]; +}; + + +/* static mappings between PCMs and modules - may be dynamic in future */ +static struct hsw_pcm_module_map mod_map[] = { + {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM}, + {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM}, + {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM}, + {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE}, + {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE}, }; static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data); @@ -168,9 +178,14 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); - struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; u32 volume; + int dai, stream; + + dai = mod_map[mc->reg].dai_id; + stream = mod_map[mc->reg].stream; + pcm_data = &pdata->pcm[dai][stream]; mutex_lock(&pcm_data->mutex); pm_runtime_get_sync(pdata->dev); @@ -212,9 +227,14 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); - struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; u32 volume; + int dai, stream; + + dai = mod_map[mc->reg].dai_id; + stream = mod_map[mc->reg].stream; + pcm_data = &pdata->pcm[dai][stream]; mutex_lock(&pcm_data->mutex); pm_runtime_get_sync(pdata->dev); @@ -309,7 +329,7 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { ARRAY_SIZE(volume_map) - 1, 0, hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), /* Mic Capture volume */ - SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 0, 0, 8, + SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, ARRAY_SIZE(volume_map) - 1, 0, hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), }; @@ -353,7 +373,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(rtd->platform); - struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; struct sst_module *module_data; struct sst_dsp *dsp; @@ -362,7 +382,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, enum sst_hsw_stream_path_id path_id; u32 rate, bits, map, pages, module_id; u8 channels; - int ret; + int ret, dai; + + dai = mod_map[rtd->cpu_dai->id].dai_id; + pcm_data = &pdata->pcm[dai][substream->stream]; /* check if we are being called a subsequent time */ if (pcm_data->allocated) { @@ -552,8 +575,12 @@ static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(rtd->platform); - struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; + int dai; + + dai = mod_map[rtd->cpu_dai->id].dai_id; + pcm_data = &pdata->pcm[dai][substream->stream]; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -597,11 +624,16 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(rtd->platform); - struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; snd_pcm_uframes_t offset; uint64_t ppos; - u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream); + u32 position; + int dai; + + dai = mod_map[rtd->cpu_dai->id].dai_id; + pcm_data = &pdata->pcm[dai][substream->stream]; + position = sst_hsw_get_dsp_position(hsw, pcm_data->stream); offset = bytes_to_frames(runtime, position); ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); @@ -618,8 +650,10 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream) snd_soc_platform_get_drvdata(rtd->platform); struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; + int dai; - pcm_data = &pdata->pcm[rtd->cpu_dai->id]; + dai = mod_map[rtd->cpu_dai->id].dai_id; + pcm_data = &pdata->pcm[dai][substream->stream]; mutex_lock(&pcm_data->mutex); pm_runtime_get_sync(pdata->dev); @@ -648,9 +682,12 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(rtd->platform); - struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); + struct hsw_pcm_data *pcm_data; struct sst_hsw *hsw = pdata->hsw; - int ret; + int ret, dai; + + dai = mod_map[rtd->cpu_dai->id].dai_id; + pcm_data = &pdata->pcm[dai][substream->stream]; mutex_lock(&pcm_data->mutex); ret = sst_hsw_stream_reset(hsw, pcm_data->stream); @@ -685,15 +722,6 @@ static struct snd_pcm_ops hsw_pcm_ops = { .page = snd_pcm_sgbuf_ops_page, }; -/* static mappings between PCMs and modules - may be dynamic in future */ -static struct hsw_pcm_module_map mod_map[] = { - {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM}, - {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM}, - {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM}, - {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE}, - {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE}, -}; - static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) { struct sst_hsw *hsw = pdata->hsw; @@ -701,7 +729,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) int i; for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; /* create new runtime module, use same offset if recreated */ pcm_data->runtime = sst_hsw_runtime_module_create(hsw, @@ -716,7 +744,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) err: for (--i; i >= 0; i--) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; sst_hsw_runtime_module_free(pcm_data->runtime); } @@ -729,7 +757,7 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) int i; for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; sst_hsw_runtime_module_free(pcm_data->runtime); } @@ -757,7 +785,10 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) return ret; } } - priv_data->pcm[rtd->cpu_dai->id].hsw_pcm = pcm; + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) + priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_PLAYBACK].hsw_pcm = pcm; + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) + priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_CAPTURE].hsw_pcm = pcm; return ret; } @@ -866,10 +897,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) /* allocate DSP buffer page tables */ for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { - mutex_init(&priv_data->pcm[i].mutex); - /* playback */ if (hsw_dais[i].playback.channels_min) { + mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_PLAYBACK].mutex); ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, PAGE_SIZE, &priv_data->dmab[i][0]); if (ret < 0) @@ -878,6 +908,7 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) /* capture */ if (hsw_dais[i].capture.channels_min) { + mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_CAPTURE].mutex); ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev, PAGE_SIZE, &priv_data->dmab[i][1]); if (ret < 0) @@ -1076,7 +1107,7 @@ static void hsw_pcm_complete(struct device *dev) } for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; if (!pcm_data->substream) continue; @@ -1110,7 +1141,7 @@ static int hsw_pcm_prepare(struct device *dev) return 0; /* suspend all active streams */ for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; if (!pcm_data->substream) continue; @@ -1129,7 +1160,7 @@ static int hsw_pcm_prepare(struct device *dev) /* preserve persistent memory */ for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[i]; + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; if (!pcm_data->substream) continue; From 9e446ad500db0fd0823990409da17fde9e9cffdc Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 14 Jan 2015 10:48:59 -0200 Subject: [PATCH 14/32] ASoC: fsl_ssi: Change irq type to 'int' Since commit 2ffa531078037a0 ("ASoC: fsl_ssi: Fix module unbound") the irq number is retrieved via platform_get_irq(), which may fail and return a negative number, so adapt its type to 'int'. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index a65f17d57ffb..4a48da5673ce 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -160,7 +160,7 @@ struct fsl_ssi_soc_data { */ struct fsl_ssi_private { struct regmap *regs; - unsigned int irq; + int irq; struct snd_soc_dai_driver cpu_dai_drv; unsigned int dai_fmt; From 7a3a907022439524704caecb717639aea2f1ef9c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 14 Jan 2015 16:39:15 -0200 Subject: [PATCH 15/32] ASoC: fsl: imx-spdif: Set the card owner field Set the card owner field to avoid getting a kernel crash when the imx-spdif is unloaded while the playback is active. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-spdif.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c index e94704f1b9ee..33da26a12457 100644 --- a/sound/soc/fsl/imx-spdif.c +++ b/sound/soc/fsl/imx-spdif.c @@ -60,6 +60,7 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) data->card.dev = &pdev->dev; data->card.dai_link = &data->dai; data->card.num_links = 1; + data->card.owner = THIS_MODULE; ret = snd_soc_of_parse_card_name(&data->card, "model"); if (ret) From a0a7c48fe1a6dc6cae7c589640443bbaaddc28b3 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Mon, 12 Jan 2015 17:17:34 +0800 Subject: [PATCH 16/32] ASoC: Intel: initial stream_hw_id to invalid value The stream_hw_id for System stream is 0x0, if we use initial stream_hw_id value 0, it may return wrong(not committed) stream when calling function get_stream_by_id() with stream_id=0. Here initial stream_hw_id to invalid value to fix this issue. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 3f8c48231364..083292362da6 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -94,6 +94,8 @@ /* Mailbox */ #define IPC_MAX_MAILBOX_BYTES 256 +#define INVALID_STREAM_HW_ID 0xffffffff + /* Global Message - Types and Replies */ enum ipc_glb_type { IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ @@ -1208,6 +1210,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, return NULL; spin_lock_irqsave(&sst->spinlock, flags); + stream->reply.stream_hw_id = INVALID_STREAM_HW_ID; list_add(&stream->node, &hsw->stream_list); stream->notify_position = notify_position; stream->pdata = data; From 5c4ca99df718f6569849ab5fabdf18c14755b144 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 21 Jan 2015 20:50:15 +0800 Subject: [PATCH 17/32] ASoC: rt5645: Add rt5650 codec support This patch adds support for rt5650 codec. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 158 ++++++++++++++++++++++++++++++++++---- sound/soc/codecs/rt5645.h | 15 ++++ 2 files changed, 156 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 27141e2df878..21b2d72b4ea8 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -31,6 +31,7 @@ #include "rt5645.h" #define RT5645_DEVICE_ID 0x6308 +#define RT5650_DEVICE_ID 0x6419 #define RT5645_PR_RANGE_BASE (0xff + 1) #define RT5645_PR_SPACING 0x100 @@ -59,6 +60,10 @@ static const struct reg_default init_list[] = { }; #define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list) +static const struct reg_default rt5650_init_list[] = { + {0xf6, 0x0100}, +}; + static const struct reg_default rt5645_reg[] = { { 0x00, 0x0000 }, { 0x01, 0xc8c8 }, @@ -86,6 +91,7 @@ static const struct reg_default rt5645_reg[] = { { 0x2a, 0x5656 }, { 0x2b, 0x5454 }, { 0x2c, 0xaaa0 }, + { 0x2d, 0x0000 }, { 0x2f, 0x1002 }, { 0x31, 0x5000 }, { 0x32, 0x0000 }, @@ -193,6 +199,8 @@ static const struct reg_default rt5645_reg[] = { { 0xdb, 0x0003 }, { 0xdc, 0x0049 }, { 0xdd, 0x001b }, + { 0xdf, 0x0008 }, + { 0xe0, 0x4000 }, { 0xe6, 0x8000 }, { 0xe7, 0x0200 }, { 0xec, 0xb300 }, @@ -242,6 +250,7 @@ static bool rt5645_volatile_register(struct device *dev, unsigned int reg) case RT5645_IRQ_CTRL3: case RT5645_INT_IRQ_ST: case RT5645_IL_CMD: + case RT5650_4BTN_IL_CMD1: case RT5645_VENDOR_ID: case RT5645_VENDOR_ID1: case RT5645_VENDOR_ID2: @@ -287,6 +296,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg) case RT5645_STO_DAC_MIXER: case RT5645_MONO_DAC_MIXER: case RT5645_DIG_MIXER: + case RT5650_A_DAC_SOUR: case RT5645_DIG_INF1_DATA: case RT5645_PDM_OUT_CTRL: case RT5645_REC_L1_MIXER: @@ -378,6 +388,8 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg) case RT5645_IL_CMD: case RT5645_IL_CMD2: case RT5645_IL_CMD3: + case RT5650_4BTN_IL_CMD1: + case RT5650_4BTN_IL_CMD2: case RT5645_DRC1_HL_CTRL1: case RT5645_DRC2_HL_CTRL1: case RT5645_ADC_MONO_HP_CTRL1: @@ -1007,6 +1019,44 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5645_if1_adc_in_mux = SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum); +/* MX-2d [3] [2] */ +static const char * const rt5650_a_dac1_src[] = { + "DAC1", "Stereo DAC Mixer" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5650_a_dac1_l_enum, RT5650_A_DAC_SOUR, + RT5650_A_DAC1_L_IN_SFT, rt5650_a_dac1_src); + +static const struct snd_kcontrol_new rt5650_a_dac1_l_mux = + SOC_DAPM_ENUM("A DAC1 L source", rt5650_a_dac1_l_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5650_a_dac1_r_enum, RT5650_A_DAC_SOUR, + RT5650_A_DAC1_R_IN_SFT, rt5650_a_dac1_src); + +static const struct snd_kcontrol_new rt5650_a_dac1_r_mux = + SOC_DAPM_ENUM("A DAC1 R source", rt5650_a_dac1_r_enum); + +/* MX-2d [1] [0] */ +static const char * const rt5650_a_dac2_src[] = { + "Stereo DAC Mixer", "Mono DAC Mixer" +}; + +static SOC_ENUM_SINGLE_DECL( + rt5650_a_dac2_l_enum, RT5650_A_DAC_SOUR, + RT5650_A_DAC2_L_IN_SFT, rt5650_a_dac2_src); + +static const struct snd_kcontrol_new rt5650_a_dac2_l_mux = + SOC_DAPM_ENUM("A DAC2 L source", rt5650_a_dac2_l_enum); + +static SOC_ENUM_SINGLE_DECL( + rt5650_a_dac2_r_enum, RT5650_A_DAC_SOUR, + RT5650_A_DAC2_R_IN_SFT, rt5650_a_dac2_src); + +static const struct snd_kcontrol_new rt5650_a_dac2_r_mux = + SOC_DAPM_ENUM("A DAC2 R source", rt5650_a_dac2_r_enum); + /* MX-2F [13:12] */ static const char * const rt5645_if2_adc_in_src[] = { "IF_ADC1", "IF_ADC2", "VAD_ADC" @@ -1151,11 +1201,16 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: hp_amp_power(codec, 1); /* headphone unmute sequence */ - snd_soc_update_bits(codec, RT5645_DEPOP_M3, RT5645_CP_FQ1_MASK | - RT5645_CP_FQ2_MASK | RT5645_CP_FQ3_MASK, - (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) | - (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | - (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT)); + if (rt5645->codec_type == CODEC_TYPE_RT5650) { + snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737); + } else { + snd_soc_update_bits(codec, RT5645_DEPOP_M3, + RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | + RT5645_CP_FQ3_MASK, + (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) | + (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | + (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT)); + } regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_update_bits(codec, RT5645_DEPOP_M1, @@ -1175,12 +1230,16 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMD: /* headphone mute sequence */ - snd_soc_update_bits(codec, RT5645_DEPOP_M3, - RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | - RT5645_CP_FQ3_MASK, - (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) | - (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | - (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT)); + if (rt5645->codec_type == CODEC_TYPE_RT5650) { + snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737); + } else { + snd_soc_update_bits(codec, RT5645_DEPOP_M3, + RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK | + RT5645_CP_FQ3_MASK, + (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) | + (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) | + (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT)); + } regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_update_bits(codec, RT5645_DEPOP_M1, @@ -1574,6 +1633,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("SPOR"), }; +static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = { + SND_SOC_DAPM_MUX("A DAC1 L Mux", SND_SOC_NOPM, + 0, 0, &rt5650_a_dac1_l_mux), + SND_SOC_DAPM_MUX("A DAC1 R Mux", SND_SOC_NOPM, + 0, 0, &rt5650_a_dac1_r_mux), + SND_SOC_DAPM_MUX("A DAC2 L Mux", SND_SOC_NOPM, + 0, 0, &rt5650_a_dac2_l_mux), + SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM, + 0, 0, &rt5650_a_dac2_r_mux), +}; + static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc }, { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc }, @@ -1779,13 +1849,9 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { { "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" }, { "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" }, - { "DAC L1", NULL, "Stereo DAC MIXL" }, { "DAC L1", NULL, "PLL1", is_sys_clk_from_pll }, - { "DAC R1", NULL, "Stereo DAC MIXR" }, { "DAC R1", NULL, "PLL1", is_sys_clk_from_pll }, - { "DAC L2", NULL, "Mono DAC MIXL" }, { "DAC L2", NULL, "PLL1", is_sys_clk_from_pll }, - { "DAC R2", NULL, "Mono DAC MIXR" }, { "DAC R2", NULL, "PLL1", is_sys_clk_from_pll }, { "SPK MIXL", "BST1 Switch", "BST1" }, @@ -1874,6 +1940,30 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { { "SPOR", NULL, "SPK amp" }, }; +static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = { + { "A DAC1 L Mux", "DAC1", "DAC1 MIXL"}, + { "A DAC1 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"}, + { "A DAC1 R Mux", "DAC1", "DAC1 MIXR"}, + { "A DAC1 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"}, + + { "A DAC2 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"}, + { "A DAC2 L Mux", "Mono DAC Mixer", "Mono DAC MIXL"}, + { "A DAC2 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"}, + { "A DAC2 R Mux", "Mono DAC Mixer", "Mono DAC MIXR"}, + + { "DAC L1", NULL, "A DAC1 L Mux" }, + { "DAC R1", NULL, "A DAC1 R Mux" }, + { "DAC L2", NULL, "A DAC2 L Mux" }, + { "DAC R2", NULL, "A DAC2 R Mux" }, +}; + +static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = { + { "DAC L1", NULL, "Stereo DAC MIXL" }, + { "DAC R1", NULL, "Stereo DAC MIXR" }, + { "DAC L2", NULL, "Mono DAC MIXL" }, + { "DAC R2", NULL, "Mono DAC MIXR" }, +}; + static int rt5645_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { @@ -2293,6 +2383,22 @@ static int rt5645_probe(struct snd_soc_codec *codec) rt5645->codec = codec; + switch (rt5645->codec_type) { + case CODEC_TYPE_RT5645: + snd_soc_dapm_add_routes(&codec->dapm, + rt5645_specific_dapm_routes, + ARRAY_SIZE(rt5645_specific_dapm_routes)); + break; + case CODEC_TYPE_RT5650: + snd_soc_dapm_new_controls(&codec->dapm, + rt5650_specific_dapm_widgets, + ARRAY_SIZE(rt5650_specific_dapm_widgets)); + snd_soc_dapm_add_routes(&codec->dapm, + rt5650_specific_dapm_routes, + ARRAY_SIZE(rt5650_specific_dapm_routes)); + break; + } + rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF); snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); @@ -2424,6 +2530,7 @@ static const struct regmap_config rt5645_regmap = { static const struct i2c_device_id rt5645_i2c_id[] = { { "rt5645", 0 }, + { "rt5650", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); @@ -2456,9 +2563,18 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, } regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val); - if (val != RT5645_DEVICE_ID) { + + switch (val) { + case RT5645_DEVICE_ID: + rt5645->codec_type = CODEC_TYPE_RT5645; + break; + case RT5650_DEVICE_ID: + rt5645->codec_type = CODEC_TYPE_RT5650; + break; + default: dev_err(&i2c->dev, - "Device with ID register %x is not rt5645\n", val); + "Device with ID register %x is not rt5645 or rt5650\n", + val); return -ENODEV; } @@ -2469,6 +2585,14 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + if (rt5645->codec_type == CODEC_TYPE_RT5650) { + ret = regmap_register_patch(rt5645->regmap, rt5650_init_list, + ARRAY_SIZE(rt5650_init_list)); + if (ret != 0) + dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n", + ret); + } + if (rt5645->pdata.in2_diff) regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL, RT5645_IN_DF2, RT5645_IN_DF2); diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index a815e36a2bdb..74542310d3f0 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -47,6 +47,7 @@ #define RT5645_STO_DAC_MIXER 0x2a #define RT5645_MONO_DAC_MIXER 0x2b #define RT5645_DIG_MIXER 0x2c +#define RT5650_A_DAC_SOUR 0x2d #define RT5645_DIG_INF1_DATA 0x2f /* Mixer - PDM */ #define RT5645_PDM_OUT_CTRL 0x31 @@ -150,6 +151,8 @@ #define RT5645_IL_CMD 0xdb #define RT5645_IL_CMD2 0xdc #define RT5645_IL_CMD3 0xdd +#define RT5650_4BTN_IL_CMD1 0xdf +#define RT5650_4BTN_IL_CMD2 0xe0 #define RT5645_DRC1_HL_CTRL1 0xe7 #define RT5645_DRC2_HL_CTRL1 0xe9 #define RT5645_MUTI_DRC_CTRL1 0xea @@ -472,6 +475,12 @@ #define RT5645_DAC_L2_DAC_R_VOL_MASK (0x1 << 4) #define RT5645_DAC_L2_DAC_R_VOL_SFT 4 +/* Analog DAC1/2 Input Source Control (0x2d) */ +#define RT5650_A_DAC1_L_IN_SFT 3 +#define RT5650_A_DAC1_R_IN_SFT 2 +#define RT5650_A_DAC2_L_IN_SFT 1 +#define RT5650_A_DAC2_R_IN_SFT 0 + /* Digital Interface Data Control (0x2f) */ #define RT5645_IF1_ADC2_IN_SEL (0x1 << 15) #define RT5645_IF1_ADC2_IN_SFT 15 @@ -2175,6 +2184,11 @@ enum { RT5645_DMIC_DATA_GPIO11, }; +enum { + CODEC_TYPE_RT5645, + CODEC_TYPE_RT5650, +}; + struct rt5645_priv { struct snd_soc_codec *codec; struct rt5645_platform_data pdata; @@ -2184,6 +2198,7 @@ struct rt5645_priv { struct snd_soc_jack *mic_jack; struct delayed_work jack_detect_work; + int codec_type; int sysclk; int sysclk_src; int lrck[RT5645_AIFS]; From c33bd08d65d19288faaf779ff42453075da8f3ba Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 28 Jan 2015 09:42:10 +0300 Subject: [PATCH 18/32] ASoC: Intel: remove an unused struct member We never set the ->scratch pointer, so let's delete it. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 083292362da6..ccd9669bc307 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -277,7 +277,6 @@ struct sst_hsw { /* FW config */ struct sst_hsw_ipc_fw_ready fw_ready; struct sst_hsw_ipc_fw_version version; - struct sst_module *scratch; bool fw_done; struct sst_fw *sst_fw; @@ -2105,7 +2104,6 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, hsw->dx_context, hsw->dx_context_paddr); sst_dsp_free(hsw->dsp); - kfree(hsw->scratch); kthread_stop(hsw->tx_thread); kfree(hsw->msg); } From 842aaa0cbf66621f00d641f5abfd2db40c61320b Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Sat, 31 Jan 2015 15:22:40 -0800 Subject: [PATCH 19/32] ASoC: Intel: Add support rt5645 in sst driver Added entry in sst driver to support rt5645 codec for intel Braswell platform. Signed-off-by: Fang, Yang A Signed-off-by: Mark Brown --- sound/soc/intel/sst/sst_acpi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c index df2b5cc23766..21b22e6a1ccb 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/sst/sst_acpi.c @@ -352,6 +352,8 @@ static struct sst_machines sst_acpi_bytcr[] = { static struct sst_machines sst_acpi_chv[] = { {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "fw_sst_22a8.bin", &chv_platform_data }, + {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "fw_sst_22a8.bin", + &chv_platform_data }, {}, }; From c41cda1dbe50816d839c32271007c7b832d4d14a Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Wed, 4 Feb 2015 20:23:13 +0800 Subject: [PATCH 20/32] ASoC: Intel: initial scalar variable ba Reported by Coverity: CID 1267985 CID 1267986 Fix these two Defects: Uninitialized scalar variable. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/sst-firmware.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index cad6ea179cea..dcc145f81ec9 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c @@ -786,6 +786,7 @@ int sst_module_alloc_blocks(struct sst_module *module) struct sst_block_allocator ba; int ret; + memset(&ba, 0, sizeof(ba)); ba.size = module->size; ba.type = module->type; ba.offset = module->offset; @@ -859,6 +860,7 @@ int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime, if (module->persistent_size == 0) return 0; + memset(&ba, 0, sizeof(ba)); ba.size = module->persistent_size; ba.type = SST_MEM_DRAM; From 26b0aad80a86d39b8c3a3189fbaf477ef92a64ff Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Tue, 3 Feb 2015 10:55:57 +0000 Subject: [PATCH 21/32] ASoC: jz4740: Add dynamic sampling rate support to jz4740-i2s The div clock register is not modified during jz4740_i2s_hw_params. Hence, default sampling rates are actually used regardless of sampling rates input from userspace. This patch adds support to calculate the value of the divider from the parameters passed from userspace and update the relevant div registers Signed-off-by: Zubair Lutfullah Kakakhel Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/jz4740/jz4740-i2s.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index d3d45c6f064f..b7a7e8295d3c 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -83,6 +83,8 @@ #define JZ_AIC_I2S_STATUS_BUSY BIT(2) #define JZ_AIC_CLK_DIV_MASK 0xf +#define I2SDIV_DV_SHIFT 8 +#define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT) struct jz4740_i2s { struct resource *mem; @@ -237,10 +239,14 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, { struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int sample_size; - uint32_t ctrl; + uint32_t ctrl, div_reg; + int div; ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); + div_reg = jz4740_i2s_read(i2s, JZ_REG_AIC_CLK_DIV); + div = clk_get_rate(i2s->clk_i2s) / (64 * params_rate(params)); + switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: sample_size = 0; @@ -264,7 +270,10 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET; } + div_reg &= ~I2SDIV_DV_MASK; + div_reg |= (div - 1) << I2SDIV_DV_SHIFT; jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); + jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg); return 0; } From 6fb4aebee9d128f1c61c3bc9e6a0132b12ab563c Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Tue, 3 Feb 2015 10:55:58 +0000 Subject: [PATCH 22/32] ASoC: jz4740: Add binding documentation for jz4740-i2s This patch adds binding for the jz4740-i2s driver. Signed-off-by: Zubair Lutfullah Kakakhel Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- .../bindings/sound/ingenic,jz4740-i2s.txt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt diff --git a/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt new file mode 100644 index 000000000000..b41433386e2f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt @@ -0,0 +1,23 @@ +Ingenic JZ4740 I2S controller + +Required properties: +- compatible : "ingenic,jz4740-i2s" +- reg : I2S registers location and length +- clocks : AIC and I2S PLL clock specifiers. +- clock-names: "aic" and "i2s" +- dmas: DMA controller phandle and DMA request line for I2S Tx and Rx channels +- dma-names: Must be "tx" and "rx" + +Example: + +i2s: i2s@10020000 { + compatible = "ingenic,jz4740-i2s"; + reg = <0x10020000 0x94>; + + clocks = <&cgu JZ4740_CLK_AIC>, <&cgu JZ4740_CLK_I2SPLL>; + clock-names = "aic", "i2s"; + + dmas = <&dma 2>, <&dma 3>; + dma-names = "tx", "rx"; + +}; From f2610571fd82417f44825f3b705fd651e3788ceb Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Tue, 3 Feb 2015 10:55:59 +0000 Subject: [PATCH 23/32] ASoC: jz4740: Add DT support to jz4740-i2s driver This patch adds device tree support for the jz4740 driver. Signed-off-by: Zubair Lutfullah Kakakhel Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/jz4740/jz4740-i2s.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index b7a7e8295d3c..07f77815a586 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include #include @@ -424,6 +426,13 @@ static const struct snd_soc_component_driver jz4740_i2s_component = { .name = "jz4740-i2s", }; +#ifdef CONFIG_OF +static const struct of_device_id jz4740_of_matches[] = { + { .compatible = "ingenic,jz4740-i2s" }, + { /* sentinel */ } +}; +#endif + static int jz4740_i2s_dev_probe(struct platform_device *pdev) { struct jz4740_i2s *i2s; @@ -464,6 +473,7 @@ static struct platform_driver jz4740_i2s_driver = { .probe = jz4740_i2s_dev_probe, .driver = { .name = "jz4740-i2s", + .of_match_table = of_match_ptr(jz4740_of_matches) }, }; From cd311dd123f5ae5c6da71bdfa9a379a694eb9917 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Thu, 5 Feb 2015 22:56:48 +0800 Subject: [PATCH 24/32] ASoC: Intel: add a status for runtime suspend/resume For runtime suspend/resume, it is some different with suspend/resume, e.g. codec power supply won't be switch off, codec jack detection still working(to wake up system from Jack event), won't call call snd_soc_suspend/resume, etc. So here, we add a platform PM status, HSW_PM_STATE_RTD3, to make the status more clear, when in idle, it will enter this status, to transfer from HSW_PM_STATE_RTD3 to HSW_PM_STATE_D3, we will do those extra jobs, and vice versa for resuming. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-pcm.c | 70 ++++++++++++++++--------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index ad7f4a51e138..78fa01be57f2 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -119,8 +119,9 @@ struct hsw_pcm_data { }; enum hsw_pm_state { - HSW_PM_STATE_D3 = 0, - HSW_PM_STATE_D0 = 1, + HSW_PM_STATE_D0 = 0, + HSW_PM_STATE_RTD3 = 1, + HSW_PM_STATE_D3 = 2, }; /* private data for the driver */ @@ -1035,12 +1036,12 @@ static int hsw_pcm_runtime_suspend(struct device *dev) struct hsw_priv_data *pdata = dev_get_drvdata(dev); struct sst_hsw *hsw = pdata->hsw; - if (pdata->pm_state == HSW_PM_STATE_D3) + if (pdata->pm_state >= HSW_PM_STATE_RTD3) return 0; sst_hsw_dsp_runtime_suspend(hsw); sst_hsw_dsp_runtime_sleep(hsw); - pdata->pm_state = HSW_PM_STATE_D3; + pdata->pm_state = HSW_PM_STATE_RTD3; return 0; } @@ -1051,7 +1052,7 @@ static int hsw_pcm_runtime_resume(struct device *dev) struct sst_hsw *hsw = pdata->hsw; int ret; - if (pdata->pm_state == HSW_PM_STATE_D0) + if (pdata->pm_state != HSW_PM_STATE_RTD3) return 0; ret = sst_hsw_dsp_load(hsw); @@ -1091,7 +1092,7 @@ static void hsw_pcm_complete(struct device *dev) struct hsw_pcm_data *pcm_data; int i, err; - if (pdata->pm_state == HSW_PM_STATE_D0) + if (pdata->pm_state != HSW_PM_STATE_D3) return; err = sst_hsw_dsp_load(hsw); @@ -1139,41 +1140,42 @@ static int hsw_pcm_prepare(struct device *dev) if (pdata->pm_state == HSW_PM_STATE_D3) return 0; - /* suspend all active streams */ - for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; + else if (pdata->pm_state == HSW_PM_STATE_D0) { + /* suspend all active streams */ + for (i = 0; i < ARRAY_SIZE(mod_map); i++) { + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; - if (!pcm_data->substream) - continue; - dev_dbg(dev, "suspending pcm %d\n", i); - snd_pcm_suspend_all(pcm_data->hsw_pcm); + if (!pcm_data->substream) + continue; + dev_dbg(dev, "suspending pcm %d\n", i); + snd_pcm_suspend_all(pcm_data->hsw_pcm); - /* We need to wait until the DSP FW stops the streams */ - msleep(2); + /* We need to wait until the DSP FW stops the streams */ + msleep(2); + } + + /* preserve persistent memory */ + for (i = 0; i < ARRAY_SIZE(mod_map); i++) { + pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; + + if (!pcm_data->substream) + continue; + + dev_dbg(dev, "saving context pcm %d\n", i); + err = sst_module_runtime_save(pcm_data->runtime, + &pcm_data->context); + if (err < 0) + dev_err(dev, "failed to save context for PCM %d\n", i); + } + /* enter D3 state and stall */ + sst_hsw_dsp_runtime_suspend(hsw); + /* put the DSP to sleep */ + sst_hsw_dsp_runtime_sleep(hsw); } snd_soc_suspend(pdata->soc_card->dev); snd_soc_poweroff(pdata->soc_card->dev); - /* enter D3 state and stall */ - sst_hsw_dsp_runtime_suspend(hsw); - - /* preserve persistent memory */ - for (i = 0; i < ARRAY_SIZE(mod_map); i++) { - pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; - - if (!pcm_data->substream) - continue; - - dev_dbg(dev, "saving context pcm %d\n", i); - err = sst_module_runtime_save(pcm_data->runtime, - &pcm_data->context); - if (err < 0) - dev_err(dev, "failed to save context for PCM %d\n", i); - } - - /* put the DSP to sleep */ - sst_hsw_dsp_runtime_sleep(hsw); pdata->pm_state = HSW_PM_STATE_D3; return 0; From 79080a8b42a08fb68a1ea2e036e54a4749edbd43 Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Wed, 4 Feb 2015 18:19:31 -0800 Subject: [PATCH 25/32] ASoC: rt5645: add API to select ASRC clock source This patch defines an API to select the clock source for specified filters. Signed-off-by: Fang, Yang A Acked-by: Kevin Strasser Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 81 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5645.h | 72 +++++++++++++++------------------- 2 files changed, 112 insertions(+), 41 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 21b2d72b4ea8..debf16c5b549 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -613,6 +613,87 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source, } +/** + * rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5645 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + unsigned int asrc2_mask = 0; + unsigned int asrc2_value = 0; + unsigned int asrc3_mask = 0; + unsigned int asrc3_value = 0; + + switch (clk_src) { + case RT5645_CLK_SEL_SYS: + case RT5645_CLK_SEL_I2S1_ASRC: + case RT5645_CLK_SEL_I2S2_ASRC: + case RT5645_CLK_SEL_SYS2: + break; + + default: + return -EINVAL; + } + + if (filter_mask & RT5645_DA_STEREO_FILTER) { + asrc2_mask |= RT5645_DA_STO_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_DA_STO_CLK_SEL_MASK) + | (clk_src << RT5645_DA_STO_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_DA_MONO_L_FILTER) { + asrc2_mask |= RT5645_DA_MONOL_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_DA_MONOL_CLK_SEL_MASK) + | (clk_src << RT5645_DA_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_DA_MONO_R_FILTER) { + asrc2_mask |= RT5645_DA_MONOR_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_DA_MONOR_CLK_SEL_MASK) + | (clk_src << RT5645_DA_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_AD_STEREO_FILTER) { + asrc2_mask |= RT5645_AD_STO1_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5645_AD_STO1_CLK_SEL_MASK) + | (clk_src << RT5645_AD_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_AD_MONO_L_FILTER) { + asrc3_mask |= RT5645_AD_MONOL_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5645_AD_MONOL_CLK_SEL_MASK) + | (clk_src << RT5645_AD_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5645_AD_MONO_R_FILTER) { + asrc3_mask |= RT5645_AD_MONOR_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5645_AD_MONOR_CLK_SEL_MASK) + | (clk_src << RT5645_AD_MONOR_CLK_SEL_SFT); + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5645_ASRC_2, + asrc2_mask, asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5645_ASRC_3, + asrc3_mask, asrc3_value); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5645_sel_asrc_clk_src); + /* Digital Mixer */ static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 74542310d3f0..dbfd98c22f4d 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -1120,50 +1120,27 @@ #define RT5645_DMIC_2_M_NOR (0x0 << 8) #define RT5645_DMIC_2_M_ASYN (0x1 << 8) +/* ASRC clock source selection (0x84, 0x85) */ +#define RT5645_CLK_SEL_SYS (0x0) +#define RT5645_CLK_SEL_I2S1_ASRC (0x1) +#define RT5645_CLK_SEL_I2S2_ASRC (0x2) +#define RT5645_CLK_SEL_SYS2 (0x5) + /* ASRC Control 2 (0x84) */ -#define RT5645_MDA_L_M_MASK (0x1 << 15) -#define RT5645_MDA_L_M_SFT 15 -#define RT5645_MDA_L_M_NOR (0x0 << 15) -#define RT5645_MDA_L_M_ASYN (0x1 << 15) -#define RT5645_MDA_R_M_MASK (0x1 << 14) -#define RT5645_MDA_R_M_SFT 14 -#define RT5645_MDA_R_M_NOR (0x0 << 14) -#define RT5645_MDA_R_M_ASYN (0x1 << 14) -#define RT5645_MAD_L_M_MASK (0x1 << 13) -#define RT5645_MAD_L_M_SFT 13 -#define RT5645_MAD_L_M_NOR (0x0 << 13) -#define RT5645_MAD_L_M_ASYN (0x1 << 13) -#define RT5645_MAD_R_M_MASK (0x1 << 12) -#define RT5645_MAD_R_M_SFT 12 -#define RT5645_MAD_R_M_NOR (0x0 << 12) -#define RT5645_MAD_R_M_ASYN (0x1 << 12) -#define RT5645_ADC_M_MASK (0x1 << 11) -#define RT5645_ADC_M_SFT 11 -#define RT5645_ADC_M_NOR (0x0 << 11) -#define RT5645_ADC_M_ASYN (0x1 << 11) -#define RT5645_STO_DAC_M_MASK (0x1 << 5) -#define RT5645_STO_DAC_M_SFT 5 -#define RT5645_STO_DAC_M_NOR (0x0 << 5) -#define RT5645_STO_DAC_M_ASYN (0x1 << 5) -#define RT5645_I2S1_R_D_MASK (0x1 << 4) -#define RT5645_I2S1_R_D_SFT 4 -#define RT5645_I2S1_R_D_DIS (0x0 << 4) -#define RT5645_I2S1_R_D_EN (0x1 << 4) -#define RT5645_I2S2_R_D_MASK (0x1 << 3) -#define RT5645_I2S2_R_D_SFT 3 -#define RT5645_I2S2_R_D_DIS (0x0 << 3) -#define RT5645_I2S2_R_D_EN (0x1 << 3) -#define RT5645_PRE_SCLK_MASK (0x3) -#define RT5645_PRE_SCLK_SFT 0 -#define RT5645_PRE_SCLK_512 (0x0) -#define RT5645_PRE_SCLK_1024 (0x1) -#define RT5645_PRE_SCLK_2048 (0x2) +#define RT5645_DA_STO_CLK_SEL_MASK (0xf << 12) +#define RT5645_DA_STO_CLK_SEL_SFT 12 +#define RT5645_DA_MONOL_CLK_SEL_MASK (0xf << 8) +#define RT5645_DA_MONOL_CLK_SEL_SFT 8 +#define RT5645_DA_MONOR_CLK_SEL_MASK (0xf << 4) +#define RT5645_DA_MONOR_CLK_SEL_SFT 4 +#define RT5645_AD_STO1_CLK_SEL_MASK (0xf << 0) +#define RT5645_AD_STO1_CLK_SEL_SFT 0 /* ASRC Control 3 (0x85) */ -#define RT5645_I2S1_RATE_MASK (0xf << 12) -#define RT5645_I2S1_RATE_SFT 12 -#define RT5645_I2S2_RATE_MASK (0xf << 8) -#define RT5645_I2S2_RATE_SFT 8 +#define RT5645_AD_MONOL_CLK_SEL_MASK (0xf << 4) +#define RT5645_AD_MONOL_CLK_SEL_SFT 4 +#define RT5645_AD_MONOR_CLK_SEL_MASK (0xf << 0) +#define RT5645_AD_MONOR_CLK_SEL_SFT 0 /* ASRC Control 4 (0x89) */ #define RT5645_I2S1_PD_MASK (0x7 << 12) @@ -2189,6 +2166,19 @@ enum { CODEC_TYPE_RT5650, }; +/* filter mask */ +enum { + RT5645_DA_STEREO_FILTER = 0x1, + RT5645_DA_MONO_L_FILTER = (0x1 << 1), + RT5645_DA_MONO_R_FILTER = (0x1 << 2), + RT5645_AD_STEREO_FILTER = (0x1 << 3), + RT5645_AD_MONO_L_FILTER = (0x1 << 4), + RT5645_AD_MONO_R_FILTER = (0x1 << 5), +}; + +int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); + struct rt5645_priv { struct snd_soc_codec *codec; struct rt5645_platform_data pdata; From e18acdc04ab2c4125ed4020db7f49a8dc35d1979 Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Wed, 4 Feb 2015 18:19:32 -0800 Subject: [PATCH 26/32] ASoC: Intel: Add Cherrytrail & Braswell machine driver cht_bsw_rt5645 Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5645 codec Signed-off-by: Fang, Yang A Acked-by: Vinod Koul Acked-by: Kevin Strasser Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 11 ++ sound/soc/intel/Makefile | 2 + sound/soc/intel/cht_bsw_rt5645.c | 327 +++++++++++++++++++++++++++++++ 3 files changed, 340 insertions(+) create mode 100644 sound/soc/intel/cht_bsw_rt5645.c diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index f06fcf1e21a5..12093fdfd678 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -110,3 +110,14 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH platforms with RT5672 audio codec. Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_CHT_BSW_RT5645_MACH + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645 codec" + depends on X86_INTEL_LPSS + select SND_SOC_RT5645 + select SND_SST_MFLD_PLATFORM + select SND_SST_IPC_ACPI + help + This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell + platforms with RT5645 audio codec. + If unsure select "N". diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index e928ec385300..a8e53c45c6b6 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -28,6 +28,7 @@ snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o +snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o @@ -35,6 +36,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o +obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o # DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c new file mode 100644 index 000000000000..b6f8377b6e33 --- /dev/null +++ b/sound/soc/intel/cht_bsw_rt5645.c @@ -0,0 +1,327 @@ +/* + * cht-bsw-rt5645.c - ASoc Machine driver for Intel Cherryview-based platforms + * Cherrytrail and Braswell, with RT5645 codec. + * + * Copyright (C) 2015 Intel Corp + * Author: Fang, Yang A + * N,Harshapriya + * This file is modified from cht_bsw_rt5672.c + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../codecs/rt5645.h" +#include "sst-atom-controls.h" + +#define CHT_PLAT_CLK_3_HZ 19200000 +#define CHT_CODEC_DAI "rt5645-aif1" + +struct cht_mc_private { + struct snd_soc_jack hp_jack; + struct snd_soc_jack mic_jack; +}; + +static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) +{ + int i; + + for (i = 0; i < card->num_rtd; i++) { + struct snd_soc_pcm_runtime *rtd; + + rtd = card->rtd + i; + if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, + strlen(CHT_CODEC_DAI))) + return rtd->codec_dai; + } + return NULL; +} + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret; + + codec_dai = cht_get_codec_dai(card); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); + return -EIO; + } + + if (!SND_SOC_DAPM_EVENT_OFF(event)) + return 0; + + /* Set codec sysclk source to its internal clock because codec PLL will + * be off when idle and MCLK will also be off by ACPI when codec is + * runtime suspended. Codec needs clock for jack detection and button + * press. + */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route cht_audio_map[] = { + {"IN1P", NULL, "Headset Mic"}, + {"IN1N", NULL, "Headset Mic"}, + {"DMIC L1", NULL, "Int Mic"}, + {"DMIC R1", NULL, "Int Mic"}, + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + {"Ext Spk", NULL, "SPOL"}, + {"Ext Spk", NULL, "SPOR"}, + {"AIF1 Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx" }, + {"codec_in1", NULL, "ssp2 Rx" }, + {"ssp2 Rx", NULL, "AIF1 Capture"}, + {"Headphone", NULL, "Platform Clock"}, + {"Headset Mic", NULL, "Platform Clock"}, + {"Int Mic", NULL, "Platform Clock"}, + {"Ext Spk", NULL, "Platform Clock"}, +}; + +static const struct snd_kcontrol_new cht_mc_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Ext Spk"), +}; + +static int cht_aif1_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 *codec_dai = rtd->codec_dai; + int ret; + + /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK, + CHT_PLAT_CLK_3_HZ, params_rate(params) * 512); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1, + params_rate(params) * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } + + return 0; +} + +static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_codec *codec = runtime->codec; + struct snd_soc_dai *codec_dai = runtime->codec_dai; + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); + + /* Select clk_i2s1_asrc as ASRC clock source */ + rt5645_sel_asrc_clk_src(codec, + RT5645_DA_STEREO_FILTER | + RT5645_DA_MONO_L_FILTER | + RT5645_DA_MONO_R_FILTER | + RT5645_AD_STEREO_FILTER, + RT5645_CLK_SEL_I2S1_ASRC); + + /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); + if (ret < 0) { + dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret); + return ret; + } + + ret = snd_soc_jack_new(codec, "Headphone Jack", + SND_JACK_HEADPHONE, + &ctx->hp_jack); + if (ret) { + dev_err(runtime->dev, "HP jack creation failed %d\n", ret); + return ret; + } + + ret = snd_soc_jack_new(codec, "Mic Jack", + SND_JACK_MICROPHONE, + &ctx->mic_jack); + if (ret) { + dev_err(runtime->dev, "Mic jack creation failed %d\n", ret); + return ret; + } + + rt5645_set_jack_detect(codec, &ctx->hp_jack, &ctx->mic_jack); + + return ret; +} + +static int cht_codec_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); + + /* The DSP will covert the FE rate to 48k, stereo, 24bits */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP2 to 24-bit */ + snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - + SNDRV_PCM_HW_PARAM_FIRST_MASK], + SNDRV_PCM_FORMAT_S24_LE); + return 0; +} + +static unsigned int rates_48000[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_48000 = { + .count = ARRAY_SIZE(rates_48000), + .list = rates_48000, +}; + +static int cht_aif1_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_48000); +} + +static struct snd_soc_ops cht_aif1_ops = { + .startup = cht_aif1_startup, +}; + +static struct snd_soc_ops cht_be_ssp2_ops = { + .hw_params = cht_aif1_hw_params, +}; + +static struct snd_soc_dai_link cht_dailink[] = { + [MERR_DPCM_AUDIO] = { + .name = "Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "media-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .ignore_suspend = 1, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &cht_aif1_ops, + }, + [MERR_DPCM_COMPR] = { + .name = "Compressed Port", + .stream_name = "Compress", + .cpu_dai_name = "compress-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + }, + /* CODEC<->CODEC link */ + /* back ends */ + { + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "rt5645-aif1", + .codec_name = "i2c-10EC5645:00", + .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .init = cht_codec_init, + .be_hw_params_fixup = cht_codec_fixup, + .ignore_suspend = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &cht_be_ssp2_ops, + }, +}; + +/* SoC card */ +static struct snd_soc_card snd_soc_card_cht = { + .name = "chtrt5645", + .dai_link = cht_dailink, + .num_links = ARRAY_SIZE(cht_dailink), + .dapm_widgets = cht_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets), + .dapm_routes = cht_audio_map, + .num_dapm_routes = ARRAY_SIZE(cht_audio_map), + .controls = cht_mc_controls, + .num_controls = ARRAY_SIZE(cht_mc_controls), +}; + +static int snd_cht_mc_probe(struct platform_device *pdev) +{ + int ret_val = 0; + struct cht_mc_private *drv; + + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); + if (!drv) + return -ENOMEM; + + snd_soc_card_cht.dev = &pdev->dev; + snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); + ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); + if (ret_val) { + dev_err(&pdev->dev, + "snd_soc_register_card failed %d\n", ret_val); + return ret_val; + } + platform_set_drvdata(pdev, &snd_soc_card_cht); + return ret_val; +} + +static struct platform_driver snd_cht_mc_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "cht-bsw-rt5645", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_cht_mc_probe, +}; + +module_platform_driver(snd_cht_mc_driver) + +MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver"); +MODULE_AUTHOR("Fang, Yang A,N,Harshapriya"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cht-bsw-rt5645"); From e948262ad01fc683d893abe10d1161231b2a6457 Mon Sep 17 00:00:00 2001 From: Kevin Strasser Date: Wed, 4 Feb 2015 11:35:07 -0800 Subject: [PATCH 27/32] ASoC: Intel: fix sst firmware path All sst firmware is provided under the intel directory of the linux-firmware tree. By default this directory structure is kept when installing on a target system. Change the path to expect a default linux-firmware installation. Signed-off-by: Kevin Strasser Signed-off-by: Mark Brown --- sound/soc/intel/sst/sst_acpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c index 21b22e6a1ccb..378ef3c3042c 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/sst/sst_acpi.c @@ -343,16 +343,16 @@ static int sst_acpi_remove(struct platform_device *pdev) } static struct sst_machines sst_acpi_bytcr[] = { - {"10EC5640", "T100", "bytt100_rt5640", NULL, "fw_sst_0f28.bin", + {"10EC5640", "T100", "bytt100_rt5640", NULL, "intel/fw_sst_0f28.bin", &byt_rvp_platform_data }, {}, }; /* Cherryview-based platforms: CherryTrail and Braswell */ static struct sst_machines sst_acpi_chv[] = { - {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "fw_sst_22a8.bin", + {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin", &chv_platform_data }, - {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "fw_sst_22a8.bin", + {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", &chv_platform_data }, {}, }; From c028d4165fe56fc51efb53dd4b04aa157d005dc5 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Thu, 5 Feb 2015 12:53:38 -0800 Subject: [PATCH 28/32] ASoC: max98357a: Document MAX98357A bindings Add documentation to the sound directory of the device-tree bindings for the Maxim MAX98357A audio DAC. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/max98357a.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/max98357a.txt diff --git a/Documentation/devicetree/bindings/sound/max98357a.txt b/Documentation/devicetree/bindings/sound/max98357a.txt new file mode 100644 index 000000000000..a7a149a236e5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98357a.txt @@ -0,0 +1,14 @@ +Maxim MAX98357A audio DAC + +This node models the Maxim MAX98357A DAC. + +Required properties: +- compatible : "maxim,max98357a" +- sdmode-gpios : GPIO specifier for the GPIO -> DAC SDMODE pin + +Example: + +max98357a { + compatible = "maxim,max98357a"; + sdmode-gpios = <&qcom_pinmux 25 0>; +}; From af5adf129369125bba8fa7ca594a7abaf226b27c Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Thu, 5 Feb 2015 12:53:40 -0800 Subject: [PATCH 29/32] ASoC: max98357a: Add MAX98357A codec driver Add codec driver for the Maxim MAX98357A DAC. Signed-off-by: Kenneth Westfield Acked-by: Banajit Goswami Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/max98357a.c | 138 +++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 sound/soc/codecs/max98357a.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8349f982a586..6ecac1e4428e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -69,6 +69,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98088 if I2C select SND_SOC_MAX98090 if I2C select SND_SOC_MAX98095 if I2C + select SND_SOC_MAX98357A select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9768 if I2C select SND_SOC_MAX9877 if I2C @@ -456,6 +457,9 @@ config SND_SOC_MAX98090 config SND_SOC_MAX98095 tristate +config SND_SOC_MAX98357A + tristate + config SND_SOC_MAX9850 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index bbdfd1e1c182..69b8666d187a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -64,6 +64,7 @@ snd-soc-max9768-objs := max9768.o snd-soc-max98088-objs := max98088.o snd-soc-max98090-objs := max98090.o snd-soc-max98095-objs := max98095.o +snd-soc-max98357a-objs := max98357a.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o @@ -245,6 +246,7 @@ obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o +obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c new file mode 100644 index 000000000000..98b915314d7a --- /dev/null +++ b/sound/soc/codecs/max98357a.c @@ -0,0 +1,138 @@ +/* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * max98357a.c -- MAX98357A ALSA SoC Codec driver + */ + +#include +#include +#include + +#define DRV_NAME "max98357a" + +static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + gpiod_set_value(sdmode, 1); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + gpiod_set_value(sdmode, 0); + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = { + SND_SOC_DAPM_DAC("SDMode", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("Speaker"), +}; + +static const struct snd_soc_dapm_route max98357a_dapm_routes[] = { + {"Speaker", NULL, "SDMode"}, +}; + +static int max98357a_codec_probe(struct snd_soc_codec *codec) +{ + struct gpio_desc *sdmode; + + sdmode = devm_gpiod_get(codec->dev, "sdmode"); + if (IS_ERR(sdmode)) { + dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n", + __func__, PTR_ERR(sdmode)); + return PTR_ERR(sdmode); + } + gpiod_direction_output(sdmode, 0); + snd_soc_codec_set_drvdata(codec, sdmode); + + return 0; +} + +static struct snd_soc_codec_driver max98357a_codec_driver = { + .probe = max98357a_codec_probe, + .dapm_widgets = max98357a_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98357a_dapm_widgets), + .dapm_routes = max98357a_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(max98357a_dapm_routes), +}; + +static struct snd_soc_dai_ops max98357a_dai_ops = { + .trigger = max98357a_daiops_trigger, +}; + +static struct snd_soc_dai_driver max98357a_dai_driver = { + .name = DRV_NAME, + .playback = { + .stream_name = DRV_NAME "-playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &max98357a_dai_ops, +}; + +static int max98357a_platform_probe(struct platform_device *pdev) +{ + int ret; + + ret = snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver, + &max98357a_dai_driver, 1); + if (ret) + dev_err(&pdev->dev, "%s() error registering codec driver: %d\n", + __func__, ret); + + return ret; +} + +static int max98357a_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id max98357a_device_id[] = { + { .compatible = "maxim," DRV_NAME, }, + {} +}; +#endif + +static struct platform_driver max98357a_platform_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(max98357a_device_id), + }, + .probe = max98357a_platform_probe, + .remove = max98357a_platform_remove, +}; +module_platform_driver(max98357a_platform_driver); + +MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, max98357a_device_id); From 5985837e34ba8b0b51357a917e7587df10989a70 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 18 Jan 2015 00:38:46 +0100 Subject: [PATCH 30/32] ASoC: intel: sst-haswell-ipc: Remove unused functions Removes some functions that are not used anywhere: sst_hsw_stream_unmute() sst_hsw_stream_mute() msg_set_stage_type() sst_hsw_dx_get_state() sst_hsw_stream_set_write_position() sst_hsw_stream_get_vol_reg() sst_hsw_stream_get_peak_reg() sst_hsw_stream_get_pointer_reg() sst_hsw_stream_get_read_reg() sst_hsw_stream_get_mixer_id() sst_hsw_stream_get_hw_id() sst_hsw_mixer_set_volume_curve() sst_hsw_mixer_unmute() sst_hsw_mixer_mute() sst_hsw_stream_set_volume_curve() This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 168 ------------------------------ sound/soc/intel/sst-haswell-ipc.h | 31 ------ 2 files changed, 199 deletions(-) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index a282179a3064..0ab1309ef274 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -338,12 +338,6 @@ static inline u32 msg_get_stage_type(u32 msg) return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; } -static inline u32 msg_set_stage_type(u32 msg, u32 type) -{ - return (msg & ~IPC_STG_TYPE_MASK) + - (type << IPC_STG_TYPE_SHIFT); -} - static inline u32 msg_get_stream_id(u32 msg) { return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT; @@ -970,45 +964,6 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw, } /* Mixer Controls */ -int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, - u32 stage_id, u32 channel) -{ - int ret; - - ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel, - &stream->mute_volume[channel]); - if (ret < 0) - return ret; - - ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0); - if (ret < 0) { - dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n", - stream->reply.stream_hw_id, channel); - return ret; - } - - stream->mute[channel] = 1; - return 0; -} - -int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, - u32 stage_id, u32 channel) - -{ - int ret; - - stream->mute[channel] = 0; - ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, - stream->mute_volume[channel]); - if (ret < 0) { - dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n", - stream->reply.stream_hw_id, channel); - return ret; - } - - return 0; -} - int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume) { @@ -1022,17 +977,6 @@ int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream return 0; } -int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u64 curve_duration, - enum sst_hsw_volume_curve curve) -{ - /* curve duration in steps of 100ns */ - stream->vol_req.curve_duration = curve_duration; - stream->vol_req.curve_type = curve; - - return 0; -} - /* stream volume */ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume) @@ -1084,42 +1028,6 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, return 0; } -int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel) -{ - int ret; - - ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel, - &hsw->mute_volume[channel]); - if (ret < 0) - return ret; - - ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0); - if (ret < 0) { - dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n", - channel); - return ret; - } - - hsw->mute[channel] = 1; - return 0; -} - -int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel) -{ - int ret; - - ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, - hsw->mixer_info.volume_register_address[channel]); - if (ret < 0) { - dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n", - channel); - return ret; - } - - hsw->mute[channel] = 0; - return 0; -} - int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, u32 *volume) { @@ -1133,16 +1041,6 @@ int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, return 0; } -int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw, - u64 curve_duration, enum sst_hsw_volume_curve curve) -{ - /* curve duration in steps of 100ns */ - hsw->curve_duration = curve_duration; - hsw->curve_type = curve; - - return 0; -} - /* global mixer volume */ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, u32 volume) @@ -1451,48 +1349,6 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) /* Stream Information - these calls could be inline but we want the IPC ABI to be opaque to client PCM drivers to cope with any future ABI changes */ -int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw, - struct sst_hsw_stream *stream) -{ - return stream->reply.stream_hw_id; -} - -int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw, - struct sst_hsw_stream *stream) -{ - return stream->reply.mixer_hw_id; -} - -u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream) -{ - return stream->reply.read_position_register_address; -} - -u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream) -{ - return stream->reply.presentation_position_register_address; -} - -u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 channel) -{ - if (channel >= 2) - return 0; - - return stream->reply.peak_meter_register_address[channel]; -} - -u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 channel) -{ - if (channel >= 2) - return 0; - - return stream->reply.volume_register_address[channel]; -} - int sst_hsw_mixer_get_info(struct sst_hsw *hsw) { struct sst_hsw_ipc_stream_info_reply *reply; @@ -1630,30 +1486,6 @@ u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, return ppos; } -int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 stage_id, u32 position) -{ - u32 header; - int ret; - - trace_stream_write_position(stream->reply.stream_hw_id, position); - - header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | - IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); - header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); - header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT); - header |= (stage_id << IPC_STG_ID_SHIFT); - stream->wpos.position = position; - - ret = ipc_tx_message_nowait(hsw, header, &stream->wpos, - sizeof(stream->wpos)); - if (ret < 0) - dev_err(hsw->dev, "error: stream %d set position %d failed\n", - stream->reply.stream_hw_id, position); - - return ret; -} - /* physical BE config */ int sst_hsw_device_set_config(struct sst_hsw *hsw, enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk, diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 138e894ab413..c1ad901342f2 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -376,32 +376,17 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw, u32 create_channel_map(enum sst_hsw_channel_config config); /* Stream Mixer Controls - */ -int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, - u32 stage_id, u32 channel); -int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, - u32 stage_id, u32 channel); - int sst_hsw_stream_set_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume); int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume); -int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u64 curve_duration, - enum sst_hsw_volume_curve curve); - /* Global Mixer Controls - */ -int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel); -int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel); - int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, u32 volume); int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, u32 *volume); -int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw, - u64 curve_duration, enum sst_hsw_volume_curve curve); - /* Stream API */ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data), @@ -440,18 +425,6 @@ int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 offset, u32 size); int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 offset, u32 size); -int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw, - struct sst_hsw_stream *stream); -int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw, - struct sst_hsw_stream *stream); -u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream); -u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream); -u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 channel); -u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 channel); int sst_hsw_mixer_get_info(struct sst_hsw *hsw); /* Stream ALSA trigger operations */ @@ -466,8 +439,6 @@ int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 *position); int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw, struct sst_hsw_stream *stream, u32 *position); -int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, - struct sst_hsw_stream *stream, u32 stage_id, u32 position); u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw, struct sst_hsw_stream *stream); u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw, @@ -481,8 +452,6 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, /* DX Config */ int sst_hsw_dx_set_state(struct sst_hsw *hsw, enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx); -int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, - u32 *offset, u32 *size, u32 *source); /* init */ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); From 812e85bb224a088678eb315307d367d91d0b94e2 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sun, 8 Feb 2015 18:35:47 +0800 Subject: [PATCH 31/32] ASoC: Intel: fix platform_no_drv_owner.cocci warnings sound/soc/intel/cht_bsw_rt5645.c:315:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/intel/cht_bsw_rt5645.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c index b6f8377b6e33..bd29617a9ab9 100644 --- a/sound/soc/intel/cht_bsw_rt5645.c +++ b/sound/soc/intel/cht_bsw_rt5645.c @@ -312,7 +312,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) static struct platform_driver snd_cht_mc_driver = { .driver = { - .owner = THIS_MODULE, .name = "cht-bsw-rt5645", .pm = &snd_soc_pm_ops, }, From 3efa130de40e7b2d7c7095683af9571bfef1d3a4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 9 Feb 2015 14:36:47 +0800 Subject: [PATCH 32/32] ASoC: max98357a: Fix build in !CONFIG_OF case Reported-by: Stephen Rothwell Signed-off-by: Mark Brown --- sound/soc/codecs/max98357a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 98b915314d7a..1806333ea29e 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -120,6 +120,7 @@ static const struct of_device_id max98357a_device_id[] = { { .compatible = "maxim," DRV_NAME, }, {} }; +MODULE_DEVICE_TABLE(of, max98357a_device_id); #endif static struct platform_driver max98357a_platform_driver = { @@ -135,4 +136,3 @@ module_platform_driver(max98357a_platform_driver); MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); -MODULE_DEVICE_TABLE(of, max98357a_device_id);