18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  bytcht_es8316.c - ASoc Machine driver for Intel Baytrail/Cherrytrail
48c2ecf20Sopenharmony_ci *                    platforms with Everest ES8316 SoC
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *  Copyright (C) 2017 Endless Mobile, Inc.
78c2ecf20Sopenharmony_ci *  Authors: David Yang <yangxiaohua@everest-semi.com>,
88c2ecf20Sopenharmony_ci *           Daniel Drake <drake@endlessm.com>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci#include <linux/acpi.h>
158c2ecf20Sopenharmony_ci#include <linux/clk.h>
168c2ecf20Sopenharmony_ci#include <linux/device.h>
178c2ecf20Sopenharmony_ci#include <linux/dmi.h>
188c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
198c2ecf20Sopenharmony_ci#include <linux/i2c.h>
208c2ecf20Sopenharmony_ci#include <linux/init.h>
218c2ecf20Sopenharmony_ci#include <linux/input.h>
228c2ecf20Sopenharmony_ci#include <linux/module.h>
238c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
248c2ecf20Sopenharmony_ci#include <linux/slab.h>
258c2ecf20Sopenharmony_ci#include <sound/jack.h>
268c2ecf20Sopenharmony_ci#include <sound/pcm.h>
278c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
288c2ecf20Sopenharmony_ci#include <sound/soc.h>
298c2ecf20Sopenharmony_ci#include <sound/soc-acpi.h>
308c2ecf20Sopenharmony_ci#include "../atom/sst-atom-controls.h"
318c2ecf20Sopenharmony_ci#include "../common/soc-intel-quirks.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/* jd-inv + terminating entry */
348c2ecf20Sopenharmony_ci#define MAX_NO_PROPS 2
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistruct byt_cht_es8316_private {
378c2ecf20Sopenharmony_ci	struct clk *mclk;
388c2ecf20Sopenharmony_ci	struct snd_soc_jack jack;
398c2ecf20Sopenharmony_ci	struct gpio_desc *speaker_en_gpio;
408c2ecf20Sopenharmony_ci	bool speaker_en;
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cienum {
448c2ecf20Sopenharmony_ci	BYT_CHT_ES8316_INTMIC_IN1_MAP,
458c2ecf20Sopenharmony_ci	BYT_CHT_ES8316_INTMIC_IN2_MAP,
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define BYT_CHT_ES8316_MAP(quirk)		((quirk) & GENMASK(3, 0))
498c2ecf20Sopenharmony_ci#define BYT_CHT_ES8316_SSP0			BIT(16)
508c2ecf20Sopenharmony_ci#define BYT_CHT_ES8316_MONO_SPEAKER		BIT(17)
518c2ecf20Sopenharmony_ci#define BYT_CHT_ES8316_JD_INVERTED		BIT(18)
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic unsigned long quirk;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic int quirk_override = -1;
568c2ecf20Sopenharmony_cimodule_param_named(quirk, quirk_override, int, 0444);
578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(quirk, "Board-specific quirk override");
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic void log_quirks(struct device *dev)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN1_MAP)
628c2ecf20Sopenharmony_ci		dev_info(dev, "quirk IN1_MAP enabled");
638c2ecf20Sopenharmony_ci	if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN2_MAP)
648c2ecf20Sopenharmony_ci		dev_info(dev, "quirk IN2_MAP enabled");
658c2ecf20Sopenharmony_ci	if (quirk & BYT_CHT_ES8316_SSP0)
668c2ecf20Sopenharmony_ci		dev_info(dev, "quirk SSP0 enabled");
678c2ecf20Sopenharmony_ci	if (quirk & BYT_CHT_ES8316_MONO_SPEAKER)
688c2ecf20Sopenharmony_ci		dev_info(dev, "quirk MONO_SPEAKER enabled\n");
698c2ecf20Sopenharmony_ci	if (quirk & BYT_CHT_ES8316_JD_INVERTED)
708c2ecf20Sopenharmony_ci		dev_info(dev, "quirk JD_INVERTED enabled\n");
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
748c2ecf20Sopenharmony_ci	struct snd_kcontrol *kcontrol, int event)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct snd_soc_card *card = w->dapm->card;
778c2ecf20Sopenharmony_ci	struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (SND_SOC_DAPM_EVENT_ON(event))
808c2ecf20Sopenharmony_ci		priv->speaker_en = true;
818c2ecf20Sopenharmony_ci	else
828c2ecf20Sopenharmony_ci		priv->speaker_en = false;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	return 0;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = {
908c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SPK("Speaker", NULL),
918c2ecf20Sopenharmony_ci	SND_SOC_DAPM_HP("Headphone", NULL),
928c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MIC("Headset Mic", NULL),
938c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MIC("Internal Mic", NULL),
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0,
968c2ecf20Sopenharmony_ci			    byt_cht_es8316_speaker_power_event,
978c2ecf20Sopenharmony_ci			    SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = {
1018c2ecf20Sopenharmony_ci	{"Headphone", NULL, "HPOL"},
1028c2ecf20Sopenharmony_ci	{"Headphone", NULL, "HPOR"},
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/*
1058c2ecf20Sopenharmony_ci	 * There is no separate speaker output instead the speakers are muxed to
1068c2ecf20Sopenharmony_ci	 * the HP outputs. The mux is controlled by the "Speaker Power" supply.
1078c2ecf20Sopenharmony_ci	 */
1088c2ecf20Sopenharmony_ci	{"Speaker", NULL, "HPOL"},
1098c2ecf20Sopenharmony_ci	{"Speaker", NULL, "HPOR"},
1108c2ecf20Sopenharmony_ci	{"Speaker", NULL, "Speaker Power"},
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route byt_cht_es8316_intmic_in1_map[] = {
1148c2ecf20Sopenharmony_ci	{"MIC1", NULL, "Internal Mic"},
1158c2ecf20Sopenharmony_ci	{"MIC2", NULL, "Headset Mic"},
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route byt_cht_es8316_intmic_in2_map[] = {
1198c2ecf20Sopenharmony_ci	{"MIC2", NULL, "Internal Mic"},
1208c2ecf20Sopenharmony_ci	{"MIC1", NULL, "Headset Mic"},
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = {
1248c2ecf20Sopenharmony_ci	{"Playback", NULL, "ssp0 Tx"},
1258c2ecf20Sopenharmony_ci	{"ssp0 Tx", NULL, "modem_out"},
1268c2ecf20Sopenharmony_ci	{"modem_in", NULL, "ssp0 Rx"},
1278c2ecf20Sopenharmony_ci	{"ssp0 Rx", NULL, "Capture"},
1288c2ecf20Sopenharmony_ci};
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = {
1318c2ecf20Sopenharmony_ci	{"Playback", NULL, "ssp2 Tx"},
1328c2ecf20Sopenharmony_ci	{"ssp2 Tx", NULL, "codec_out0"},
1338c2ecf20Sopenharmony_ci	{"ssp2 Tx", NULL, "codec_out1"},
1348c2ecf20Sopenharmony_ci	{"codec_in0", NULL, "ssp2 Rx" },
1358c2ecf20Sopenharmony_ci	{"codec_in1", NULL, "ssp2 Rx" },
1368c2ecf20Sopenharmony_ci	{"ssp2 Rx", NULL, "Capture"},
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new byt_cht_es8316_controls[] = {
1408c2ecf20Sopenharmony_ci	SOC_DAPM_PIN_SWITCH("Speaker"),
1418c2ecf20Sopenharmony_ci	SOC_DAPM_PIN_SWITCH("Headphone"),
1428c2ecf20Sopenharmony_ci	SOC_DAPM_PIN_SWITCH("Headset Mic"),
1438c2ecf20Sopenharmony_ci	SOC_DAPM_PIN_SWITCH("Internal Mic"),
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = {
1478c2ecf20Sopenharmony_ci	{
1488c2ecf20Sopenharmony_ci		.pin	= "Headphone",
1498c2ecf20Sopenharmony_ci		.mask	= SND_JACK_HEADPHONE,
1508c2ecf20Sopenharmony_ci	},
1518c2ecf20Sopenharmony_ci	{
1528c2ecf20Sopenharmony_ci		.pin	= "Headset Mic",
1538c2ecf20Sopenharmony_ci		.mask	= SND_JACK_MICROPHONE,
1548c2ecf20Sopenharmony_ci	},
1558c2ecf20Sopenharmony_ci};
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct snd_soc_component *codec = asoc_rtd_to_codec(runtime, 0)->component;
1608c2ecf20Sopenharmony_ci	struct snd_soc_card *card = runtime->card;
1618c2ecf20Sopenharmony_ci	struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
1628c2ecf20Sopenharmony_ci	const struct snd_soc_dapm_route *custom_map;
1638c2ecf20Sopenharmony_ci	int num_routes;
1648c2ecf20Sopenharmony_ci	int ret;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	card->dapm.idle_bias_off = true;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	switch (BYT_CHT_ES8316_MAP(quirk)) {
1698c2ecf20Sopenharmony_ci	case BYT_CHT_ES8316_INTMIC_IN1_MAP:
1708c2ecf20Sopenharmony_ci	default:
1718c2ecf20Sopenharmony_ci		custom_map = byt_cht_es8316_intmic_in1_map;
1728c2ecf20Sopenharmony_ci		num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in1_map);
1738c2ecf20Sopenharmony_ci		break;
1748c2ecf20Sopenharmony_ci	case BYT_CHT_ES8316_INTMIC_IN2_MAP:
1758c2ecf20Sopenharmony_ci		custom_map = byt_cht_es8316_intmic_in2_map;
1768c2ecf20Sopenharmony_ci		num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in2_map);
1778c2ecf20Sopenharmony_ci		break;
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci	ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
1808c2ecf20Sopenharmony_ci	if (ret)
1818c2ecf20Sopenharmony_ci		return ret;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (quirk & BYT_CHT_ES8316_SSP0) {
1848c2ecf20Sopenharmony_ci		custom_map = byt_cht_es8316_ssp0_map;
1858c2ecf20Sopenharmony_ci		num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map);
1868c2ecf20Sopenharmony_ci	} else {
1878c2ecf20Sopenharmony_ci		custom_map = byt_cht_es8316_ssp2_map;
1888c2ecf20Sopenharmony_ci		num_routes = ARRAY_SIZE(byt_cht_es8316_ssp2_map);
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci	ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
1918c2ecf20Sopenharmony_ci	if (ret)
1928c2ecf20Sopenharmony_ci		return ret;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/*
1958c2ecf20Sopenharmony_ci	 * The firmware might enable the clock at boot (this information
1968c2ecf20Sopenharmony_ci	 * may or may not be reflected in the enable clock register).
1978c2ecf20Sopenharmony_ci	 * To change the rate we must disable the clock first to cover these
1988c2ecf20Sopenharmony_ci	 * cases. Due to common clock framework restrictions that do not allow
1998c2ecf20Sopenharmony_ci	 * to disable a clock that has not been enabled, we need to enable
2008c2ecf20Sopenharmony_ci	 * the clock first.
2018c2ecf20Sopenharmony_ci	 */
2028c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(priv->mclk);
2038c2ecf20Sopenharmony_ci	if (!ret)
2048c2ecf20Sopenharmony_ci		clk_disable_unprepare(priv->mclk);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	ret = clk_set_rate(priv->mclk, 19200000);
2078c2ecf20Sopenharmony_ci	if (ret)
2088c2ecf20Sopenharmony_ci		dev_err(card->dev, "unable to set MCLK rate\n");
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(priv->mclk);
2118c2ecf20Sopenharmony_ci	if (ret)
2128c2ecf20Sopenharmony_ci		dev_err(card->dev, "unable to enable MCLK\n");
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(runtime, 0), 0, 19200000,
2158c2ecf20Sopenharmony_ci				     SND_SOC_CLOCK_IN);
2168c2ecf20Sopenharmony_ci	if (ret < 0) {
2178c2ecf20Sopenharmony_ci		dev_err(card->dev, "can't set codec clock %d\n", ret);
2188c2ecf20Sopenharmony_ci		return ret;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	ret = snd_soc_card_jack_new(card, "Headset",
2228c2ecf20Sopenharmony_ci				    SND_JACK_HEADSET | SND_JACK_BTN_0,
2238c2ecf20Sopenharmony_ci				    &priv->jack, byt_cht_es8316_jack_pins,
2248c2ecf20Sopenharmony_ci				    ARRAY_SIZE(byt_cht_es8316_jack_pins));
2258c2ecf20Sopenharmony_ci	if (ret) {
2268c2ecf20Sopenharmony_ci		dev_err(card->dev, "jack creation failed %d\n", ret);
2278c2ecf20Sopenharmony_ci		return ret;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
2318c2ecf20Sopenharmony_ci	snd_soc_component_set_jack(codec, &priv->jack, NULL);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return 0;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
2378c2ecf20Sopenharmony_ci			    struct snd_pcm_hw_params *params)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	struct snd_interval *rate = hw_param_interval(params,
2408c2ecf20Sopenharmony_ci			SNDRV_PCM_HW_PARAM_RATE);
2418c2ecf20Sopenharmony_ci	struct snd_interval *channels = hw_param_interval(params,
2428c2ecf20Sopenharmony_ci						SNDRV_PCM_HW_PARAM_CHANNELS);
2438c2ecf20Sopenharmony_ci	int ret, bits;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* The DSP will covert the FE rate to 48k, stereo */
2468c2ecf20Sopenharmony_ci	rate->min = rate->max = 48000;
2478c2ecf20Sopenharmony_ci	channels->min = channels->max = 2;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (quirk & BYT_CHT_ES8316_SSP0) {
2508c2ecf20Sopenharmony_ci		/* set SSP0 to 16-bit */
2518c2ecf20Sopenharmony_ci		params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
2528c2ecf20Sopenharmony_ci		bits = 16;
2538c2ecf20Sopenharmony_ci	} else {
2548c2ecf20Sopenharmony_ci		/* set SSP2 to 24-bit */
2558c2ecf20Sopenharmony_ci		params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
2568c2ecf20Sopenharmony_ci		bits = 24;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/*
2608c2ecf20Sopenharmony_ci	 * Default mode for SSP configuration is TDM 4 slot, override config
2618c2ecf20Sopenharmony_ci	 * with explicit setting to I2S 2ch 24-bit. The word length is set with
2628c2ecf20Sopenharmony_ci	 * dai_set_tdm_slot() since there is no other API exposed
2638c2ecf20Sopenharmony_ci	 */
2648c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
2658c2ecf20Sopenharmony_ci				SND_SOC_DAIFMT_I2S     |
2668c2ecf20Sopenharmony_ci				SND_SOC_DAIFMT_NB_NF   |
2678c2ecf20Sopenharmony_ci				SND_SOC_DAIFMT_CBS_CFS
2688c2ecf20Sopenharmony_ci		);
2698c2ecf20Sopenharmony_ci	if (ret < 0) {
2708c2ecf20Sopenharmony_ci		dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
2718c2ecf20Sopenharmony_ci		return ret;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
2758c2ecf20Sopenharmony_ci	if (ret < 0) {
2768c2ecf20Sopenharmony_ci		dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
2778c2ecf20Sopenharmony_ci		return ret;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return 0;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic int byt_cht_es8316_aif1_startup(struct snd_pcm_substream *substream)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	return snd_pcm_hw_constraint_single(substream->runtime,
2868c2ecf20Sopenharmony_ci			SNDRV_PCM_HW_PARAM_RATE, 48000);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic const struct snd_soc_ops byt_cht_es8316_aif1_ops = {
2908c2ecf20Sopenharmony_ci	.startup = byt_cht_es8316_aif1_startup,
2918c2ecf20Sopenharmony_ci};
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(dummy,
2948c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_DUMMY()));
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(media,
2978c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(deepbuffer,
3008c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(ssp2_port,
3038c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
3048c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(ssp2_codec,
3058c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8316:00", "ES8316 HiFi")));
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(platform,
3088c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link byt_cht_es8316_dais[] = {
3118c2ecf20Sopenharmony_ci	[MERR_DPCM_AUDIO] = {
3128c2ecf20Sopenharmony_ci		.name = "Audio Port",
3138c2ecf20Sopenharmony_ci		.stream_name = "Audio",
3148c2ecf20Sopenharmony_ci		.nonatomic = true,
3158c2ecf20Sopenharmony_ci		.dynamic = 1,
3168c2ecf20Sopenharmony_ci		.dpcm_playback = 1,
3178c2ecf20Sopenharmony_ci		.dpcm_capture = 1,
3188c2ecf20Sopenharmony_ci		.ops = &byt_cht_es8316_aif1_ops,
3198c2ecf20Sopenharmony_ci		SND_SOC_DAILINK_REG(media, dummy, platform),
3208c2ecf20Sopenharmony_ci	},
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	[MERR_DPCM_DEEP_BUFFER] = {
3238c2ecf20Sopenharmony_ci		.name = "Deep-Buffer Audio Port",
3248c2ecf20Sopenharmony_ci		.stream_name = "Deep-Buffer Audio",
3258c2ecf20Sopenharmony_ci		.nonatomic = true,
3268c2ecf20Sopenharmony_ci		.dynamic = 1,
3278c2ecf20Sopenharmony_ci		.dpcm_playback = 1,
3288c2ecf20Sopenharmony_ci		.ops = &byt_cht_es8316_aif1_ops,
3298c2ecf20Sopenharmony_ci		SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
3308c2ecf20Sopenharmony_ci	},
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		/* back ends */
3338c2ecf20Sopenharmony_ci	{
3348c2ecf20Sopenharmony_ci		/* Only SSP2 has been tested here, so BYT-CR platforms that
3358c2ecf20Sopenharmony_ci		 * require SSP0 will not work.
3368c2ecf20Sopenharmony_ci		 */
3378c2ecf20Sopenharmony_ci		.name = "SSP2-Codec",
3388c2ecf20Sopenharmony_ci		.id = 0,
3398c2ecf20Sopenharmony_ci		.no_pcm = 1,
3408c2ecf20Sopenharmony_ci		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
3418c2ecf20Sopenharmony_ci						| SND_SOC_DAIFMT_CBS_CFS,
3428c2ecf20Sopenharmony_ci		.be_hw_params_fixup = byt_cht_es8316_codec_fixup,
3438c2ecf20Sopenharmony_ci		.nonatomic = true,
3448c2ecf20Sopenharmony_ci		.dpcm_playback = 1,
3458c2ecf20Sopenharmony_ci		.dpcm_capture = 1,
3468c2ecf20Sopenharmony_ci		.init = byt_cht_es8316_init,
3478c2ecf20Sopenharmony_ci		SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
3488c2ecf20Sopenharmony_ci	},
3498c2ecf20Sopenharmony_ci};
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci/* SoC card */
3538c2ecf20Sopenharmony_cistatic char codec_name[SND_ACPI_I2C_ID_LEN];
3548c2ecf20Sopenharmony_ci#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
3558c2ecf20Sopenharmony_cistatic char long_name[50]; /* = "bytcht-es8316-*-spk-*-mic" */
3568c2ecf20Sopenharmony_ci#endif
3578c2ecf20Sopenharmony_cistatic char components_string[32]; /* = "cfg-spk:* cfg-mic:* */
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic int byt_cht_es8316_suspend(struct snd_soc_card *card)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct snd_soc_component *component;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	for_each_card_components(card, component) {
3648c2ecf20Sopenharmony_ci		if (!strcmp(component->name, codec_name)) {
3658c2ecf20Sopenharmony_ci			dev_dbg(component->dev, "disabling jack detect before suspend\n");
3668c2ecf20Sopenharmony_ci			snd_soc_component_set_jack(component, NULL, NULL);
3678c2ecf20Sopenharmony_ci			break;
3688c2ecf20Sopenharmony_ci		}
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	return 0;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic int byt_cht_es8316_resume(struct snd_soc_card *card)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
3778c2ecf20Sopenharmony_ci	struct snd_soc_component *component;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	for_each_card_components(card, component) {
3808c2ecf20Sopenharmony_ci		if (!strcmp(component->name, codec_name)) {
3818c2ecf20Sopenharmony_ci			dev_dbg(component->dev, "re-enabling jack detect after resume\n");
3828c2ecf20Sopenharmony_ci			snd_soc_component_set_jack(component, &priv->jack, NULL);
3838c2ecf20Sopenharmony_ci			break;
3848c2ecf20Sopenharmony_ci		}
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/*
3888c2ecf20Sopenharmony_ci	 * Some Cherry Trail boards with an ES8316 codec have a bug in their
3898c2ecf20Sopenharmony_ci	 * ACPI tables where the MSSL1680 touchscreen's _PS0 and _PS3 methods
3908c2ecf20Sopenharmony_ci	 * wrongly also set the speaker-enable GPIO to 1/0. Testing has shown
3918c2ecf20Sopenharmony_ci	 * that this really is a bug and the GPIO has no influence on the
3928c2ecf20Sopenharmony_ci	 * touchscreen at all.
3938c2ecf20Sopenharmony_ci	 *
3948c2ecf20Sopenharmony_ci	 * The silead.c touchscreen driver does not support runtime suspend, so
3958c2ecf20Sopenharmony_ci	 * the GPIO can only be changed underneath us during a system suspend.
3968c2ecf20Sopenharmony_ci	 * This resume() function runs from a pm complete() callback, and thus
3978c2ecf20Sopenharmony_ci	 * is guaranteed to run after the touchscreen driver/ACPI-subsys has
3988c2ecf20Sopenharmony_ci	 * brought the touchscreen back up again (and thus changed the GPIO).
3998c2ecf20Sopenharmony_ci	 *
4008c2ecf20Sopenharmony_ci	 * So to work around this we pass GPIOD_FLAGS_BIT_NONEXCLUSIVE when
4018c2ecf20Sopenharmony_ci	 * requesting the GPIO and we set its value here to undo any changes
4028c2ecf20Sopenharmony_ci	 * done by the touchscreen's broken _PS0 ACPI method.
4038c2ecf20Sopenharmony_ci	 */
4048c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	return 0;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
4108c2ecf20Sopenharmony_ci/* use space before codec name to simplify card ID, and simplify driver name */
4118c2ecf20Sopenharmony_ci#define CARD_NAME "bytcht es8316" /* card name will be 'sof-bytcht es8316' */
4128c2ecf20Sopenharmony_ci#define DRIVER_NAME "SOF"
4138c2ecf20Sopenharmony_ci#else
4148c2ecf20Sopenharmony_ci#define CARD_NAME "bytcht-es8316"
4158c2ecf20Sopenharmony_ci#define DRIVER_NAME NULL /* card name will be used for driver name */
4168c2ecf20Sopenharmony_ci#endif
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic struct snd_soc_card byt_cht_es8316_card = {
4198c2ecf20Sopenharmony_ci	.name = CARD_NAME,
4208c2ecf20Sopenharmony_ci	.driver_name = DRIVER_NAME,
4218c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
4228c2ecf20Sopenharmony_ci	.dai_link = byt_cht_es8316_dais,
4238c2ecf20Sopenharmony_ci	.num_links = ARRAY_SIZE(byt_cht_es8316_dais),
4248c2ecf20Sopenharmony_ci	.dapm_widgets = byt_cht_es8316_widgets,
4258c2ecf20Sopenharmony_ci	.num_dapm_widgets = ARRAY_SIZE(byt_cht_es8316_widgets),
4268c2ecf20Sopenharmony_ci	.dapm_routes = byt_cht_es8316_audio_map,
4278c2ecf20Sopenharmony_ci	.num_dapm_routes = ARRAY_SIZE(byt_cht_es8316_audio_map),
4288c2ecf20Sopenharmony_ci	.controls = byt_cht_es8316_controls,
4298c2ecf20Sopenharmony_ci	.num_controls = ARRAY_SIZE(byt_cht_es8316_controls),
4308c2ecf20Sopenharmony_ci	.fully_routed = true,
4318c2ecf20Sopenharmony_ci	.suspend_pre = byt_cht_es8316_suspend,
4328c2ecf20Sopenharmony_ci	.resume_post = byt_cht_es8316_resume,
4338c2ecf20Sopenharmony_ci};
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params first_gpio = { 0, 0, false };
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = {
4388c2ecf20Sopenharmony_ci	{ "speaker-enable-gpios", &first_gpio, 1 },
4398c2ecf20Sopenharmony_ci	{ },
4408c2ecf20Sopenharmony_ci};
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/* Please keep this list alphabetically sorted */
4438c2ecf20Sopenharmony_cistatic const struct dmi_system_id byt_cht_es8316_quirk_table[] = {
4448c2ecf20Sopenharmony_ci	{	/* Irbis NB41 */
4458c2ecf20Sopenharmony_ci		.matches = {
4468c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "IRBIS"),
4478c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "NB41"),
4488c2ecf20Sopenharmony_ci		},
4498c2ecf20Sopenharmony_ci		.driver_data = (void *)(BYT_CHT_ES8316_SSP0
4508c2ecf20Sopenharmony_ci					| BYT_CHT_ES8316_INTMIC_IN2_MAP
4518c2ecf20Sopenharmony_ci					| BYT_CHT_ES8316_JD_INVERTED),
4528c2ecf20Sopenharmony_ci	},
4538c2ecf20Sopenharmony_ci	{	/* Nanote UMPC-01 */
4548c2ecf20Sopenharmony_ci		.matches = {
4558c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "RWC CO.,LTD"),
4568c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "UMPC-01"),
4578c2ecf20Sopenharmony_ci		},
4588c2ecf20Sopenharmony_ci		.driver_data = (void *)BYT_CHT_ES8316_INTMIC_IN1_MAP,
4598c2ecf20Sopenharmony_ci	},
4608c2ecf20Sopenharmony_ci	{	/* Teclast X98 Plus II */
4618c2ecf20Sopenharmony_ci		.matches = {
4628c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
4638c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"),
4648c2ecf20Sopenharmony_ci		},
4658c2ecf20Sopenharmony_ci		.driver_data = (void *)(BYT_CHT_ES8316_INTMIC_IN1_MAP
4668c2ecf20Sopenharmony_ci					| BYT_CHT_ES8316_JD_INVERTED),
4678c2ecf20Sopenharmony_ci	},
4688c2ecf20Sopenharmony_ci	{}
4698c2ecf20Sopenharmony_ci};
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	static const char * const mic_name[] = { "in1", "in2" };
4748c2ecf20Sopenharmony_ci	struct property_entry props[MAX_NO_PROPS] = {};
4758c2ecf20Sopenharmony_ci	struct byt_cht_es8316_private *priv;
4768c2ecf20Sopenharmony_ci	const struct dmi_system_id *dmi_id;
4778c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
4788c2ecf20Sopenharmony_ci	struct snd_soc_acpi_mach *mach;
4798c2ecf20Sopenharmony_ci	const char *platform_name;
4808c2ecf20Sopenharmony_ci	struct acpi_device *adev;
4818c2ecf20Sopenharmony_ci	struct device *codec_dev;
4828c2ecf20Sopenharmony_ci	unsigned int cnt = 0;
4838c2ecf20Sopenharmony_ci	int dai_index = 0;
4848c2ecf20Sopenharmony_ci	int i;
4858c2ecf20Sopenharmony_ci	int ret = 0;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
4888c2ecf20Sopenharmony_ci	if (!priv)
4898c2ecf20Sopenharmony_ci		return -ENOMEM;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	mach = dev->platform_data;
4928c2ecf20Sopenharmony_ci	/* fix index of codec dai */
4938c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) {
4948c2ecf20Sopenharmony_ci		if (!strcmp(byt_cht_es8316_dais[i].codecs->name,
4958c2ecf20Sopenharmony_ci			    "i2c-ESSX8316:00")) {
4968c2ecf20Sopenharmony_ci			dai_index = i;
4978c2ecf20Sopenharmony_ci			break;
4988c2ecf20Sopenharmony_ci		}
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	/* fixup codec name based on HID */
5028c2ecf20Sopenharmony_ci	adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1);
5038c2ecf20Sopenharmony_ci	if (adev) {
5048c2ecf20Sopenharmony_ci		snprintf(codec_name, sizeof(codec_name),
5058c2ecf20Sopenharmony_ci			 "i2c-%s", acpi_dev_name(adev));
5068c2ecf20Sopenharmony_ci		put_device(&adev->dev);
5078c2ecf20Sopenharmony_ci		byt_cht_es8316_dais[dai_index].codecs->name = codec_name;
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	/* override plaform name, if required */
5118c2ecf20Sopenharmony_ci	byt_cht_es8316_card.dev = dev;
5128c2ecf20Sopenharmony_ci	platform_name = mach->mach_params.platform;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card,
5158c2ecf20Sopenharmony_ci						    platform_name);
5168c2ecf20Sopenharmony_ci	if (ret)
5178c2ecf20Sopenharmony_ci		return ret;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	/* Check for BYTCR or other platform and setup quirks */
5208c2ecf20Sopenharmony_ci	dmi_id = dmi_first_match(byt_cht_es8316_quirk_table);
5218c2ecf20Sopenharmony_ci	if (dmi_id) {
5228c2ecf20Sopenharmony_ci		quirk = (unsigned long)dmi_id->driver_data;
5238c2ecf20Sopenharmony_ci	} else if (soc_intel_is_byt() &&
5248c2ecf20Sopenharmony_ci		   mach->mach_params.acpi_ipc_irq_index == 0) {
5258c2ecf20Sopenharmony_ci		/* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */
5268c2ecf20Sopenharmony_ci		quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP |
5278c2ecf20Sopenharmony_ci			BYT_CHT_ES8316_MONO_SPEAKER;
5288c2ecf20Sopenharmony_ci	} else {
5298c2ecf20Sopenharmony_ci		/* Others default to internal-mic-in1-map, mono-speaker */
5308c2ecf20Sopenharmony_ci		quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP |
5318c2ecf20Sopenharmony_ci			BYT_CHT_ES8316_MONO_SPEAKER;
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci	if (quirk_override != -1) {
5348c2ecf20Sopenharmony_ci		dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n",
5358c2ecf20Sopenharmony_ci			 quirk, quirk_override);
5368c2ecf20Sopenharmony_ci		quirk = quirk_override;
5378c2ecf20Sopenharmony_ci	}
5388c2ecf20Sopenharmony_ci	log_quirks(dev);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (quirk & BYT_CHT_ES8316_SSP0)
5418c2ecf20Sopenharmony_ci		byt_cht_es8316_dais[dai_index].cpus->dai_name = "ssp0-port";
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/* get the clock */
5448c2ecf20Sopenharmony_ci	priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3");
5458c2ecf20Sopenharmony_ci	if (IS_ERR(priv->mclk)) {
5468c2ecf20Sopenharmony_ci		ret = PTR_ERR(priv->mclk);
5478c2ecf20Sopenharmony_ci		dev_err(dev, "clk_get pmc_plt_clk_3 failed: %d\n", ret);
5488c2ecf20Sopenharmony_ci		return ret;
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	/* get speaker enable GPIO */
5528c2ecf20Sopenharmony_ci	codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, codec_name);
5538c2ecf20Sopenharmony_ci	if (!codec_dev)
5548c2ecf20Sopenharmony_ci		return -EPROBE_DEFER;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	if (quirk & BYT_CHT_ES8316_JD_INVERTED)
5578c2ecf20Sopenharmony_ci		props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted");
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (cnt) {
5608c2ecf20Sopenharmony_ci		ret = device_add_properties(codec_dev, props);
5618c2ecf20Sopenharmony_ci		if (ret) {
5628c2ecf20Sopenharmony_ci			put_device(codec_dev);
5638c2ecf20Sopenharmony_ci			return ret;
5648c2ecf20Sopenharmony_ci		}
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios);
5688c2ecf20Sopenharmony_ci	priv->speaker_en_gpio =
5698c2ecf20Sopenharmony_ci		gpiod_get_index(codec_dev, "speaker-enable", 0,
5708c2ecf20Sopenharmony_ci				/* see comment in byt_cht_es8316_resume */
5718c2ecf20Sopenharmony_ci				GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
5728c2ecf20Sopenharmony_ci	put_device(codec_dev);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	if (IS_ERR(priv->speaker_en_gpio)) {
5758c2ecf20Sopenharmony_ci		ret = PTR_ERR(priv->speaker_en_gpio);
5768c2ecf20Sopenharmony_ci		switch (ret) {
5778c2ecf20Sopenharmony_ci		case -ENOENT:
5788c2ecf20Sopenharmony_ci			priv->speaker_en_gpio = NULL;
5798c2ecf20Sopenharmony_ci			break;
5808c2ecf20Sopenharmony_ci		default:
5818c2ecf20Sopenharmony_ci			dev_err(dev, "get speaker GPIO failed: %d\n", ret);
5828c2ecf20Sopenharmony_ci			fallthrough;
5838c2ecf20Sopenharmony_ci		case -EPROBE_DEFER:
5848c2ecf20Sopenharmony_ci			return ret;
5858c2ecf20Sopenharmony_ci		}
5868c2ecf20Sopenharmony_ci	}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	snprintf(components_string, sizeof(components_string),
5898c2ecf20Sopenharmony_ci		 "cfg-spk:%s cfg-mic:%s",
5908c2ecf20Sopenharmony_ci		 (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "1" : "2",
5918c2ecf20Sopenharmony_ci		 mic_name[BYT_CHT_ES8316_MAP(quirk)]);
5928c2ecf20Sopenharmony_ci	byt_cht_es8316_card.components = components_string;
5938c2ecf20Sopenharmony_ci#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
5948c2ecf20Sopenharmony_ci	snprintf(long_name, sizeof(long_name), "bytcht-es8316-%s-spk-%s-mic",
5958c2ecf20Sopenharmony_ci		 (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo",
5968c2ecf20Sopenharmony_ci		 mic_name[BYT_CHT_ES8316_MAP(quirk)]);
5978c2ecf20Sopenharmony_ci	byt_cht_es8316_card.long_name = long_name;
5988c2ecf20Sopenharmony_ci#endif
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	/* register the soc card */
6018c2ecf20Sopenharmony_ci	snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card);
6048c2ecf20Sopenharmony_ci	if (ret) {
6058c2ecf20Sopenharmony_ci		gpiod_put(priv->speaker_en_gpio);
6068c2ecf20Sopenharmony_ci		dev_err(dev, "snd_soc_register_card failed: %d\n", ret);
6078c2ecf20Sopenharmony_ci		return ret;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, &byt_cht_es8316_card);
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	struct snd_soc_card *card = platform_get_drvdata(pdev);
6168c2ecf20Sopenharmony_ci	struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	gpiod_put(priv->speaker_en_gpio);
6198c2ecf20Sopenharmony_ci	return 0;
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_cistatic struct platform_driver snd_byt_cht_es8316_mc_driver = {
6238c2ecf20Sopenharmony_ci	.driver = {
6248c2ecf20Sopenharmony_ci		.name = "bytcht_es8316",
6258c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
6268c2ecf20Sopenharmony_ci		.pm = &snd_soc_pm_ops,
6278c2ecf20Sopenharmony_ci#endif
6288c2ecf20Sopenharmony_ci	},
6298c2ecf20Sopenharmony_ci	.probe = snd_byt_cht_es8316_mc_probe,
6308c2ecf20Sopenharmony_ci	.remove = snd_byt_cht_es8316_mc_remove,
6318c2ecf20Sopenharmony_ci};
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cimodule_platform_driver(snd_byt_cht_es8316_mc_driver);
6348c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver");
6358c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
6368c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
6378c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:bytcht_es8316");
638