xref: /openbmc/linux/sound/soc/codecs/es8316.c (revision f972d02f)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b8b88b70SDaniel Drake /*
3b8b88b70SDaniel Drake  * es8316.c -- es8316 ALSA SoC audio driver
4b8b88b70SDaniel Drake  * Copyright Everest Semiconductor Co.,Ltd
5b8b88b70SDaniel Drake  *
6b8b88b70SDaniel Drake  * Authors: David Yang <yangxiaohua@everest-semi.com>,
7b8b88b70SDaniel Drake  *          Daniel Drake <drake@endlessm.com>
8b8b88b70SDaniel Drake  */
9b8b88b70SDaniel Drake 
10b8b88b70SDaniel Drake #include <linux/module.h>
11b8b88b70SDaniel Drake #include <linux/acpi.h>
12b8b88b70SDaniel Drake #include <linux/delay.h>
13b8b88b70SDaniel Drake #include <linux/i2c.h>
14b8b88b70SDaniel Drake #include <linux/mod_devicetable.h>
1582225766SHans de Goede #include <linux/mutex.h>
16b8b88b70SDaniel Drake #include <linux/regmap.h>
17b8b88b70SDaniel Drake #include <sound/pcm.h>
18b8b88b70SDaniel Drake #include <sound/pcm_params.h>
19b8b88b70SDaniel Drake #include <sound/soc.h>
20b8b88b70SDaniel Drake #include <sound/soc-dapm.h>
21b8b88b70SDaniel Drake #include <sound/tlv.h>
2282225766SHans de Goede #include <sound/jack.h>
23b8b88b70SDaniel Drake #include "es8316.h"
24b8b88b70SDaniel Drake 
25b8b88b70SDaniel Drake /* In slave mode at single speed, the codec is documented as accepting 5
26b8b88b70SDaniel Drake  * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on
27b8b88b70SDaniel Drake  * Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK).
28b8b88b70SDaniel Drake  */
29b8b88b70SDaniel Drake #define NR_SUPPORTED_MCLK_LRCK_RATIOS 6
30b8b88b70SDaniel Drake static const unsigned int supported_mclk_lrck_ratios[] = {
31b8b88b70SDaniel Drake 	256, 384, 400, 512, 768, 1024
32b8b88b70SDaniel Drake };
33b8b88b70SDaniel Drake 
34b8b88b70SDaniel Drake struct es8316_priv {
3582225766SHans de Goede 	struct mutex lock;
3682225766SHans de Goede 	struct regmap *regmap;
3782225766SHans de Goede 	struct snd_soc_component *component;
3882225766SHans de Goede 	struct snd_soc_jack *jack;
3982225766SHans de Goede 	int irq;
40b8b88b70SDaniel Drake 	unsigned int sysclk;
41b8b88b70SDaniel Drake 	unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS];
42b8b88b70SDaniel Drake 	struct snd_pcm_hw_constraint_list sysclk_constraints;
430bbcedd6SPaul Cercueil 	bool jd_inverted;
44b8b88b70SDaniel Drake };
45b8b88b70SDaniel Drake 
46b8b88b70SDaniel Drake /*
47b8b88b70SDaniel Drake  * ES8316 controls
48b8b88b70SDaniel Drake  */
49b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9600, 50, 1);
50b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9600, 50, 1);
51b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_max_gain_tlv, -650, 150, 0);
52b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_min_gain_tlv, -1200, 150, 0);
53b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_target_tlv, -1650, 150, 0);
54f972d02fSKatsuhiro Suzuki static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpmixer_gain_tlv,
55f972d02fSKatsuhiro Suzuki 	0, 4, TLV_DB_SCALE_ITEM(-1200, 150, 0),
56f972d02fSKatsuhiro Suzuki 	8, 11, TLV_DB_SCALE_ITEM(-450, 150, 0),
57f972d02fSKatsuhiro Suzuki );
58b8b88b70SDaniel Drake 
59b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(adc_pga_gain_tlv,
60b8b88b70SDaniel Drake 	0, 0, TLV_DB_SCALE_ITEM(-350, 0, 0),
61b8b88b70SDaniel Drake 	1, 1, TLV_DB_SCALE_ITEM(0, 0, 0),
62b8b88b70SDaniel Drake 	2, 2, TLV_DB_SCALE_ITEM(250, 0, 0),
63b8b88b70SDaniel Drake 	3, 3, TLV_DB_SCALE_ITEM(450, 0, 0),
64b8b88b70SDaniel Drake 	4, 4, TLV_DB_SCALE_ITEM(700, 0, 0),
65b8b88b70SDaniel Drake 	5, 5, TLV_DB_SCALE_ITEM(1000, 0, 0),
66b8b88b70SDaniel Drake 	6, 6, TLV_DB_SCALE_ITEM(1300, 0, 0),
67b8b88b70SDaniel Drake 	7, 7, TLV_DB_SCALE_ITEM(1600, 0, 0),
68b8b88b70SDaniel Drake 	8, 8, TLV_DB_SCALE_ITEM(1800, 0, 0),
69b8b88b70SDaniel Drake 	9, 9, TLV_DB_SCALE_ITEM(2100, 0, 0),
70b8b88b70SDaniel Drake 	10, 10, TLV_DB_SCALE_ITEM(2400, 0, 0),
71b8b88b70SDaniel Drake );
72b8b88b70SDaniel Drake 
73b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpout_vol_tlv,
74b8b88b70SDaniel Drake 	0, 0, TLV_DB_SCALE_ITEM(-4800, 0, 0),
75b8b88b70SDaniel Drake 	1, 3, TLV_DB_SCALE_ITEM(-2400, 1200, 0),
76b8b88b70SDaniel Drake );
77b8b88b70SDaniel Drake 
78b8b88b70SDaniel Drake static const char * const ng_type_txt[] =
79b8b88b70SDaniel Drake 	{ "Constant PGA Gain", "Mute ADC Output" };
80b8b88b70SDaniel Drake static const struct soc_enum ng_type =
81b8b88b70SDaniel Drake 	SOC_ENUM_SINGLE(ES8316_ADC_ALC_NG, 6, 2, ng_type_txt);
82b8b88b70SDaniel Drake 
83b8b88b70SDaniel Drake static const char * const adcpol_txt[] = { "Normal", "Invert" };
84b8b88b70SDaniel Drake static const struct soc_enum adcpol =
85b8b88b70SDaniel Drake 	SOC_ENUM_SINGLE(ES8316_ADC_MUTE, 1, 2, adcpol_txt);
86b8b88b70SDaniel Drake static const char *const dacpol_txt[] =
87b8b88b70SDaniel Drake 	{ "Normal", "R Invert", "L Invert", "L + R Invert" };
88b8b88b70SDaniel Drake static const struct soc_enum dacpol =
89b8b88b70SDaniel Drake 	SOC_ENUM_SINGLE(ES8316_DAC_SET1, 0, 4, dacpol_txt);
90b8b88b70SDaniel Drake 
91b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_snd_controls[] = {
92b8b88b70SDaniel Drake 	SOC_DOUBLE_TLV("Headphone Playback Volume", ES8316_CPHP_ICAL_VOL,
93b8b88b70SDaniel Drake 		       4, 0, 3, 1, hpout_vol_tlv),
94b8b88b70SDaniel Drake 	SOC_DOUBLE_TLV("Headphone Mixer Volume", ES8316_HPMIX_VOL,
95f972d02fSKatsuhiro Suzuki 		       0, 4, 11, 0, hpmixer_gain_tlv),
96b8b88b70SDaniel Drake 
97b8b88b70SDaniel Drake 	SOC_ENUM("Playback Polarity", dacpol),
98b8b88b70SDaniel Drake 	SOC_DOUBLE_R_TLV("DAC Playback Volume", ES8316_DAC_VOLL,
99b8b88b70SDaniel Drake 			 ES8316_DAC_VOLR, 0, 0xc0, 1, dac_vol_tlv),
100b8b88b70SDaniel Drake 	SOC_SINGLE("DAC Soft Ramp Switch", ES8316_DAC_SET1, 4, 1, 1),
101b8b88b70SDaniel Drake 	SOC_SINGLE("DAC Soft Ramp Rate", ES8316_DAC_SET1, 2, 4, 0),
102b8b88b70SDaniel Drake 	SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0),
103b8b88b70SDaniel Drake 	SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0),
104b8b88b70SDaniel Drake 	SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0),
10524b53f17SHans de Goede 	SOC_SINGLE("DAC Mono Mix Switch", ES8316_DAC_SET3, 3, 1, 0),
106b8b88b70SDaniel Drake 
107b8b88b70SDaniel Drake 	SOC_ENUM("Capture Polarity", adcpol),
108b8b88b70SDaniel Drake 	SOC_SINGLE("Mic Boost Switch", ES8316_ADC_D2SEPGA, 0, 1, 0),
109b8b88b70SDaniel Drake 	SOC_SINGLE_TLV("ADC Capture Volume", ES8316_ADC_VOLUME,
110b8b88b70SDaniel Drake 		       0, 0xc0, 1, adc_vol_tlv),
111b8b88b70SDaniel Drake 	SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8316_ADC_PGAGAIN,
112b8b88b70SDaniel Drake 		       4, 10, 0, adc_pga_gain_tlv),
113b8b88b70SDaniel Drake 	SOC_SINGLE("ADC Soft Ramp Switch", ES8316_ADC_MUTE, 4, 1, 0),
114b8b88b70SDaniel Drake 	SOC_SINGLE("ADC Double Fs Switch", ES8316_ADC_DMIC, 4, 1, 0),
115b8b88b70SDaniel Drake 
116b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Switch", ES8316_ADC_ALC1, 6, 1, 0),
117b8b88b70SDaniel Drake 	SOC_SINGLE_TLV("ALC Capture Max Volume", ES8316_ADC_ALC1, 0, 28, 0,
118b8b88b70SDaniel Drake 		       alc_max_gain_tlv),
119b8b88b70SDaniel Drake 	SOC_SINGLE_TLV("ALC Capture Min Volume", ES8316_ADC_ALC2, 0, 28, 0,
120b8b88b70SDaniel Drake 		       alc_min_gain_tlv),
121b8b88b70SDaniel Drake 	SOC_SINGLE_TLV("ALC Capture Target Volume", ES8316_ADC_ALC3, 4, 10, 0,
122b8b88b70SDaniel Drake 		       alc_target_tlv),
123b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Hold Time", ES8316_ADC_ALC3, 0, 10, 0),
124b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Decay Time", ES8316_ADC_ALC4, 4, 10, 0),
125b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Attack Time", ES8316_ADC_ALC4, 0, 10, 0),
126b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Noise Gate Switch", ES8316_ADC_ALC_NG,
127b8b88b70SDaniel Drake 		   5, 1, 0),
128b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Noise Gate Threshold", ES8316_ADC_ALC_NG,
129b8b88b70SDaniel Drake 		   0, 31, 0),
130b8b88b70SDaniel Drake 	SOC_ENUM("ALC Capture Noise Gate Type", ng_type),
131b8b88b70SDaniel Drake };
132b8b88b70SDaniel Drake 
133b8b88b70SDaniel Drake /* Analog Input Mux */
134b8b88b70SDaniel Drake static const char * const es8316_analog_in_txt[] = {
135b8b88b70SDaniel Drake 		"lin1-rin1",
136b8b88b70SDaniel Drake 		"lin2-rin2",
137b8b88b70SDaniel Drake 		"lin1-rin1 with 20db Boost",
138b8b88b70SDaniel Drake 		"lin2-rin2 with 20db Boost"
139b8b88b70SDaniel Drake };
140b8b88b70SDaniel Drake static const unsigned int es8316_analog_in_values[] = { 0, 1, 2, 3 };
141b8b88b70SDaniel Drake static const struct soc_enum es8316_analog_input_enum =
142b8b88b70SDaniel Drake 	SOC_VALUE_ENUM_SINGLE(ES8316_ADC_PDN_LINSEL, 4, 3,
143b8b88b70SDaniel Drake 			      ARRAY_SIZE(es8316_analog_in_txt),
144b8b88b70SDaniel Drake 			      es8316_analog_in_txt,
145b8b88b70SDaniel Drake 			      es8316_analog_in_values);
146b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_analog_in_mux_controls =
147b8b88b70SDaniel Drake 	SOC_DAPM_ENUM("Route", es8316_analog_input_enum);
148b8b88b70SDaniel Drake 
149b8b88b70SDaniel Drake static const char * const es8316_dmic_txt[] = {
150b8b88b70SDaniel Drake 		"dmic disable",
151b8b88b70SDaniel Drake 		"dmic data at high level",
152b8b88b70SDaniel Drake 		"dmic data at low level",
153b8b88b70SDaniel Drake };
154b8b88b70SDaniel Drake static const unsigned int es8316_dmic_values[] = { 0, 1, 2 };
155b8b88b70SDaniel Drake static const struct soc_enum es8316_dmic_src_enum =
156b8b88b70SDaniel Drake 	SOC_VALUE_ENUM_SINGLE(ES8316_ADC_DMIC, 0, 3,
157b8b88b70SDaniel Drake 			      ARRAY_SIZE(es8316_dmic_txt),
158b8b88b70SDaniel Drake 			      es8316_dmic_txt,
159b8b88b70SDaniel Drake 			      es8316_dmic_values);
160b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_dmic_src_controls =
161b8b88b70SDaniel Drake 	SOC_DAPM_ENUM("Route", es8316_dmic_src_enum);
162b8b88b70SDaniel Drake 
163b8b88b70SDaniel Drake /* hp mixer mux */
164b8b88b70SDaniel Drake static const char * const es8316_hpmux_texts[] = {
165b8b88b70SDaniel Drake 	"lin1-rin1",
166b8b88b70SDaniel Drake 	"lin2-rin2",
167b8b88b70SDaniel Drake 	"lin-rin with Boost",
168b8b88b70SDaniel Drake 	"lin-rin with Boost and PGA"
169b8b88b70SDaniel Drake };
170b8b88b70SDaniel Drake 
171b8b88b70SDaniel Drake static SOC_ENUM_SINGLE_DECL(es8316_left_hpmux_enum, ES8316_HPMIX_SEL,
172b8b88b70SDaniel Drake 	4, es8316_hpmux_texts);
173b8b88b70SDaniel Drake 
174b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_left_hpmux_controls =
175b8b88b70SDaniel Drake 	SOC_DAPM_ENUM("Route", es8316_left_hpmux_enum);
176b8b88b70SDaniel Drake 
177b8b88b70SDaniel Drake static SOC_ENUM_SINGLE_DECL(es8316_right_hpmux_enum, ES8316_HPMIX_SEL,
178b8b88b70SDaniel Drake 	0, es8316_hpmux_texts);
179b8b88b70SDaniel Drake 
180b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_right_hpmux_controls =
181b8b88b70SDaniel Drake 	SOC_DAPM_ENUM("Route", es8316_right_hpmux_enum);
182b8b88b70SDaniel Drake 
183b8b88b70SDaniel Drake /* headphone Output Mixer */
184b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_out_left_mix[] = {
185b8b88b70SDaniel Drake 	SOC_DAPM_SINGLE("LLIN Switch", ES8316_HPMIX_SWITCH, 6, 1, 0),
186b8b88b70SDaniel Drake 	SOC_DAPM_SINGLE("Left DAC Switch", ES8316_HPMIX_SWITCH, 7, 1, 0),
187b8b88b70SDaniel Drake };
188b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_out_right_mix[] = {
189b8b88b70SDaniel Drake 	SOC_DAPM_SINGLE("RLIN Switch", ES8316_HPMIX_SWITCH, 2, 1, 0),
190b8b88b70SDaniel Drake 	SOC_DAPM_SINGLE("Right DAC Switch", ES8316_HPMIX_SWITCH, 3, 1, 0),
191b8b88b70SDaniel Drake };
192b8b88b70SDaniel Drake 
193b8b88b70SDaniel Drake /* DAC data source mux */
194b8b88b70SDaniel Drake static const char * const es8316_dacsrc_texts[] = {
195b8b88b70SDaniel Drake 	"LDATA TO LDAC, RDATA TO RDAC",
196b8b88b70SDaniel Drake 	"LDATA TO LDAC, LDATA TO RDAC",
197b8b88b70SDaniel Drake 	"RDATA TO LDAC, RDATA TO RDAC",
198b8b88b70SDaniel Drake 	"RDATA TO LDAC, LDATA TO RDAC",
199b8b88b70SDaniel Drake };
200b8b88b70SDaniel Drake 
201b8b88b70SDaniel Drake static SOC_ENUM_SINGLE_DECL(es8316_dacsrc_mux_enum, ES8316_DAC_SET1,
202b8b88b70SDaniel Drake 	6, es8316_dacsrc_texts);
203b8b88b70SDaniel Drake 
204b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_dacsrc_mux_controls =
205b8b88b70SDaniel Drake 	SOC_DAPM_ENUM("Route", es8316_dacsrc_mux_enum);
206b8b88b70SDaniel Drake 
207b8b88b70SDaniel Drake static const struct snd_soc_dapm_widget es8316_dapm_widgets[] = {
208b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Bias", ES8316_SYS_PDN, 3, 1, NULL, 0),
209b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Analog power", ES8316_SYS_PDN, 4, 1, NULL, 0),
210b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Mic Bias", ES8316_SYS_PDN, 5, 1, NULL, 0),
211b8b88b70SDaniel Drake 
212b8b88b70SDaniel Drake 	SND_SOC_DAPM_INPUT("DMIC"),
213b8b88b70SDaniel Drake 	SND_SOC_DAPM_INPUT("MIC1"),
214b8b88b70SDaniel Drake 	SND_SOC_DAPM_INPUT("MIC2"),
215b8b88b70SDaniel Drake 
216b8b88b70SDaniel Drake 	/* Input Mux */
217b8b88b70SDaniel Drake 	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
218b8b88b70SDaniel Drake 			 &es8316_analog_in_mux_controls),
219b8b88b70SDaniel Drake 
220b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("ADC Vref", ES8316_SYS_PDN, 1, 1, NULL, 0),
221b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("ADC bias", ES8316_SYS_PDN, 2, 1, NULL, 0),
222b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("ADC Clock", ES8316_CLKMGR_CLKSW, 3, 0, NULL, 0),
223b8b88b70SDaniel Drake 	SND_SOC_DAPM_PGA("Line input PGA", ES8316_ADC_PDN_LINSEL,
224b8b88b70SDaniel Drake 			 7, 1, NULL, 0),
225b8b88b70SDaniel Drake 	SND_SOC_DAPM_ADC("Mono ADC", NULL, ES8316_ADC_PDN_LINSEL, 6, 1),
226b8b88b70SDaniel Drake 	SND_SOC_DAPM_MUX("Digital Mic Mux", SND_SOC_NOPM, 0, 0,
227b8b88b70SDaniel Drake 			 &es8316_dmic_src_controls),
228b8b88b70SDaniel Drake 
229b8b88b70SDaniel Drake 	/* Digital Interface */
230b8b88b70SDaniel Drake 	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture",  1,
231b8b88b70SDaniel Drake 			     ES8316_SERDATA_ADC, 6, 1),
232b8b88b70SDaniel Drake 	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0,
233b8b88b70SDaniel Drake 			    SND_SOC_NOPM, 0, 0),
234b8b88b70SDaniel Drake 
235b8b88b70SDaniel Drake 	SND_SOC_DAPM_MUX("DAC Source Mux", SND_SOC_NOPM, 0, 0,
236b8b88b70SDaniel Drake 			 &es8316_dacsrc_mux_controls),
237b8b88b70SDaniel Drake 
238b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("DAC Vref", ES8316_SYS_PDN, 0, 1, NULL, 0),
239b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("DAC Clock", ES8316_CLKMGR_CLKSW, 2, 0, NULL, 0),
240b8b88b70SDaniel Drake 	SND_SOC_DAPM_DAC("Right DAC", NULL, ES8316_DAC_PDN, 0, 1),
241b8b88b70SDaniel Drake 	SND_SOC_DAPM_DAC("Left DAC", NULL, ES8316_DAC_PDN, 4, 1),
242b8b88b70SDaniel Drake 
243b8b88b70SDaniel Drake 	/* Headphone Output Side */
244b8b88b70SDaniel Drake 	SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0,
245b8b88b70SDaniel Drake 			 &es8316_left_hpmux_controls),
246b8b88b70SDaniel Drake 	SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0,
247b8b88b70SDaniel Drake 			 &es8316_right_hpmux_controls),
248b8b88b70SDaniel Drake 	SND_SOC_DAPM_MIXER("Left Headphone Mixer", ES8316_HPMIX_PDN,
249b8b88b70SDaniel Drake 			   5, 1, &es8316_out_left_mix[0],
250b8b88b70SDaniel Drake 			   ARRAY_SIZE(es8316_out_left_mix)),
251b8b88b70SDaniel Drake 	SND_SOC_DAPM_MIXER("Right Headphone Mixer", ES8316_HPMIX_PDN,
252b8b88b70SDaniel Drake 			   1, 1, &es8316_out_right_mix[0],
253b8b88b70SDaniel Drake 			   ARRAY_SIZE(es8316_out_right_mix)),
254b8b88b70SDaniel Drake 	SND_SOC_DAPM_PGA("Left Headphone Mixer Out", ES8316_HPMIX_PDN,
255b8b88b70SDaniel Drake 			 4, 1, NULL, 0),
256b8b88b70SDaniel Drake 	SND_SOC_DAPM_PGA("Right Headphone Mixer Out", ES8316_HPMIX_PDN,
257b8b88b70SDaniel Drake 			 0, 1, NULL, 0),
258b8b88b70SDaniel Drake 
259b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUT_DRV("Left Headphone Charge Pump", ES8316_CPHP_OUTEN,
260b8b88b70SDaniel Drake 			     6, 0, NULL, 0),
261b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUT_DRV("Right Headphone Charge Pump", ES8316_CPHP_OUTEN,
262b8b88b70SDaniel Drake 			     2, 0, NULL, 0),
263b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8316_CPHP_PDN2,
264b8b88b70SDaniel Drake 			    5, 1, NULL, 0),
265b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump Clock", ES8316_CLKMGR_CLKSW,
266b8b88b70SDaniel Drake 			    4, 0, NULL, 0),
267b8b88b70SDaniel Drake 
268b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUT_DRV("Left Headphone Driver", ES8316_CPHP_OUTEN,
269b8b88b70SDaniel Drake 			     5, 0, NULL, 0),
270b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUT_DRV("Right Headphone Driver", ES8316_CPHP_OUTEN,
271b8b88b70SDaniel Drake 			     1, 0, NULL, 0),
272b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Headphone Out", ES8316_CPHP_PDN1, 2, 1, NULL, 0),
273b8b88b70SDaniel Drake 
274b8b88b70SDaniel Drake 	/* pdn_Lical and pdn_Rical bits are documented as Reserved, but must
275b8b88b70SDaniel Drake 	 * be explicitly unset in order to enable HP output
276b8b88b70SDaniel Drake 	 */
277b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Left Headphone ical", ES8316_CPHP_ICAL_VOL,
278b8b88b70SDaniel Drake 			    7, 1, NULL, 0),
279b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Right Headphone ical", ES8316_CPHP_ICAL_VOL,
280b8b88b70SDaniel Drake 			    3, 1, NULL, 0),
281b8b88b70SDaniel Drake 
282b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUTPUT("HPOL"),
283b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUTPUT("HPOR"),
284b8b88b70SDaniel Drake };
285b8b88b70SDaniel Drake 
286b8b88b70SDaniel Drake static const struct snd_soc_dapm_route es8316_dapm_routes[] = {
287b8b88b70SDaniel Drake 	/* Recording */
288b8b88b70SDaniel Drake 	{"MIC1", NULL, "Mic Bias"},
289b8b88b70SDaniel Drake 	{"MIC2", NULL, "Mic Bias"},
290b8b88b70SDaniel Drake 	{"MIC1", NULL, "Bias"},
291b8b88b70SDaniel Drake 	{"MIC2", NULL, "Bias"},
292b8b88b70SDaniel Drake 	{"MIC1", NULL, "Analog power"},
293b8b88b70SDaniel Drake 	{"MIC2", NULL, "Analog power"},
294b8b88b70SDaniel Drake 
295b8b88b70SDaniel Drake 	{"Differential Mux", "lin1-rin1", "MIC1"},
296b8b88b70SDaniel Drake 	{"Differential Mux", "lin2-rin2", "MIC2"},
297b8b88b70SDaniel Drake 	{"Line input PGA", NULL, "Differential Mux"},
298b8b88b70SDaniel Drake 
299b8b88b70SDaniel Drake 	{"Mono ADC", NULL, "ADC Clock"},
300b8b88b70SDaniel Drake 	{"Mono ADC", NULL, "ADC Vref"},
301b8b88b70SDaniel Drake 	{"Mono ADC", NULL, "ADC bias"},
302b8b88b70SDaniel Drake 	{"Mono ADC", NULL, "Line input PGA"},
303b8b88b70SDaniel Drake 
304b8b88b70SDaniel Drake 	/* It's not clear why, but to avoid recording only silence,
305b8b88b70SDaniel Drake 	 * the DAC clock must be running for the ADC to work.
306b8b88b70SDaniel Drake 	 */
307b8b88b70SDaniel Drake 	{"Mono ADC", NULL, "DAC Clock"},
308b8b88b70SDaniel Drake 
309b8b88b70SDaniel Drake 	{"Digital Mic Mux", "dmic disable", "Mono ADC"},
310b8b88b70SDaniel Drake 
311b8b88b70SDaniel Drake 	{"I2S OUT", NULL, "Digital Mic Mux"},
312b8b88b70SDaniel Drake 
313b8b88b70SDaniel Drake 	/* Playback */
314b8b88b70SDaniel Drake 	{"DAC Source Mux", "LDATA TO LDAC, RDATA TO RDAC", "I2S IN"},
315b8b88b70SDaniel Drake 
316b8b88b70SDaniel Drake 	{"Left DAC", NULL, "DAC Clock"},
317b8b88b70SDaniel Drake 	{"Right DAC", NULL, "DAC Clock"},
318b8b88b70SDaniel Drake 
319b8b88b70SDaniel Drake 	{"Left DAC", NULL, "DAC Vref"},
320b8b88b70SDaniel Drake 	{"Right DAC", NULL, "DAC Vref"},
321b8b88b70SDaniel Drake 
322b8b88b70SDaniel Drake 	{"Left DAC", NULL, "DAC Source Mux"},
323b8b88b70SDaniel Drake 	{"Right DAC", NULL, "DAC Source Mux"},
324b8b88b70SDaniel Drake 
325b8b88b70SDaniel Drake 	{"Left Headphone Mux", "lin-rin with Boost and PGA", "Line input PGA"},
326b8b88b70SDaniel Drake 	{"Right Headphone Mux", "lin-rin with Boost and PGA", "Line input PGA"},
327b8b88b70SDaniel Drake 
328b8b88b70SDaniel Drake 	{"Left Headphone Mixer", "LLIN Switch", "Left Headphone Mux"},
329b8b88b70SDaniel Drake 	{"Left Headphone Mixer", "Left DAC Switch", "Left DAC"},
330b8b88b70SDaniel Drake 
331b8b88b70SDaniel Drake 	{"Right Headphone Mixer", "RLIN Switch", "Right Headphone Mux"},
332b8b88b70SDaniel Drake 	{"Right Headphone Mixer", "Right DAC Switch", "Right DAC"},
333b8b88b70SDaniel Drake 
334b8b88b70SDaniel Drake 	{"Left Headphone Mixer Out", NULL, "Left Headphone Mixer"},
335b8b88b70SDaniel Drake 	{"Right Headphone Mixer Out", NULL, "Right Headphone Mixer"},
336b8b88b70SDaniel Drake 
337b8b88b70SDaniel Drake 	{"Left Headphone Charge Pump", NULL, "Left Headphone Mixer Out"},
338b8b88b70SDaniel Drake 	{"Right Headphone Charge Pump", NULL, "Right Headphone Mixer Out"},
339b8b88b70SDaniel Drake 
340b8b88b70SDaniel Drake 	{"Left Headphone Charge Pump", NULL, "Headphone Charge Pump"},
341b8b88b70SDaniel Drake 	{"Right Headphone Charge Pump", NULL, "Headphone Charge Pump"},
342b8b88b70SDaniel Drake 
343b8b88b70SDaniel Drake 	{"Left Headphone Charge Pump", NULL, "Headphone Charge Pump Clock"},
344b8b88b70SDaniel Drake 	{"Right Headphone Charge Pump", NULL, "Headphone Charge Pump Clock"},
345b8b88b70SDaniel Drake 
346b8b88b70SDaniel Drake 	{"Left Headphone Driver", NULL, "Left Headphone Charge Pump"},
347b8b88b70SDaniel Drake 	{"Right Headphone Driver", NULL, "Right Headphone Charge Pump"},
348b8b88b70SDaniel Drake 
349b8b88b70SDaniel Drake 	{"HPOL", NULL, "Left Headphone Driver"},
350b8b88b70SDaniel Drake 	{"HPOR", NULL, "Right Headphone Driver"},
351b8b88b70SDaniel Drake 
352b8b88b70SDaniel Drake 	{"HPOL", NULL, "Left Headphone ical"},
353b8b88b70SDaniel Drake 	{"HPOR", NULL, "Right Headphone ical"},
354b8b88b70SDaniel Drake 
355b8b88b70SDaniel Drake 	{"Headphone Out", NULL, "Bias"},
356b8b88b70SDaniel Drake 	{"Headphone Out", NULL, "Analog power"},
357b8b88b70SDaniel Drake 	{"HPOL", NULL, "Headphone Out"},
358b8b88b70SDaniel Drake 	{"HPOR", NULL, "Headphone Out"},
359b8b88b70SDaniel Drake };
360b8b88b70SDaniel Drake 
361b8b88b70SDaniel Drake static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
362b8b88b70SDaniel Drake 				 int clk_id, unsigned int freq, int dir)
363b8b88b70SDaniel Drake {
3642ff52976SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
3652ff52976SKuninori Morimoto 	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
366b8b88b70SDaniel Drake 	int i;
367b8b88b70SDaniel Drake 	int count = 0;
368b8b88b70SDaniel Drake 
369b8b88b70SDaniel Drake 	es8316->sysclk = freq;
370b8b88b70SDaniel Drake 
371b8b88b70SDaniel Drake 	if (freq == 0)
372b8b88b70SDaniel Drake 		return 0;
373b8b88b70SDaniel Drake 
374b8b88b70SDaniel Drake 	/* Limit supported sample rates to ones that can be autodetected
375b8b88b70SDaniel Drake 	 * by the codec running in slave mode.
376b8b88b70SDaniel Drake 	 */
377b8b88b70SDaniel Drake 	for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) {
378b8b88b70SDaniel Drake 		const unsigned int ratio = supported_mclk_lrck_ratios[i];
379b8b88b70SDaniel Drake 
380b8b88b70SDaniel Drake 		if (freq % ratio == 0)
381b8b88b70SDaniel Drake 			es8316->allowed_rates[count++] = freq / ratio;
382b8b88b70SDaniel Drake 	}
383b8b88b70SDaniel Drake 
384b8b88b70SDaniel Drake 	es8316->sysclk_constraints.list = es8316->allowed_rates;
385b8b88b70SDaniel Drake 	es8316->sysclk_constraints.count = count;
386b8b88b70SDaniel Drake 
387b8b88b70SDaniel Drake 	return 0;
388b8b88b70SDaniel Drake }
389b8b88b70SDaniel Drake 
390b8b88b70SDaniel Drake static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai,
391b8b88b70SDaniel Drake 			      unsigned int fmt)
392b8b88b70SDaniel Drake {
3932ff52976SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
394b8b88b70SDaniel Drake 	u8 serdata1 = 0;
395b8b88b70SDaniel Drake 	u8 serdata2 = 0;
396b8b88b70SDaniel Drake 	u8 clksw;
397b8b88b70SDaniel Drake 	u8 mask;
398b8b88b70SDaniel Drake 
399b8b88b70SDaniel Drake 	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
4002ff52976SKuninori Morimoto 		dev_err(component->dev, "Codec driver only supports slave mode\n");
401b8b88b70SDaniel Drake 		return -EINVAL;
402b8b88b70SDaniel Drake 	}
403b8b88b70SDaniel Drake 
404b8b88b70SDaniel Drake 	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
4052ff52976SKuninori Morimoto 		dev_err(component->dev, "Codec driver only supports I2S format\n");
406b8b88b70SDaniel Drake 		return -EINVAL;
407b8b88b70SDaniel Drake 	}
408b8b88b70SDaniel Drake 
409b8b88b70SDaniel Drake 	/* Clock inversion */
410b8b88b70SDaniel Drake 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
411b8b88b70SDaniel Drake 	case SND_SOC_DAIFMT_NB_NF:
412b8b88b70SDaniel Drake 		break;
413b8b88b70SDaniel Drake 	case SND_SOC_DAIFMT_IB_IF:
414b8b88b70SDaniel Drake 		serdata1 |= ES8316_SERDATA1_BCLK_INV;
415b8b88b70SDaniel Drake 		serdata2 |= ES8316_SERDATA2_ADCLRP;
416b8b88b70SDaniel Drake 		break;
417b8b88b70SDaniel Drake 	case SND_SOC_DAIFMT_IB_NF:
418b8b88b70SDaniel Drake 		serdata1 |= ES8316_SERDATA1_BCLK_INV;
419b8b88b70SDaniel Drake 		break;
420b8b88b70SDaniel Drake 	case SND_SOC_DAIFMT_NB_IF:
421b8b88b70SDaniel Drake 		serdata2 |= ES8316_SERDATA2_ADCLRP;
422b8b88b70SDaniel Drake 		break;
423b8b88b70SDaniel Drake 	default:
424b8b88b70SDaniel Drake 		return -EINVAL;
425b8b88b70SDaniel Drake 	}
426b8b88b70SDaniel Drake 
427b8b88b70SDaniel Drake 	mask = ES8316_SERDATA1_MASTER | ES8316_SERDATA1_BCLK_INV;
4282ff52976SKuninori Morimoto 	snd_soc_component_update_bits(component, ES8316_SERDATA1, mask, serdata1);
429b8b88b70SDaniel Drake 
430b8b88b70SDaniel Drake 	mask = ES8316_SERDATA2_FMT_MASK | ES8316_SERDATA2_ADCLRP;
4312ff52976SKuninori Morimoto 	snd_soc_component_update_bits(component, ES8316_SERDATA_ADC, mask, serdata2);
4322ff52976SKuninori Morimoto 	snd_soc_component_update_bits(component, ES8316_SERDATA_DAC, mask, serdata2);
433b8b88b70SDaniel Drake 
434b8b88b70SDaniel Drake 	/* Enable BCLK and MCLK inputs in slave mode */
435b8b88b70SDaniel Drake 	clksw = ES8316_CLKMGR_CLKSW_MCLK_ON | ES8316_CLKMGR_CLKSW_BCLK_ON;
4362ff52976SKuninori Morimoto 	snd_soc_component_update_bits(component, ES8316_CLKMGR_CLKSW, clksw, clksw);
437b8b88b70SDaniel Drake 
438b8b88b70SDaniel Drake 	return 0;
439b8b88b70SDaniel Drake }
440b8b88b70SDaniel Drake 
441b8b88b70SDaniel Drake static int es8316_pcm_startup(struct snd_pcm_substream *substream,
442b8b88b70SDaniel Drake 			      struct snd_soc_dai *dai)
443b8b88b70SDaniel Drake {
4442ff52976SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
4452ff52976SKuninori Morimoto 	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
446b8b88b70SDaniel Drake 
447b8b88b70SDaniel Drake 	if (es8316->sysclk == 0) {
4482ff52976SKuninori Morimoto 		dev_err(component->dev, "No sysclk provided\n");
449b8b88b70SDaniel Drake 		return -EINVAL;
450b8b88b70SDaniel Drake 	}
451b8b88b70SDaniel Drake 
452b8b88b70SDaniel Drake 	/* The set of sample rates that can be supported depends on the
453b8b88b70SDaniel Drake 	 * MCLK supplied to the CODEC.
454b8b88b70SDaniel Drake 	 */
455b8b88b70SDaniel Drake 	snd_pcm_hw_constraint_list(substream->runtime, 0,
456b8b88b70SDaniel Drake 				   SNDRV_PCM_HW_PARAM_RATE,
457b8b88b70SDaniel Drake 				   &es8316->sysclk_constraints);
458b8b88b70SDaniel Drake 
459b8b88b70SDaniel Drake 	return 0;
460b8b88b70SDaniel Drake }
461b8b88b70SDaniel Drake 
462b8b88b70SDaniel Drake static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
463b8b88b70SDaniel Drake 				struct snd_pcm_hw_params *params,
464b8b88b70SDaniel Drake 				struct snd_soc_dai *dai)
465b8b88b70SDaniel Drake {
4662ff52976SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
4672ff52976SKuninori Morimoto 	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
468b8b88b70SDaniel Drake 	u8 wordlen = 0;
469b8b88b70SDaniel Drake 
470b8b88b70SDaniel Drake 	if (!es8316->sysclk) {
4712ff52976SKuninori Morimoto 		dev_err(component->dev, "No MCLK configured\n");
472b8b88b70SDaniel Drake 		return -EINVAL;
473b8b88b70SDaniel Drake 	}
474b8b88b70SDaniel Drake 
475b8b88b70SDaniel Drake 	switch (params_format(params)) {
476b8b88b70SDaniel Drake 	case SNDRV_PCM_FORMAT_S16_LE:
477b8b88b70SDaniel Drake 		wordlen = ES8316_SERDATA2_LEN_16;
478b8b88b70SDaniel Drake 		break;
479b8b88b70SDaniel Drake 	case SNDRV_PCM_FORMAT_S20_3LE:
480b8b88b70SDaniel Drake 		wordlen = ES8316_SERDATA2_LEN_20;
481b8b88b70SDaniel Drake 		break;
482b8b88b70SDaniel Drake 	case SNDRV_PCM_FORMAT_S24_LE:
483b8b88b70SDaniel Drake 		wordlen = ES8316_SERDATA2_LEN_24;
484b8b88b70SDaniel Drake 		break;
485b8b88b70SDaniel Drake 	case SNDRV_PCM_FORMAT_S32_LE:
486b8b88b70SDaniel Drake 		wordlen = ES8316_SERDATA2_LEN_32;
487b8b88b70SDaniel Drake 		break;
488b8b88b70SDaniel Drake 	default:
489b8b88b70SDaniel Drake 		return -EINVAL;
490b8b88b70SDaniel Drake 	}
491b8b88b70SDaniel Drake 
4922ff52976SKuninori Morimoto 	snd_soc_component_update_bits(component, ES8316_SERDATA_DAC,
493b8b88b70SDaniel Drake 			    ES8316_SERDATA2_LEN_MASK, wordlen);
4942ff52976SKuninori Morimoto 	snd_soc_component_update_bits(component, ES8316_SERDATA_ADC,
495b8b88b70SDaniel Drake 			    ES8316_SERDATA2_LEN_MASK, wordlen);
496b8b88b70SDaniel Drake 	return 0;
497b8b88b70SDaniel Drake }
498b8b88b70SDaniel Drake 
499b8b88b70SDaniel Drake static int es8316_mute(struct snd_soc_dai *dai, int mute)
500b8b88b70SDaniel Drake {
5012ff52976SKuninori Morimoto 	snd_soc_component_update_bits(dai->component, ES8316_DAC_SET1, 0x20,
502b8b88b70SDaniel Drake 			    mute ? 0x20 : 0);
503b8b88b70SDaniel Drake 	return 0;
504b8b88b70SDaniel Drake }
505b8b88b70SDaniel Drake 
506b8b88b70SDaniel Drake #define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
507b8b88b70SDaniel Drake 			SNDRV_PCM_FMTBIT_S24_LE)
508b8b88b70SDaniel Drake 
509eb59d73cSArvind Yadav static const struct snd_soc_dai_ops es8316_ops = {
510b8b88b70SDaniel Drake 	.startup = es8316_pcm_startup,
511b8b88b70SDaniel Drake 	.hw_params = es8316_pcm_hw_params,
512b8b88b70SDaniel Drake 	.set_fmt = es8316_set_dai_fmt,
513b8b88b70SDaniel Drake 	.set_sysclk = es8316_set_dai_sysclk,
514b8b88b70SDaniel Drake 	.digital_mute = es8316_mute,
515b8b88b70SDaniel Drake };
516b8b88b70SDaniel Drake 
517b8b88b70SDaniel Drake static struct snd_soc_dai_driver es8316_dai = {
518b8b88b70SDaniel Drake 	.name = "ES8316 HiFi",
519b8b88b70SDaniel Drake 	.playback = {
520b8b88b70SDaniel Drake 		.stream_name = "Playback",
521b8b88b70SDaniel Drake 		.channels_min = 1,
522b8b88b70SDaniel Drake 		.channels_max = 2,
523b8b88b70SDaniel Drake 		.rates = SNDRV_PCM_RATE_8000_48000,
524b8b88b70SDaniel Drake 		.formats = ES8316_FORMATS,
525b8b88b70SDaniel Drake 	},
526b8b88b70SDaniel Drake 	.capture = {
527b8b88b70SDaniel Drake 		.stream_name = "Capture",
528b8b88b70SDaniel Drake 		.channels_min = 1,
529b8b88b70SDaniel Drake 		.channels_max = 2,
530b8b88b70SDaniel Drake 		.rates = SNDRV_PCM_RATE_8000_48000,
531b8b88b70SDaniel Drake 		.formats = ES8316_FORMATS,
532b8b88b70SDaniel Drake 	},
533b8b88b70SDaniel Drake 	.ops = &es8316_ops,
534b8b88b70SDaniel Drake 	.symmetric_rates = 1,
535b8b88b70SDaniel Drake };
536b8b88b70SDaniel Drake 
53782225766SHans de Goede static void es8316_enable_micbias_for_mic_gnd_short_detect(
53882225766SHans de Goede 	struct snd_soc_component *component)
53982225766SHans de Goede {
54082225766SHans de Goede 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
54182225766SHans de Goede 
54282225766SHans de Goede 	snd_soc_dapm_mutex_lock(dapm);
54382225766SHans de Goede 	snd_soc_dapm_force_enable_pin_unlocked(dapm, "Bias");
54482225766SHans de Goede 	snd_soc_dapm_force_enable_pin_unlocked(dapm, "Analog power");
54582225766SHans de Goede 	snd_soc_dapm_force_enable_pin_unlocked(dapm, "Mic Bias");
54682225766SHans de Goede 	snd_soc_dapm_sync_unlocked(dapm);
54782225766SHans de Goede 	snd_soc_dapm_mutex_unlock(dapm);
54882225766SHans de Goede 
54982225766SHans de Goede 	msleep(20);
55082225766SHans de Goede }
55182225766SHans de Goede 
55282225766SHans de Goede static void es8316_disable_micbias_for_mic_gnd_short_detect(
55382225766SHans de Goede 	struct snd_soc_component *component)
55482225766SHans de Goede {
55582225766SHans de Goede 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
55682225766SHans de Goede 
55782225766SHans de Goede 	snd_soc_dapm_mutex_lock(dapm);
55882225766SHans de Goede 	snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Bias");
55982225766SHans de Goede 	snd_soc_dapm_disable_pin_unlocked(dapm, "Analog power");
56082225766SHans de Goede 	snd_soc_dapm_disable_pin_unlocked(dapm, "Bias");
56182225766SHans de Goede 	snd_soc_dapm_sync_unlocked(dapm);
56282225766SHans de Goede 	snd_soc_dapm_mutex_unlock(dapm);
56382225766SHans de Goede }
56482225766SHans de Goede 
56582225766SHans de Goede static irqreturn_t es8316_irq(int irq, void *data)
56682225766SHans de Goede {
56782225766SHans de Goede 	struct es8316_priv *es8316 = data;
56882225766SHans de Goede 	struct snd_soc_component *comp = es8316->component;
56982225766SHans de Goede 	unsigned int flags;
57082225766SHans de Goede 
57182225766SHans de Goede 	mutex_lock(&es8316->lock);
57282225766SHans de Goede 
57382225766SHans de Goede 	regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags);
57482225766SHans de Goede 	if (flags == 0x00)
57582225766SHans de Goede 		goto out; /* Powered-down / reset */
57682225766SHans de Goede 
57782225766SHans de Goede 	/* Catch spurious IRQ before set_jack is called */
57882225766SHans de Goede 	if (!es8316->jack)
57982225766SHans de Goede 		goto out;
58082225766SHans de Goede 
5810bbcedd6SPaul Cercueil 	if (es8316->jd_inverted)
5820bbcedd6SPaul Cercueil 		flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED;
5830bbcedd6SPaul Cercueil 
58482225766SHans de Goede 	dev_dbg(comp->dev, "gpio flags %#04x\n", flags);
58582225766SHans de Goede 	if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) {
58682225766SHans de Goede 		/* Jack removed, or spurious IRQ? */
58782225766SHans de Goede 		if (es8316->jack->status & SND_JACK_MICROPHONE)
58882225766SHans de Goede 			es8316_disable_micbias_for_mic_gnd_short_detect(comp);
58982225766SHans de Goede 
59082225766SHans de Goede 		if (es8316->jack->status & SND_JACK_HEADPHONE) {
59182225766SHans de Goede 			snd_soc_jack_report(es8316->jack, 0,
59282225766SHans de Goede 					    SND_JACK_HEADSET | SND_JACK_BTN_0);
59382225766SHans de Goede 			dev_dbg(comp->dev, "jack unplugged\n");
59482225766SHans de Goede 		}
59582225766SHans de Goede 	} else if (!(es8316->jack->status & SND_JACK_HEADPHONE)) {
59682225766SHans de Goede 		/* Jack inserted, determine type */
59782225766SHans de Goede 		es8316_enable_micbias_for_mic_gnd_short_detect(comp);
59882225766SHans de Goede 		regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags);
5990bbcedd6SPaul Cercueil 		if (es8316->jd_inverted)
6000bbcedd6SPaul Cercueil 			flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED;
60182225766SHans de Goede 		dev_dbg(comp->dev, "gpio flags %#04x\n", flags);
60282225766SHans de Goede 		if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) {
60382225766SHans de Goede 			/* Jack unplugged underneath us */
60482225766SHans de Goede 			es8316_disable_micbias_for_mic_gnd_short_detect(comp);
60582225766SHans de Goede 		} else if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) {
60682225766SHans de Goede 			/* Open, headset */
60782225766SHans de Goede 			snd_soc_jack_report(es8316->jack,
60882225766SHans de Goede 					    SND_JACK_HEADSET,
60982225766SHans de Goede 					    SND_JACK_HEADSET);
61082225766SHans de Goede 			/* Keep mic-gnd-short detection on for button press */
61182225766SHans de Goede 		} else {
61282225766SHans de Goede 			/* Shorted, headphones */
61382225766SHans de Goede 			snd_soc_jack_report(es8316->jack,
61482225766SHans de Goede 					    SND_JACK_HEADPHONE,
61582225766SHans de Goede 					    SND_JACK_HEADSET);
61682225766SHans de Goede 			/* No longer need mic-gnd-short detection */
61782225766SHans de Goede 			es8316_disable_micbias_for_mic_gnd_short_detect(comp);
61882225766SHans de Goede 		}
61982225766SHans de Goede 	} else if (es8316->jack->status & SND_JACK_MICROPHONE) {
62082225766SHans de Goede 		/* Interrupt while jack inserted, report button state */
62182225766SHans de Goede 		if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) {
62282225766SHans de Goede 			/* Open, button release */
62382225766SHans de Goede 			snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0);
62482225766SHans de Goede 		} else {
62582225766SHans de Goede 			/* Short, button press */
62682225766SHans de Goede 			snd_soc_jack_report(es8316->jack,
62782225766SHans de Goede 					    SND_JACK_BTN_0,
62882225766SHans de Goede 					    SND_JACK_BTN_0);
62982225766SHans de Goede 		}
63082225766SHans de Goede 	}
63182225766SHans de Goede 
63282225766SHans de Goede out:
63382225766SHans de Goede 	mutex_unlock(&es8316->lock);
63482225766SHans de Goede 	return IRQ_HANDLED;
63582225766SHans de Goede }
63682225766SHans de Goede 
63782225766SHans de Goede static void es8316_enable_jack_detect(struct snd_soc_component *component,
63882225766SHans de Goede 				      struct snd_soc_jack *jack)
63982225766SHans de Goede {
64082225766SHans de Goede 	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
64182225766SHans de Goede 
6420bbcedd6SPaul Cercueil 	/*
6430bbcedd6SPaul Cercueil 	 * Init es8316->jd_inverted here and not in the probe, as we cannot
6440bbcedd6SPaul Cercueil 	 * guarantee that the bytchr-es8316 driver, which might set this
6450bbcedd6SPaul Cercueil 	 * property, will probe before us.
6460bbcedd6SPaul Cercueil 	 */
6470bbcedd6SPaul Cercueil 	es8316->jd_inverted = device_property_read_bool(component->dev,
6480bbcedd6SPaul Cercueil 							"everest,jack-detect-inverted");
6490bbcedd6SPaul Cercueil 
65082225766SHans de Goede 	mutex_lock(&es8316->lock);
65182225766SHans de Goede 
65282225766SHans de Goede 	es8316->jack = jack;
65382225766SHans de Goede 
65482225766SHans de Goede 	if (es8316->jack->status & SND_JACK_MICROPHONE)
65582225766SHans de Goede 		es8316_enable_micbias_for_mic_gnd_short_detect(component);
65682225766SHans de Goede 
65782225766SHans de Goede 	snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
65882225766SHans de Goede 				      ES8316_GPIO_ENABLE_INTERRUPT,
65982225766SHans de Goede 				      ES8316_GPIO_ENABLE_INTERRUPT);
66082225766SHans de Goede 
66182225766SHans de Goede 	mutex_unlock(&es8316->lock);
66282225766SHans de Goede 
66382225766SHans de Goede 	/* Enable irq and sync initial jack state */
66482225766SHans de Goede 	enable_irq(es8316->irq);
66582225766SHans de Goede 	es8316_irq(es8316->irq, es8316);
66682225766SHans de Goede }
66782225766SHans de Goede 
66882225766SHans de Goede static void es8316_disable_jack_detect(struct snd_soc_component *component)
66982225766SHans de Goede {
67082225766SHans de Goede 	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
67182225766SHans de Goede 
67282225766SHans de Goede 	disable_irq(es8316->irq);
67382225766SHans de Goede 
67482225766SHans de Goede 	mutex_lock(&es8316->lock);
67582225766SHans de Goede 
67682225766SHans de Goede 	snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
67782225766SHans de Goede 				      ES8316_GPIO_ENABLE_INTERRUPT, 0);
67882225766SHans de Goede 
67982225766SHans de Goede 	if (es8316->jack->status & SND_JACK_MICROPHONE) {
68082225766SHans de Goede 		es8316_disable_micbias_for_mic_gnd_short_detect(component);
68182225766SHans de Goede 		snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0);
68282225766SHans de Goede 	}
68382225766SHans de Goede 
68482225766SHans de Goede 	es8316->jack = NULL;
68582225766SHans de Goede 
68682225766SHans de Goede 	mutex_unlock(&es8316->lock);
68782225766SHans de Goede }
68882225766SHans de Goede 
68982225766SHans de Goede static int es8316_set_jack(struct snd_soc_component *component,
69082225766SHans de Goede 			   struct snd_soc_jack *jack, void *data)
69182225766SHans de Goede {
69282225766SHans de Goede 	if (jack)
69382225766SHans de Goede 		es8316_enable_jack_detect(component, jack);
69482225766SHans de Goede 	else
69582225766SHans de Goede 		es8316_disable_jack_detect(component);
69682225766SHans de Goede 
69782225766SHans de Goede 	return 0;
69882225766SHans de Goede }
69982225766SHans de Goede 
7002ff52976SKuninori Morimoto static int es8316_probe(struct snd_soc_component *component)
701b8b88b70SDaniel Drake {
70282225766SHans de Goede 	struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
70382225766SHans de Goede 
70482225766SHans de Goede 	es8316->component = component;
70582225766SHans de Goede 
706b8b88b70SDaniel Drake 	/* Reset codec and enable current state machine */
7072ff52976SKuninori Morimoto 	snd_soc_component_write(component, ES8316_RESET, 0x3f);
708b8b88b70SDaniel Drake 	usleep_range(5000, 5500);
7092ff52976SKuninori Morimoto 	snd_soc_component_write(component, ES8316_RESET, ES8316_RESET_CSM_ON);
710b8b88b70SDaniel Drake 	msleep(30);
711b8b88b70SDaniel Drake 
712b8b88b70SDaniel Drake 	/*
713b8b88b70SDaniel Drake 	 * Documentation is unclear, but this value from the vendor driver is
714b8b88b70SDaniel Drake 	 * needed otherwise audio output is silent.
715b8b88b70SDaniel Drake 	 */
7162ff52976SKuninori Morimoto 	snd_soc_component_write(component, ES8316_SYS_VMIDSEL, 0xff);
717b8b88b70SDaniel Drake 
718b8b88b70SDaniel Drake 	/*
719b8b88b70SDaniel Drake 	 * Documentation for this register is unclear and incomplete,
720b8b88b70SDaniel Drake 	 * but here is a vendor-provided value that improves volume
721b8b88b70SDaniel Drake 	 * and quality for Intel CHT platforms.
722b8b88b70SDaniel Drake 	 */
7232ff52976SKuninori Morimoto 	snd_soc_component_write(component, ES8316_CLKMGR_ADCOSR, 0x32);
724b8b88b70SDaniel Drake 
725b8b88b70SDaniel Drake 	return 0;
726b8b88b70SDaniel Drake }
727b8b88b70SDaniel Drake 
7282ff52976SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_es8316 = {
729b8b88b70SDaniel Drake 	.probe			= es8316_probe,
73082225766SHans de Goede 	.set_jack		= es8316_set_jack,
731b8b88b70SDaniel Drake 	.controls		= es8316_snd_controls,
732b8b88b70SDaniel Drake 	.num_controls		= ARRAY_SIZE(es8316_snd_controls),
733b8b88b70SDaniel Drake 	.dapm_widgets		= es8316_dapm_widgets,
734b8b88b70SDaniel Drake 	.num_dapm_widgets	= ARRAY_SIZE(es8316_dapm_widgets),
735b8b88b70SDaniel Drake 	.dapm_routes		= es8316_dapm_routes,
736b8b88b70SDaniel Drake 	.num_dapm_routes	= ARRAY_SIZE(es8316_dapm_routes),
7372ff52976SKuninori Morimoto 	.use_pmdown_time	= 1,
7382ff52976SKuninori Morimoto 	.endianness		= 1,
7392ff52976SKuninori Morimoto 	.non_legacy_dai_naming	= 1,
740b8b88b70SDaniel Drake };
741b8b88b70SDaniel Drake 
74282225766SHans de Goede static const struct regmap_range es8316_volatile_ranges[] = {
74382225766SHans de Goede 	regmap_reg_range(ES8316_GPIO_FLAG, ES8316_GPIO_FLAG),
74482225766SHans de Goede };
74582225766SHans de Goede 
74682225766SHans de Goede static const struct regmap_access_table es8316_volatile_table = {
74782225766SHans de Goede 	.yes_ranges	= es8316_volatile_ranges,
74882225766SHans de Goede 	.n_yes_ranges	= ARRAY_SIZE(es8316_volatile_ranges),
74982225766SHans de Goede };
75082225766SHans de Goede 
751b8b88b70SDaniel Drake static const struct regmap_config es8316_regmap = {
752b8b88b70SDaniel Drake 	.reg_bits = 8,
753b8b88b70SDaniel Drake 	.val_bits = 8,
754b8b88b70SDaniel Drake 	.max_register = 0x53,
75582225766SHans de Goede 	.volatile_table	= &es8316_volatile_table,
756b8b88b70SDaniel Drake 	.cache_type = REGCACHE_RBTREE,
757b8b88b70SDaniel Drake };
758b8b88b70SDaniel Drake 
759b8b88b70SDaniel Drake static int es8316_i2c_probe(struct i2c_client *i2c_client,
760b8b88b70SDaniel Drake 			    const struct i2c_device_id *id)
761b8b88b70SDaniel Drake {
76282225766SHans de Goede 	struct device *dev = &i2c_client->dev;
763b8b88b70SDaniel Drake 	struct es8316_priv *es8316;
76482225766SHans de Goede 	int ret;
765b8b88b70SDaniel Drake 
766b8b88b70SDaniel Drake 	es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv),
767b8b88b70SDaniel Drake 			      GFP_KERNEL);
768b8b88b70SDaniel Drake 	if (es8316 == NULL)
769b8b88b70SDaniel Drake 		return -ENOMEM;
770b8b88b70SDaniel Drake 
771b8b88b70SDaniel Drake 	i2c_set_clientdata(i2c_client, es8316);
772b8b88b70SDaniel Drake 
77382225766SHans de Goede 	es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap);
77482225766SHans de Goede 	if (IS_ERR(es8316->regmap))
77582225766SHans de Goede 		return PTR_ERR(es8316->regmap);
77682225766SHans de Goede 
77782225766SHans de Goede 	es8316->irq = i2c_client->irq;
77882225766SHans de Goede 	mutex_init(&es8316->lock);
77982225766SHans de Goede 
78082225766SHans de Goede 	ret = devm_request_threaded_irq(dev, es8316->irq, NULL, es8316_irq,
78182225766SHans de Goede 					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
78282225766SHans de Goede 					"es8316", es8316);
78382225766SHans de Goede 	if (ret == 0) {
78482225766SHans de Goede 		/* Gets re-enabled by es8316_set_jack() */
78582225766SHans de Goede 		disable_irq(es8316->irq);
78682225766SHans de Goede 	} else {
78782225766SHans de Goede 		dev_warn(dev, "Failed to get IRQ %d: %d\n", es8316->irq, ret);
78882225766SHans de Goede 		es8316->irq = -ENXIO;
78982225766SHans de Goede 	}
790b8b88b70SDaniel Drake 
7912ff52976SKuninori Morimoto 	return devm_snd_soc_register_component(&i2c_client->dev,
7922ff52976SKuninori Morimoto 				      &soc_component_dev_es8316,
793b8b88b70SDaniel Drake 				      &es8316_dai, 1);
794b8b88b70SDaniel Drake }
795b8b88b70SDaniel Drake 
796b8b88b70SDaniel Drake static const struct i2c_device_id es8316_i2c_id[] = {
797b8b88b70SDaniel Drake 	{"es8316", 0 },
798b8b88b70SDaniel Drake 	{}
799b8b88b70SDaniel Drake };
800b8b88b70SDaniel Drake MODULE_DEVICE_TABLE(i2c, es8316_i2c_id);
801b8b88b70SDaniel Drake 
802b8b88b70SDaniel Drake static const struct of_device_id es8316_of_match[] = {
803b8b88b70SDaniel Drake 	{ .compatible = "everest,es8316", },
804b8b88b70SDaniel Drake 	{},
805b8b88b70SDaniel Drake };
806b8b88b70SDaniel Drake MODULE_DEVICE_TABLE(of, es8316_of_match);
807b8b88b70SDaniel Drake 
808b8b88b70SDaniel Drake static const struct acpi_device_id es8316_acpi_match[] = {
809b8b88b70SDaniel Drake 	{"ESSX8316", 0},
810b8b88b70SDaniel Drake 	{},
811b8b88b70SDaniel Drake };
812b8b88b70SDaniel Drake MODULE_DEVICE_TABLE(acpi, es8316_acpi_match);
813b8b88b70SDaniel Drake 
814b8b88b70SDaniel Drake static struct i2c_driver es8316_i2c_driver = {
815b8b88b70SDaniel Drake 	.driver = {
816b8b88b70SDaniel Drake 		.name			= "es8316",
817b8b88b70SDaniel Drake 		.acpi_match_table	= ACPI_PTR(es8316_acpi_match),
818b8b88b70SDaniel Drake 		.of_match_table		= of_match_ptr(es8316_of_match),
819b8b88b70SDaniel Drake 	},
820b8b88b70SDaniel Drake 	.probe		= es8316_i2c_probe,
821b8b88b70SDaniel Drake 	.id_table	= es8316_i2c_id,
822b8b88b70SDaniel Drake };
823b8b88b70SDaniel Drake module_i2c_driver(es8316_i2c_driver);
824b8b88b70SDaniel Drake 
825b8b88b70SDaniel Drake MODULE_DESCRIPTION("Everest Semi ES8316 ALSA SoC Codec Driver");
826b8b88b70SDaniel Drake MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
827b8b88b70SDaniel Drake MODULE_LICENSE("GPL v2");
828