From mboxrd@z Thu Jan 1 00:00:00 1970 From: Pierre-Louis Bossart Subject: Re: [PATCH 2/2] ASoC: Intel: add machine driver for BYT/CHT + ES8316 Date: Wed, 10 May 2017 13:49:03 -0500 Message-ID: References: <20170510181649.14580-1-drake@endlessm.com> <20170510181649.14580-2-drake@endlessm.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii"; Format="flowed" Content-Transfer-Encoding: 7bit Return-path: Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by alsa0.perex.cz (Postfix) with ESMTP id CC4ED266B21 for ; Wed, 10 May 2017 20:49:05 +0200 (CEST) In-Reply-To: <20170510181649.14580-2-drake@endlessm.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org To: Daniel Drake , lgirdwood@gmail.com, broonie@kernel.org Cc: alsa-devel@alsa-project.org, linux@endlessm.com, yangxiaohua@everest-semi.com List-Id: alsa-devel@alsa-project.org 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 > --- > 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 , same comment about the signoff. > + * Daniel Drake > + * > + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; version 2 of the License. > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License for more details. > + * > + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#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 "); > +MODULE_LICENSE("GPL v2"); > +MODULE_ALIAS("platform:bytcht_es8316"); >