Message ID | 20170510181649.14580-2-drake@endlessm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 5/10/17 1:16 PM, Daniel Drake wrote: > Add new machine driver, tested with Weibu F3C MiniPC. You may want to add a comment that this patch is based on the use of SSP2 and hence cannot work on BYT-CR devices. > > Based heavily on code provided by David Yang @ Everest, and other > machine drivers in the same directory. > > Signed-off-by: Daniel Drake <drake@endlessm.com> > --- > sound/soc/intel/Kconfig | 12 ++ > sound/soc/intel/atom/sst/sst_acpi.c | 2 + > sound/soc/intel/boards/Makefile | 2 + > sound/soc/intel/boards/bytcht_es8316.c | 338 +++++++++++++++++++++++++++++++++ > 4 files changed, 354 insertions(+) > create mode 100644 sound/soc/intel/boards/bytcht_es8316.c > > diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig > index 67968ef3bbda..013f056c6c12 100644 > --- a/sound/soc/intel/Kconfig > +++ b/sound/soc/intel/Kconfig > @@ -214,6 +214,18 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH > platforms with DA7212/7213 audio codec. > If unsure select "N". > > +config SND_SOC_INTEL_BYT_CHT_ES8316_MACH > + tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec" > + depends on X86_INTEL_LPSS && I2C && ACPI > + select SND_SOC_ES8316 > + select SND_SST_ATOM_HIFI2_PLATFORM > + select SND_SST_IPC_ACPI > + select SND_SOC_INTEL_SST_MATCH if ACPI > + help > + This adds support for ASoC machine driver for Intel(R) Baytrail & > + Cherrytrail platforms with ES8316 audio codec. > + If unsure select "N". > + > config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH > tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" > depends on X86_INTEL_LPSS && I2C && ACPI > diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c > index dd250b8b26f2..e0b7346cbb16 100644 > --- a/sound/soc/intel/atom/sst/sst_acpi.c > +++ b/sound/soc/intel/atom/sst/sst_acpi.c > @@ -533,6 +533,8 @@ static struct sst_acpi_mach sst_acpi_chv[] = { > &chv_platform_data }, > {"DLGS7213", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL, > &chv_platform_data }, > + {"ESSX8316", "bytcht_es8316", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, > + &chv_platform_data }, > /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ > {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk, > &chv_platform_data }, > diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile > index 56896e09445d..0cca726d249b 100644 > --- a/sound/soc/intel/boards/Makefile > +++ b/sound/soc/intel/boards/Makefile > @@ -11,6 +11,7 @@ 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 > snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o > +snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o > snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o > snd-soc-skl_rt286-objs := skl_rt286.o > snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o > @@ -29,6 +30,7 @@ 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 > obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o > +obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o > obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o > obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o > obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o > diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c > new file mode 100644 > index 000000000000..5e94e0befa34 > --- /dev/null > +++ b/sound/soc/intel/boards/bytcht_es8316.c > @@ -0,0 +1,338 @@ > +/* > + * bytbyt_cht_es8316.c - ASoc Machine driver for Intel Baytrail/Cherrytrail typo bytbyt > + * platforms with Everest ES8316 SoC > + * > + * Copyright (C) 2017 Endless Mobile, Inc. > + * Authors: David Yang <yangxiaohua@everest-semi.com>, same comment about the signoff. > + * Daniel Drake <drake@endlessm.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/init.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/device.h> > +#include <linux/slab.h> > +#include <asm/platform_sst_audio.h> > +#include <linux/clk.h> > +#include <sound/pcm.h> > +#include <sound/pcm_params.h> > +#include <sound/soc.h> > +#include "../atom/sst-atom-controls.h" > +#include "../common/sst-acpi.h" > +#include "../common/sst-dsp.h" > + > +struct byt_cht_es8316_private { > + struct clk *mclk; > +}; > + > +#define CODEC_DAI1 "ES8316 HiFi" > + > +static inline struct snd_soc_dai *get_codec_dai(struct snd_soc_card *card) > +{ > + struct snd_soc_pcm_runtime *rtd; > + > + list_for_each_entry(rtd, &card->rtd_list, list) { > + if (!strncmp(rtd->codec_dai->name, CODEC_DAI1, > + strlen(CODEC_DAI1))) > + 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 = get_codec_dai(card); > + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(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_ON(event)) { > + int ret = clk_prepare_enable(priv->mclk); > + > + if (ret < 0) { > + dev_err(card->dev, > + "could not configure MCLK state"); > + return ret; > + } > + } else { > + clk_disable_unprepare(priv->mclk); what is the behavior on the codec side if the sysclk is set to 19.2 MHz but the MCLK is stopped? > + } > + > + return 0; > +} > + > +static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { > + SND_SOC_DAPM_HP("Headphone", NULL), > + SND_SOC_DAPM_MIC("Microphone 1", NULL), > + SND_SOC_DAPM_MIC("Microphone 2", NULL), > + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, > + platform_clock_control, SND_SOC_DAPM_PRE_PMU | > + SND_SOC_DAPM_POST_PMD), > +}; > + > +static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { > + {"MIC1", NULL, "Microphone 1"}, > + {"MIC2", NULL, "Microphone 2"}, > + > + {"Headphone", NULL, "HPOL"}, > + {"Headphone", NULL, "HPOR"}, > + > + {"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, "Capture"}, > + > + {"Headphone", NULL, "Platform Clock"}, > + {"Microphone 1", NULL, "Platform Clock"}, > + {"Microphone 2", NULL, "Platform Clock"}, > +}; > + > +static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { > + SOC_DAPM_PIN_SWITCH("Headphone"), > + SOC_DAPM_PIN_SWITCH("Microphone 1"), > + SOC_DAPM_PIN_SWITCH("Microphone 2"), do you really need to control the two analog mics independently? And along the same lines, should there be a path for DMICS? > +}; > + > +static int byt_cht_es8316_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, 0, 19200000, SND_SOC_CLOCK_IN); > + if (ret < 0) { > + dev_err(rtd->dev, "can't set codec clock %d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) > +{ > + struct snd_soc_card *card = runtime->card; > + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); > + int ret; > + > + card->dapm.idle_bias_off = true; > + > + /* > + * The firmware might enable the clock at boot (this information > + * may or may not be reflected in the enable clock register). > + * To change the rate we must disable the clock first to cover these > + * cases. Due to common clock framework restrictions that do not allow > + * to disable a clock that has not been enabled, we need to enable > + * the clock first. > + */ > + ret = clk_prepare_enable(priv->mclk); > + if (!ret) > + clk_disable_unprepare(priv->mclk); > + > + ret = clk_set_rate(priv->mclk, 19200000); > + if (ret) > + dev_err(card->dev, "unable to set MCLK rate\n"); > + > + return 0; > +} > + > +static const struct snd_soc_pcm_stream byt_cht_es8316_dai_params = { > + .formats = SNDRV_PCM_FMTBIT_S24_LE, > + .rate_min = 48000, > + .rate_max = 48000, > + .channels_min = 2, > + .channels_max = 2, > +}; > + > +static int byt_cht_es8316_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; > + > + /* The DSP will covert the FE rate to 48k, stereo */ > + rate->min = rate->max = 48000; > + channels->min = channels->max = 2; > + > + /* set SSP2 to 24-bit */ > + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); > + > + /* > + * Default mode for SSP configuration is TDM 4 slot, override config > + * with explicit setting to I2S 2ch 24-bit. The word length is set with > + * dai_set_tdm_slot() since there is no other API exposed > + */ > + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, > + SND_SOC_DAIFMT_I2S | > + SND_SOC_DAIFMT_NB_NF | > + SND_SOC_DAIFMT_CBS_CFS > + ); > + if (ret < 0) { > + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); > + return ret; > + } > + > + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); > + if (ret < 0) { > + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +static int byt_cht_es8316_aif1_startup(struct snd_pcm_substream *substream) > +{ > + return snd_pcm_hw_constraint_single(substream->runtime, > + SNDRV_PCM_HW_PARAM_RATE, 48000); > +} > + > +static const struct snd_soc_ops byt_cht_es8316_aif1_ops = { > + .startup = byt_cht_es8316_aif1_startup, > +}; > + > +static const struct snd_soc_ops byt_cht_es8316_be_ssp2_ops = { > + .hw_params = byt_cht_es8316_aif1_hw_params, > +}; > + > +static struct snd_soc_dai_link byt_cht_es8316_dais[] = { > + [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 = &byt_cht_es8316_aif1_ops, > + }, > + > + [MERR_DPCM_DEEP_BUFFER] = { > + .name = "Deep-Buffer Audio Port", > + .stream_name = "Deep-Buffer Audio", > + .cpu_dai_name = "deepbuffer-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, > + .ops = &byt_cht_es8316_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", > + .id = 1, > + .cpu_dai_name = "ssp2-port", > + .platform_name = "sst-mfld-platform", > + .no_pcm = 1, > + .codec_dai_name = "ES8316 HiFi", > + .codec_name = "i2c-ESSX8316:00", > + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF > + | SND_SOC_DAIFMT_CBS_CFS, > + .be_hw_params_fixup = byt_cht_es8316_codec_fixup, > + .nonatomic = true, > + .dpcm_playback = 1, > + .dpcm_capture = 1, > + .init = byt_cht_es8316_init, > + .ops = &byt_cht_es8316_be_ssp2_ops, > + }, > +}; > + > + > +/* SoC card */ > +static struct snd_soc_card byt_cht_es8316_card = { > + .name = "bytcht-es8316", > + .owner = THIS_MODULE, > + .dai_link = byt_cht_es8316_dais, > + .num_links = ARRAY_SIZE(byt_cht_es8316_dais), > + .dapm_widgets = byt_cht_es8316_widgets, > + .num_dapm_widgets = ARRAY_SIZE(byt_cht_es8316_widgets), > + .dapm_routes = byt_cht_es8316_audio_map, > + .num_dapm_routes = ARRAY_SIZE(byt_cht_es8316_audio_map), > + .controls = byt_cht_es8316_controls, > + .num_controls = ARRAY_SIZE(byt_cht_es8316_controls), > + .fully_routed = true, > +}; > + > +static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) > +{ > + int ret = 0; > + struct byt_cht_es8316_private *priv; > + > + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); > + if (!priv) > + return -ENOMEM; > + > + /* register the soc card */ > + byt_cht_es8316_card.dev = &pdev->dev; > + snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); > + > + priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); > + if (IS_ERR(priv->mclk)) { > + ret = PTR_ERR(priv->mclk); > + dev_err(&pdev->dev, > + "Failed to get MCLK from pmc_plt_clk_3: %d\n", > + ret); > + return ret; > + } > + > + ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card); > + if (ret) { > + dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); > + return ret; > + } > + platform_set_drvdata(pdev, &byt_cht_es8316_card); > + return ret; > +} > + > +static struct platform_driver snd_byt_cht_es8316_mc_driver = { > + .driver = { > + .name = "bytcht_es8316", > + }, > + .probe = snd_byt_cht_es8316_mc_probe, > +}; > + > +module_platform_driver(snd_byt_cht_es8316_mc_driver); > +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver"); > +MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>"); > +MODULE_LICENSE("GPL v2"); > +MODULE_ALIAS("platform:bytcht_es8316"); >
On Wed, May 10, 2017 at 12:49 PM, Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> wrote: > You may want to add a comment that this patch is based on the use of SSP2 > and hence cannot work on BYT-CR devices. I'm not quite clear on the terminology here. What does BYT-CR mean exactly? I named the driver with "byt" in addition to "cht" as I was hoping it can support the baytrail devices mentioned here: https://bugzilla.kernel.org/show_bug.cgi?id=189261#c71 I also see that bytcht_da7213 is documented as supporting Baytrail devices and only uses SSP2. But bytcr_rt5640 does switch to SSP0 on valleyview, and I could do the same. Not sure which way I should go here at least without more info from the reporter, let me know if you have any suggestions. >> +static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { >> + SOC_DAPM_PIN_SWITCH("Headphone"), >> + SOC_DAPM_PIN_SWITCH("Microphone 1"), >> + SOC_DAPM_PIN_SWITCH("Microphone 2"), > > > do you really need to control the two analog mics independently? And along > the same lines, should there be a path for DMICS? The ES8316 datasheet is clear that it supports 2 independent analog stereo mics, and the codec driver exposes the relevant controls for that, so I added two here. There is a mux so you have to choose which one you feed into the ADC, but (if you wanted to) you could e.g. feed the other into the HP output mixer, and use both simultaneously. The product I'm working with only uses one of them though, so I could delete the other one if you think that makes sense? The datasheet does say "Support digital mic" but it makes almost no other mention of DMIC support, not even which of the 4 mic input pins you would use for that. The codec driver does expose a single SND_SOC_DAPM_INPUT("DMIC") though so I could very easily add a route here, although I would have no way of testing it. Thanks for your help Daniel
On 5/15/17 1:07 PM, Daniel Drake wrote: > On Wed, May 10, 2017 at 12:49 PM, Pierre-Louis Bossart > <pierre-louis.bossart@linux.intel.com> wrote: >> You may want to add a comment that this patch is based on the use of SSP2 >> and hence cannot work on BYT-CR devices. > > I'm not quite clear on the terminology here. What does BYT-CR mean exactly? a cost-reduced version where the packaging is different with only SSP0 and SSP2 exposed. > > I named the driver with "byt" in addition to "cht" as I was hoping it > can support the baytrail devices mentioned here: > https://bugzilla.kernel.org/show_bug.cgi?id=189261#c71 > > I also see that bytcht_da7213 is documented as supporting Baytrail > devices and only uses SSP2. But bytcr_rt5640 does switch to SSP0 on > valleyview, and I could do the same. > > Not sure which way I should go here at least without more info from > the reporter, let me know if you have any suggestions. just add a note that SSP0 routing is not supported at the moment, no reason to add code if you can't test it. > >>> +static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { >>> + SOC_DAPM_PIN_SWITCH("Headphone"), >>> + SOC_DAPM_PIN_SWITCH("Microphone 1"), >>> + SOC_DAPM_PIN_SWITCH("Microphone 2"), >> >> >> do you really need to control the two analog mics independently? And along >> the same lines, should there be a path for DMICS? > > The ES8316 datasheet is clear that it supports 2 independent analog > stereo mics, and the codec driver exposes the relevant controls for > that, so I added two here. There is a mux so you have to choose which > one you feed into the ADC, but (if you wanted to) you could e.g. feed > the other into the HP output mixer, and use both simultaneously. > > The product I'm working with only uses one of them though, so I could > delete the other one if you think that makes sense? I am not sure what the recommendation is. I've always seen a single 'mic' or 'int mic' switch being used regardless of the number of mics. Usually you have additional routing controls to define which mics are used, this control seems to be a higher level kill switch of sorts. > > The datasheet does say "Support digital mic" but it makes almost no > other mention of DMIC support, not even which of the 4 mic input pins > you would use for that. The codec driver does expose a single > SND_SOC_DAPM_INPUT("DMIC") though so I could very easily add a route > here, although I would have no way of testing it. ok, fair enough. adding a note of what was tested is helpful in general. > > Thanks for your help > > Daniel > _______________________________________________ > Alsa-devel mailing list > Alsa-devel@alsa-project.org > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel >
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 67968ef3bbda..013f056c6c12 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -214,6 +214,18 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH platforms with DA7212/7213 audio codec. If unsure select "N". +config SND_SOC_INTEL_BYT_CHT_ES8316_MACH + tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail with ES8316 codec" + depends on X86_INTEL_LPSS && I2C && ACPI + select SND_SOC_ES8316 + select SND_SST_ATOM_HIFI2_PLATFORM + select SND_SST_IPC_ACPI + select SND_SOC_INTEL_SST_MATCH if ACPI + help + This adds support for ASoC machine driver for Intel(R) Baytrail & + Cherrytrail platforms with ES8316 audio codec. + If unsure select "N". + config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH tristate "ASoC Audio driver for Intel Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" depends on X86_INTEL_LPSS && I2C && ACPI diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index dd250b8b26f2..e0b7346cbb16 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -533,6 +533,8 @@ static struct sst_acpi_mach sst_acpi_chv[] = { &chv_platform_data }, {"DLGS7213", "bytcht_da7213", "intel/fw_sst_22a8.bin", "bytcht_da7213", NULL, &chv_platform_data }, + {"ESSX8316", "bytcht_es8316", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, + &chv_platform_data }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk, &chv_platform_data }, diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 56896e09445d..0cca726d249b 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -11,6 +11,7 @@ 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 snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o +snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-skl_rt286-objs := skl_rt286.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o @@ -29,6 +30,7 @@ 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 obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o +obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c new file mode 100644 index 000000000000..5e94e0befa34 --- /dev/null +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -0,0 +1,338 @@ +/* + * bytbyt_cht_es8316.c - ASoc Machine driver for Intel Baytrail/Cherrytrail + * platforms with Everest ES8316 SoC + * + * Copyright (C) 2017 Endless Mobile, Inc. + * Authors: David Yang <yangxiaohua@everest-semi.com>, + * Daniel Drake <drake@endlessm.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/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <asm/platform_sst_audio.h> +#include <linux/clk.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../atom/sst-atom-controls.h" +#include "../common/sst-acpi.h" +#include "../common/sst-dsp.h" + +struct byt_cht_es8316_private { + struct clk *mclk; +}; + +#define CODEC_DAI1 "ES8316 HiFi" + +static inline struct snd_soc_dai *get_codec_dai(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (!strncmp(rtd->codec_dai->name, CODEC_DAI1, + strlen(CODEC_DAI1))) + 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 = get_codec_dai(card); + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(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_ON(event)) { + int ret = clk_prepare_enable(priv->mclk); + + if (ret < 0) { + dev_err(card->dev, + "could not configure MCLK state"); + return ret; + } + } else { + clk_disable_unprepare(priv->mclk); + } + + return 0; +} + +static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Microphone 1", NULL), + SND_SOC_DAPM_MIC("Microphone 2", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { + {"MIC1", NULL, "Microphone 1"}, + {"MIC2", NULL, "Microphone 2"}, + + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + + {"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, "Capture"}, + + {"Headphone", NULL, "Platform Clock"}, + {"Microphone 1", NULL, "Platform Clock"}, + {"Microphone 2", NULL, "Platform Clock"}, +}; + +static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Microphone 1"), + SOC_DAPM_PIN_SWITCH("Microphone 2"), +}; + +static int byt_cht_es8316_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, 0, 19200000, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec clock %d\n", ret); + return ret; + } + + return 0; +} + +static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + int ret; + + card->dapm.idle_bias_off = true; + + /* + * The firmware might enable the clock at boot (this information + * may or may not be reflected in the enable clock register). + * To change the rate we must disable the clock first to cover these + * cases. Due to common clock framework restrictions that do not allow + * to disable a clock that has not been enabled, we need to enable + * the clock first. + */ + ret = clk_prepare_enable(priv->mclk); + if (!ret) + clk_disable_unprepare(priv->mclk); + + ret = clk_set_rate(priv->mclk, 19200000); + if (ret) + dev_err(card->dev, "unable to set MCLK rate\n"); + + return 0; +} + +static const struct snd_soc_pcm_stream byt_cht_es8316_dai_params = { + .formats = SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, +}; + +static int byt_cht_es8316_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; + + /* The DSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 24-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS + ); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + + return 0; +} + +static int byt_cht_es8316_aif1_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, 48000); +} + +static const struct snd_soc_ops byt_cht_es8316_aif1_ops = { + .startup = byt_cht_es8316_aif1_startup, +}; + +static const struct snd_soc_ops byt_cht_es8316_be_ssp2_ops = { + .hw_params = byt_cht_es8316_aif1_hw_params, +}; + +static struct snd_soc_dai_link byt_cht_es8316_dais[] = { + [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 = &byt_cht_es8316_aif1_ops, + }, + + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-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, + .ops = &byt_cht_es8316_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", + .id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "ES8316 HiFi", + .codec_name = "i2c-ESSX8316:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .be_hw_params_fixup = byt_cht_es8316_codec_fixup, + .nonatomic = true, + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = byt_cht_es8316_init, + .ops = &byt_cht_es8316_be_ssp2_ops, + }, +}; + + +/* SoC card */ +static struct snd_soc_card byt_cht_es8316_card = { + .name = "bytcht-es8316", + .owner = THIS_MODULE, + .dai_link = byt_cht_es8316_dais, + .num_links = ARRAY_SIZE(byt_cht_es8316_dais), + .dapm_widgets = byt_cht_es8316_widgets, + .num_dapm_widgets = ARRAY_SIZE(byt_cht_es8316_widgets), + .dapm_routes = byt_cht_es8316_audio_map, + .num_dapm_routes = ARRAY_SIZE(byt_cht_es8316_audio_map), + .controls = byt_cht_es8316_controls, + .num_controls = ARRAY_SIZE(byt_cht_es8316_controls), + .fully_routed = true, +}; + +static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct byt_cht_es8316_private *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); + if (!priv) + return -ENOMEM; + + /* register the soc card */ + byt_cht_es8316_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); + + priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (IS_ERR(priv->mclk)) { + ret = PTR_ERR(priv->mclk); + dev_err(&pdev->dev, + "Failed to get MCLK from pmc_plt_clk_3: %d\n", + ret); + return ret; + } + + ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); + return ret; + } + platform_set_drvdata(pdev, &byt_cht_es8316_card); + return ret; +} + +static struct platform_driver snd_byt_cht_es8316_mc_driver = { + .driver = { + .name = "bytcht_es8316", + }, + .probe = snd_byt_cht_es8316_mc_probe, +}; + +module_platform_driver(snd_byt_cht_es8316_mc_driver); +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver"); +MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bytcht_es8316");
Add new machine driver, tested with Weibu F3C MiniPC. Based heavily on code provided by David Yang @ Everest, and other machine drivers in the same directory. Signed-off-by: Daniel Drake <drake@endlessm.com> --- sound/soc/intel/Kconfig | 12 ++ sound/soc/intel/atom/sst/sst_acpi.c | 2 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/bytcht_es8316.c | 338 +++++++++++++++++++++++++++++++++ 4 files changed, 354 insertions(+) create mode 100644 sound/soc/intel/boards/bytcht_es8316.c