xref: /linux/sound/soc/codecs/es9356.c (revision fab183d632628381b466a41479489541ac0e29a0)
15d9cb740SZhang Yi // SPDX-License-Identifier: GPL-2.0-only
25d9cb740SZhang Yi //
35d9cb740SZhang Yi // es9356.c -- SoundWire codec driver
45d9cb740SZhang Yi //
55d9cb740SZhang Yi // Copyright(c) 2025 Everest Semiconductor Co., Ltd
65d9cb740SZhang Yi //
75d9cb740SZhang Yi //
85d9cb740SZhang Yi 
95d9cb740SZhang Yi #include <linux/cleanup.h>
105d9cb740SZhang Yi #include <linux/device.h>
115d9cb740SZhang Yi #include <linux/module.h>
125d9cb740SZhang Yi #include <linux/soundwire/sdw.h>
135d9cb740SZhang Yi #include <linux/soundwire/sdw_type.h>
145d9cb740SZhang Yi #include <linux/soundwire/sdw_registers.h>
155d9cb740SZhang Yi #include <sound/core.h>
165d9cb740SZhang Yi #include <sound/pcm.h>
175d9cb740SZhang Yi #include <sound/pcm_params.h>
185d9cb740SZhang Yi #include <linux/pm_runtime.h>
195d9cb740SZhang Yi #include <sound/sdw.h>
205d9cb740SZhang Yi #include <sound/soc.h>
215d9cb740SZhang Yi #include <sound/soc-dapm.h>
225d9cb740SZhang Yi #include <sound/tlv.h>
235d9cb740SZhang Yi #include <linux/interrupt.h>
245d9cb740SZhang Yi #include <linux/irq.h>
255d9cb740SZhang Yi #include <sound/jack.h>
265d9cb740SZhang Yi #include <sound/sdca_asoc.h>
275d9cb740SZhang Yi #include "es9356.h"
285d9cb740SZhang Yi 
295d9cb740SZhang Yi struct  es9356_sdw_priv {
305d9cb740SZhang Yi 	struct sdw_slave *slave;
315d9cb740SZhang Yi 	struct device *dev;
325d9cb740SZhang Yi 	struct regmap *regmap;
335d9cb740SZhang Yi 	struct snd_soc_component *component;
345d9cb740SZhang Yi 	struct snd_soc_jack *hs_jack;
355d9cb740SZhang Yi 
365d9cb740SZhang Yi 	/* lock for irq*/
375d9cb740SZhang Yi 	struct mutex disable_irq_lock;
385d9cb740SZhang Yi 
395d9cb740SZhang Yi 	/* lock for pde*/
405d9cb740SZhang Yi 	struct mutex pde_lock;
415d9cb740SZhang Yi 
425d9cb740SZhang Yi 	bool hw_init;
435d9cb740SZhang Yi 	bool first_hw_init;
445d9cb740SZhang Yi 	int jack_type;
455d9cb740SZhang Yi 	bool disable_irq;
465d9cb740SZhang Yi 
475d9cb740SZhang Yi 	struct delayed_work interrupt_handle_work;
485d9cb740SZhang Yi 	struct delayed_work button_detect_work;
495d9cb740SZhang Yi 	unsigned int sdca_status;
505d9cb740SZhang Yi };
515d9cb740SZhang Yi 
es9356_sdw_component_probe(struct snd_soc_component * component)525d9cb740SZhang Yi static int es9356_sdw_component_probe(struct snd_soc_component *component)
535d9cb740SZhang Yi {
545d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
555d9cb740SZhang Yi 
565d9cb740SZhang Yi 	es9356->component = component;
575d9cb740SZhang Yi 
585d9cb740SZhang Yi 	return 0;
595d9cb740SZhang Yi }
605d9cb740SZhang Yi 
615d9cb740SZhang Yi static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -9600, 12, 0);
625d9cb740SZhang Yi static const DECLARE_TLV_DB_SCALE(amic_gain_tlv, 0, 3, 0);
635d9cb740SZhang Yi static const DECLARE_TLV_DB_SCALE(dmic_gain_tlv, 0, 6, 0);
645d9cb740SZhang Yi 
655d9cb740SZhang Yi static const struct snd_kcontrol_new es9356_sdca_controls[] = {
665d9cb740SZhang Yi 	SDCA_SINGLE_Q78_TLV("FU41 Left Playback Volume",
675d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_VOLUME, CH_L),
685d9cb740SZhang Yi 		ES9356_VOLUME_MIN, ES9356_VOLUME_MAX, ES9356_VOLUME_STEP, out_vol_tlv),
695d9cb740SZhang Yi 	SDCA_SINGLE_Q78_TLV("FU41 Right Playback Volume",
705d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_VOLUME, CH_R),
715d9cb740SZhang Yi 		ES9356_VOLUME_MIN, ES9356_VOLUME_MAX, ES9356_VOLUME_STEP, out_vol_tlv),
725d9cb740SZhang Yi 	SDCA_SINGLE_Q78_TLV("FU36 Left Capture Volume",
735d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_L),
745d9cb740SZhang Yi 		ES9356_VOLUME_MIN, ES9356_VOLUME_MAX, ES9356_VOLUME_STEP, out_vol_tlv),
755d9cb740SZhang Yi 	SDCA_SINGLE_Q78_TLV("FU36 Right Capture Volume",
765d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_R),
775d9cb740SZhang Yi 		ES9356_VOLUME_MIN, ES9356_VOLUME_MAX, ES9356_VOLUME_STEP, out_vol_tlv),
785d9cb740SZhang Yi 	SDCA_SINGLE_Q78_TLV("FU33 Capture Volume",
795d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU33, ES9356_SDCA_CTL_FU_CH_GAIN, 0),
805d9cb740SZhang Yi 		ES9356_GAIN_MIN, ES9356_AMIC_GAIN_MAX, ES9356_AMIC_GAIN_STEP, amic_gain_tlv),
815d9cb740SZhang Yi 	SDCA_SINGLE_Q78_TLV("FU21 Left Playback Volume",
825d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_VOLUME, CH_L),
835d9cb740SZhang Yi 		ES9356_VOLUME_MIN, ES9356_VOLUME_MAX, ES9356_VOLUME_STEP, out_vol_tlv),
845d9cb740SZhang Yi 	SDCA_SINGLE_Q78_TLV("FU21 Right Playback Volume",
855d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_VOLUME, CH_R),
865d9cb740SZhang Yi 		ES9356_VOLUME_MIN, ES9356_VOLUME_MAX, ES9356_VOLUME_STEP, out_vol_tlv),
875d9cb740SZhang Yi 	SDCA_SINGLE_Q78_TLV("FU113 Left Capture Volume",
885d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_L),
895d9cb740SZhang Yi 		ES9356_VOLUME_MIN, ES9356_VOLUME_MAX, ES9356_VOLUME_STEP, out_vol_tlv),
905d9cb740SZhang Yi 	SDCA_SINGLE_Q78_TLV("FU113 Right Capture Volume",
915d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_R),
925d9cb740SZhang Yi 		ES9356_VOLUME_MIN, ES9356_VOLUME_MAX, ES9356_VOLUME_STEP, out_vol_tlv),
935d9cb740SZhang Yi 	SDCA_SINGLE_Q78_TLV("FU11 Capture Volume",
945d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU11, ES9356_SDCA_CTL_FU_CH_GAIN, 0),
955d9cb740SZhang Yi 		ES9356_GAIN_MIN, ES9356_DMIC_GAIN_MAX, ES9356_DMIC_GAIN_STEP, dmic_gain_tlv),
965d9cb740SZhang Yi };
975d9cb740SZhang Yi 
985d9cb740SZhang Yi static const char *const es9356_left_mux_txt[] = {
995d9cb740SZhang Yi 	"Left",
1005d9cb740SZhang Yi 	"Right",
1015d9cb740SZhang Yi };
1025d9cb740SZhang Yi 
1035d9cb740SZhang Yi static const char *const es9356_right_mux_txt[] = {
1045d9cb740SZhang Yi 	"Right",
1055d9cb740SZhang Yi 	"Left",
1065d9cb740SZhang Yi };
1075d9cb740SZhang Yi 
1085d9cb740SZhang Yi static const struct soc_enum es9356_left_mux_enum =
1095d9cb740SZhang Yi 	SOC_ENUM_SINGLE(ES9356_DAC_SWAP, 1,
1105d9cb740SZhang Yi 			ARRAY_SIZE(es9356_left_mux_txt), es9356_left_mux_txt);
1115d9cb740SZhang Yi static const struct soc_enum es9356_right_mux_enum =
1125d9cb740SZhang Yi 	SOC_ENUM_SINGLE(ES9356_DAC_SWAP, 0,
1135d9cb740SZhang Yi 			ARRAY_SIZE(es9356_right_mux_txt), es9356_right_mux_txt);
1145d9cb740SZhang Yi 
1155d9cb740SZhang Yi static const struct snd_kcontrol_new es9356_left_mux_controls =
1165d9cb740SZhang Yi 	SOC_DAPM_ENUM("Channel MUX", es9356_left_mux_enum);
1175d9cb740SZhang Yi static const struct snd_kcontrol_new es9356_right_mux_controls =
1185d9cb740SZhang Yi 	SOC_DAPM_ENUM("Channel MUX", es9356_right_mux_enum);
1195d9cb740SZhang Yi 
1205d9cb740SZhang Yi static const struct snd_soc_dapm_widget es9356_dapm_widgets[] = {
1215d9cb740SZhang Yi 	SND_SOC_DAPM_OUTPUT("HP"),
1225d9cb740SZhang Yi 	SND_SOC_DAPM_OUTPUT("SPK"),
1235d9cb740SZhang Yi 	SND_SOC_DAPM_INPUT("MIC1"),
1245d9cb740SZhang Yi 	SND_SOC_DAPM_INPUT("PDM_DIN"),
1255d9cb740SZhang Yi 
1265d9cb740SZhang Yi 	SND_SOC_DAPM_SUPPLY("DMIC Clock", ES9356_DMIC_GPIO, 1, 1, NULL, 0),
1275d9cb740SZhang Yi 
1285d9cb740SZhang Yi 	SND_SOC_DAPM_AIF_IN("DP4RX", "DP4 Playback", 0, SND_SOC_NOPM, 0, 0),
1295d9cb740SZhang Yi 	SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0),
1305d9cb740SZhang Yi 	SND_SOC_DAPM_AIF_OUT("DP1TX", "DP1 Capture", 0, SND_SOC_NOPM, 0, 0),
1315d9cb740SZhang Yi 	SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0),
1325d9cb740SZhang Yi 
1335d9cb740SZhang Yi 	SND_SOC_DAPM_PGA("IF DP3RXL", SND_SOC_NOPM, 0, 0, NULL, 0),
1345d9cb740SZhang Yi 	SND_SOC_DAPM_PGA("IF DP3RXR", SND_SOC_NOPM, 0, 0, NULL, 0),
1355d9cb740SZhang Yi 
1365d9cb740SZhang Yi 	SND_SOC_DAPM_MUX("Left Channel MUX", SND_SOC_NOPM, 0, 0, &es9356_left_mux_controls),
1375d9cb740SZhang Yi 	SND_SOC_DAPM_MUX("Right Channel MUX", SND_SOC_NOPM, 0, 0, &es9356_right_mux_controls),
1385d9cb740SZhang Yi 
1395d9cb740SZhang Yi 	SND_SOC_DAPM_DAC("FU 21 Left", NULL,
1405d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_MUTE, CH_L), 0, 1),
1415d9cb740SZhang Yi 	SND_SOC_DAPM_DAC("FU 21 Right", NULL,
1425d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_MUTE, CH_R), 0, 1),
1435d9cb740SZhang Yi 	SND_SOC_DAPM_DAC("FU 41 Left", NULL,
1445d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_MUTE, CH_L), 0, 1),
1455d9cb740SZhang Yi 	SND_SOC_DAPM_DAC("FU 41 Right", NULL,
1465d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_MUTE, CH_R), 0, 1),
1475d9cb740SZhang Yi 	SND_SOC_DAPM_DAC("FU 113 Left", NULL,
1485d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_MUTE, CH_L), 0, 1),
1495d9cb740SZhang Yi 	SND_SOC_DAPM_DAC("FU 113 Right", NULL,
1505d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_MUTE, CH_R), 0, 1),
1515d9cb740SZhang Yi 	SND_SOC_DAPM_DAC("FU 36 Left", NULL,
1525d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_MUTE, CH_L), 0, 1),
1535d9cb740SZhang Yi 	SND_SOC_DAPM_DAC("FU 36 Right", NULL,
1545d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_MUTE, CH_R), 0, 1),
1555d9cb740SZhang Yi };
1565d9cb740SZhang Yi 
1575d9cb740SZhang Yi static const struct snd_soc_dapm_route es9356_audio_map[] = {
1585d9cb740SZhang Yi 	{"FU 36 Left", NULL, "MIC1"},
1595d9cb740SZhang Yi 	{"FU 36 Right", NULL, "MIC1"},
1605d9cb740SZhang Yi 	{"DP2TX", NULL, "FU 36 Left"},
1615d9cb740SZhang Yi 	{"DP2TX", NULL, "FU 36 Right"},
1625d9cb740SZhang Yi 
1635d9cb740SZhang Yi 	{"PDM_DIN", NULL, "DMIC Clock"},
1645d9cb740SZhang Yi 	{"FU 113 Left", NULL, "PDM_DIN"},
1655d9cb740SZhang Yi 	{"FU 113 Right", NULL, "PDM_DIN"},
1665d9cb740SZhang Yi 	{"DP1TX", NULL, "FU 113 Left"},
1675d9cb740SZhang Yi 	{"DP1TX", NULL, "FU 113 Right"},
1685d9cb740SZhang Yi 
1695d9cb740SZhang Yi 	{"FU 41 Left", NULL, "DP4RX"},
1705d9cb740SZhang Yi 	{"FU 41 Right", NULL, "DP4RX"},
1715d9cb740SZhang Yi 
1725d9cb740SZhang Yi 	{"IF DP3RXL", NULL, "DP3RX"},
1735d9cb740SZhang Yi 	{"IF DP3RXR", NULL, "DP3RX"},
1745d9cb740SZhang Yi 
1755d9cb740SZhang Yi 	{"Left Channel MUX", "Left", "IF DP3RXL"},
1765d9cb740SZhang Yi 	{"Left Channel MUX", "Right", "IF DP3RXR"},
1775d9cb740SZhang Yi 	{"Right Channel MUX", "Left", "IF DP3RXL"},
1785d9cb740SZhang Yi 	{"Right Channel MUX", "Right", "IF DP3RXR"},
1795d9cb740SZhang Yi 
1805d9cb740SZhang Yi 	{"FU 21 Left", NULL, "Left Channel MUX"},
1815d9cb740SZhang Yi 	{"FU 21 Right", NULL, "Right Channel MUX"},
1825d9cb740SZhang Yi 
1835d9cb740SZhang Yi 	{"SPK", NULL, "FU 21 Left"},
1845d9cb740SZhang Yi 	{"SPK", NULL, "FU 21 Right"},
1855d9cb740SZhang Yi 
1865d9cb740SZhang Yi 	{"HP", NULL, "FU 41 Left"},
1875d9cb740SZhang Yi 	{"HP", NULL, "FU 41 Right"},
1885d9cb740SZhang Yi };
1895d9cb740SZhang Yi 
es9356_set_jack_detect(struct snd_soc_component * component,struct snd_soc_jack * hs_jack,void * data)1905d9cb740SZhang Yi static int es9356_set_jack_detect(struct snd_soc_component *component,
1915d9cb740SZhang Yi 	struct snd_soc_jack *hs_jack, void *data)
1925d9cb740SZhang Yi {
1935d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
1945d9cb740SZhang Yi 	int ret;
1955d9cb740SZhang Yi 
1965d9cb740SZhang Yi 	es9356->hs_jack = hs_jack;
1975d9cb740SZhang Yi 
1985d9cb740SZhang Yi 	/* we can only resume if the device was initialized at least once */
1995d9cb740SZhang Yi 	if (!es9356->first_hw_init)
2005d9cb740SZhang Yi 		return 0;
2015d9cb740SZhang Yi 
2025d9cb740SZhang Yi 	ret = pm_runtime_resume_and_get(component->dev);
2035d9cb740SZhang Yi 	if (ret < 0) {
2045d9cb740SZhang Yi 		if (ret != -EACCES) {
2055d9cb740SZhang Yi 			dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
2065d9cb740SZhang Yi 			return ret;
2075d9cb740SZhang Yi 		}
2085d9cb740SZhang Yi 		/* pm_runtime not enabled yet */
2095d9cb740SZhang Yi 		dev_info(component->dev, "%s: skipping jack init for now\n", __func__);
2105d9cb740SZhang Yi 		return 0;
2115d9cb740SZhang Yi 	}
2125d9cb740SZhang Yi 
2135d9cb740SZhang Yi 	if (es9356->hs_jack)
2145d9cb740SZhang Yi 		sdw_write_no_pm(es9356->slave, SDW_SCP_SDCA_INTMASK1,
2155d9cb740SZhang Yi 			(SDW_SCP_SDCA_INTMASK_SDCA_7 | SDW_SCP_SDCA_INTMASK_SDCA_5 | SDW_SCP_SDCA_INTMASK_SDCA_1));
2165d9cb740SZhang Yi 
2175d9cb740SZhang Yi 	pm_runtime_mark_last_busy(component->dev);
2185d9cb740SZhang Yi 	pm_runtime_put_autosuspend(component->dev);
2195d9cb740SZhang Yi 
2205d9cb740SZhang Yi 	return 0;
2215d9cb740SZhang Yi }
2225d9cb740SZhang Yi static const struct snd_soc_component_driver snd_soc_es9356_sdw_component = {
2235d9cb740SZhang Yi 	.probe = es9356_sdw_component_probe,
2245d9cb740SZhang Yi 	.controls = es9356_sdca_controls,
2255d9cb740SZhang Yi 	.num_controls = ARRAY_SIZE(es9356_sdca_controls),
2265d9cb740SZhang Yi 	.dapm_widgets = es9356_dapm_widgets,
2275d9cb740SZhang Yi 	.num_dapm_widgets = ARRAY_SIZE(es9356_dapm_widgets),
2285d9cb740SZhang Yi 	.dapm_routes = es9356_audio_map,
2295d9cb740SZhang Yi 	.num_dapm_routes = ARRAY_SIZE(es9356_audio_map),
2305d9cb740SZhang Yi 	.set_jack = es9356_set_jack_detect,
2315d9cb740SZhang Yi 	.endianness = 1,
2325d9cb740SZhang Yi };
2335d9cb740SZhang Yi 
es9356_sdw_set_sdw_stream(struct snd_soc_dai * dai,void * sdw_stream,int direction)2345d9cb740SZhang Yi static int es9356_sdw_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
2355d9cb740SZhang Yi 				     int direction)
2365d9cb740SZhang Yi {
2375d9cb740SZhang Yi 	snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
2385d9cb740SZhang Yi 
2395d9cb740SZhang Yi 	return 0;
2405d9cb740SZhang Yi }
2415d9cb740SZhang Yi 
es9356_sdw_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)2425d9cb740SZhang Yi static void es9356_sdw_shutdown(struct snd_pcm_substream *substream,
2435d9cb740SZhang Yi 				struct snd_soc_dai *dai)
2445d9cb740SZhang Yi {
2455d9cb740SZhang Yi 	snd_soc_dai_set_dma_data(dai, substream, NULL);
2465d9cb740SZhang Yi }
2475d9cb740SZhang Yi 
es9356_sdca_button(unsigned int * buffer)2485d9cb740SZhang Yi static int es9356_sdca_button(unsigned int *buffer)
2495d9cb740SZhang Yi {
2505d9cb740SZhang Yi 	int cur_button = -1;
2515d9cb740SZhang Yi 
2525d9cb740SZhang Yi 	if (*(buffer + 1) | *(buffer + 2))
2535d9cb740SZhang Yi 		return -EINVAL;
2545d9cb740SZhang Yi 	switch (*buffer) {
2555d9cb740SZhang Yi 	case 0x00:
2565d9cb740SZhang Yi 		cur_button = 0;
2575d9cb740SZhang Yi 		break;
2585d9cb740SZhang Yi 	case 0x20:
2595d9cb740SZhang Yi 		cur_button = SND_JACK_BTN_4;
2605d9cb740SZhang Yi 		break;
2615d9cb740SZhang Yi 	case 0x10:
2625d9cb740SZhang Yi 		cur_button = SND_JACK_BTN_2;
2635d9cb740SZhang Yi 		break;
2645d9cb740SZhang Yi 	case 0x08:
2655d9cb740SZhang Yi 		cur_button = SND_JACK_BTN_1;
2665d9cb740SZhang Yi 		break;
2675d9cb740SZhang Yi 	case 0x02:
2685d9cb740SZhang Yi 		cur_button = SND_JACK_BTN_3;
2695d9cb740SZhang Yi 		break;
2705d9cb740SZhang Yi 	case 0x01:
2715d9cb740SZhang Yi 		cur_button = SND_JACK_BTN_0;
2725d9cb740SZhang Yi 		break;
2735d9cb740SZhang Yi 	default:
2745d9cb740SZhang Yi 		break;
2755d9cb740SZhang Yi 	}
2765d9cb740SZhang Yi 
2775d9cb740SZhang Yi 	return cur_button;
2785d9cb740SZhang Yi }
2795d9cb740SZhang Yi 
es9356_sdca_button_detect(struct es9356_sdw_priv * es9356)2805d9cb740SZhang Yi static int es9356_sdca_button_detect(struct es9356_sdw_priv *es9356)
2815d9cb740SZhang Yi {
2825d9cb740SZhang Yi 	unsigned int btn_type = 0, offset, idx, val, owner;
2835d9cb740SZhang Yi 	unsigned int button[3];
2845d9cb740SZhang Yi 	int ret;
2855d9cb740SZhang Yi 
2865d9cb740SZhang Yi 	ret = regmap_read(es9356->regmap,
2875d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_HID, ES9356_SDCA_ENT_HID01, ES9356_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), &owner);
2885d9cb740SZhang Yi 	if (ret < 0 || owner == 0x01)
2895d9cb740SZhang Yi 		return 0;
2905d9cb740SZhang Yi 
2915d9cb740SZhang Yi 	ret = regmap_read(es9356->regmap, ES9356_BUF_ADDR_HID, &offset);
2925d9cb740SZhang Yi 	if (ret < 0)
2935d9cb740SZhang Yi 		goto button_det_end;
2945d9cb740SZhang Yi 
2955d9cb740SZhang Yi 	for (idx = 0; idx < ARRAY_SIZE(button); idx++) {
2965d9cb740SZhang Yi 		ret = regmap_read(es9356->regmap, ES9356_BUF_ADDR_HID + offset + idx, &val);
2975d9cb740SZhang Yi 		if (ret < 0)
2985d9cb740SZhang Yi 			goto button_det_end;
2995d9cb740SZhang Yi 		button[idx] = val;
3005d9cb740SZhang Yi 	}
3015d9cb740SZhang Yi 
3025d9cb740SZhang Yi 	btn_type = es9356_sdca_button(&button[0]);
3035d9cb740SZhang Yi 
3045d9cb740SZhang Yi button_det_end:
3055d9cb740SZhang Yi 	if (owner == 0x00)
3065d9cb740SZhang Yi 		regmap_write(es9356->regmap,
3075d9cb740SZhang Yi 			SDW_SDCA_CTL(FUNC_NUM_HID, ES9356_SDCA_ENT_HID01, ES9356_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01);
3085d9cb740SZhang Yi 
3095d9cb740SZhang Yi 	return btn_type;
3105d9cb740SZhang Yi }
3115d9cb740SZhang Yi 
es9356_sdca_headset_detect(struct es9356_sdw_priv * es9356)3125d9cb740SZhang Yi static int es9356_sdca_headset_detect(struct es9356_sdw_priv *es9356)
3135d9cb740SZhang Yi {
3145d9cb740SZhang Yi 	unsigned int reg;
3155d9cb740SZhang Yi 	int ret;
3165d9cb740SZhang Yi 
3175d9cb740SZhang Yi 	ret = regmap_read(es9356->regmap,
3185d9cb740SZhang Yi 			SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_GE35, ES9356_SDCA_CTL_DETECTED_MODE, 0), &reg);
3195d9cb740SZhang Yi 
3205d9cb740SZhang Yi 	if (ret < 0)
3215d9cb740SZhang Yi 		goto io_error;
3225d9cb740SZhang Yi 
3235d9cb740SZhang Yi 	switch (reg) {
3245d9cb740SZhang Yi 	case 0x00:
3255d9cb740SZhang Yi 		es9356->jack_type = 0;
3265d9cb740SZhang Yi 		break;
3275d9cb740SZhang Yi 	case 0x03:
3285d9cb740SZhang Yi 		es9356->jack_type = SND_JACK_HEADPHONE;
3295d9cb740SZhang Yi 		break;
3305d9cb740SZhang Yi 	case 0x04:
3315d9cb740SZhang Yi 		es9356->jack_type = SND_JACK_HEADSET;
3325d9cb740SZhang Yi 		break;
3335d9cb740SZhang Yi 	default:
3345d9cb740SZhang Yi 		es9356->jack_type = 0;
3355d9cb740SZhang Yi 		return -1;
3365d9cb740SZhang Yi 	}
3375d9cb740SZhang Yi 
3385d9cb740SZhang Yi 	if (reg) {
3395d9cb740SZhang Yi 		regmap_write(es9356->regmap,
3405d9cb740SZhang Yi 			SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_GE35, ES9356_SDCA_CTL_SELECTED_MODE, 0), reg);
3415d9cb740SZhang Yi 		regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0x75);
3425d9cb740SZhang Yi 	} else {
3435d9cb740SZhang Yi 		regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0xa4);
3445d9cb740SZhang Yi 	}
3455d9cb740SZhang Yi 
3465d9cb740SZhang Yi 	return 0;
3475d9cb740SZhang Yi 
3485d9cb740SZhang Yi io_error:
3495d9cb740SZhang Yi 	pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
3505d9cb740SZhang Yi 	return ret;
3515d9cb740SZhang Yi }
3525d9cb740SZhang Yi 
es9356_interrupt_handler(struct work_struct * work)3535d9cb740SZhang Yi static void es9356_interrupt_handler(struct work_struct *work)
3545d9cb740SZhang Yi {
3555d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 =
3565d9cb740SZhang Yi 		container_of(work, struct es9356_sdw_priv, interrupt_handle_work.work);
3575d9cb740SZhang Yi 	int ret, btn_type = 0;
3585d9cb740SZhang Yi 
3595d9cb740SZhang Yi 	if (!es9356->hs_jack)
3605d9cb740SZhang Yi 		return;
3615d9cb740SZhang Yi 
3625d9cb740SZhang Yi 	if (!es9356->component->card || !es9356->component->card->instantiated)
3635d9cb740SZhang Yi 		return;
3645d9cb740SZhang Yi 
3655d9cb740SZhang Yi 	/* Handling different types of interrupts based on the mask bit */
3665d9cb740SZhang Yi 	if (es9356->sdca_status & SDW_SCP_SDCA_INT_SDCA_7) {
3675d9cb740SZhang Yi 		btn_type = es9356_sdca_button_detect(es9356);
3685d9cb740SZhang Yi 		if (btn_type < 0)
3695d9cb740SZhang Yi 			return;
3705d9cb740SZhang Yi 	} else {
3715d9cb740SZhang Yi 		ret = es9356_sdca_headset_detect(es9356);
3725d9cb740SZhang Yi 		if (ret < 0)
3735d9cb740SZhang Yi 			return;
3745d9cb740SZhang Yi 	}
3755d9cb740SZhang Yi 
3765d9cb740SZhang Yi 	if (es9356->jack_type != SND_JACK_HEADSET)
3775d9cb740SZhang Yi 		btn_type = 0;
3785d9cb740SZhang Yi 
3795d9cb740SZhang Yi 	snd_soc_jack_report(es9356->hs_jack, es9356->jack_type | btn_type,
3805d9cb740SZhang Yi 			SND_JACK_HEADSET |
3815d9cb740SZhang Yi 			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
3825d9cb740SZhang Yi 			SND_JACK_BTN_2 | SND_JACK_BTN_3 |
3835d9cb740SZhang Yi 			SND_JACK_BTN_4);
3845d9cb740SZhang Yi 
3855d9cb740SZhang Yi 	if (btn_type) {
3865d9cb740SZhang Yi 		snd_soc_jack_report(es9356->hs_jack, es9356->jack_type,
3875d9cb740SZhang Yi 			SND_JACK_HEADSET |
3885d9cb740SZhang Yi 			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
3895d9cb740SZhang Yi 			SND_JACK_BTN_2 | SND_JACK_BTN_3 |
3905d9cb740SZhang Yi 			SND_JACK_BTN_4);
3915d9cb740SZhang Yi 		mod_delayed_work(system_power_efficient_wq,
3925d9cb740SZhang Yi 			&es9356->button_detect_work, msecs_to_jiffies(280));
3935d9cb740SZhang Yi 	}
3945d9cb740SZhang Yi }
3955d9cb740SZhang Yi 
es9356_button_detect_handler(struct work_struct * work)3965d9cb740SZhang Yi static void es9356_button_detect_handler(struct work_struct *work)
3975d9cb740SZhang Yi {
3985d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 =
3995d9cb740SZhang Yi 		container_of(work, struct es9356_sdw_priv, button_detect_work.work);
4005d9cb740SZhang Yi 	int ret, idx, btn_type = 0;
4015d9cb740SZhang Yi 	unsigned int reg, offset;
4025d9cb740SZhang Yi 	unsigned int button[3];
4035d9cb740SZhang Yi 
4045d9cb740SZhang Yi 	/* Check headset */
4055d9cb740SZhang Yi 	ret = regmap_read(es9356->regmap,
4065d9cb740SZhang Yi 			SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_GE35, ES9356_SDCA_CTL_DETECTED_MODE, 0), &reg);
4075d9cb740SZhang Yi 
4085d9cb740SZhang Yi 	if (ret < 0)
4095d9cb740SZhang Yi 		goto io_error;
4105d9cb740SZhang Yi 
4115d9cb740SZhang Yi 	if (reg == 0x04) {
4125d9cb740SZhang Yi 		ret = regmap_read(es9356->regmap, ES9356_BUF_ADDR_HID, &offset);
4135d9cb740SZhang Yi 		if (ret < 0)
4145d9cb740SZhang Yi 			goto io_error;
4155d9cb740SZhang Yi 		for (idx = 0; idx < ARRAY_SIZE(button); idx++) {
4165d9cb740SZhang Yi 			ret = regmap_read(es9356->regmap, ES9356_BUF_ADDR_HID + offset + idx, &reg);
4175d9cb740SZhang Yi 			if (ret < 0)
4185d9cb740SZhang Yi 				goto io_error;
4195d9cb740SZhang Yi 			button[idx] = reg;
4205d9cb740SZhang Yi 		}
4215d9cb740SZhang Yi 		btn_type = es9356_sdca_button(&button[0]);
4225d9cb740SZhang Yi 		if (btn_type < 0)
4235d9cb740SZhang Yi 			return;
4245d9cb740SZhang Yi 	}
4255d9cb740SZhang Yi 
4265d9cb740SZhang Yi 	snd_soc_jack_report(es9356->hs_jack, es9356->jack_type | btn_type,
4275d9cb740SZhang Yi 			SND_JACK_HEADSET |
4285d9cb740SZhang Yi 			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
4295d9cb740SZhang Yi 			SND_JACK_BTN_2 | SND_JACK_BTN_3 |
4305d9cb740SZhang Yi 			SND_JACK_BTN_4);
4315d9cb740SZhang Yi 
4325d9cb740SZhang Yi 	if (btn_type) {
4335d9cb740SZhang Yi 		snd_soc_jack_report(es9356->hs_jack, es9356->jack_type,
4345d9cb740SZhang Yi 			SND_JACK_HEADSET |
4355d9cb740SZhang Yi 			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
4365d9cb740SZhang Yi 			SND_JACK_BTN_2 | SND_JACK_BTN_3 |
4375d9cb740SZhang Yi 			SND_JACK_BTN_4);
4385d9cb740SZhang Yi 		mod_delayed_work(system_power_efficient_wq,
4395d9cb740SZhang Yi 			&es9356->button_detect_work, msecs_to_jiffies(280));
4405d9cb740SZhang Yi 	}
4415d9cb740SZhang Yi 
4425d9cb740SZhang Yi 	return;
4435d9cb740SZhang Yi io_error:
4445d9cb740SZhang Yi 	pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
4455d9cb740SZhang Yi }
4465d9cb740SZhang Yi 
es9356_pde_transition_delay(struct es9356_sdw_priv * es9356,unsigned char func,unsigned char entity,unsigned char ps)4475d9cb740SZhang Yi static int es9356_pde_transition_delay(struct es9356_sdw_priv *es9356, unsigned char func,
4485d9cb740SZhang Yi 	unsigned char entity, unsigned char ps)
4495d9cb740SZhang Yi {
4505d9cb740SZhang Yi 	unsigned int retries = 10, val;
4515d9cb740SZhang Yi 
4525d9cb740SZhang Yi 	/* waiting for Actual PDE becomes to PS0/PS3 */
4535d9cb740SZhang Yi 	while (retries) {
4545d9cb740SZhang Yi 		regmap_read(es9356->regmap,
4555d9cb740SZhang Yi 			SDW_SDCA_CTL(func, entity, ES9356_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val);
4565d9cb740SZhang Yi 		if (val == ps)
4575d9cb740SZhang Yi 			return 1;
4585d9cb740SZhang Yi 
4595d9cb740SZhang Yi 		usleep_range(1000, 1500);
4605d9cb740SZhang Yi 		retries--;
4615d9cb740SZhang Yi 	}
4625d9cb740SZhang Yi 	if (!retries) {
4635d9cb740SZhang Yi 		dev_dbg(&es9356->slave->dev, "%s PDE is NOT %s", __func__, ps?"PS3":"PS0");
4645d9cb740SZhang Yi 	}
4655d9cb740SZhang Yi 	return 0;
4665d9cb740SZhang Yi }
4675d9cb740SZhang Yi 
es9356_power_state(struct snd_soc_dai * dai,unsigned char ps,unsigned int * rate)4685d9cb740SZhang Yi static int es9356_power_state(struct snd_soc_dai *dai, unsigned char ps, unsigned int *rate)
4695d9cb740SZhang Yi {
4705d9cb740SZhang Yi 	struct snd_soc_component *component = dai->component;
4715d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
4725d9cb740SZhang Yi 	unsigned char ps0 = 0x0, ps3 = 0x3;
4735d9cb740SZhang Yi 	unsigned char func, cs_entity, pde_entity;
4745d9cb740SZhang Yi 	int ret;
4755d9cb740SZhang Yi 
4765d9cb740SZhang Yi 	switch (dai->id) {
4775d9cb740SZhang Yi 	case ES9356_DMIC:
4785d9cb740SZhang Yi 		func = FUNC_NUM_MIC;
4795d9cb740SZhang Yi 		cs_entity = ES9356_SDCA_ENT_CS113;
4805d9cb740SZhang Yi 		pde_entity = ES9356_SDCA_ENT_PDE11;
4815d9cb740SZhang Yi 		break;
4825d9cb740SZhang Yi 	case ES9356_AMP:
4835d9cb740SZhang Yi 		func = FUNC_NUM_AMP;
4845d9cb740SZhang Yi 		cs_entity = ES9356_SDCA_ENT_CS21;
4855d9cb740SZhang Yi 		pde_entity = ES9356_SDCA_ENT_PDE23;
4865d9cb740SZhang Yi 		break;
4875d9cb740SZhang Yi 	case ES9356_JACK_IN:
4885d9cb740SZhang Yi 		func = FUNC_NUM_UAJ;
4895d9cb740SZhang Yi 		cs_entity = ES9356_SDCA_ENT_CS36;
4905d9cb740SZhang Yi 		pde_entity = ES9356_SDCA_ENT_PDE34;
4915d9cb740SZhang Yi 		break;
4925d9cb740SZhang Yi 	case ES9356_JACK_OUT:
4935d9cb740SZhang Yi 		func = FUNC_NUM_UAJ;
4945d9cb740SZhang Yi 		cs_entity = ES9356_SDCA_ENT_CS41;
4955d9cb740SZhang Yi 		pde_entity = ES9356_SDCA_ENT_PDE47;
4965d9cb740SZhang Yi 		break;
4975d9cb740SZhang Yi 	default:
4985d9cb740SZhang Yi 		return -EINVAL;
4995d9cb740SZhang Yi 	}
5005d9cb740SZhang Yi 
5015d9cb740SZhang Yi 	/* power state changes are not independent across functions */
5025d9cb740SZhang Yi 	scoped_guard(mutex, &es9356->pde_lock) {
5035d9cb740SZhang Yi 		ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps0 : ps3);
5045d9cb740SZhang Yi 		if (ret) {
5055d9cb740SZhang Yi 			regmap_write(es9356->regmap,
5065d9cb740SZhang Yi 				     SDW_SDCA_CTL(func, pde_entity,
5075d9cb740SZhang Yi 						  ES9356_SDCA_CTL_REQ_POWER_STATE, 0),
5085d9cb740SZhang Yi 				     ps ? ps3 : ps0);
5095d9cb740SZhang Yi 			es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps3 : ps0);
5105d9cb740SZhang Yi 		} else {
5115d9cb740SZhang Yi 			dev_dbg(component->dev, "%s PDE is already %d\n", __func__,
5125d9cb740SZhang Yi 				ps ? ps0 : ps3);
5135d9cb740SZhang Yi 		}
5145d9cb740SZhang Yi 	}
5155d9cb740SZhang Yi 
5165d9cb740SZhang Yi 	if (rate)
5175d9cb740SZhang Yi 		regmap_write(es9356->regmap,
5185d9cb740SZhang Yi 			SDW_SDCA_CTL(func, cs_entity, ES9356_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), *rate);
5195d9cb740SZhang Yi 
5205d9cb740SZhang Yi 	return 0;
5215d9cb740SZhang Yi }
5225d9cb740SZhang Yi 
es9356_sdw_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)5235d9cb740SZhang Yi static int es9356_sdw_pcm_hw_params(struct snd_pcm_substream *substream,
5245d9cb740SZhang Yi 				    struct snd_pcm_hw_params *params,
5255d9cb740SZhang Yi 				    struct snd_soc_dai *dai)
5265d9cb740SZhang Yi {
5275d9cb740SZhang Yi 	struct snd_soc_component *component = dai->component;
5285d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
5295d9cb740SZhang Yi 	struct sdw_stream_config stream_config = {0};
5305d9cb740SZhang Yi 	struct sdw_port_config port_config = {0};
5315d9cb740SZhang Yi 	struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
5325d9cb740SZhang Yi 	unsigned char ps0 = 0x0;
5335d9cb740SZhang Yi 	unsigned int rate;
5345d9cb740SZhang Yi 	int ret;
5355d9cb740SZhang Yi 
5365d9cb740SZhang Yi 	if (!sdw_stream)
5375d9cb740SZhang Yi 		return -EINVAL;
5385d9cb740SZhang Yi 
5395d9cb740SZhang Yi 	if (!es9356->slave)
5405d9cb740SZhang Yi 		return -EINVAL;
5415d9cb740SZhang Yi 
5425d9cb740SZhang Yi 	/* SoundWire specific configuration */
5435d9cb740SZhang Yi 	snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
5445d9cb740SZhang Yi 
5455d9cb740SZhang Yi 	port_config.num = dai->id;
5465d9cb740SZhang Yi 
5475d9cb740SZhang Yi 	ret = sdw_stream_add_slave(es9356->slave, &stream_config,
5485d9cb740SZhang Yi 				   &port_config, 1, sdw_stream);
5495d9cb740SZhang Yi 	if (ret) {
5505d9cb740SZhang Yi 		dev_err(dai->dev, "Unable to configure port\n");
5515d9cb740SZhang Yi 		return -EINVAL;
5525d9cb740SZhang Yi 	}
5535d9cb740SZhang Yi 
5545d9cb740SZhang Yi 	switch (params_rate(params)) {
5555d9cb740SZhang Yi 	case 16000:
5565d9cb740SZhang Yi 		rate = ES9356_SDCA_RATE_16000HZ;
5575d9cb740SZhang Yi 		break;
5585d9cb740SZhang Yi 	case 44100:
5595d9cb740SZhang Yi 		rate = ES9356_SDCA_RATE_44100HZ;
5605d9cb740SZhang Yi 		break;
5615d9cb740SZhang Yi 	case 48000:
5625d9cb740SZhang Yi 		rate = ES9356_SDCA_RATE_48000HZ;
5635d9cb740SZhang Yi 		break;
5645d9cb740SZhang Yi 	case 96000:
5655d9cb740SZhang Yi 		rate = ES9356_SDCA_RATE_96000HZ;
5665d9cb740SZhang Yi 		break;
5675d9cb740SZhang Yi 	default:
5685d9cb740SZhang Yi 		dev_err(component->dev, "%s: Rate %d is not supported\n",
5695d9cb740SZhang Yi 			__func__, params_rate(params));
5705d9cb740SZhang Yi 		return -EINVAL;
5715d9cb740SZhang Yi 	}
5725d9cb740SZhang Yi 
5735d9cb740SZhang Yi 	ret = es9356_power_state(dai, ps0, &rate);
5745d9cb740SZhang Yi 	if (ret) {
5755d9cb740SZhang Yi 		dev_err(component->dev, "%s: Invalid dai id: %d\n",
5765d9cb740SZhang Yi 			__func__, dai->id);
5775d9cb740SZhang Yi 		return -EINVAL;
5785d9cb740SZhang Yi 	}
5795d9cb740SZhang Yi 
5805d9cb740SZhang Yi 	return 0;
5815d9cb740SZhang Yi }
5825d9cb740SZhang Yi 
es9356_sdw_pcm_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)5835d9cb740SZhang Yi static int es9356_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
5845d9cb740SZhang Yi 				  struct snd_soc_dai *dai)
5855d9cb740SZhang Yi {
5865d9cb740SZhang Yi 	struct snd_soc_component *component = dai->component;
5875d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
5885d9cb740SZhang Yi 	struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
5895d9cb740SZhang Yi 	unsigned char ps3 = 0x3;
5905d9cb740SZhang Yi 	int ret;
5915d9cb740SZhang Yi 
5925d9cb740SZhang Yi 	if (!es9356->slave)
5935d9cb740SZhang Yi 		return -EINVAL;
5945d9cb740SZhang Yi 
5955d9cb740SZhang Yi 	sdw_stream_remove_slave(es9356->slave, sdw_stream);
5965d9cb740SZhang Yi 
5975d9cb740SZhang Yi 	ret = es9356_power_state(dai, ps3, NULL);
5985d9cb740SZhang Yi 	if (ret) {
5995d9cb740SZhang Yi 		dev_err(component->dev, "%s: Invalid dai id: %d\n",
6005d9cb740SZhang Yi 			__func__, dai->id);
6015d9cb740SZhang Yi 		return -EINVAL;
6025d9cb740SZhang Yi 	}
6035d9cb740SZhang Yi 
6045d9cb740SZhang Yi 	return 0;
6055d9cb740SZhang Yi }
6065d9cb740SZhang Yi 
6075d9cb740SZhang Yi static const struct snd_soc_dai_ops es9356_sdw_ops = {
6085d9cb740SZhang Yi 	.hw_params	= es9356_sdw_pcm_hw_params,
6095d9cb740SZhang Yi 	.hw_free	= es9356_sdw_pcm_hw_free,
6105d9cb740SZhang Yi 	.set_stream	= es9356_sdw_set_sdw_stream,
6115d9cb740SZhang Yi 	.shutdown	= es9356_sdw_shutdown,
6125d9cb740SZhang Yi };
6135d9cb740SZhang Yi 
6145d9cb740SZhang Yi static struct snd_soc_dai_driver es9356_sdw_dai[] = {
6155d9cb740SZhang Yi 	{
6165d9cb740SZhang Yi 		.name = "es9356-sdp-aif4",
6175d9cb740SZhang Yi 		.id = ES9356_DMIC,
6185d9cb740SZhang Yi 		.capture = {
6195d9cb740SZhang Yi 			.stream_name = "DP1 Capture",
6205d9cb740SZhang Yi 			.channels_min = 1,
6215d9cb740SZhang Yi 			.channels_max = 2,
6225d9cb740SZhang Yi 		},
6235d9cb740SZhang Yi 		.ops = &es9356_sdw_ops,
6245d9cb740SZhang Yi 	},
6255d9cb740SZhang Yi 	{
6265d9cb740SZhang Yi 		.name = "es9356-sdp-aif2",
6275d9cb740SZhang Yi 		.id = ES9356_JACK_IN,
6285d9cb740SZhang Yi 		.capture = {
6295d9cb740SZhang Yi 			.stream_name = "DP2 Capture",
6305d9cb740SZhang Yi 			.channels_min = 1,
6315d9cb740SZhang Yi 			.channels_max = 2,
6325d9cb740SZhang Yi 		},
6335d9cb740SZhang Yi 		.ops = &es9356_sdw_ops,
6345d9cb740SZhang Yi 	},
6355d9cb740SZhang Yi 	{
6365d9cb740SZhang Yi 		.name = "es9356-sdp-aif3",
6375d9cb740SZhang Yi 		.id = ES9356_AMP,
6385d9cb740SZhang Yi 		.playback = {
6395d9cb740SZhang Yi 			.stream_name = "DP3 Playback",
6405d9cb740SZhang Yi 			.channels_min = 1,
6415d9cb740SZhang Yi 			.channels_max = 2,
6425d9cb740SZhang Yi 		},
6435d9cb740SZhang Yi 		.ops = &es9356_sdw_ops,
6445d9cb740SZhang Yi 	},
6455d9cb740SZhang Yi 	{
6465d9cb740SZhang Yi 		.name = "es9356-sdp-aif1",
6475d9cb740SZhang Yi 		.id = ES9356_JACK_OUT,
6485d9cb740SZhang Yi 		.playback = {
6495d9cb740SZhang Yi 			.stream_name = "DP4 Playback",
6505d9cb740SZhang Yi 			.channels_min = 1,
6515d9cb740SZhang Yi 			.channels_max = 2,
6525d9cb740SZhang Yi 		},
6535d9cb740SZhang Yi 		.ops = &es9356_sdw_ops,
6545d9cb740SZhang Yi 	},
6555d9cb740SZhang Yi };
6565d9cb740SZhang Yi 
es9356_sdca_mbq_size(struct device * dev,unsigned int reg)6575d9cb740SZhang Yi static int es9356_sdca_mbq_size(struct device *dev, unsigned int reg)
6585d9cb740SZhang Yi {
6595d9cb740SZhang Yi 	switch (reg) {
6605d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_L):
6615d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_R):
6625d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_VOLUME, CH_L):
6635d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_VOLUME, CH_R):
6645d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_VOLUME, CH_L):
6655d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_VOLUME, CH_R):
6665d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_L):
6675d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_R):
6685d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU33, ES9356_SDCA_CTL_FU_CH_GAIN, 0):
6695d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU11, ES9356_SDCA_CTL_FU_CH_GAIN, 0):
6705d9cb740SZhang Yi 		return 2;
6715d9cb740SZhang Yi 	default:
6725d9cb740SZhang Yi 		return 1;
6735d9cb740SZhang Yi 	}
6745d9cb740SZhang Yi }
6755d9cb740SZhang Yi 
6765d9cb740SZhang Yi static const struct regmap_sdw_mbq_cfg es9356_mbq_config = {
6775d9cb740SZhang Yi 	.mbq_size = es9356_sdca_mbq_size,
6785d9cb740SZhang Yi };
6795d9cb740SZhang Yi 
es9356_sdca_volatile_register(struct device * dev,unsigned int reg)6805d9cb740SZhang Yi static bool es9356_sdca_volatile_register(struct device *dev, unsigned int reg)
6815d9cb740SZhang Yi {
6825d9cb740SZhang Yi 	switch (reg) {
6835d9cb740SZhang Yi 	case ES9356_BUF_ADDR_HID:
6845d9cb740SZhang Yi 	case ES9356_HID_BYTE2:
6855d9cb740SZhang Yi 	case ES9356_HID_BYTE3:
6865d9cb740SZhang Yi 	case ES9356_HID_BYTE4:
6875d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_HID, ES9356_SDCA_ENT_HID01, ES9356_SDCA_CTL_HIDTX_CURRENT_OWNER, 0):
6885d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_GE35, ES9356_SDCA_CTL_DETECTED_MODE, 0):
6895d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_GE35, ES9356_SDCA_CTL_SELECTED_MODE, 0):
6905d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_PDE23, ES9356_SDCA_CTL_REQ_POWER_STATE, 0):
6915d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_PDE23, ES9356_SDCA_CTL_ACTUAL_POWER_STATE, 0):
6925d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_PDE11, ES9356_SDCA_CTL_REQ_POWER_STATE, 0):
6935d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_PDE11, ES9356_SDCA_CTL_ACTUAL_POWER_STATE, 0):
6945d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE47, ES9356_SDCA_CTL_REQ_POWER_STATE, 0):
6955d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE47, ES9356_SDCA_CTL_ACTUAL_POWER_STATE, 0):
6965d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE34, ES9356_SDCA_CTL_REQ_POWER_STATE, 0):
6975d9cb740SZhang Yi 	case SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE34, ES9356_SDCA_CTL_ACTUAL_POWER_STATE, 0):
6985d9cb740SZhang Yi 	case ES9356_FLAGS_HP:
6995d9cb740SZhang Yi 		return true;
7005d9cb740SZhang Yi 	default:
7015d9cb740SZhang Yi 		return false;
7025d9cb740SZhang Yi 	}
7035d9cb740SZhang Yi }
7045d9cb740SZhang Yi 
7055d9cb740SZhang Yi static const struct regmap_config es9356_sdca_regmap = {
7065d9cb740SZhang Yi 	.reg_bits = 32,
7075d9cb740SZhang Yi 	.val_bits = 16,
7085d9cb740SZhang Yi 	.volatile_reg = es9356_sdca_volatile_register,
7095d9cb740SZhang Yi 	.max_register = 0x45ffffff,
7105d9cb740SZhang Yi 	.cache_type = REGCACHE_MAPLE,
7115d9cb740SZhang Yi 	.use_single_read = true,
7125d9cb740SZhang Yi 	.use_single_write = true,
7135d9cb740SZhang Yi };
7145d9cb740SZhang Yi 
es9356_register_init(struct es9356_sdw_priv * es9356)7155d9cb740SZhang Yi static void es9356_register_init(struct es9356_sdw_priv *es9356)
7165d9cb740SZhang Yi {
7175d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_STATE, 0x02);
7185d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_ENDPOINT_MODE, 0x24);
7195d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_PRE_DIV_CTL, 0x00);
7205d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_ADC_OSR, 0x18);
7215d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_ADC_OSRGAIN, 0x13);
7225d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_DAC_OSR, 0x16);
7235d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_CLK_CTL, 0x0f);
7245d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_CSM_RESET, 0x01);
7255d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_CLK_SEL, 0x30);
7265d9cb740SZhang Yi 
7275d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_DETCLK_CTL, 0x51);
7285d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_HP_TYPE, 0x10);
7295d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_MICBIAS_CTL, 0x10);
7305d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_HPDETECT_CTL, 0x07);
7315d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_ADC_ANA, 0x30);
7325d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_PGA_CTL, 0xa8);
7335d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_ADC_INT, 0xaa);
7345d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_ADC_LP, 0x19);
7355d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_VMID1SEL, 0xbc);
7365d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_VMID_TIME, 0x0b);
7375d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_STATE_TIME, 0xbb);
7385d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_HP_SPK_TIME, 0x77);
7395d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0xa4);
7405d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_MICBIAS_SEL, 0x15);
7415d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_KEY_PRESS_TIME, 0xff);
7425d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_KEY_RELEASE_TIME, 0xff);
7435d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_KEY_HOLD_TIME, 0x0f);
7445d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_BTSEL_REF, 0x00);
7455d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_KEYD_DETECT, 0x18);
7465d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_MICBIAS_RES, 0x03);
7475d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_BUTTON_CHARGE, 0x00);
7485d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_CALIBRATION_TIME, 0x13);
7495d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_CALIBRATION_SETTING, 0xf4);
7505d9cb740SZhang Yi 
7515d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_SPK_VOLUME, 0x33);
7525d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_DAC_VROI, 0x01);
7535d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_DAC_LP, 0x00);
7545d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_HP_IBIAS, 0x04);
7555d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_HP_LP, 0x03);
7565d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_SPKLDO_CTL, 0x65);
7575d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_SPKBIAS_COMP, 0x09);
7585d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_VMID1STL, 0x00);
7595d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_VMID2STL, 0x00);
7605d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_VSEL, 0xfc);
7615d9cb740SZhang Yi 
7625d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_IBIASGEN, 0x10);
7635d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_ADC_AMIC_CTL, 0x0d);
7645d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_STATE, 0x0e);
7655d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_CSM_RESET, 0x00);
7665d9cb740SZhang Yi 	regmap_write(es9356->regmap, ES9356_HP_TYPE, 0x08);
7675d9cb740SZhang Yi 
7685d9cb740SZhang Yi 	regmap_write(es9356->regmap,
7695d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
7705d9cb740SZhang Yi 	regmap_write(es9356->regmap,
7715d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
7725d9cb740SZhang Yi 
7735d9cb740SZhang Yi 	regmap_write(es9356->regmap,
7745d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
7755d9cb740SZhang Yi 	regmap_write(es9356->regmap,
7765d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
7775d9cb740SZhang Yi 
7785d9cb740SZhang Yi 	regmap_write(es9356->regmap,
7795d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
7805d9cb740SZhang Yi 	regmap_write(es9356->regmap,
7815d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
7825d9cb740SZhang Yi 
7835d9cb740SZhang Yi 	regmap_write(es9356->regmap,
7845d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
7855d9cb740SZhang Yi 	regmap_write(es9356->regmap,
7865d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
7875d9cb740SZhang Yi }
7885d9cb740SZhang Yi 
es9356_sdca_io_init(struct device * dev,struct sdw_slave * slave)7895d9cb740SZhang Yi static int es9356_sdca_io_init(struct device *dev, struct sdw_slave *slave)
7905d9cb740SZhang Yi {
7915d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = dev_get_drvdata(&slave->dev);
7925d9cb740SZhang Yi 
7935d9cb740SZhang Yi 	if (es9356->hw_init)
7945d9cb740SZhang Yi 		return 0;
7955d9cb740SZhang Yi 
7965d9cb740SZhang Yi 	es9356->disable_irq = false;
7975d9cb740SZhang Yi 
7985d9cb740SZhang Yi 	regcache_cache_only(es9356->regmap, false);
7995d9cb740SZhang Yi 
8005d9cb740SZhang Yi 	if (es9356->first_hw_init) {
8015d9cb740SZhang Yi 		regcache_cache_bypass(es9356->regmap, true);
8025d9cb740SZhang Yi 	} else {
8035d9cb740SZhang Yi 		/* update count of parent 'active' children */
8045d9cb740SZhang Yi 		pm_runtime_set_active(&slave->dev);
8055d9cb740SZhang Yi 
8065d9cb740SZhang Yi 		es9356_register_init(es9356);
8075d9cb740SZhang Yi 	}
8085d9cb740SZhang Yi 	pm_runtime_get_noresume(&slave->dev);
8095d9cb740SZhang Yi 
8105d9cb740SZhang Yi 	regmap_write(es9356->regmap,
8115d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_XU12, ES9356_SDCA_CTL_SELECTED_MODE, 0), 0x01);
8125d9cb740SZhang Yi 	regmap_write(es9356->regmap,
8135d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT0, ES9356_SDCA_CTL_FUNC_STATUS, 0), 0x40);
8145d9cb740SZhang Yi 	regmap_write(es9356->regmap,
8155d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_XU22, ES9356_SDCA_CTL_SELECTED_MODE, 0), 0x01);
8165d9cb740SZhang Yi 	regmap_write(es9356->regmap,
8175d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT0, ES9356_SDCA_CTL_FUNC_STATUS, 0), 0x40);
8185d9cb740SZhang Yi 	regmap_write(es9356->regmap,
8195d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_XU42, ES9356_SDCA_CTL_SELECTED_MODE, 0), 0x01);
8205d9cb740SZhang Yi 	regmap_write(es9356->regmap,
8215d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_XU36, ES9356_SDCA_CTL_SELECTED_MODE, 0), 0x01);
8225d9cb740SZhang Yi 	regmap_write(es9356->regmap,
8235d9cb740SZhang Yi 		SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT0, ES9356_SDCA_CTL_FUNC_STATUS, 0), 0x40);
8245d9cb740SZhang Yi 
8255d9cb740SZhang Yi 	if (es9356->first_hw_init) {
8265d9cb740SZhang Yi 		regcache_cache_bypass(es9356->regmap, false);
8275d9cb740SZhang Yi 		regcache_mark_dirty(es9356->regmap);
8285d9cb740SZhang Yi 	} else
8295d9cb740SZhang Yi 		es9356->first_hw_init = true;
8305d9cb740SZhang Yi 
8315d9cb740SZhang Yi 	es9356->hw_init = true;
8325d9cb740SZhang Yi 
8335d9cb740SZhang Yi 	pm_runtime_mark_last_busy(&slave->dev);
8345d9cb740SZhang Yi 	pm_runtime_put_autosuspend(&slave->dev);
8355d9cb740SZhang Yi 
8365d9cb740SZhang Yi 	return 0;
8375d9cb740SZhang Yi }
8385d9cb740SZhang Yi 
es9356_sdw_update_status(struct sdw_slave * slave,enum sdw_slave_status status)8395d9cb740SZhang Yi static int es9356_sdw_update_status(struct sdw_slave *slave,
8405d9cb740SZhang Yi 				    enum sdw_slave_status status)
8415d9cb740SZhang Yi {
8425d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = dev_get_drvdata(&slave->dev);
8435d9cb740SZhang Yi 
8445d9cb740SZhang Yi 	if (status == SDW_SLAVE_UNATTACHED) {
8455d9cb740SZhang Yi 		es9356->hw_init = false;
8465d9cb740SZhang Yi 		cancel_delayed_work_sync(&es9356->interrupt_handle_work);
8475d9cb740SZhang Yi 		cancel_delayed_work_sync(&es9356->button_detect_work);
8485d9cb740SZhang Yi 		regcache_cache_only(es9356->regmap, true);
8495d9cb740SZhang Yi 	}
8505d9cb740SZhang Yi 
8515d9cb740SZhang Yi 	if (status == SDW_SLAVE_ATTACHED) {
8525d9cb740SZhang Yi 		if (es9356->hs_jack)
8535d9cb740SZhang Yi 			sdw_write_no_pm(es9356->slave, SDW_SCP_SDCA_INTMASK1,
8545d9cb740SZhang Yi 			(SDW_SCP_SDCA_INTMASK_SDCA_7 | SDW_SCP_SDCA_INTMASK_SDCA_5 | SDW_SCP_SDCA_INTMASK_SDCA_1));
8555d9cb740SZhang Yi 	}
8565d9cb740SZhang Yi 
8575d9cb740SZhang Yi 	if (es9356->hw_init || status != SDW_SLAVE_ATTACHED)
8585d9cb740SZhang Yi 		return 0;
8595d9cb740SZhang Yi 
8605d9cb740SZhang Yi 	return es9356_sdca_io_init(&slave->dev, slave);
8615d9cb740SZhang Yi }
8625d9cb740SZhang Yi 
es9356_sdw_read_prop(struct sdw_slave * slave)8635d9cb740SZhang Yi static int es9356_sdw_read_prop(struct sdw_slave *slave)
8645d9cb740SZhang Yi {
8655d9cb740SZhang Yi 	struct sdw_slave_prop *prop = &slave->prop;
8665d9cb740SZhang Yi 	int nval;
8675d9cb740SZhang Yi 	int i, j;
8685d9cb740SZhang Yi 	u32 bit;
8695d9cb740SZhang Yi 	unsigned long addr;
8705d9cb740SZhang Yi 	struct sdw_dpn_prop *dpn;
8715d9cb740SZhang Yi 
8725d9cb740SZhang Yi 	prop->paging_support = true;
8735d9cb740SZhang Yi 
8745d9cb740SZhang Yi 	/*
8755d9cb740SZhang Yi 	 * first we need to allocate memory for set bits in port lists
8765d9cb740SZhang Yi 	 * the port allocation is completely arbitrary:
8775d9cb740SZhang Yi 	 * DP0 is not supported
8785d9cb740SZhang Yi 	 * DP3 and DP4 is sink
8795d9cb740SZhang Yi 	 * DP1 and DP2 is source
8805d9cb740SZhang Yi 	 */
8815d9cb740SZhang Yi 	prop->source_ports = BIT(1) | BIT(2);
8825d9cb740SZhang Yi 	prop->sink_ports = BIT(3) | BIT(4);
8835d9cb740SZhang Yi 
8845d9cb740SZhang Yi 	nval = hweight32(prop->source_ports);
8855d9cb740SZhang Yi 	prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
8865d9cb740SZhang Yi 					  sizeof(*prop->src_dpn_prop),
8875d9cb740SZhang Yi 					  GFP_KERNEL);
8885d9cb740SZhang Yi 	if (!prop->src_dpn_prop)
8895d9cb740SZhang Yi 		return -ENOMEM;
8905d9cb740SZhang Yi 
8915d9cb740SZhang Yi 	i = 0;
8925d9cb740SZhang Yi 	dpn = prop->src_dpn_prop;
8935d9cb740SZhang Yi 	addr = prop->source_ports;
8945d9cb740SZhang Yi 	for_each_set_bit(bit, &addr, 32) {
8955d9cb740SZhang Yi 		dpn[i].num = bit;
8965d9cb740SZhang Yi 		dpn[i].type = SDW_DPN_FULL;
8975d9cb740SZhang Yi 		dpn[i].simple_ch_prep_sm = true;
8985d9cb740SZhang Yi 		i++;
8995d9cb740SZhang Yi 	}
9005d9cb740SZhang Yi 
9015d9cb740SZhang Yi 	/* do this again for sink now */
9025d9cb740SZhang Yi 	nval = hweight32(prop->sink_ports);
9035d9cb740SZhang Yi 	prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
9045d9cb740SZhang Yi 					   sizeof(*prop->sink_dpn_prop),
9055d9cb740SZhang Yi 					   GFP_KERNEL);
9065d9cb740SZhang Yi 	if (!prop->sink_dpn_prop)
9075d9cb740SZhang Yi 		return -ENOMEM;
9085d9cb740SZhang Yi 
9095d9cb740SZhang Yi 	j = 0;
9105d9cb740SZhang Yi 	dpn = prop->sink_dpn_prop;
9115d9cb740SZhang Yi 	addr = prop->sink_ports;
9125d9cb740SZhang Yi 	for_each_set_bit(bit, &addr, 32) {
9135d9cb740SZhang Yi 		dpn[j].num = bit;
9145d9cb740SZhang Yi 		dpn[j].type = SDW_DPN_FULL;
9155d9cb740SZhang Yi 		dpn[j].simple_ch_prep_sm = true;
9165d9cb740SZhang Yi 		j++;
9175d9cb740SZhang Yi 	}
9185d9cb740SZhang Yi 
9195d9cb740SZhang Yi 	/* wake-up event */
9205d9cb740SZhang Yi 	prop->wake_capable = 1;
9215d9cb740SZhang Yi 
9225d9cb740SZhang Yi 	return 0;
9235d9cb740SZhang Yi }
9245d9cb740SZhang Yi 
es9356_sdw_interrupt_callback(struct sdw_slave * slave,struct sdw_slave_intr_status * status)9255d9cb740SZhang Yi static int es9356_sdw_interrupt_callback(struct sdw_slave *slave,
9265d9cb740SZhang Yi 					 struct sdw_slave_intr_status *status)
9275d9cb740SZhang Yi {
9285d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = dev_get_drvdata(&slave->dev);
9295d9cb740SZhang Yi 	unsigned int sdca_cascade, scp_sdca_stat1 = 0;
9305d9cb740SZhang Yi 	int count = 0, retry = 3;
9315d9cb740SZhang Yi 	int ret, stat, reg;
9325d9cb740SZhang Yi 
9335d9cb740SZhang Yi 	mutex_lock(&es9356->disable_irq_lock);
9345d9cb740SZhang Yi 
9355d9cb740SZhang Yi 	ret = sdw_read_no_pm(es9356->slave, SDW_SCP_SDCA_INT1);
9365d9cb740SZhang Yi 	if (ret < 0)
9375d9cb740SZhang Yi 		goto io_error;
9385d9cb740SZhang Yi 	es9356->sdca_status = ret;
9395d9cb740SZhang Yi 
9405d9cb740SZhang Yi 	do {
9415d9cb740SZhang Yi 		reg = sdw_read_no_pm(es9356->slave, SDW_SCP_SDCA_INT1);
9425d9cb740SZhang Yi 		if (reg < 0)
9435d9cb740SZhang Yi 			goto io_error;
9445d9cb740SZhang Yi 		if (reg & SDW_SCP_SDCA_INTMASK_SDCA_1) {
9455d9cb740SZhang Yi 			ret = sdw_update_no_pm(es9356->slave, SDW_SCP_SDCA_INT1,
9465d9cb740SZhang Yi 				SDW_SCP_SDCA_INT_SDCA_1, SDW_SCP_SDCA_INT_SDCA_1);
9475d9cb740SZhang Yi 			if (ret < 0)
9485d9cb740SZhang Yi 				goto io_error;
9495d9cb740SZhang Yi 		}
9505d9cb740SZhang Yi 
9515d9cb740SZhang Yi 		if (reg & SDW_SCP_SDCA_INTMASK_SDCA_5) {
9525d9cb740SZhang Yi 			ret = sdw_update_no_pm(es9356->slave, SDW_SCP_SDCA_INT1,
9535d9cb740SZhang Yi 				SDW_SCP_SDCA_INT_SDCA_5, SDW_SCP_SDCA_INT_SDCA_5);
9545d9cb740SZhang Yi 			if (ret < 0)
9555d9cb740SZhang Yi 				goto io_error;
9565d9cb740SZhang Yi 		}
9575d9cb740SZhang Yi 
9585d9cb740SZhang Yi 		if (reg & SDW_SCP_SDCA_INTMASK_SDCA_7) {
9595d9cb740SZhang Yi 			ret = sdw_update_no_pm(es9356->slave, SDW_SCP_SDCA_INT1,
9605d9cb740SZhang Yi 				SDW_SCP_SDCA_INT_SDCA_7, SDW_SCP_SDCA_INT_SDCA_7);
9615d9cb740SZhang Yi 			if (ret < 0)
9625d9cb740SZhang Yi 				goto io_error;
9635d9cb740SZhang Yi 		}
9645d9cb740SZhang Yi 
9655d9cb740SZhang Yi 		ret = sdw_read_no_pm(es9356->slave, SDW_DP0_INT);
9665d9cb740SZhang Yi 		if (ret < 0)
9675d9cb740SZhang Yi 			goto io_error;
9685d9cb740SZhang Yi 		sdca_cascade = ret & SDW_DP0_SDCA_CASCADE;
9695d9cb740SZhang Yi 
9705d9cb740SZhang Yi 		ret = sdw_read_no_pm(es9356->slave, SDW_SCP_SDCA_INT1);
9715d9cb740SZhang Yi 		if (ret < 0)
9725d9cb740SZhang Yi 			goto io_error;
9735d9cb740SZhang Yi 		scp_sdca_stat1 = ret &
9745d9cb740SZhang Yi 			(SDW_SCP_SDCA_INTMASK_SDCA_1 | SDW_SCP_SDCA_INTMASK_SDCA_5 | SDW_SCP_SDCA_INTMASK_SDCA_7);
9755d9cb740SZhang Yi 
9765d9cb740SZhang Yi 		stat = scp_sdca_stat1 || sdca_cascade;
9775d9cb740SZhang Yi 
9785d9cb740SZhang Yi 		count++;
9795d9cb740SZhang Yi 	} while (stat != 0 && count < retry);
9805d9cb740SZhang Yi 
9815d9cb740SZhang Yi 	/* The 280 ms figure was determined through testing */
9825d9cb740SZhang Yi 	if (status->sdca_cascade && !es9356->disable_irq)
9835d9cb740SZhang Yi 		mod_delayed_work(system_power_efficient_wq,
9845d9cb740SZhang Yi 			&es9356->interrupt_handle_work, msecs_to_jiffies(280));
9855d9cb740SZhang Yi 
9865d9cb740SZhang Yi 	mutex_unlock(&es9356->disable_irq_lock);
9875d9cb740SZhang Yi 	return 0;
9885d9cb740SZhang Yi 
9895d9cb740SZhang Yi io_error:
9905d9cb740SZhang Yi 	mutex_unlock(&es9356->disable_irq_lock);
9915d9cb740SZhang Yi 	pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
9925d9cb740SZhang Yi 	return ret;
9935d9cb740SZhang Yi }
9945d9cb740SZhang Yi 
9955d9cb740SZhang Yi static const struct sdw_slave_ops es9356_sdw_slave_ops = {
9965d9cb740SZhang Yi 	.read_prop = es9356_sdw_read_prop,
9975d9cb740SZhang Yi 	.interrupt_callback = es9356_sdw_interrupt_callback,
9985d9cb740SZhang Yi 	.update_status = es9356_sdw_update_status,
9995d9cb740SZhang Yi };
10005d9cb740SZhang Yi 
es9356_sdca_init(struct device * dev,struct regmap * regmap,struct sdw_slave * slave)10015d9cb740SZhang Yi static int es9356_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave)
10025d9cb740SZhang Yi {
10035d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356;
10045d9cb740SZhang Yi 	int ret;
10055d9cb740SZhang Yi 
10065d9cb740SZhang Yi 	es9356 = devm_kzalloc(dev, sizeof(*es9356), GFP_KERNEL);
10075d9cb740SZhang Yi 	if (!es9356)
10085d9cb740SZhang Yi 		return -ENOMEM;
10095d9cb740SZhang Yi 
10105d9cb740SZhang Yi 	dev_set_drvdata(dev, es9356);
10115d9cb740SZhang Yi 
10125d9cb740SZhang Yi 	es9356->slave = slave;
10135d9cb740SZhang Yi 	es9356->regmap = regmap;
10145d9cb740SZhang Yi 	mutex_init(&es9356->disable_irq_lock);
10155d9cb740SZhang Yi 	mutex_init(&es9356->pde_lock);
10165d9cb740SZhang Yi 
10175d9cb740SZhang Yi 	regcache_cache_only(es9356->regmap, true);
10185d9cb740SZhang Yi 
10195d9cb740SZhang Yi 	es9356->hw_init = false;
10205d9cb740SZhang Yi 	es9356->first_hw_init = false;
10215d9cb740SZhang Yi 
10225d9cb740SZhang Yi 	INIT_DELAYED_WORK(&es9356->interrupt_handle_work,
10235d9cb740SZhang Yi 			  es9356_interrupt_handler);
10245d9cb740SZhang Yi 	INIT_DELAYED_WORK(&es9356->button_detect_work,
10255d9cb740SZhang Yi 			  es9356_button_detect_handler);
10265d9cb740SZhang Yi 
10275d9cb740SZhang Yi 	ret = devm_snd_soc_register_component(dev,
10285d9cb740SZhang Yi 					       &snd_soc_es9356_sdw_component,
10295d9cb740SZhang Yi 					       es9356_sdw_dai,
10305d9cb740SZhang Yi 					       ARRAY_SIZE(es9356_sdw_dai));
10315d9cb740SZhang Yi 	if (ret) {
10325d9cb740SZhang Yi 		dev_err_probe(dev, ret, "Failed to register component\n");
10335d9cb740SZhang Yi 		return ret;
10345d9cb740SZhang Yi 	}
10355d9cb740SZhang Yi 	/* set autosuspend parameters */
10365d9cb740SZhang Yi 	pm_runtime_set_autosuspend_delay(dev, 3000);
10375d9cb740SZhang Yi 	pm_runtime_use_autosuspend(dev);
10385d9cb740SZhang Yi 	/* make sure the device does not suspend immediately */
10395d9cb740SZhang Yi 	pm_runtime_mark_last_busy(dev);
10405d9cb740SZhang Yi 	pm_runtime_enable(dev);
10415d9cb740SZhang Yi 
10425d9cb740SZhang Yi 	return 0;
10435d9cb740SZhang Yi }
10445d9cb740SZhang Yi 
es9356_sdw_probe(struct sdw_slave * slave,const struct sdw_device_id * id)10455d9cb740SZhang Yi static int es9356_sdw_probe(struct sdw_slave *slave,
10465d9cb740SZhang Yi 				const struct sdw_device_id *id)
10475d9cb740SZhang Yi {
10485d9cb740SZhang Yi 	struct regmap *regmap;
10495d9cb740SZhang Yi 
10505d9cb740SZhang Yi 	regmap = devm_regmap_init_sdw_mbq_cfg(&slave->dev, slave, &es9356_sdca_regmap, &es9356_mbq_config);
10515d9cb740SZhang Yi 	if (IS_ERR(regmap))
10525d9cb740SZhang Yi 		return PTR_ERR(regmap);
10535d9cb740SZhang Yi 
10545d9cb740SZhang Yi 	return es9356_sdca_init(&slave->dev, regmap, slave);
10555d9cb740SZhang Yi }
10565d9cb740SZhang Yi 
es9356_sdw_remove(struct sdw_slave * slave)10575d9cb740SZhang Yi static void es9356_sdw_remove(struct sdw_slave *slave)
10585d9cb740SZhang Yi {
10595d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = dev_get_drvdata(&slave->dev);
10605d9cb740SZhang Yi 
10615d9cb740SZhang Yi 	if (es9356->hw_init) {
10625d9cb740SZhang Yi 		cancel_delayed_work_sync(&es9356->interrupt_handle_work);
10635d9cb740SZhang Yi 		cancel_delayed_work_sync(&es9356->button_detect_work);
10645d9cb740SZhang Yi 	}
10655d9cb740SZhang Yi 
10665d9cb740SZhang Yi 	if (es9356->first_hw_init)
10675d9cb740SZhang Yi 		pm_runtime_disable(&slave->dev);
10685d9cb740SZhang Yi 
10695d9cb740SZhang Yi 	mutex_destroy(&es9356->disable_irq_lock);
10705d9cb740SZhang Yi 	mutex_destroy(&es9356->pde_lock);
10715d9cb740SZhang Yi }
10725d9cb740SZhang Yi 
10735d9cb740SZhang Yi static const struct sdw_device_id es9356_sdw_id[] = {
10745d9cb740SZhang Yi 	SDW_SLAVE_ENTRY_EXT(0x04b3, 0x9356, 0x02, 0, 0),
10755d9cb740SZhang Yi 	SDW_SLAVE_ENTRY_EXT(0x04b3, 0x9356, 0x03, 0, 0),
10765d9cb740SZhang Yi 	{},
10775d9cb740SZhang Yi };
10785d9cb740SZhang Yi MODULE_DEVICE_TABLE(sdw, es9356_sdw_id);
10795d9cb740SZhang Yi 
es9356_sdca_dev_suspend(struct device * dev)10805d9cb740SZhang Yi static int es9356_sdca_dev_suspend(struct device *dev)
10815d9cb740SZhang Yi {
10825d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = dev_get_drvdata(dev);
10835d9cb740SZhang Yi 
10845d9cb740SZhang Yi 	cancel_delayed_work_sync(&es9356->interrupt_handle_work);
10855d9cb740SZhang Yi 	cancel_delayed_work_sync(&es9356->button_detect_work);
10865d9cb740SZhang Yi 
10875d9cb740SZhang Yi 	regcache_cache_only(es9356->regmap, true);
10885d9cb740SZhang Yi 
10895d9cb740SZhang Yi 	return 0;
10905d9cb740SZhang Yi }
10915d9cb740SZhang Yi 
es9356_sdca_dev_system_suspend(struct device * dev)10925d9cb740SZhang Yi static int es9356_sdca_dev_system_suspend(struct device *dev)
10935d9cb740SZhang Yi {
10945d9cb740SZhang Yi 	struct es9356_sdw_priv *es9356 = dev_get_drvdata(dev);
10955d9cb740SZhang Yi 
10965d9cb740SZhang Yi 	scoped_guard(mutex, &es9356->disable_irq_lock)
10975d9cb740SZhang Yi 		es9356->disable_irq = true;
10985d9cb740SZhang Yi 
10995d9cb740SZhang Yi 	return es9356_sdca_dev_suspend(dev);
11005d9cb740SZhang Yi }
11015d9cb740SZhang Yi 
11025d9cb740SZhang Yi #define es9356_PROBE_TIMEOUT 2000
11035d9cb740SZhang Yi 
es9356_sdca_dev_resume(struct device * dev)11045d9cb740SZhang Yi static int es9356_sdca_dev_resume(struct device *dev)
11055d9cb740SZhang Yi {
11065d9cb740SZhang Yi 	struct sdw_slave *slave = dev_to_sdw_dev(dev);
1107aec0d8c8SCharles Keepax 	struct es9356_sdw_priv *es9356 = dev_get_drvdata(dev);
11085d9cb740SZhang Yi 	int ret;
1109aec0d8c8SCharles Keepax 
11105d9cb740SZhang Yi 	if (!slave->unattach_request)
11115d9cb740SZhang Yi 		es9356->disable_irq = false;
1112aec0d8c8SCharles Keepax 
1113*ce524503SCharles Keepax 	ret = sdw_slave_wait_for_init(slave, es9356_PROBE_TIMEOUT);
1114*ce524503SCharles Keepax 	if (ret) {
1115aec0d8c8SCharles Keepax 		sdw_show_ping_status(slave->bus, true);
1116*ce524503SCharles Keepax 		return ret;
11175d9cb740SZhang Yi 	}
11185d9cb740SZhang Yi 
11195d9cb740SZhang Yi 	regcache_cache_only(es9356->regmap, false);
11205d9cb740SZhang Yi 	regcache_sync(es9356->regmap);
11215d9cb740SZhang Yi 	return 0;
11225d9cb740SZhang Yi }
11235d9cb740SZhang Yi 
11245d9cb740SZhang Yi static const struct dev_pm_ops es9356_sdca_pm = {
11255d9cb740SZhang Yi 	SYSTEM_SLEEP_PM_OPS(es9356_sdca_dev_system_suspend, es9356_sdca_dev_resume)
11265d9cb740SZhang Yi 	RUNTIME_PM_OPS(es9356_sdca_dev_suspend, es9356_sdca_dev_resume, NULL)
11275d9cb740SZhang Yi };
11285d9cb740SZhang Yi 
11295d9cb740SZhang Yi static struct sdw_driver es9356_sdw_driver = {
11305d9cb740SZhang Yi 	.driver = {
11315d9cb740SZhang Yi 		.name = "es9356",
11325d9cb740SZhang Yi 		.pm = pm_ptr(&es9356_sdca_pm),
11335d9cb740SZhang Yi 	},
11345d9cb740SZhang Yi 	.probe = es9356_sdw_probe,
11355d9cb740SZhang Yi 	.remove = es9356_sdw_remove,
11365d9cb740SZhang Yi 	.ops = &es9356_sdw_slave_ops,
11375d9cb740SZhang Yi 	.id_table = es9356_sdw_id,
11385d9cb740SZhang Yi };
11395d9cb740SZhang Yi module_sdw_driver(es9356_sdw_driver);
11405d9cb740SZhang Yi 
11415d9cb740SZhang Yi MODULE_IMPORT_NS("SND_SOC_SDCA");
11425d9cb740SZhang Yi MODULE_DESCRIPTION("ASoC ES9356 SDCA SDW codec driver");
11435d9cb740SZhang Yi MODULE_AUTHOR("Michael Zhang <zhangyi@everest-semi.com>");
1144 MODULE_LICENSE("GPL");
1145