[alsa-devel] [PATCH] ASoC: Intel: Add Cherrytrail & Braswell machine driver cht_bsw_rt5672
From: Mengdong Lin mengdong.lin@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 2a3af88..7479ce0 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -16,6 +16,9 @@ config SND_SST_MFLD_PLATFORM config SND_SST_IPC tristate
+config SND_SST_MACHINE + tristate + config SND_SOC_INTEL_SST tristate "ASoC support for Intel(R) Smart Sound Technology" select SND_SOC_INTEL_SST_ACPI if ACPI @@ -76,3 +79,20 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_CHT_BSW_RT5672_MACH + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" + depends on X86_INTEL_LPSS + select SND_SOC_RT5670 + select SND_SST_MFLD_PLATFORM + select SND_SOC_INTEL_SST + select SND_SST_IPC + select SND_SST_MACHINE + default n + + help + This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell + platforms with RT5672 audio codec. + Say Y if you have such a device + If unsure select "N". + diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 9ab43be..4069d3f 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -31,6 +31,7 @@ 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 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_SST_MACHINE) += board/
# DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/board/Makefile b/sound/soc/intel/board/Makefile new file mode 100644 index 0000000..9ecc227 --- /dev/null +++ b/sound/soc/intel/board/Makefile @@ -0,0 +1,2 @@ +snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o +obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o diff --git a/sound/soc/intel/board/cht_bsw_rt5672.c b/sound/soc/intel/board/cht_bsw_rt5672.c new file mode 100644 index 0000000..dffd8b1 --- /dev/null +++ b/sound/soc/intel/board/cht_bsw_rt5672.c @@ -0,0 +1,286 @@ +/* + * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms + * Cherrytrail and Braswell, with RT5672 codec. + * + * Copyright (C) 2014 Intel Corp + * Author: Subhransu S. Prusty subhransu.s.prusty@intel.com + * Mengdong Lin mengdong.lin@intel.com + * + * 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 <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../../codecs/rt5670.h" +#include "../sst-atom-controls.h" + +#define CHT_PLAT_CLK_3_HZ 19200000 + +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), +}; + +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, "SPOLP"}, + {"Ext Spk", NULL, "SPOLN"}, + {"Ext Spk", NULL, "SPORP"}, + {"Ext Spk", NULL, "SPORN"}, + {"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"}, +}; + +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; + unsigned int fmt; + + if (strncmp(codec_dai->name, "rt5670-aif1", 11)) + return 0; + + /* 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, + SNDRV_PCM_FORMAT_GSM); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret); + return ret; + } + + /* TDM slave Mode */ + fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF + | SND_SOC_DAIFMT_CBS_CFS; + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec DAI fmt %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_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, RT5670_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_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 int cht_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + case SND_SOC_BIAS_STANDBY: + case SND_SOC_BIAS_OFF: + break; + default: + dev_err(card->dev, "Invalid bias level=%d\n", level); + return -EINVAL; + } + card->dapm.bias_level = level; + return 0; +} + +static int cht_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_card *card = runtime->card; + + /* Set card bias level */ + cht_set_bias_level(card, &card->dapm, SND_SOC_BIAS_OFF); + card->dapm.idle_bias_off = true; + + ret = snd_soc_dapm_sync(&card->dapm); + if (ret) { + dev_err(card->dev, "unable to sync dapm\n"); + return ret; + } + return ret; +} + +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[] = { + /* Front End DAI links */ + [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", + .init = cht_init, + .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", + }, + + /* Back End DAI links */ + { + /* SSP2 - Codec */ + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "rt5670-aif1", + .codec_name = "i2c-10EC5670:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .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 = "cherrytrailcraudio", + .dai_link = cht_dailink, + .num_links = ARRAY_SIZE(cht_dailink), + .set_bias_level = cht_set_bias_level, + .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; + + /* register the soc card */ + snd_soc_card_cht.dev = &pdev->dev; + ret_val = snd_soc_register_card(&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 int snd_cht_mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *soc_card = platform_get_drvdata(pdev); + + snd_soc_card_set_drvdata(soc_card, NULL); + snd_soc_unregister_card(soc_card); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver snd_cht_mc_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "cht-bsw-rt5672", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_cht_mc_probe, + .remove = snd_cht_mc_remove, +}; + +module_platform_driver(snd_cht_mc_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); +MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cht-bsw-rt5672");
On Fri, Oct 24, 2014 at 07:14:07PM +0800, mengdong.lin@intel.com wrote:
From: Mengdong Lin mengdong.lin@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
This doesn't seem to have any ACPI stuff - how does the driver get loaded?
+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;
- unsigned int fmt;
- if (strncmp(codec_dai->name, "rt5670-aif1", 11))
return 0;
- /* 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,
SNDRV_PCM_FORMAT_GSM);
- if (ret < 0) {
dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
return ret;
- }
This doesn't depend on the parameters so should be set on init and your use of SNDRV_PCM_FORMAT_GSM doesn't seem to make much sense here - what's going on?
- /* TDM slave Mode */
- fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
| SND_SOC_DAIFMT_CBS_CFS;
- ret = snd_soc_dai_set_fmt(codec_dai, fmt);
- if (ret < 0) {
dev_err(rtd->dev, "can't set codec DAI fmt %d\n", ret);
return ret;
- }
Likewise, set on init (in the dai_link)
+static int cht_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
+{
- switch (level) {
- case SND_SOC_BIAS_ON:
- case SND_SOC_BIAS_PREPARE:
- case SND_SOC_BIAS_STANDBY:
- case SND_SOC_BIAS_OFF:
break;
- default:
dev_err(card->dev, "Invalid bias level=%d\n", level);
return -EINVAL;
- }
- card->dapm.bias_level = level;
- return 0;
+}
This does nothing and can be removed.
+static int cht_init(struct snd_soc_pcm_runtime *runtime) +{
- int ret;
- struct snd_soc_card *card = runtime->card;
- /* Set card bias level */
- cht_set_bias_level(card, &card->dapm, SND_SOC_BIAS_OFF);
- card->dapm.idle_bias_off = true;
- ret = snd_soc_dapm_sync(&card->dapm);
- if (ret) {
dev_err(card->dev, "unable to sync dapm\n");
return ret;
- }
- return ret;
+}
This also does nothing and can be removed.
+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);
+}
If the rates are restricted to 48kHz then is there any need for rate dependent code in hw_params() at all?
+static int snd_cht_mc_remove(struct platform_device *pdev) +{
- struct snd_soc_card *soc_card = platform_get_drvdata(pdev);
- snd_soc_card_set_drvdata(soc_card, NULL);
- snd_soc_unregister_card(soc_card);
- platform_set_drvdata(pdev, NULL);
- return 0;
+}
No need to set the driver data to NULL, the driver core will do it anyway and it's buggy to look at the driver data for unbound devices.
Hi Mark,
-----Original Message----- From: Mark Brown [mailto:broonie@kernel.org] Sent: Saturday, October 25, 2014 12:24 AM
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
This doesn't seem to have any ACPI stuff - how does the driver get loaded?
The ACPI stuff will be upstream later. The machine device will be created by the SST ACPI loader sst-acpi.c, like Broadwell and Baytrail. We're trying to merge ACPI stuff of new machines to the ACPI loader.
+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;
- unsigned int fmt;
- if (strncmp(codec_dai->name, "rt5670-aif1", 11))
return 0;
- /* 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,
SNDRV_PCM_FORMAT_GSM);
- if (ret < 0) {
dev_err(rtd->dev, "can't set codec TDM slot %d\n", ret);
return ret;
- }
This doesn't depend on the parameters so should be set on init and your use of SNDRV_PCM_FORMAT_GSM doesn't seem to make much sense here - what's going on?
Sorry, this is a misuse of SNDRV_PCM_FORMAT_GSM which happen to be 24 I'll correct this to snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24) , create a dai_link init function cht_codec_init() and move the code there.
- /* TDM slave Mode */
- fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
| SND_SOC_DAIFMT_CBS_CFS;
- ret = snd_soc_dai_set_fmt(codec_dai, fmt);
- if (ret < 0) {
dev_err(rtd->dev, "can't set codec DAI fmt %d\n", ret);
return ret;
- }
Likewise, set on init (in the dai_link)
I'll move it to back end dai link .dai_fmt as below: .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS,
+static int cht_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
+{
- switch (level) {
- case SND_SOC_BIAS_ON:
- case SND_SOC_BIAS_PREPARE:
- case SND_SOC_BIAS_STANDBY:
- case SND_SOC_BIAS_OFF:
break;
- default:
dev_err(card->dev, "Invalid bias level=%d\n", level);
return -EINVAL;
- }
- card->dapm.bias_level = level;
- return 0;
+}
This does nothing and can be removed.
Okay.
+static int cht_init(struct snd_soc_pcm_runtime *runtime) {
- int ret;
- struct snd_soc_card *card = runtime->card;
- /* Set card bias level */
- cht_set_bias_level(card, &card->dapm, SND_SOC_BIAS_OFF);
- card->dapm.idle_bias_off = true;
- ret = snd_soc_dapm_sync(&card->dapm);
- if (ret) {
dev_err(card->dev, "unable to sync dapm\n");
return ret;
- }
- return ret;
+}
This also does nothing and can be removed.
Okay.
+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);
+}
If the rates are restricted to 48kHz then is there any need for rate dependent code in hw_params() at all?
Currently, we only tested 48kHz, but later will support 8KHz and 16KHz for VoIP application. So hw_params() be reserved for reuse later?
+static int snd_cht_mc_remove(struct platform_device *pdev) {
- struct snd_soc_card *soc_card = platform_get_drvdata(pdev);
- snd_soc_card_set_drvdata(soc_card, NULL);
- snd_soc_unregister_card(soc_card);
- platform_set_drvdata(pdev, NULL);
- return 0;
+}
No need to set the driver data to NULL, the driver core will do it anyway and it's buggy to look at the driver data for unbound devices.
Okay.
Thanks for your review! I'll submit the v2 patch based on your comment. But I lost the message ID of my original patch, sorry for this.
Regards Mengdong
From: Mengdong Lin mengdong.lin@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 2a3af88..7479ce0 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -16,6 +16,9 @@ config SND_SST_MFLD_PLATFORM config SND_SST_IPC tristate
+config SND_SST_MACHINE + tristate + config SND_SOC_INTEL_SST tristate "ASoC support for Intel(R) Smart Sound Technology" select SND_SOC_INTEL_SST_ACPI if ACPI @@ -76,3 +79,20 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_CHT_BSW_RT5672_MACH + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" + depends on X86_INTEL_LPSS + select SND_SOC_RT5670 + select SND_SST_MFLD_PLATFORM + select SND_SOC_INTEL_SST + select SND_SST_IPC + select SND_SST_MACHINE + default n + + help + This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell + platforms with RT5672 audio codec. + Say Y if you have such a device + If unsure select "N". + diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 9ab43be..4069d3f 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -31,6 +31,7 @@ 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 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_SST_MACHINE) += board/
# DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/board/Makefile b/sound/soc/intel/board/Makefile new file mode 100644 index 0000000..9ecc227 --- /dev/null +++ b/sound/soc/intel/board/Makefile @@ -0,0 +1,2 @@ +snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o +obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o diff --git a/sound/soc/intel/board/cht_bsw_rt5672.c b/sound/soc/intel/board/cht_bsw_rt5672.c new file mode 100644 index 0000000..789d1a0 --- /dev/null +++ b/sound/soc/intel/board/cht_bsw_rt5672.c @@ -0,0 +1,246 @@ +/* + * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms + * Cherrytrail and Braswell, with RT5672 codec. + * + * Copyright (C) 2014 Intel Corp + * Author: Subhransu S. Prusty subhransu.s.prusty@intel.com + * Mengdong Lin mengdong.lin@intel.com + * + * 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 <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../../codecs/rt5670.h" +#include "../sst-atom-controls.h" + +#define CHT_PLAT_CLK_3_HZ 19200000 + +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), +}; + +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, "SPOLP"}, + {"Ext Spk", NULL, "SPOLN"}, + {"Ext Spk", NULL, "SPORP"}, + {"Ext Spk", NULL, "SPORN"}, + {"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"}, +}; + +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; + + if (strncmp(codec_dai->name, "rt5670-aif1", 11)) + return 0; + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_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, RT5670_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_dai *codec_dai = runtime->codec_dai; + + /* 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; + } + + return 0; +} + +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[] = { + /* Front End DAI links */ + [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", + }, + + /* Back End DAI links */ + { + /* SSP2 - Codec */ + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "rt5670-aif1", + .codec_name = "i2c-10EC5670: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 = "cherrytrailcraudio", + .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; + + /* register the soc card */ + snd_soc_card_cht.dev = &pdev->dev; + ret_val = snd_soc_register_card(&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 int snd_cht_mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *soc_card = platform_get_drvdata(pdev); + + snd_soc_unregister_card(soc_card); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver snd_cht_mc_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "cht-bsw-rt5672", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_cht_mc_probe, + .remove = snd_cht_mc_remove, +}; + +module_platform_driver(snd_cht_mc_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); +MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cht-bsw-rt5672");
On Tue, Oct 28, 2014 at 07:30:32PM +0800, mengdong.lin@intel.com wrote:
+config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
depends on X86_INTEL_LPSS
select SND_SOC_RT5670
select SND_SST_MFLD_PLATFORM
select SND_SOC_INTEL_SST
select SND_SST_IPC
select SND_SST_MACHINE
default n
n is the default anyway.
+obj-$(CONFIG_SND_SST_MACHINE) += board/
It's a bit weird to have the Kconfig in the root Intel directory if the boards are getting moved into a subdirectory - why not just source a Kconfig in the board directory?
+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;
- if (strncmp(codec_dai->name, "rt5670-aif1", 11))
return 0;
11 is a magic number! Why not use strlen() here (and why do we do nothing in the AIF1 hw_params() if we're working with AIF1)?
- ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_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, RT5670_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;
- }
Nothing ever stops the PLL - a set_bias_level() callback with a handler for _OFF. Otherwise we're wasting power.
- snd_soc_card_cht.dev = &pdev->dev;
- ret_val = snd_soc_register_card(&snd_soc_card_cht);
- if (ret_val) {
devm_snd_soc_register_card() and the removal function can go entirely.
-----Original Message----- From: Mark Brown [mailto:broonie@kernel.org] Sent: Wednesday, October 29, 2014 12:48 AM
+config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with
RT5672 codec"
depends on X86_INTEL_LPSS
select SND_SOC_RT5670
select SND_SST_MFLD_PLATFORM
select SND_SOC_INTEL_SST
select SND_SST_IPC
select SND_SST_MACHINE
default n
n is the default anyway.
Will remove " default n"
+obj-$(CONFIG_SND_SST_MACHINE) += board/
It's a bit weird to have the Kconfig in the root Intel directory if the boards are getting moved into a subdirectory - why not just source a Kconfig in the board directory?
Will source a Kconfig in the board directory.
+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;
- if (strncmp(codec_dai->name, "rt5670-aif1", 11))
return 0;
11 is a magic number! Why not use strlen() here (and why do we do nothing in the AIF1 hw_params() if we're working with AIF1)?
It not necessary. Will remove.
- ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_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, RT5670_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;
- }
Nothing ever stops the PLL - a set_bias_level() callback with a handler for _OFF. Otherwise we're wasting power.
Can we introduce a power supply widget for the platform clock used as MCLK? That widget can be added into the playback and capture path. So when idle, the platform clock can be turn off and let the codec PLL selects its internal low frequency clock only for jack detection. It's verified internally.
The platform clock driver is not upstream yet, so in the widget control we can't really turn off the MCLK output to codec, but at least we can let the codec PLL no longer locked to the high frequency MCLK.
Or we don't change the code at moment, until we upstream the platform clock driver at first?
Which way is better?
- snd_soc_card_cht.dev = &pdev->dev;
- ret_val = snd_soc_register_card(&snd_soc_card_cht);
- if (ret_val) {
devm_snd_soc_register_card() and the removal function can go entirely.
Okay.
Thanks Mengdong
On Wed, Oct 29, 2014 at 06:45:05AM +0000, Lin, Mengdong wrote:
Nothing ever stops the PLL - a set_bias_level() callback with a handler for _OFF. Otherwise we're wasting power.
Can we introduce a power supply widget for the platform clock used as MCLK? That widget can be added into the playback and capture path. So when idle, the platform clock can be turn off and let the codec PLL selects its internal low frequency clock only for jack detection. It's verified internally.
That should be fine also, it's just usually a bit more work to add all the routes for DAPM.
Or we don't change the code at moment, until we upstream the platform clock driver at first?
Which way is better?
Well, currently the code to load the driver is also not upstream so may as well have the driver be what's wanted! But it's not a massive deal, main thing would be to get everything done as part of initial upstreaming instead of having to come back and work on it again later.
+ Liam.
-----Original Message----- From: Mark Brown [mailto:broonie@kernel.org] Sent: Wednesday, October 29, 2014 6:31 PM
Nothing ever stops the PLL - a set_bias_level() callback with a handler for
_OFF.
Otherwise we're wasting power.
Can we introduce a power supply widget for the platform clock used as
MCLK?
That widget can be added into the playback and capture path. So when idle, the platform clock can be turn off and let the codec PLL selects its internal low frequency clock only for jack detection. It's verified
internally.
That should be fine also, it's just usually a bit more work to add all the routes for DAPM.
Or we don't change the code at moment, until we upstream the platform clock driver at first?
Which way is better?
Well, currently the code to load the driver is also not upstream so may as well have the driver be what's wanted! But it's not a massive deal, main thing would be to get everything done as part of initial upstreaming instead of having to come back and work on it again later.
Now we're working with Realtek to enable runtime PM on RT5672 codec driver. With help of ACPI, - the codec will be in suspended to D3 when idle , switch to its internal clock, and BIOS will turn off the platform clock output (MCLK) to save power. - And when the codec resumes to D0, BIOS will turn on the clock at first. And hw_params will make the codec use PLL and lock to MCLK again.
Thus the machine driver does not need to explicitly turn on/off the platform codec by itself.
Thanks Mengdong
On Fri, Oct 31, 2014 at 12:48:26PM +0000, Lin, Mengdong wrote:
Now we're working with Realtek to enable runtime PM on RT5672 codec driver. With help of ACPI,
- the codec will be in suspended to D3 when idle , switch to its internal clock,
and BIOS will turn off the platform clock output (MCLK) to save power.
- And when the codec resumes to D0, BIOS will turn on the clock at first. And
hw_params will make the codec use PLL and lock to MCLK again.
Thus the machine driver does not need to explicitly turn on/off the platform codec by itself.
If the machine driver has asked for the PLL to be on I'd expect the CODEC driver to be respecting that...
-----Original Message----- From: Mark Brown [mailto:broonie@kernel.org] Sent: Friday, October 31, 2014 8:54 PM
On Fri, Oct 31, 2014 at 12:48:26PM +0000, Lin, Mengdong wrote:
Now we're working with Realtek to enable runtime PM on RT5672 codec
driver.
With help of ACPI,
- the codec will be in suspended to D3 when idle , switch to its
internal clock, and BIOS will turn off the platform clock output (MCLK) to
save power.
- And when the codec resumes to D0, BIOS will turn on the clock at
first. And hw_params will make the codec use PLL and lock to MCLK again.
Thus the machine driver does not need to explicitly turn on/off the platform codec by itself.
If the machine driver has asked for the PLL to be on I'd expect the CODEC driver to be respecting that...
The codec driver rt5670 defines a supply widget to control the power of PLL. So the PLL will be power on when there is active audio streaming and power off when Idle. The machine driver need not explicitly turn on/off the PLL, but only need to select PLL source to MCLK in hw_params and configure the in/out frequency.
And we've verified to enable runtime PM on the codec driver and trigger ACPI method to dynamically control the MCLK output from SOC to the codec: - When codec is active (D0), BIOS will turn on MCLK at first - When codec is suspended on idle (D3), codec will switch to its internal clock, and BIOS will turn off MCLK
I'll post V3 machine driver based on your comments on v2. After an internal sync, this machine driver will be moved to sound/soc/intel directory, with other existing Intel machines.
Thanks Mengdong
Hi Mark,
I've posted the v3 patch. Would you please have a review?
There are other Intel machine drivers submitted at the same time, hope they can be integrated smoothly to avoid conflict on Kconfig and Makefile.
Thanks Mengdong
-----Original Message----- From: alsa-devel-bounces@alsa-project.org [mailto:alsa-devel-bounces@alsa-project.org] On Behalf Of Lin, Mengdong Sent: Monday, November 03, 2014 8:11 PM To: Mark Brown Cc: Koul, Vinod; alsa-devel@alsa-project.org; Prusty, Subhransu S; Girdwood, Liam R Subject: Re: [alsa-devel] [PATCH v2] ASoC: Intel: Add Cherrytrail & Braswell machine driver cht_bsw_rt5672
-----Original Message----- From: Mark Brown [mailto:broonie@kernel.org] Sent: Friday, October 31, 2014 8:54 PM
On Fri, Oct 31, 2014 at 12:48:26PM +0000, Lin, Mengdong wrote:
Now we're working with Realtek to enable runtime PM on RT5672 codec
driver.
With help of ACPI,
- the codec will be in suspended to D3 when idle , switch to its
internal clock, and BIOS will turn off the platform clock output (MCLK) to
save power.
- And when the codec resumes to D0, BIOS will turn on the clock at
first. And hw_params will make the codec use PLL and lock to MCLK again.
Thus the machine driver does not need to explicitly turn on/off the platform codec by itself.
If the machine driver has asked for the PLL to be on I'd expect the CODEC driver to be respecting that...
The codec driver rt5670 defines a supply widget to control the power of PLL. So the PLL will be power on when there is active audio streaming and power off when Idle. The machine driver need not explicitly turn on/off the PLL, but only need to select PLL source to MCLK in hw_params and configure the in/out frequency.
And we've verified to enable runtime PM on the codec driver and trigger ACPI method to dynamically control the MCLK output from SOC to the codec:
- When codec is active (D0), BIOS will turn on MCLK at first
- When codec is suspended on idle (D3), codec will switch to its internal clock,
and BIOS will turn off MCLK
I'll post V3 machine driver based on your comments on v2. After an internal sync, this machine driver will be moved to sound/soc/intel directory, with other existing Intel machines.
Thanks Mengdong _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On Tue, Nov 04, 2014 at 03:15:15PM +0530, Lin, Mengdong wrote:
Hi Mark,
I've posted the v3 patch. Would you please have a review?
There are other Intel machine drivers submitted at the same time, hope they can be integrated smoothly to avoid conflict on Kconfig and Makefile.
Mengdong, I am about to send v3 series of my driver changes. Should I add this driver in my series to avoid merge conflict in Kconfig?
-----Original Message----- From: Koul, Vinod Sent: Tuesday, November 04, 2014 6:23 PM To: Lin, Mengdong Cc: Mark Brown; alsa-devel@alsa-project.org; Prusty, Subhransu S; Girdwood, Liam R Subject: Re: [PATCH v2] ASoC: Intel: Add Cherrytrail & Braswell machine driver cht_bsw_rt5672
On Tue, Nov 04, 2014 at 03:15:15PM +0530, Lin, Mengdong wrote:
Hi Mark,
I've posted the v3 patch. Would you please have a review?
There are other Intel machine drivers submitted at the same time, hope they can be integrated smoothly to avoid conflict on Kconfig and Makefile.
Mengdong, I am about to send v3 series of my driver changes. Should I add this driver in my series to avoid merge conflict in Kconfig?
Okay, please. It will help to avoid merge conflict.
Thanks Mengdong
On Tue, Nov 04, 2014 at 09:45:15AM +0000, Lin, Mengdong wrote:
Hi Mark,
I've posted the v3 patch. Would you please have a review?
You only posted it yesterday. Please allow reasonable time for review, demanding a review within a day is not reasonable and will only annoy maintainers.
-----Original Message----- From: alsa-devel-bounces@alsa-project.org [mailto:alsa-devel-bounces@alsa-project.org] On Behalf Of Mark Brown Sent: Tuesday, November 04, 2014 7:47 PM To: Lin, Mengdong Cc: Koul, Vinod; alsa-devel@alsa-project.org; Prusty, Subhransu S; Girdwood, Liam R Subject: Re: [alsa-devel] [PATCH v2] ASoC: Intel: Add Cherrytrail & Braswell machine driver cht_bsw_rt5672
On Tue, Nov 04, 2014 at 09:45:15AM +0000, Lin, Mengdong wrote:
Hi Mark,
I've posted the v3 patch. Would you please have a review?
You only posted it yesterday. Please allow reasonable time for review, demanding a review within a day is not reasonable and will only annoy maintainers.
I'm sorry for this. Vinod is posting other Intel machine drivers at the same time now. He will add this machine driver in his v3 patch series to avoid conflict in Kconfig and Makefile.
Thanks Mengdong
From: Mengdong Lin mengdong.lin@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 2a3af88..86cae96 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -76,3 +76,18 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_CHT_BSW_RT5672_MACH + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" + depends on X86_INTEL_LPSS + select SND_SOC_RT5670 + select SND_SST_MFLD_PLATFORM + select SND_SOC_INTEL_SST + select SND_SST_IPC + + help + This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell + platforms with RT5672 audio codec. + Say Y if you have such a device + If unsure select "N". + diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 9ab43be..5939b56 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -26,11 +26,13 @@ snd-soc-sst-haswell-objs := haswell.o snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o snd-soc-sst-broadwell-objs := broadwell.o +snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.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 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_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
# DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c new file mode 100644 index 0000000..aa9bf5a --- /dev/null +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -0,0 +1,233 @@ +/* + * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms + * Cherrytrail and Braswell, with RT5672 codec. + * + * Copyright (C) 2014 Intel Corp + * Author: Subhransu S. Prusty subhransu.s.prusty@intel.com + * Mengdong Lin mengdong.lin@intel.com + * + * 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 <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../codecs/rt5670.h" +#include "sst-atom-controls.h" + +#define CHT_PLAT_CLK_3_HZ 19200000 + +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), +}; + +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, "SPOLP"}, + {"Ext Spk", NULL, "SPOLN"}, + {"Ext Spk", NULL, "SPORP"}, + {"Ext Spk", NULL, "SPORN"}, + {"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"}, +}; + +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; + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_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, RT5670_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_dai *codec_dai = runtime->codec_dai; + + /* 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; + } + + return 0; +} + +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[] = { + /* Front End DAI links */ + [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", + }, + + /* Back End DAI links */ + { + /* SSP2 - Codec */ + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "rt5670-aif1", + .codec_name = "i2c-10EC5670: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 = "cherrytrailcraudio", + .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; + + /* register the soc card */ + snd_soc_card_cht.dev = &pdev->dev; + 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-rt5672", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_cht_mc_probe, +}; + +module_platform_driver(snd_cht_mc_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); +MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cht-bsw-rt5672");
From: Mengdong Lin mengdong.lin@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a992e85..0a02d88 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -86,3 +86,17 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_CHT_BSW_RT5672_MACH + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" + depends on X86_INTEL_LPSS + select SND_SOC_RT5670 + select SND_SST_MFLD_PLATFORM + select SND_SOC_INTEL_SST + select SND_SST_IPC_ACPI + + help + This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell + platforms with RT5672 audio codec. + Say Y if you have such a device + If unsure select "N". diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 9ab43be..5939b56 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -26,11 +26,13 @@ snd-soc-sst-haswell-objs := haswell.o snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o snd-soc-sst-broadwell-objs := broadwell.o +snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.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 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_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
# DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c new file mode 100644 index 0000000..9b8b561 --- /dev/null +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -0,0 +1,285 @@ +/* + * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms + * Cherrytrail and Braswell, with RT5672 codec. + * + * Copyright (C) 2014 Intel Corp + * Author: Subhransu S. Prusty subhransu.s.prusty@intel.com + * Mengdong Lin mengdong.lin@intel.com + * + * 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 <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../codecs/rt5670.h" +#include "sst-atom-controls.h" + +/* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ +#define CHT_PLAT_CLK_3_HZ 19200000 +#define CHT_CODEC_DAI "rt5670-aif1" + +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; + + 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. + */ + snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, + 0, SND_SOC_CLOCK_IN); + + 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, "SPOLP"}, + {"Ext Spk", NULL, "SPOLN"}, + {"Ext Spk", NULL, "SPORP"}, + {"Ext Spk", NULL, "SPORN"}, + {"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, RT5670_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; + } + + /* set codec sysclk source to PLL */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_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_dai *codec_dai = runtime->codec_dai; + + /* 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; + } + + return 0; +} + +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[] = { + /* Front End DAI links */ + [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", + }, + + /* Back End DAI links */ + { + /* SSP2 - Codec */ + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "rt5670-aif1", + .codec_name = "i2c-10EC5670: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 = "cherrytrailcraudio", + .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; + + /* register the soc card */ + snd_soc_card_cht.dev = &pdev->dev; + 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-rt5672", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_cht_mc_probe, +}; + +module_platform_driver(snd_cht_mc_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); +MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cht-bsw-rt5672");
On Mon, Nov 17, 2014 at 05:34:09PM +0800, mengdong.lin@intel.com wrote:
From: Mengdong Lin mengdong.lin@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a992e85..0a02d88 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -86,3 +86,17 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y if you have such a device If unsure select "N".
+config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
depends on X86_INTEL_LPSS
select SND_SOC_RT5670
select SND_SST_MFLD_PLATFORM
select SND_SOC_INTEL_SST
This is not correct, it could have been SND_INTEL_IPC but that is selected by below entry so adding SND_SST_IPC_ACPI is enough.
select SND_SST_IPC_ACPI
-----Original Message----- From: Koul, Vinod Sent: Monday, November 17, 2014 11:35 PM
On Mon, Nov 17, 2014 at 05:34:09PM +0800, mengdong.lin@intel.com wrote:
From: Mengdong Lin mengdong.lin@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a992e85..0a02d88 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -86,3 +86,17 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y if you have such a device If unsure select "N".
+config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with
RT5672 codec"
depends on X86_INTEL_LPSS
select SND_SOC_RT5670
select SND_SST_MFLD_PLATFORM
select SND_SOC_INTEL_SST
This is not correct, it could have been SND_INTEL_IPC but that is selected by below entry so adding SND_SST_IPC_ACPI is enough.
select SND_SST_IPC_ACPI
I removed the SND_SOC_INTEL_SST and keep SND_SST_IPC_ACPI in v5 of this patch. Thanks for pointing out this!
Mengdong
From: Mengdong Lin mengdong.lin@intel.com
This patch add ACPI device ID and platform data for two Cherryview-based platforms, Cherrytrail and Braswell. Also reuse mfld driver ops in sst driver.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c index b2b5604..2be4f3f 100644 --- a/sound/soc/intel/sst/sst.c +++ b/sound/soc/intel/sst/sst.c @@ -183,6 +183,7 @@ int sst_driver_ops(struct intel_sst_drv *sst) switch (sst->dev_id) { case SST_MRFLD_PCI_ID: case SST_BYT_ACPI_ID: + case SST_CHV_ACPI_ID: sst->tstamp = SST_TIME_STAMP_MRFLD; sst->ops = &mrfld_ops; return 0; diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h index 683dc71..7f4bbfc 100644 --- a/sound/soc/intel/sst/sst.h +++ b/sound/soc/intel/sst/sst.h @@ -30,6 +30,7 @@ #define SST_DRV_NAME "intel_sst_driver" #define SST_MRFLD_PCI_ID 0x119A #define SST_BYT_ACPI_ID 0x80860F28 +#define SST_CHV_ACPI_ID 0x808622A8
#define SST_SUSPEND_DELAY 2000 #define FW_CONTEXT_MEM (64*1024) diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c index b261821..c2e5edf 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/sst/sst_acpi.c @@ -129,6 +129,17 @@ struct sst_platform_info byt_rvp_platform_data = { .platform = "sst-mfld-platform", };
+/* Cherryview (Cherrytrail and Braswell) uses same mrfld dpcm fw as Baytrail, + * so pdata is same as Baytrail. + */ +struct sst_platform_info chv_platform_data = { + .probe_data = &byt_fwparse_info, + .ipc_info = &byt_ipc_info, + .lib_info = &byt_lib_dnld_info, + .res_info = &byt_rvp_res_info, + .platform = "sst-mfld-platform", +}; + static int sst_platform_get_resources(struct intel_sst_drv *ctx) { struct resource *rsrc; @@ -337,8 +348,16 @@ static struct sst_machines sst_acpi_bytcr[] = { {}, };
+/* Cherryview-based platforms: CherryTrail and Braswell */ +static struct sst_machines sst_acpi_chv[] = { + {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "fw_sst_22a8.bin", + &chv_platform_data }, + {}, +}; + static const struct acpi_device_id sst_acpi_ids[] = { { "80860F28", (unsigned long)&sst_acpi_bytcr}, + { "808622A8", (unsigned long) &sst_acpi_chv}, { }, };
On Mon, Nov 17, 2014 at 05:34:27PM +0800, mengdong.lin@intel.com wrote:
From: Mengdong Lin mengdong.lin@intel.com
This patch add ACPI device ID and platform data for two Cherryview-based platforms, Cherrytrail and Braswell. Also reuse mfld driver ops in sst driver.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com
Acked-by: Vinod Koul vinod.koul@intel.com
From: Mengdong Lin mengdong.lin@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a992e85..8c8ccff 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -86,3 +86,15 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_CHT_BSW_RT5672_MACH + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" + depends on X86_INTEL_LPSS + select SND_SOC_RT5670 + 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 RT5672 audio codec. + Say Y if you have such a device + If unsure select "N". diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 9ab43be..5939b56 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -26,11 +26,13 @@ snd-soc-sst-haswell-objs := haswell.o snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o snd-soc-sst-broadwell-objs := broadwell.o +snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.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 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_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
# DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c new file mode 100644 index 0000000..9b8b561 --- /dev/null +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -0,0 +1,285 @@ +/* + * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms + * Cherrytrail and Braswell, with RT5672 codec. + * + * Copyright (C) 2014 Intel Corp + * Author: Subhransu S. Prusty subhransu.s.prusty@intel.com + * Mengdong Lin mengdong.lin@intel.com + * + * 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 <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../codecs/rt5670.h" +#include "sst-atom-controls.h" + +/* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ +#define CHT_PLAT_CLK_3_HZ 19200000 +#define CHT_CODEC_DAI "rt5670-aif1" + +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; + + 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. + */ + snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, + 0, SND_SOC_CLOCK_IN); + + 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, "SPOLP"}, + {"Ext Spk", NULL, "SPOLN"}, + {"Ext Spk", NULL, "SPORP"}, + {"Ext Spk", NULL, "SPORN"}, + {"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, RT5670_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; + } + + /* set codec sysclk source to PLL */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_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_dai *codec_dai = runtime->codec_dai; + + /* 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; + } + + return 0; +} + +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[] = { + /* Front End DAI links */ + [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", + }, + + /* Back End DAI links */ + { + /* SSP2 - Codec */ + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "rt5670-aif1", + .codec_name = "i2c-10EC5670: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 = "cherrytrailcraudio", + .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; + + /* register the soc card */ + snd_soc_card_cht.dev = &pdev->dev; + 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-rt5672", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_cht_mc_probe, +}; + +module_platform_driver(snd_cht_mc_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); +MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cht-bsw-rt5672");
From: Mengdong Lin mengdong.lin@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com Acked-by: Vinod Koul vinod.koul@intel.com
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a26e8e8..e989ecf 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -98,3 +98,15 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH used as alsa device in audio substem in Intel(R) MID devices Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_CHT_BSW_RT5672_MACH + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" + depends on X86_INTEL_LPSS + select SND_SOC_RT5670 + 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 RT5672 audio codec. + Say Y if you have such a device + If unsure select "N". diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index fbde4b07..e928ec3 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -27,12 +27,14 @@ snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o 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
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 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
# DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c new file mode 100644 index 0000000..9b8b561 --- /dev/null +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -0,0 +1,285 @@ +/* + * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms + * Cherrytrail and Braswell, with RT5672 codec. + * + * Copyright (C) 2014 Intel Corp + * Author: Subhransu S. Prusty subhransu.s.prusty@intel.com + * Mengdong Lin mengdong.lin@intel.com + * + * 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 <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../codecs/rt5670.h" +#include "sst-atom-controls.h" + +/* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ +#define CHT_PLAT_CLK_3_HZ 19200000 +#define CHT_CODEC_DAI "rt5670-aif1" + +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; + + 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. + */ + snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, + 0, SND_SOC_CLOCK_IN); + + 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, "SPOLP"}, + {"Ext Spk", NULL, "SPOLN"}, + {"Ext Spk", NULL, "SPORP"}, + {"Ext Spk", NULL, "SPORN"}, + {"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, RT5670_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; + } + + /* set codec sysclk source to PLL */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_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_dai *codec_dai = runtime->codec_dai; + + /* 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; + } + + return 0; +} + +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[] = { + /* Front End DAI links */ + [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", + }, + + /* Back End DAI links */ + { + /* SSP2 - Codec */ + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "rt5670-aif1", + .codec_name = "i2c-10EC5670: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 = "cherrytrailcraudio", + .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; + + /* register the soc card */ + snd_soc_card_cht.dev = &pdev->dev; + 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-rt5672", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_cht_mc_probe, +}; + +module_platform_driver(snd_cht_mc_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); +MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cht-bsw-rt5672");
On Fri, Nov 21, 2014 at 04:08:59PM +0800, mengdong.lin@intel.com wrote:
From: Mengdong Lin mengdong.lin@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with RT5672 codec.
Applied both, thanks.
From: Mengdong Lin mengdong.lin@intel.com
This patch add ACPI device ID and platform data for two Cherryview-based platforms, Cherrytrail and Braswell. Also reuse mfld driver ops in sst driver.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com Acked-by: Vinod Koul vinod.koul@intel.com
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c index b2b5604..2be4f3f 100644 --- a/sound/soc/intel/sst/sst.c +++ b/sound/soc/intel/sst/sst.c @@ -183,6 +183,7 @@ int sst_driver_ops(struct intel_sst_drv *sst) switch (sst->dev_id) { case SST_MRFLD_PCI_ID: case SST_BYT_ACPI_ID: + case SST_CHV_ACPI_ID: sst->tstamp = SST_TIME_STAMP_MRFLD; sst->ops = &mrfld_ops; return 0; diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h index 683dc71..7f4bbfc 100644 --- a/sound/soc/intel/sst/sst.h +++ b/sound/soc/intel/sst/sst.h @@ -30,6 +30,7 @@ #define SST_DRV_NAME "intel_sst_driver" #define SST_MRFLD_PCI_ID 0x119A #define SST_BYT_ACPI_ID 0x80860F28 +#define SST_CHV_ACPI_ID 0x808622A8
#define SST_SUSPEND_DELAY 2000 #define FW_CONTEXT_MEM (64*1024) diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c index b261821..c2e5edf 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/sst/sst_acpi.c @@ -129,6 +129,17 @@ struct sst_platform_info byt_rvp_platform_data = { .platform = "sst-mfld-platform", };
+/* Cherryview (Cherrytrail and Braswell) uses same mrfld dpcm fw as Baytrail, + * so pdata is same as Baytrail. + */ +struct sst_platform_info chv_platform_data = { + .probe_data = &byt_fwparse_info, + .ipc_info = &byt_ipc_info, + .lib_info = &byt_lib_dnld_info, + .res_info = &byt_rvp_res_info, + .platform = "sst-mfld-platform", +}; + static int sst_platform_get_resources(struct intel_sst_drv *ctx) { struct resource *rsrc; @@ -337,8 +348,16 @@ static struct sst_machines sst_acpi_bytcr[] = { {}, };
+/* Cherryview-based platforms: CherryTrail and Braswell */ +static struct sst_machines sst_acpi_chv[] = { + {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "fw_sst_22a8.bin", + &chv_platform_data }, + {}, +}; + static const struct acpi_device_id sst_acpi_ids[] = { { "80860F28", (unsigned long)&sst_acpi_bytcr}, + { "808622A8", (unsigned long) &sst_acpi_chv}, { }, };
participants (4)
-
Lin, Mengdong
-
Mark Brown
-
mengdong.lin@intel.com
-
Vinod Koul