[alsa-devel] [PATCH 1/4] ASoC: Intel: Add support max98090 in sst driver
From: "Fang, Yang A" yang.a.fang@intel.com
Added entry in sst driver to support max98090 codec for intel Braswell platform.
Signed-off-by: Fang, Yang A yang.a.fang@intel.com --- sound/soc/intel/atom/sst/sst_acpi.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index fc02a48..bb19b58 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -356,6 +356,8 @@ static struct sst_machines sst_acpi_chv[] = { &chv_platform_data }, {"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", &chv_platform_data }, + {"193C9890", "cht-bsw", "cht-bsw-max98090", NULL, + "intel/fw_sst_22a8.bin", &chv_platform_data }, {}, };
From: "Fang, Yang A" yang.a.fang@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with max98090 codec.
Signed-off-by: Fang, Yang A yang.a.fang@intel.com --- sound/soc/intel/Kconfig | 12 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/cht_bsw_max98090.c | 286 +++++++++++++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 sound/soc/intel/boards/cht_bsw_max98090.c
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index c181a6a..5789a07 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -121,3 +121,15 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5645/5650 audio codec. If unsure select "N". + +config SND_SOC_INTEL_CHT_BSW_MAX98090_MACH + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 codec" + depends on X86_INTEL_LPSS + select SND_SOC_MAX98090 + select SND_SOC_TS3A227E + 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 MAX98090 audio codec. + If unsure select "N". diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index f8237f0..51ec4d1 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -5,6 +5,7 @@ snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o +snd-soc-sst-cht-bsw-max98090-objs := cht_bsw_max98090.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 @@ -13,3 +14,4 @@ obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-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 +obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_MACH) += snd-soc-sst-cht-bsw-max98090.o diff --git a/sound/soc/intel/boards/cht_bsw_max98090.c b/sound/soc/intel/boards/cht_bsw_max98090.c new file mode 100644 index 0000000..ccbbbc5 --- /dev/null +++ b/sound/soc/intel/boards/cht_bsw_max98090.c @@ -0,0 +1,286 @@ +/* + * cht-bsw-max98090.c - ASoc Machine driver for Intel Cherryview-based + * platforms Cherrytrail and Braswell, with max98090 codec. + * + * Copyright (C) 2015 Intel Corp + * Author: Fang, Yang A yang.a.fang@intel.com + * This file is modified from cht_bsw_rt5645.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 <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 <sound/jack.h> +#include "../../codecs/max98090.h" +#include "../atom/sst-atom-controls.h" +#include "../../codecs/ts3a227e.h" + +#define CHT_PLAT_CLK_3_HZ 19200000 +#define CHT_CODEC_DAI "HiFi" + +struct cht_mc_private { + struct snd_soc_jack 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 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[] = { + {"IN34", NULL, "Headset Mic"}, + {"Headset Mic", NULL, "MICBIAS"}, + {"DMICL", NULL, "Int Mic"}, + {"Headphone", NULL, "HPL"}, + {"Headphone", NULL, "HPR"}, + {"Ext Spk", NULL, "SPKL"}, + {"Ext Spk", NULL, "SPKR"}, + {"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_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK, + CHT_PLAT_CLK_3_HZ, 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 cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); + struct snd_soc_jack *jack = &ctx->jack; + + ret = snd_soc_card_jack_new(runtime->card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, jack, NULL, 0); + + if (ret) { + dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + 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); + int ret = 0; + unsigned int fmt = 0; + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16); + if (ret < 0) { + dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret); + return ret; + } + + fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS; + + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt); + if (ret < 0) { + dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret); + return ret; + } + + /* 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 int cht_max98090_headset_init(struct snd_soc_component *component) +{ + struct snd_soc_card *card = component->card; + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); + + return ts3a227e_enable_jack_detect(component, &ctx->jack); +} + +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_aux_dev cht_max98090_headset_dev = { + .name = "Headset Chip", + .init = cht_max98090_headset_init, + .codec_name = "i2c-104C227E:00", +}; + +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", + .nonatomic = true, + .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 ends */ + { + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "HiFi", + .codec_name = "i2c-193C9890:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .init = cht_codec_init, + .be_hw_params_fixup = cht_codec_fixup, + .nonatomic = true, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &cht_be_ssp2_ops, + }, +}; + +/* SoC card */ +static struct snd_soc_card snd_soc_card_cht = { + .name = "chtmax98090", + .dai_link = cht_dailink, + .num_links = ARRAY_SIZE(cht_dailink), + .aux_dev = &cht_max98090_headset_dev, + .num_aux_devs = 1, + .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; + + /* register the soc card */ + 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 = { + .name = "cht-bsw-max98090", + }, + .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 yang.a.fang@intel.com"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cht-bsw-max98090");
On Wed, Apr 29, 2015 at 06:43:56PM -0700, yang.a.fang@intel.com wrote:
From: "Fang, Yang A" yang.a.fang@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with max98090 codec.
Signed-off-by: Fang, Yang A yang.a.fang@intel.com
sound/soc/intel/Kconfig | 12 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/cht_bsw_max98090.c | 286 +++++++++++++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 sound/soc/intel/boards/cht_bsw_max98090.c
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index c181a6a..5789a07 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -121,3 +121,15 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5645/5650 audio codec. If unsure select "N".
+config SND_SOC_INTEL_CHT_BSW_MAX98090_MACH
- tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 codec"
- depends on X86_INTEL_LPSS
- select SND_SOC_MAX98090
- select SND_SOC_TS3A227E
- 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 MAX98090 audio codec.
If unsure select "N".
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index f8237f0..51ec4d1 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -5,6 +5,7 @@ snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o +snd-soc-sst-cht-bsw-max98090-objs := cht_bsw_max98090.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 @@ -13,3 +14,4 @@ obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-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 +obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_MACH) += snd-soc-sst-cht-bsw-max98090.o diff --git a/sound/soc/intel/boards/cht_bsw_max98090.c b/sound/soc/intel/boards/cht_bsw_max98090.c new file mode 100644 index 0000000..ccbbbc5 --- /dev/null +++ b/sound/soc/intel/boards/cht_bsw_max98090.c @@ -0,0 +1,286 @@ +/*
- cht-bsw-max98090.c - ASoc Machine driver for Intel Cherryview-based
- platforms Cherrytrail and Braswell, with max98090 codec.
- Copyright (C) 2015 Intel Corp
- Author: Fang, Yang A yang.a.fang@intel.com
- This file is modified from cht_bsw_rt5645.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 <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 <sound/jack.h> +#include "../../codecs/max98090.h" +#include "../atom/sst-atom-controls.h" +#include "../../codecs/ts3a227e.h"
+#define CHT_PLAT_CLK_3_HZ 19200000 +#define CHT_CODEC_DAI "HiFi"
+struct cht_mc_private {
- struct snd_soc_jack 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 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[] = {
- {"IN34", NULL, "Headset Mic"},
- {"Headset Mic", NULL, "MICBIAS"},
- {"DMICL", NULL, "Int Mic"},
- {"Headphone", NULL, "HPL"},
- {"Headphone", NULL, "HPR"},
- {"Ext Spk", NULL, "SPKL"},
- {"Ext Spk", NULL, "SPKR"},
- {"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_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK,
CHT_PLAT_CLK_3_HZ, 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 cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
- struct snd_soc_jack *jack = &ctx->jack;
- ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, jack, NULL, 0);
Do you really support all those buttons?
- if (ret) {
dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret);
return ret;
- }
- 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);
- int ret = 0;
- unsigned int fmt = 0;
- ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16);
- if (ret < 0) {
dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret);
return ret;
- }
- fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS;
- ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt);
- if (ret < 0) {
dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret);
return ret;
- }
- /* 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 int cht_max98090_headset_init(struct snd_soc_component *component) +{
- struct snd_soc_card *card = component->card;
- struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
- return ts3a227e_enable_jack_detect(component, &ctx->jack);
+}
+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_aux_dev cht_max98090_headset_dev = {
- .name = "Headset Chip",
- .init = cht_max98090_headset_init,
- .codec_name = "i2c-104C227E:00",
+};
+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",
.nonatomic = true,
.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 ends */
- {
.name = "SSP2-Codec",
.be_id = 1,
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
.codec_dai_name = "HiFi",
.codec_name = "i2c-193C9890:00",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS,
.init = cht_codec_init,
.be_hw_params_fixup = cht_codec_fixup,
.nonatomic = true,
this doesnt make sense for BEs
On Thu, Apr 30, 2015 at 10:06:52AM +0530, Vinod Koul wrote:
On Wed, Apr 29, 2015 at 06:43:56PM -0700, yang.a.fang@intel.com wrote:
From: "Fang, Yang A" yang.a.fang@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with max98090 codec.
Signed-off-by: Fang, Yang A yang.a.fang@intel.com
sound/soc/intel/Kconfig | 12 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/cht_bsw_max98090.c | 286 +++++++++++++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 sound/soc/intel/boards/cht_bsw_max98090.c
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index c181a6a..5789a07 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -121,3 +121,15 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5645/5650 audio codec. If unsure select "N".
+config SND_SOC_INTEL_CHT_BSW_MAX98090_MACH
- tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 codec"
- depends on X86_INTEL_LPSS
- select SND_SOC_MAX98090
- select SND_SOC_TS3A227E
- 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 MAX98090 audio codec.
If unsure select "N".
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index f8237f0..51ec4d1 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -5,6 +5,7 @@ snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o +snd-soc-sst-cht-bsw-max98090-objs := cht_bsw_max98090.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 @@ -13,3 +14,4 @@ obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-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 +obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_MACH) += snd-soc-sst-cht-bsw-max98090.o diff --git a/sound/soc/intel/boards/cht_bsw_max98090.c b/sound/soc/intel/boards/cht_bsw_max98090.c new file mode 100644 index 0000000..ccbbbc5 --- /dev/null +++ b/sound/soc/intel/boards/cht_bsw_max98090.c @@ -0,0 +1,286 @@ +/*
- cht-bsw-max98090.c - ASoc Machine driver for Intel Cherryview-based
- platforms Cherrytrail and Braswell, with max98090 codec.
- Copyright (C) 2015 Intel Corp
- Author: Fang, Yang A yang.a.fang@intel.com
- This file is modified from cht_bsw_rt5645.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 <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 <sound/jack.h> +#include "../../codecs/max98090.h" +#include "../atom/sst-atom-controls.h" +#include "../../codecs/ts3a227e.h"
+#define CHT_PLAT_CLK_3_HZ 19200000 +#define CHT_CODEC_DAI "HiFi"
+struct cht_mc_private {
- struct snd_soc_jack 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 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[] = {
- {"IN34", NULL, "Headset Mic"},
- {"Headset Mic", NULL, "MICBIAS"},
- {"DMICL", NULL, "Int Mic"},
- {"Headphone", NULL, "HPL"},
- {"Headphone", NULL, "HPR"},
- {"Ext Spk", NULL, "SPKL"},
- {"Ext Spk", NULL, "SPKR"},
- {"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_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK,
CHT_PLAT_CLK_3_HZ, 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 cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
- struct snd_soc_jack *jack = &ctx->jack;
- ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, jack, NULL, 0);
Do you really support all those buttons?
TI driver supports 4 buttons sound/soc/codecs/ts3a227e.c google made 4 buttons headsets
- if (ret) {
dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret);
return ret;
- }
- 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);
- int ret = 0;
- unsigned int fmt = 0;
- ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16);
- if (ret < 0) {
dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret);
return ret;
- }
- fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS;
- ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt);
- if (ret < 0) {
dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret);
return ret;
- }
- /* 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 int cht_max98090_headset_init(struct snd_soc_component *component) +{
- struct snd_soc_card *card = component->card;
- struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
- return ts3a227e_enable_jack_detect(component, &ctx->jack);
+}
+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_aux_dev cht_max98090_headset_dev = {
- .name = "Headset Chip",
- .init = cht_max98090_headset_init,
- .codec_name = "i2c-104C227E:00",
+};
+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",
.nonatomic = true,
.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 ends */
- {
.name = "SSP2-Codec",
.be_id = 1,
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
.codec_dai_name = "HiFi",
.codec_name = "i2c-193C9890:00",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS,
.init = cht_codec_init,
.be_hw_params_fixup = cht_codec_fixup,
.nonatomic = true,
this doesnt make sense for BEs
-- ~Vinod
this is taking the fix from below commit for another braswell machine driver
commit 76ca1c2cd8fc0b8764c6360263e2fbca43495ab2 Author: Vinod Koul vinod.koul@intel.com Date: Thu Feb 12 09:59:54 2015 +0530
ASoC: Intel: mark cht machine driver with nonatomic trigger
The DSP messages are sent with nonatomic context, which include trigger messages, so mark the driver as nonatomic
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com Signed-off-by: Mark Brown broonie@kernel.org
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c
.dpcm_playback = 1,
.dpcm_capture = 1,
.ops = &cht_be_ssp2_ops,
- },
+};
+/* SoC card */ +static struct snd_soc_card snd_soc_card_cht = {
- .name = "chtmax98090",
- .dai_link = cht_dailink,
- .num_links = ARRAY_SIZE(cht_dailink),
- .aux_dev = &cht_max98090_headset_dev,
- .num_aux_devs = 1,
- .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;
- /* register the soc card */
- 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 = {
.name = "cht-bsw-max98090",
- },
- .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 yang.a.fang@intel.com"); +MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cht-bsw-max98090");
1.7.9.5
--
- ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, jack, NULL, 0);
Do you really support all those buttons?
TI driver supports 4 buttons sound/soc/codecs/ts3a227e.c google made 4 buttons headsets
Not every codec is capable of handling 4 buttons. That TI codec was made specifically to detect 4 different levels of impedance. Looking at the Max98090, I see support for a single button press (change in the status of JKSNS). what makes you think you can handle 4 buttons in the codec hardware?
On Thu, Apr 30, 2015 at 8:40 AM, Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com wrote:
ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE
|
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, jack,
NULL, 0);
Do you really support all those buttons?
TI driver supports 4 buttons sound/soc/codecs/ts3a227e.c google made 4 buttons headsets
Not every codec is capable of handling 4 buttons. That TI codec was made specifically to detect 4 different levels of impedance. Looking at the Max98090, I see support for a single button press (change in the status of JKSNS). what makes you think you can handle 4 buttons in the codec hardware?
The 98090 isn't involved in the button or jack detection in this case. The ts3a227e handles all jack and button events and posts them to the jack.
On 4/30/15 11:39 AM, Dylan Reid wrote:
On Thu, Apr 30, 2015 at 8:40 AM, Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com wrote:
ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE
|
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, jack,
NULL, 0);
Do you really support all those buttons?
TI driver supports 4 buttons sound/soc/codecs/ts3a227e.c google made 4 buttons headsets
Not every codec is capable of handling 4 buttons. That TI codec was made specifically to detect 4 different levels of impedance. Looking at the Max98090, I see support for a single button press (change in the status of JKSNS). what makes you think you can handle 4 buttons in the codec hardware?
The 98090 isn't involved in the button or jack detection in this case. The ts3a227e handles all jack and button events and posts them to the jack.
ok, got it. Thanks for the clarification. Maybe the commit message could be state this dependency, it's not like the other machine drivers we've seen so far, there are only 4 lines in the patch where this TI chip is mentioned.
-----Original Message----- From: Pierre-Louis Bossart [mailto:pierre-louis.bossart@linux.intel.com] Sent: Thursday, April 30, 2015 8:40 AM To: Fang, Yang A; Koul, Vinod Cc: alsa-devel@alsa-project.org; Jain, Praveen K; Diwakar, Praveen; lgirdwood@gmail.com; Iriawan, Denny; broonie@kernel.org; kevin.strasser@linux.intel.com; dgreid@chromium.org Subject: Re: [alsa-devel] [PATCH 2/4] ASoC: Intel: Add Cherrytrail & Braswell machine driver cht_bsw_max98090
- ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
SND_JACK_HEADPHONE |
SND_JACK_MICROPHONE |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, jack,
NULL, 0);
Do you really support all those buttons?
TI driver supports 4 buttons sound/soc/codecs/ts3a227e.c google made 4 buttons headsets
Not every codec is capable of handling 4 buttons. That TI codec was made specifically to detect 4 different levels of impedance. Looking at the Max98090, I see support for a single button press (change in the status of JKSNS). what makes you think you can handle 4 buttons in the codec hardware?
This machine driver will also probe TI driver as an aux device. So Ti driver will handle Buttons event .
Thanks, Yang
On Wed, Apr 29, 2015 at 11:24:18PM -0700, Yang Fang wrote:
- /* back ends */
- {
.name = "SSP2-Codec",
.be_id = 1,
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
.codec_dai_name = "HiFi",
.codec_name = "i2c-193C9890:00",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS,
.init = cht_codec_init,
.be_hw_params_fixup = cht_codec_fixup,
.nonatomic = true,
this doesnt make sense for BEs
this is taking the fix from below commit for another braswell machine driver
Thanks for pinting, it makes sense for FE dailinks where trigger ops are invoked. Not for BE dailinks. I will get it removed from BE one
On Wed, Apr 29, 2015 at 06:43:56PM -0700, yang.a.fang@intel.com wrote:
From: "Fang, Yang A" yang.a.fang@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with max98090 codec.
This and the first patch are basically fine modulo the comments that Vinod and Pierre raised.
On Wed, Apr 29, 2015 at 06:43:56PM -0700, yang.a.fang@intel.com wrote:
From: "Fang, Yang A" yang.a.fang@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell, with max98090 codec.
Actually now I think about it one thing here: this isn't a generic driver for this combination of parts - it's specific to the Chromebook since it relies on their TI headphone amp/button detect device. This makes Pierre's concern about documentation even more pressing, and probably the driver should have an appropriate name.
Of course given that the ACPI ID appears likely to be reused by non-Chromebooks that have the same Maxim CODEC things might get a bit fun - I'd suggest trying to find something more Chromebook specific to match on, or quirking he presence of the TI device.
From: "Fang, Yang A" yang.a.fang@intel.com
Added entry in sst driver to support max98090 codec for intel Braswell platform.
Signed-off-by: Fang, Yang A yang.a.fang@intel.com --- sound/soc/intel/atom/sst/sst_acpi.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index fc02a48..bb19b58 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -356,6 +356,8 @@ static struct sst_machines sst_acpi_chv[] = { &chv_platform_data }, {"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", &chv_platform_data }, + {"193C9890", "cht-bsw", "cht-bsw-max98090", NULL, + "intel/fw_sst_22a8.bin", &chv_platform_data }, {}, };
From: "Fang, Yang A" yang.a.fang@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell. This machine driver will support max98090 codec as primary codec. it can also support TI jack detect chip as aux device if platform supports it.
Signed-off-by: Fang, Yang A yang.a.fang@intel.com --- sound/soc/intel/Kconfig | 12 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/cht_bsw_max98090_ti.c | 320 ++++++++++++++++++++++++++ 3 files changed, 334 insertions(+) create mode 100644 sound/soc/intel/boards/cht_bsw_max98090_ti.c
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index c181a6a..4419d76 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -121,3 +121,15 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with RT5645/5650 audio codec. If unsure select "N". + +config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH + tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec" + depends on X86_INTEL_LPSS + select SND_SOC_MAX98090 + select SND_SOC_TS3A227E + 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 MAX98090 audio codec it also can support TI jack chip as aux device. + If unsure select "N". diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index f8237f0..cb94895 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -5,6 +5,7 @@ snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o +snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.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 @@ -13,3 +14,4 @@ obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-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 +obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c new file mode 100644 index 0000000..3c518b1 --- /dev/null +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -0,0 +1,320 @@ +/* + * cht-bsw-max98090.c - ASoc Machine driver for Intel Cherryview-based + * platforms Cherrytrail and Braswell, with max98090 & TI codec. + * + * Copyright (C) 2015 Intel Corp + * Author: Fang, Yang A yang.a.fang@intel.com + * This file is modified from cht_bsw_rt5645.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 <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/acpi.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include "../../codecs/max98090.h" +#include "../atom/sst-atom-controls.h" +#include "../../codecs/ts3a227e.h" + +#define CHT_PLAT_CLK_3_HZ 19200000 +#define CHT_CODEC_DAI "HiFi" + +struct cht_mc_private { + struct snd_soc_jack jack; + bool ts3a227e_present; +}; + +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 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[] = { + {"IN34", NULL, "Headset Mic"}, + {"Headset Mic", NULL, "MICBIAS"}, + {"DMICL", NULL, "Int Mic"}, + {"Headphone", NULL, "HPL"}, + {"Headphone", NULL, "HPR"}, + {"Ext Spk", NULL, "SPKL"}, + {"Ext Spk", NULL, "SPKR"}, + {"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_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK, + CHT_PLAT_CLK_3_HZ, 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; + int jack_type; + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); + struct snd_soc_jack *jack = &ctx->jack; + + /** + * TI supports 4 butons headset detection + * KEY_MEDIA + * KEY_VOICECOMMAND + * KEY_VOLUMEUP + * KEY_VOLUMEDOWN + */ + if (ctx->ts3a227e_present) + jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3; + else + jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE; + + ret = snd_soc_card_jack_new(runtime->card, "Headset Jack", + jack_type, jack, NULL, 0); + + if (ret) { + dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + 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); + int ret = 0; + unsigned int fmt = 0; + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16); + if (ret < 0) { + dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret); + return ret; + } + + fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS; + + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt); + if (ret < 0) { + dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret); + return ret; + } + + /* 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 int cht_max98090_headset_init(struct snd_soc_component *component) +{ + struct snd_soc_card *card = component->card; + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); + + return ts3a227e_enable_jack_detect(component, &ctx->jack); +} + +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_aux_dev cht_max98090_headset_dev = { + .name = "Headset Chip", + .init = cht_max98090_headset_init, + .codec_name = "i2c-104C227E:00", +}; + +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", + .nonatomic = true, + .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 ends */ + { + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "HiFi", + .codec_name = "i2c-193C9890:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .init = cht_codec_init, + .be_hw_params_fixup = cht_codec_fixup, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &cht_be_ssp2_ops, + }, +}; + +/* SoC card */ +static struct snd_soc_card snd_soc_card_cht = { + .name = "chtmax98090", + .dai_link = cht_dailink, + .num_links = ARRAY_SIZE(cht_dailink), + .aux_dev = &cht_max98090_headset_dev, + .num_aux_devs = 1, + .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 acpi_status snd_acpi_codec_match(acpi_handle handle, u32 level, + void *context, void **ret) +{ + *(bool *)context = true; + return AE_OK; +} + +static int snd_cht_mc_probe(struct platform_device *pdev) +{ + int ret_val = 0; + bool found = false; + struct cht_mc_private *drv; + + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); + if (!drv) + return -ENOMEM; + + if (ACPI_SUCCESS(acpi_get_devices( + "104C227E", + snd_acpi_codec_match, + &found, NULL)) && found) { + drv->ts3a227e_present = true; + } else { + /* no need probe TI jack detection chip */ + snd_soc_card_cht.aux_dev = NULL; + snd_soc_card_cht.num_aux_devs = 0; + drv->ts3a227e_present = false; + } + + /* register the soc card */ + 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 = { + .name = "cht-bsw-max98090", + }, + .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 yang.a.fang@intel.com"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cht-bsw-max98090");
On Fri, May 01, 2015 at 11:42:03AM -0700, yang.a.fang@intel.com wrote:
From: "Fang, Yang A" yang.a.fang@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell. This machine driver will support max98090 codec as primary codec. it can also support TI jack detect chip as aux device if platform supports it.
Applied, thanks - but this seems like it was against something other than mainline since it didn't immediately apply.
-----Original Message----- From: Mark Brown [mailto:broonie@kernel.org] Sent: Monday, May 04, 2015 5:18 AM To: Fang, Yang A Cc: lgirdwood@gmail.com; alsa-devel@alsa-project.org; Koul, Vinod; Diwakar, Praveen; dgreid@chromium.org; kevin.strasser@linux.intel.com; Jain, Praveen K; Iriawan, Denny; Nujella, Sathyanarayana; Sripathi, Srinivas Subject: Re: [PATCH v2 2/2] ASoC: Intel: Add Cherrytrail & Braswell machine driver cht_bsw_max98090_ti
On Fri, May 01, 2015 at 11:42:03AM -0700, yang.a.fang@intel.com wrote:
From: "Fang, Yang A" yang.a.fang@intel.com
Add machine driver for two Intel Cherryview-based platforms, Cherrytrail and Braswell. This machine driver will support max98090 codec as primary codec. it can also support TI jack detect chip as aux device if platform supports it.
Applied, thanks - but this seems like it was against something other than mainline since it didn't immediately apply.
Hi Mark, Thanks. yes I posted another intel machine driver https://patchwork.kernel.org/patch/6264231/ On 4/23 you only applied but still did not published. May I ask again is that patch still in your local? Current patch is applied against that machine driver.
Thanks, Yang
On Mon, May 04, 2015 at 02:40:45PM +0000, Fang, Yang A wrote:
Thanks. yes I posted another intel machine driver https://patchwork.kernel.org/patch/6264231/ On 4/23 you only applied but still did not published. May I ask again is that patch still in your local? Current patch is applied against that machine driver.
I don't know what that was, sorry - *please* include human readable versions of things in messages so people can read them.
On Fri, May 01, 2015 at 11:42:02AM -0700, yang.a.fang@intel.com wrote:
From: "Fang, Yang A" yang.a.fang@intel.com
Added entry in sst driver to support max98090 codec for intel Braswell platform.
Applied, thanks.
From: "Fang, Yang A" yang.a.fang@intel.com
make irq flag part of platform data
Signed-off-by: Fang, Yang A yang.a.fang@intel.com --- include/sound/ts3a227e.h | 19 +++++++++++++++++++ sound/soc/codecs/ts3a227e.c | 9 ++++++++- sound/soc/codecs/ts3a227e.h | 2 ++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 include/sound/ts3a227e.h
diff --git a/include/sound/ts3a227e.h b/include/sound/ts3a227e.h new file mode 100644 index 0000000..c005084 --- /dev/null +++ b/include/sound/ts3a227e.h @@ -0,0 +1,19 @@ +/* + * Platform data for TS3A227E + * + * Copyright (C) 2015 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_TS3A227E_H +#define __LINUX_SND_TS3A227E_H + +struct ts3a227e_platform_data { + + unsigned long irqflag; +}; + +#endif diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 9fd80ac..422f66f 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -25,6 +25,7 @@ struct ts3a227e { struct regmap *regmap; struct snd_soc_jack *jack; + struct ts3a227e_platform_data pdata; bool plugged; bool mic_present; unsigned int buttons_held; @@ -274,6 +275,7 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, { struct ts3a227e *ts3a227e; struct device *dev = &i2c->dev; + struct ts3a227e_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret; unsigned int acc_reg;
@@ -283,6 +285,11 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, ts3a227e);
+ ts3a227e->pdata.irqflag = IRQF_TRIGGER_LOW | IRQF_ONESHOT; + + if (pdata) + ts3a227e->pdata = *pdata; + ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config); if (IS_ERR(ts3a227e->regmap)) return PTR_ERR(ts3a227e->regmap); @@ -296,7 +303,7 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, }
ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + ts3a227e->pdata.irqflag, "TS3A227E", ts3a227e); if (ret) { dev_err(dev, "Cannot request irq %d (%d)\n", i2c->irq, ret); diff --git a/sound/soc/codecs/ts3a227e.h b/sound/soc/codecs/ts3a227e.h index e2acf9c..a587a72 100644 --- a/sound/soc/codecs/ts3a227e.h +++ b/sound/soc/codecs/ts3a227e.h @@ -11,6 +11,8 @@ #ifndef _TS3A227E_H #define _TS3A227E_H
+#include <sound/ts3a227e.h> + int ts3a227e_enable_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
On Wed, Apr 29, 2015 at 06:43:57PM -0700, yang.a.fang@intel.com wrote:
@@ -296,7 +303,7 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, }
ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
if (ret) { dev_err(dev, "Cannot request irq %d (%d)\n", i2c->irq, ret);ts3a227e->pdata.irqflag, "TS3A227E", ts3a227e);
This doesn't make much sense to me - no change is made to the configuration of the device, the driver just passes the flag through to the interrupt controller code. I can't see how that's going to work well, somewhere along the line something must be misconfigured.
-----Original Message----- From: Mark Brown [mailto:broonie@kernel.org] Sent: Thursday, April 30, 2015 1:02 PM To: Fang, Yang A Cc: lgirdwood@gmail.com; alsa-devel@alsa-project.org; dgreid@chromium.org; Koul, Vinod; Diwakar, Praveen; kevin.strasser@linux.intel.com; Jain, Praveen K; Iriawan, Denny Subject: Re: [PATCH 3/4] ASoC: ts3a227e: add platform data for ts3a227e driver
On Wed, Apr 29, 2015 at 06:43:57PM -0700, yang.a.fang@intel.com wrote:
@@ -296,7 +303,7 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, }
ret = devm_request_threaded_irq(dev, i2c->irq, NULL,
ts3a227e_interrupt,
IRQF_TRIGGER_LOW |
IRQF_ONESHOT,
if (ret) { dev_err(dev, "Cannot request irq %d (%d)\n", i2c->irq, ret);ts3a227e->pdata.irqflag, "TS3A227E", ts3a227e);
This doesn't make much sense to me - no change is made to the configuration of the device, the driver just passes the flag through to the interrupt controller code. I can't see how that's going to work well, somewhere along the line something must be misconfigured.
Hi Mark,
My intention is to make irqflag configurable. I made them two patches. Patch 3/4 to make sure existing code no impact. 4/4 is set different Irq value via DMI for specific platform. Maybe I should squash them?
Thanks, Yang
On Thu, Apr 30, 2015 at 08:45:40PM +0000, Fang, Yang A wrote:
ts3a227e_interrupt,
IRQF_TRIGGER_LOW |
IRQF_ONESHOT,
if (ret) { dev_err(dev, "Cannot request irq %d (%d)\n", i2c->irq, ret);ts3a227e->pdata.irqflag, "TS3A227E", ts3a227e);
This doesn't make much sense to me - no change is made to the configuration of the device, the driver just passes the flag through to the interrupt controller code. I can't see how that's going to work well, somewhere along the line something must be misconfigured.
My intention is to make irqflag configurable. I made them two patches. Patch 3/4 to make sure existing code no impact. 4/4 is set different Irq value via DMI for specific platform. Maybe I should squash them?
No, you're missing the point - if you're changing the flags for the interrupt without also reconfiguring the hardware there's a bug. This seems like it's what Dylan identified with missing interrupts, it sounds like the device is always level triggered.
From: "Fang, Yang A" yang.a.fang@intel.com
Cyan platform need edge trigger interrupt
Signed-off-by: Fang, Yang A yang.a.fang@intel.com --- sound/soc/codecs/ts3a227e.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 422f66f..75f2a43 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/of_gpio.h> #include <linux/regmap.h> +#include <linux/dmi.h>
#include <sound/core.h> #include <sound/jack.h> @@ -270,6 +271,33 @@ static int ts3a227e_parse_dt(struct ts3a227e *ts3a227e, struct device_node *np) return 0; }
+static struct ts3a227e_platform_data *ts3a227e_pdata; + +static struct ts3a227e_platform_data cyan_platform_data = { + + .irqflag = IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + +}; + +static int cyan_quirk_cb(const struct dmi_system_id *id) +{ + + ts3a227e_pdata = &cyan_platform_data; + + return 1; +} + +static struct dmi_system_id dmi_platform_intel_braswell[] = { + { + .ident = "Braswell Cyan", + .callback = cyan_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Cyan"), + }, + }, + { } +}; + static int ts3a227e_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -287,9 +315,12 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
ts3a227e->pdata.irqflag = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
- if (pdata) + if (pdata) { ts3a227e->pdata = *pdata; - + } else { + if (dmi_check_system(dmi_platform_intel_braswell)) + ts3a227e->pdata = *ts3a227e_pdata; + } ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config); if (IS_ERR(ts3a227e->regmap)) return PTR_ERR(ts3a227e->regmap);
On Wed, Apr 29, 2015 at 6:43 PM, yang.a.fang@intel.com wrote:
From: "Fang, Yang A" yang.a.fang@intel.com
Cyan platform need edge trigger interrupt
Signed-off-by: Fang, Yang A yang.a.fang@intel.com
sound/soc/codecs/ts3a227e.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 422f66f..75f2a43 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/of_gpio.h> #include <linux/regmap.h> +#include <linux/dmi.h>
#include <sound/core.h> #include <sound/jack.h> @@ -270,6 +271,33 @@ static int ts3a227e_parse_dt(struct ts3a227e *ts3a227e, struct device_node *np) return 0; }
+static struct ts3a227e_platform_data *ts3a227e_pdata;
+static struct ts3a227e_platform_data cyan_platform_data = {
.irqflag = IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
As we discussed internally, using an edge trigger here can lead to missed interrupts if another event happens while an interrupt is being processed. I'd investigate getting the level interrupt to work on this platform, and only if that is impossible try to make this work with an edge interrupt.
+};
+static int cyan_quirk_cb(const struct dmi_system_id *id) +{
ts3a227e_pdata = &cyan_platform_data;
return 1;
+}
+static struct dmi_system_id dmi_platform_intel_braswell[] = {
{
.ident = "Braswell Cyan",
.callback = cyan_quirk_cb,
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Cyan"),
},
},
{ }
+};
static int ts3a227e_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -287,9 +315,12 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
ts3a227e->pdata.irqflag = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
if (pdata)
if (pdata) { ts3a227e->pdata = *pdata;
} else {
if (dmi_check_system(dmi_platform_intel_braswell))
ts3a227e->pdata = *ts3a227e_pdata;
} ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config); if (IS_ERR(ts3a227e->regmap)) return PTR_ERR(ts3a227e->regmap);
-- 1.7.9.5
On Thu, Apr 30, 2015 at 10:45:04AM -0700, Dylan Reid wrote:
On Wed, Apr 29, 2015 at 6:43 PM, yang.a.fang@intel.com wrote:
+static struct ts3a227e_platform_data cyan_platform_data = {
.irqflag = IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
As we discussed internally, using an edge trigger here can lead to missed interrupts if another event happens while an interrupt is being processed. I'd investigate getting the level interrupt to work on this platform, and only if that is impossible try to make this work with an edge interrupt.
TBH given the prevelance of devices out there which only support level triggered interrupts it probably makes sense to handle this somewhere in genirq, either generically in a driver that handles whatever bit of the platform creates the restriction. At the very least it should probably be put into a library since it's a bit of a pattern.
There's some workarounds for systems with similar restrictions in a few of the Wolfson drivers if you want to copy (they do need a GPIO mapping though IIRC since they do the level trigger in software).
participants (7)
-
Dylan Reid
-
Fang, Yang A
-
Mark Brown
-
Pierre-Louis Bossart
-
Vinod Koul
-
Yang Fang
-
yang.a.fang@intel.com