xref: /openbmc/linux/sound/soc/codecs/es8316.c (revision eb59d73c)
1b8b88b70SDaniel Drake /*
2b8b88b70SDaniel Drake  * es8316.c -- es8316 ALSA SoC audio driver
3b8b88b70SDaniel Drake  * Copyright Everest Semiconductor Co.,Ltd
4b8b88b70SDaniel Drake  *
5b8b88b70SDaniel Drake  * Authors: David Yang <yangxiaohua@everest-semi.com>,
6b8b88b70SDaniel Drake  *          Daniel Drake <drake@endlessm.com>
7b8b88b70SDaniel Drake  *
8b8b88b70SDaniel Drake  * This program is free software; you can redistribute it and/or modify
9b8b88b70SDaniel Drake  * it under the terms of the GNU General Public License version 2 as
10b8b88b70SDaniel Drake  * published by the Free Software Foundation.
11b8b88b70SDaniel Drake  */
12b8b88b70SDaniel Drake 
13b8b88b70SDaniel Drake #include <linux/module.h>
14b8b88b70SDaniel Drake #include <linux/acpi.h>
15b8b88b70SDaniel Drake #include <linux/delay.h>
16b8b88b70SDaniel Drake #include <linux/i2c.h>
17b8b88b70SDaniel Drake #include <linux/mod_devicetable.h>
18b8b88b70SDaniel Drake #include <linux/regmap.h>
19b8b88b70SDaniel Drake #include <sound/pcm.h>
20b8b88b70SDaniel Drake #include <sound/pcm_params.h>
21b8b88b70SDaniel Drake #include <sound/soc.h>
22b8b88b70SDaniel Drake #include <sound/soc-dapm.h>
23b8b88b70SDaniel Drake #include <sound/tlv.h>
24b8b88b70SDaniel Drake #include "es8316.h"
25b8b88b70SDaniel Drake 
26b8b88b70SDaniel Drake /* In slave mode at single speed, the codec is documented as accepting 5
27b8b88b70SDaniel Drake  * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on
28b8b88b70SDaniel Drake  * Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK).
29b8b88b70SDaniel Drake  */
30b8b88b70SDaniel Drake #define NR_SUPPORTED_MCLK_LRCK_RATIOS 6
31b8b88b70SDaniel Drake static const unsigned int supported_mclk_lrck_ratios[] = {
32b8b88b70SDaniel Drake 	256, 384, 400, 512, 768, 1024
33b8b88b70SDaniel Drake };
34b8b88b70SDaniel Drake 
35b8b88b70SDaniel Drake struct es8316_priv {
36b8b88b70SDaniel Drake 	unsigned int sysclk;
37b8b88b70SDaniel Drake 	unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS];
38b8b88b70SDaniel Drake 	struct snd_pcm_hw_constraint_list sysclk_constraints;
39b8b88b70SDaniel Drake };
40b8b88b70SDaniel Drake 
41b8b88b70SDaniel Drake /*
42b8b88b70SDaniel Drake  * ES8316 controls
43b8b88b70SDaniel Drake  */
44b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9600, 50, 1);
45b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(adc_vol_tlv, -9600, 50, 1);
46b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_max_gain_tlv, -650, 150, 0);
47b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_min_gain_tlv, -1200, 150, 0);
48b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(alc_target_tlv, -1650, 150, 0);
49b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(hpmixer_gain_tlv, -1200, 150, 0);
50b8b88b70SDaniel Drake 
51b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(adc_pga_gain_tlv,
52b8b88b70SDaniel Drake 	0, 0, TLV_DB_SCALE_ITEM(-350, 0, 0),
53b8b88b70SDaniel Drake 	1, 1, TLV_DB_SCALE_ITEM(0, 0, 0),
54b8b88b70SDaniel Drake 	2, 2, TLV_DB_SCALE_ITEM(250, 0, 0),
55b8b88b70SDaniel Drake 	3, 3, TLV_DB_SCALE_ITEM(450, 0, 0),
56b8b88b70SDaniel Drake 	4, 4, TLV_DB_SCALE_ITEM(700, 0, 0),
57b8b88b70SDaniel Drake 	5, 5, TLV_DB_SCALE_ITEM(1000, 0, 0),
58b8b88b70SDaniel Drake 	6, 6, TLV_DB_SCALE_ITEM(1300, 0, 0),
59b8b88b70SDaniel Drake 	7, 7, TLV_DB_SCALE_ITEM(1600, 0, 0),
60b8b88b70SDaniel Drake 	8, 8, TLV_DB_SCALE_ITEM(1800, 0, 0),
61b8b88b70SDaniel Drake 	9, 9, TLV_DB_SCALE_ITEM(2100, 0, 0),
62b8b88b70SDaniel Drake 	10, 10, TLV_DB_SCALE_ITEM(2400, 0, 0),
63b8b88b70SDaniel Drake );
64b8b88b70SDaniel Drake 
65b8b88b70SDaniel Drake static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpout_vol_tlv,
66b8b88b70SDaniel Drake 	0, 0, TLV_DB_SCALE_ITEM(-4800, 0, 0),
67b8b88b70SDaniel Drake 	1, 3, TLV_DB_SCALE_ITEM(-2400, 1200, 0),
68b8b88b70SDaniel Drake );
69b8b88b70SDaniel Drake 
70b8b88b70SDaniel Drake static const char * const ng_type_txt[] =
71b8b88b70SDaniel Drake 	{ "Constant PGA Gain", "Mute ADC Output" };
72b8b88b70SDaniel Drake static const struct soc_enum ng_type =
73b8b88b70SDaniel Drake 	SOC_ENUM_SINGLE(ES8316_ADC_ALC_NG, 6, 2, ng_type_txt);
74b8b88b70SDaniel Drake 
75b8b88b70SDaniel Drake static const char * const adcpol_txt[] = { "Normal", "Invert" };
76b8b88b70SDaniel Drake static const struct soc_enum adcpol =
77b8b88b70SDaniel Drake 	SOC_ENUM_SINGLE(ES8316_ADC_MUTE, 1, 2, adcpol_txt);
78b8b88b70SDaniel Drake static const char *const dacpol_txt[] =
79b8b88b70SDaniel Drake 	{ "Normal", "R Invert", "L Invert", "L + R Invert" };
80b8b88b70SDaniel Drake static const struct soc_enum dacpol =
81b8b88b70SDaniel Drake 	SOC_ENUM_SINGLE(ES8316_DAC_SET1, 0, 4, dacpol_txt);
82b8b88b70SDaniel Drake 
83b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_snd_controls[] = {
84b8b88b70SDaniel Drake 	SOC_DOUBLE_TLV("Headphone Playback Volume", ES8316_CPHP_ICAL_VOL,
85b8b88b70SDaniel Drake 		       4, 0, 3, 1, hpout_vol_tlv),
86b8b88b70SDaniel Drake 	SOC_DOUBLE_TLV("Headphone Mixer Volume", ES8316_HPMIX_VOL,
87b8b88b70SDaniel Drake 		       0, 4, 7, 0, hpmixer_gain_tlv),
88b8b88b70SDaniel Drake 
89b8b88b70SDaniel Drake 	SOC_ENUM("Playback Polarity", dacpol),
90b8b88b70SDaniel Drake 	SOC_DOUBLE_R_TLV("DAC Playback Volume", ES8316_DAC_VOLL,
91b8b88b70SDaniel Drake 			 ES8316_DAC_VOLR, 0, 0xc0, 1, dac_vol_tlv),
92b8b88b70SDaniel Drake 	SOC_SINGLE("DAC Soft Ramp Switch", ES8316_DAC_SET1, 4, 1, 1),
93b8b88b70SDaniel Drake 	SOC_SINGLE("DAC Soft Ramp Rate", ES8316_DAC_SET1, 2, 4, 0),
94b8b88b70SDaniel Drake 	SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0),
95b8b88b70SDaniel Drake 	SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0),
96b8b88b70SDaniel Drake 	SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0),
97b8b88b70SDaniel Drake 
98b8b88b70SDaniel Drake 	SOC_ENUM("Capture Polarity", adcpol),
99b8b88b70SDaniel Drake 	SOC_SINGLE("Mic Boost Switch", ES8316_ADC_D2SEPGA, 0, 1, 0),
100b8b88b70SDaniel Drake 	SOC_SINGLE_TLV("ADC Capture Volume", ES8316_ADC_VOLUME,
101b8b88b70SDaniel Drake 		       0, 0xc0, 1, adc_vol_tlv),
102b8b88b70SDaniel Drake 	SOC_SINGLE_TLV("ADC PGA Gain Volume", ES8316_ADC_PGAGAIN,
103b8b88b70SDaniel Drake 		       4, 10, 0, adc_pga_gain_tlv),
104b8b88b70SDaniel Drake 	SOC_SINGLE("ADC Soft Ramp Switch", ES8316_ADC_MUTE, 4, 1, 0),
105b8b88b70SDaniel Drake 	SOC_SINGLE("ADC Double Fs Switch", ES8316_ADC_DMIC, 4, 1, 0),
106b8b88b70SDaniel Drake 
107b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Switch", ES8316_ADC_ALC1, 6, 1, 0),
108b8b88b70SDaniel Drake 	SOC_SINGLE_TLV("ALC Capture Max Volume", ES8316_ADC_ALC1, 0, 28, 0,
109b8b88b70SDaniel Drake 		       alc_max_gain_tlv),
110b8b88b70SDaniel Drake 	SOC_SINGLE_TLV("ALC Capture Min Volume", ES8316_ADC_ALC2, 0, 28, 0,
111b8b88b70SDaniel Drake 		       alc_min_gain_tlv),
112b8b88b70SDaniel Drake 	SOC_SINGLE_TLV("ALC Capture Target Volume", ES8316_ADC_ALC3, 4, 10, 0,
113b8b88b70SDaniel Drake 		       alc_target_tlv),
114b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Hold Time", ES8316_ADC_ALC3, 0, 10, 0),
115b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Decay Time", ES8316_ADC_ALC4, 4, 10, 0),
116b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Attack Time", ES8316_ADC_ALC4, 0, 10, 0),
117b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Noise Gate Switch", ES8316_ADC_ALC_NG,
118b8b88b70SDaniel Drake 		   5, 1, 0),
119b8b88b70SDaniel Drake 	SOC_SINGLE("ALC Capture Noise Gate Threshold", ES8316_ADC_ALC_NG,
120b8b88b70SDaniel Drake 		   0, 31, 0),
121b8b88b70SDaniel Drake 	SOC_ENUM("ALC Capture Noise Gate Type", ng_type),
122b8b88b70SDaniel Drake };
123b8b88b70SDaniel Drake 
124b8b88b70SDaniel Drake /* Analog Input Mux */
125b8b88b70SDaniel Drake static const char * const es8316_analog_in_txt[] = {
126b8b88b70SDaniel Drake 		"lin1-rin1",
127b8b88b70SDaniel Drake 		"lin2-rin2",
128b8b88b70SDaniel Drake 		"lin1-rin1 with 20db Boost",
129b8b88b70SDaniel Drake 		"lin2-rin2 with 20db Boost"
130b8b88b70SDaniel Drake };
131b8b88b70SDaniel Drake static const unsigned int es8316_analog_in_values[] = { 0, 1, 2, 3 };
132b8b88b70SDaniel Drake static const struct soc_enum es8316_analog_input_enum =
133b8b88b70SDaniel Drake 	SOC_VALUE_ENUM_SINGLE(ES8316_ADC_PDN_LINSEL, 4, 3,
134b8b88b70SDaniel Drake 			      ARRAY_SIZE(es8316_analog_in_txt),
135b8b88b70SDaniel Drake 			      es8316_analog_in_txt,
136b8b88b70SDaniel Drake 			      es8316_analog_in_values);
137b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_analog_in_mux_controls =
138b8b88b70SDaniel Drake 	SOC_DAPM_ENUM("Route", es8316_analog_input_enum);
139b8b88b70SDaniel Drake 
140b8b88b70SDaniel Drake static const char * const es8316_dmic_txt[] = {
141b8b88b70SDaniel Drake 		"dmic disable",
142b8b88b70SDaniel Drake 		"dmic data at high level",
143b8b88b70SDaniel Drake 		"dmic data at low level",
144b8b88b70SDaniel Drake };
145b8b88b70SDaniel Drake static const unsigned int es8316_dmic_values[] = { 0, 1, 2 };
146b8b88b70SDaniel Drake static const struct soc_enum es8316_dmic_src_enum =
147b8b88b70SDaniel Drake 	SOC_VALUE_ENUM_SINGLE(ES8316_ADC_DMIC, 0, 3,
148b8b88b70SDaniel Drake 			      ARRAY_SIZE(es8316_dmic_txt),
149b8b88b70SDaniel Drake 			      es8316_dmic_txt,
150b8b88b70SDaniel Drake 			      es8316_dmic_values);
151b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_dmic_src_controls =
152b8b88b70SDaniel Drake 	SOC_DAPM_ENUM("Route", es8316_dmic_src_enum);
153b8b88b70SDaniel Drake 
154b8b88b70SDaniel Drake /* hp mixer mux */
155b8b88b70SDaniel Drake static const char * const es8316_hpmux_texts[] = {
156b8b88b70SDaniel Drake 	"lin1-rin1",
157b8b88b70SDaniel Drake 	"lin2-rin2",
158b8b88b70SDaniel Drake 	"lin-rin with Boost",
159b8b88b70SDaniel Drake 	"lin-rin with Boost and PGA"
160b8b88b70SDaniel Drake };
161b8b88b70SDaniel Drake 
162b8b88b70SDaniel Drake static const unsigned int es8316_hpmux_values[] = { 0, 1, 2, 3 };
163b8b88b70SDaniel Drake 
164b8b88b70SDaniel Drake static SOC_ENUM_SINGLE_DECL(es8316_left_hpmux_enum, ES8316_HPMIX_SEL,
165b8b88b70SDaniel Drake 	4, es8316_hpmux_texts);
166b8b88b70SDaniel Drake 
167b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_left_hpmux_controls =
168b8b88b70SDaniel Drake 	SOC_DAPM_ENUM("Route", es8316_left_hpmux_enum);
169b8b88b70SDaniel Drake 
170b8b88b70SDaniel Drake static SOC_ENUM_SINGLE_DECL(es8316_right_hpmux_enum, ES8316_HPMIX_SEL,
171b8b88b70SDaniel Drake 	0, es8316_hpmux_texts);
172b8b88b70SDaniel Drake 
173b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_right_hpmux_controls =
174b8b88b70SDaniel Drake 	SOC_DAPM_ENUM("Route", es8316_right_hpmux_enum);
175b8b88b70SDaniel Drake 
176b8b88b70SDaniel Drake /* headphone Output Mixer */
177b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_out_left_mix[] = {
178b8b88b70SDaniel Drake 	SOC_DAPM_SINGLE("LLIN Switch", ES8316_HPMIX_SWITCH, 6, 1, 0),
179b8b88b70SDaniel Drake 	SOC_DAPM_SINGLE("Left DAC Switch", ES8316_HPMIX_SWITCH, 7, 1, 0),
180b8b88b70SDaniel Drake };
181b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_out_right_mix[] = {
182b8b88b70SDaniel Drake 	SOC_DAPM_SINGLE("RLIN Switch", ES8316_HPMIX_SWITCH, 2, 1, 0),
183b8b88b70SDaniel Drake 	SOC_DAPM_SINGLE("Right DAC Switch", ES8316_HPMIX_SWITCH, 3, 1, 0),
184b8b88b70SDaniel Drake };
185b8b88b70SDaniel Drake 
186b8b88b70SDaniel Drake /* DAC data source mux */
187b8b88b70SDaniel Drake static const char * const es8316_dacsrc_texts[] = {
188b8b88b70SDaniel Drake 	"LDATA TO LDAC, RDATA TO RDAC",
189b8b88b70SDaniel Drake 	"LDATA TO LDAC, LDATA TO RDAC",
190b8b88b70SDaniel Drake 	"RDATA TO LDAC, RDATA TO RDAC",
191b8b88b70SDaniel Drake 	"RDATA TO LDAC, LDATA TO RDAC",
192b8b88b70SDaniel Drake };
193b8b88b70SDaniel Drake 
194b8b88b70SDaniel Drake static const unsigned int es8316_dacsrc_values[] = { 0, 1, 2, 3 };
195b8b88b70SDaniel Drake 
196b8b88b70SDaniel Drake static SOC_ENUM_SINGLE_DECL(es8316_dacsrc_mux_enum, ES8316_DAC_SET1,
197b8b88b70SDaniel Drake 	6, es8316_dacsrc_texts);
198b8b88b70SDaniel Drake 
199b8b88b70SDaniel Drake static const struct snd_kcontrol_new es8316_dacsrc_mux_controls =
200b8b88b70SDaniel Drake 	SOC_DAPM_ENUM("Route", es8316_dacsrc_mux_enum);
201b8b88b70SDaniel Drake 
202b8b88b70SDaniel Drake static const struct snd_soc_dapm_widget es8316_dapm_widgets[] = {
203b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Bias", ES8316_SYS_PDN, 3, 1, NULL, 0),
204b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Analog power", ES8316_SYS_PDN, 4, 1, NULL, 0),
205b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Mic Bias", ES8316_SYS_PDN, 5, 1, NULL, 0),
206b8b88b70SDaniel Drake 
207b8b88b70SDaniel Drake 	SND_SOC_DAPM_INPUT("DMIC"),
208b8b88b70SDaniel Drake 	SND_SOC_DAPM_INPUT("MIC1"),
209b8b88b70SDaniel Drake 	SND_SOC_DAPM_INPUT("MIC2"),
210b8b88b70SDaniel Drake 
211b8b88b70SDaniel Drake 	/* Input Mux */
212b8b88b70SDaniel Drake 	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
213b8b88b70SDaniel Drake 			 &es8316_analog_in_mux_controls),
214b8b88b70SDaniel Drake 
215b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("ADC Vref", ES8316_SYS_PDN, 1, 1, NULL, 0),
216b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("ADC bias", ES8316_SYS_PDN, 2, 1, NULL, 0),
217b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("ADC Clock", ES8316_CLKMGR_CLKSW, 3, 0, NULL, 0),
218b8b88b70SDaniel Drake 	SND_SOC_DAPM_PGA("Line input PGA", ES8316_ADC_PDN_LINSEL,
219b8b88b70SDaniel Drake 			 7, 1, NULL, 0),
220b8b88b70SDaniel Drake 	SND_SOC_DAPM_ADC("Mono ADC", NULL, ES8316_ADC_PDN_LINSEL, 6, 1),
221b8b88b70SDaniel Drake 	SND_SOC_DAPM_MUX("Digital Mic Mux", SND_SOC_NOPM, 0, 0,
222b8b88b70SDaniel Drake 			 &es8316_dmic_src_controls),
223b8b88b70SDaniel Drake 
224b8b88b70SDaniel Drake 	/* Digital Interface */
225b8b88b70SDaniel Drake 	SND_SOC_DAPM_AIF_OUT("I2S OUT", "I2S1 Capture",  1,
226b8b88b70SDaniel Drake 			     ES8316_SERDATA_ADC, 6, 1),
227b8b88b70SDaniel Drake 	SND_SOC_DAPM_AIF_IN("I2S IN", "I2S1 Playback", 0,
228b8b88b70SDaniel Drake 			    SND_SOC_NOPM, 0, 0),
229b8b88b70SDaniel Drake 
230b8b88b70SDaniel Drake 	SND_SOC_DAPM_MUX("DAC Source Mux", SND_SOC_NOPM, 0, 0,
231b8b88b70SDaniel Drake 			 &es8316_dacsrc_mux_controls),
232b8b88b70SDaniel Drake 
233b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("DAC Vref", ES8316_SYS_PDN, 0, 1, NULL, 0),
234b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("DAC Clock", ES8316_CLKMGR_CLKSW, 2, 0, NULL, 0),
235b8b88b70SDaniel Drake 	SND_SOC_DAPM_DAC("Right DAC", NULL, ES8316_DAC_PDN, 0, 1),
236b8b88b70SDaniel Drake 	SND_SOC_DAPM_DAC("Left DAC", NULL, ES8316_DAC_PDN, 4, 1),
237b8b88b70SDaniel Drake 
238b8b88b70SDaniel Drake 	/* Headphone Output Side */
239b8b88b70SDaniel Drake 	SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0,
240b8b88b70SDaniel Drake 			 &es8316_left_hpmux_controls),
241b8b88b70SDaniel Drake 	SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0,
242b8b88b70SDaniel Drake 			 &es8316_right_hpmux_controls),
243b8b88b70SDaniel Drake 	SND_SOC_DAPM_MIXER("Left Headphone Mixer", ES8316_HPMIX_PDN,
244b8b88b70SDaniel Drake 			   5, 1, &es8316_out_left_mix[0],
245b8b88b70SDaniel Drake 			   ARRAY_SIZE(es8316_out_left_mix)),
246b8b88b70SDaniel Drake 	SND_SOC_DAPM_MIXER("Right Headphone Mixer", ES8316_HPMIX_PDN,
247b8b88b70SDaniel Drake 			   1, 1, &es8316_out_right_mix[0],
248b8b88b70SDaniel Drake 			   ARRAY_SIZE(es8316_out_right_mix)),
249b8b88b70SDaniel Drake 	SND_SOC_DAPM_PGA("Left Headphone Mixer Out", ES8316_HPMIX_PDN,
250b8b88b70SDaniel Drake 			 4, 1, NULL, 0),
251b8b88b70SDaniel Drake 	SND_SOC_DAPM_PGA("Right Headphone Mixer Out", ES8316_HPMIX_PDN,
252b8b88b70SDaniel Drake 			 0, 1, NULL, 0),
253b8b88b70SDaniel Drake 
254b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUT_DRV("Left Headphone Charge Pump", ES8316_CPHP_OUTEN,
255b8b88b70SDaniel Drake 			     6, 0, NULL, 0),
256b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUT_DRV("Right Headphone Charge Pump", ES8316_CPHP_OUTEN,
257b8b88b70SDaniel Drake 			     2, 0, NULL, 0),
258b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8316_CPHP_PDN2,
259b8b88b70SDaniel Drake 			    5, 1, NULL, 0),
260b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Headphone Charge Pump Clock", ES8316_CLKMGR_CLKSW,
261b8b88b70SDaniel Drake 			    4, 0, NULL, 0),
262b8b88b70SDaniel Drake 
263b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUT_DRV("Left Headphone Driver", ES8316_CPHP_OUTEN,
264b8b88b70SDaniel Drake 			     5, 0, NULL, 0),
265b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUT_DRV("Right Headphone Driver", ES8316_CPHP_OUTEN,
266b8b88b70SDaniel Drake 			     1, 0, NULL, 0),
267b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Headphone Out", ES8316_CPHP_PDN1, 2, 1, NULL, 0),
268b8b88b70SDaniel Drake 
269b8b88b70SDaniel Drake 	/* pdn_Lical and pdn_Rical bits are documented as Reserved, but must
270b8b88b70SDaniel Drake 	 * be explicitly unset in order to enable HP output
271b8b88b70SDaniel Drake 	 */
272b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Left Headphone ical", ES8316_CPHP_ICAL_VOL,
273b8b88b70SDaniel Drake 			    7, 1, NULL, 0),
274b8b88b70SDaniel Drake 	SND_SOC_DAPM_SUPPLY("Right Headphone ical", ES8316_CPHP_ICAL_VOL,
275b8b88b70SDaniel Drake 			    3, 1, NULL, 0),
276b8b88b70SDaniel Drake 
277b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUTPUT("HPOL"),
278b8b88b70SDaniel Drake 	SND_SOC_DAPM_OUTPUT("HPOR"),
279b8b88b70SDaniel Drake };
280b8b88b70SDaniel Drake 
281b8b88b70SDaniel Drake static const struct snd_soc_dapm_route es8316_dapm_routes[] = {
282b8b88b70SDaniel Drake 	/* Recording */
283b8b88b70SDaniel Drake 	{"MIC1", NULL, "Mic Bias"},
284b8b88b70SDaniel Drake 	{"MIC2", NULL, "Mic Bias"},
285b8b88b70SDaniel Drake 	{"MIC1", NULL, "Bias"},
286b8b88b70SDaniel Drake 	{"MIC2", NULL, "Bias"},
287b8b88b70SDaniel Drake 	{"MIC1", NULL, "Analog power"},
288b8b88b70SDaniel Drake 	{"MIC2", NULL, "Analog power"},
289b8b88b70SDaniel Drake 
290b8b88b70SDaniel Drake 	{"Differential Mux", "lin1-rin1", "MIC1"},
291b8b88b70SDaniel Drake 	{"Differential Mux", "lin2-rin2", "MIC2"},
292b8b88b70SDaniel Drake 	{"Line input PGA", NULL, "Differential Mux"},
293b8b88b70SDaniel Drake 
294b8b88b70SDaniel Drake 	{"Mono ADC", NULL, "ADC Clock"},
295b8b88b70SDaniel Drake 	{"Mono ADC", NULL, "ADC Vref"},
296b8b88b70SDaniel Drake 	{"Mono ADC", NULL, "ADC bias"},
297b8b88b70SDaniel Drake 	{"Mono ADC", NULL, "Line input PGA"},
298b8b88b70SDaniel Drake 
299b8b88b70SDaniel Drake 	/* It's not clear why, but to avoid recording only silence,
300b8b88b70SDaniel Drake 	 * the DAC clock must be running for the ADC to work.
301b8b88b70SDaniel Drake 	 */
302b8b88b70SDaniel Drake 	{"Mono ADC", NULL, "DAC Clock"},
303b8b88b70SDaniel Drake 
304b8b88b70SDaniel Drake 	{"Digital Mic Mux", "dmic disable", "Mono ADC"},
305b8b88b70SDaniel Drake 
306b8b88b70SDaniel Drake 	{"I2S OUT", NULL, "Digital Mic Mux"},
307b8b88b70SDaniel Drake 
308b8b88b70SDaniel Drake 	/* Playback */
309b8b88b70SDaniel Drake 	{"DAC Source Mux", "LDATA TO LDAC, RDATA TO RDAC", "I2S IN"},
310b8b88b70SDaniel Drake 
311b8b88b70SDaniel Drake 	{"Left DAC", NULL, "DAC Clock"},
312b8b88b70SDaniel Drake 	{"Right DAC", NULL, "DAC Clock"},
313b8b88b70SDaniel Drake 
314b8b88b70SDaniel Drake 	{"Left DAC", NULL, "DAC Vref"},
315b8b88b70SDaniel Drake 	{"Right DAC", NULL, "DAC Vref"},
316b8b88b70SDaniel Drake 
317b8b88b70SDaniel Drake 	{"Left DAC", NULL, "DAC Source Mux"},
318b8b88b70SDaniel Drake 	{"Right DAC", NULL, "DAC Source Mux"},
319b8b88b70SDaniel Drake 
320b8b88b70SDaniel Drake 	{"Left Headphone Mux", "lin-rin with Boost and PGA", "Line input PGA"},
321b8b88b70SDaniel Drake 	{"Right Headphone Mux", "lin-rin with Boost and PGA", "Line input PGA"},
322b8b88b70SDaniel Drake 
323b8b88b70SDaniel Drake 	{"Left Headphone Mixer", "LLIN Switch", "Left Headphone Mux"},
324b8b88b70SDaniel Drake 	{"Left Headphone Mixer", "Left DAC Switch", "Left DAC"},
325b8b88b70SDaniel Drake 
326b8b88b70SDaniel Drake 	{"Right Headphone Mixer", "RLIN Switch", "Right Headphone Mux"},
327b8b88b70SDaniel Drake 	{"Right Headphone Mixer", "Right DAC Switch", "Right DAC"},
328b8b88b70SDaniel Drake 
329b8b88b70SDaniel Drake 	{"Left Headphone Mixer Out", NULL, "Left Headphone Mixer"},
330b8b88b70SDaniel Drake 	{"Right Headphone Mixer Out", NULL, "Right Headphone Mixer"},
331b8b88b70SDaniel Drake 
332b8b88b70SDaniel Drake 	{"Left Headphone Charge Pump", NULL, "Left Headphone Mixer Out"},
333b8b88b70SDaniel Drake 	{"Right Headphone Charge Pump", NULL, "Right Headphone Mixer Out"},
334b8b88b70SDaniel Drake 
335b8b88b70SDaniel Drake 	{"Left Headphone Charge Pump", NULL, "Headphone Charge Pump"},
336b8b88b70SDaniel Drake 	{"Right Headphone Charge Pump", NULL, "Headphone Charge Pump"},
337b8b88b70SDaniel Drake 
338b8b88b70SDaniel Drake 	{"Left Headphone Charge Pump", NULL, "Headphone Charge Pump Clock"},
339b8b88b70SDaniel Drake 	{"Right Headphone Charge Pump", NULL, "Headphone Charge Pump Clock"},
340b8b88b70SDaniel Drake 
341b8b88b70SDaniel Drake 	{"Left Headphone Driver", NULL, "Left Headphone Charge Pump"},
342b8b88b70SDaniel Drake 	{"Right Headphone Driver", NULL, "Right Headphone Charge Pump"},
343b8b88b70SDaniel Drake 
344b8b88b70SDaniel Drake 	{"HPOL", NULL, "Left Headphone Driver"},
345b8b88b70SDaniel Drake 	{"HPOR", NULL, "Right Headphone Driver"},
346b8b88b70SDaniel Drake 
347b8b88b70SDaniel Drake 	{"HPOL", NULL, "Left Headphone ical"},
348b8b88b70SDaniel Drake 	{"HPOR", NULL, "Right Headphone ical"},
349b8b88b70SDaniel Drake 
350b8b88b70SDaniel Drake 	{"Headphone Out", NULL, "Bias"},
351b8b88b70SDaniel Drake 	{"Headphone Out", NULL, "Analog power"},
352b8b88b70SDaniel Drake 	{"HPOL", NULL, "Headphone Out"},
353b8b88b70SDaniel Drake 	{"HPOR", NULL, "Headphone Out"},
354b8b88b70SDaniel Drake };
355b8b88b70SDaniel Drake 
356b8b88b70SDaniel Drake static int es8316_set_dai_sysclk(struct snd_soc_dai *codec_dai,
357b8b88b70SDaniel Drake 				 int clk_id, unsigned int freq, int dir)
358b8b88b70SDaniel Drake {
359b8b88b70SDaniel Drake 	struct snd_soc_codec *codec = codec_dai->codec;
360b8b88b70SDaniel Drake 	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
361b8b88b70SDaniel Drake 	int i;
362b8b88b70SDaniel Drake 	int count = 0;
363b8b88b70SDaniel Drake 
364b8b88b70SDaniel Drake 	es8316->sysclk = freq;
365b8b88b70SDaniel Drake 
366b8b88b70SDaniel Drake 	if (freq == 0)
367b8b88b70SDaniel Drake 		return 0;
368b8b88b70SDaniel Drake 
369b8b88b70SDaniel Drake 	/* Limit supported sample rates to ones that can be autodetected
370b8b88b70SDaniel Drake 	 * by the codec running in slave mode.
371b8b88b70SDaniel Drake 	 */
372b8b88b70SDaniel Drake 	for (i = 0; i < NR_SUPPORTED_MCLK_LRCK_RATIOS; i++) {
373b8b88b70SDaniel Drake 		const unsigned int ratio = supported_mclk_lrck_ratios[i];
374b8b88b70SDaniel Drake 
375b8b88b70SDaniel Drake 		if (freq % ratio == 0)
376b8b88b70SDaniel Drake 			es8316->allowed_rates[count++] = freq / ratio;
377b8b88b70SDaniel Drake 	}
378b8b88b70SDaniel Drake 
379b8b88b70SDaniel Drake 	es8316->sysclk_constraints.list = es8316->allowed_rates;
380b8b88b70SDaniel Drake 	es8316->sysclk_constraints.count = count;
381b8b88b70SDaniel Drake 
382b8b88b70SDaniel Drake 	return 0;
383b8b88b70SDaniel Drake }
384b8b88b70SDaniel Drake 
385b8b88b70SDaniel Drake static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai,
386b8b88b70SDaniel Drake 			      unsigned int fmt)
387b8b88b70SDaniel Drake {
388b8b88b70SDaniel Drake 	struct snd_soc_codec *codec = codec_dai->codec;
389b8b88b70SDaniel Drake 	u8 serdata1 = 0;
390b8b88b70SDaniel Drake 	u8 serdata2 = 0;
391b8b88b70SDaniel Drake 	u8 clksw;
392b8b88b70SDaniel Drake 	u8 mask;
393b8b88b70SDaniel Drake 
394b8b88b70SDaniel Drake 	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
395b8b88b70SDaniel Drake 		dev_err(codec->dev, "Codec driver only supports slave mode\n");
396b8b88b70SDaniel Drake 		return -EINVAL;
397b8b88b70SDaniel Drake 	}
398b8b88b70SDaniel Drake 
399b8b88b70SDaniel Drake 	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
400b8b88b70SDaniel Drake 		dev_err(codec->dev, "Codec driver only supports I2S format\n");
401b8b88b70SDaniel Drake 		return -EINVAL;
402b8b88b70SDaniel Drake 	}
403b8b88b70SDaniel Drake 
404b8b88b70SDaniel Drake 	/* Clock inversion */
405b8b88b70SDaniel Drake 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
406b8b88b70SDaniel Drake 	case SND_SOC_DAIFMT_NB_NF:
407b8b88b70SDaniel Drake 		break;
408b8b88b70SDaniel Drake 	case SND_SOC_DAIFMT_IB_IF:
409b8b88b70SDaniel Drake 		serdata1 |= ES8316_SERDATA1_BCLK_INV;
410b8b88b70SDaniel Drake 		serdata2 |= ES8316_SERDATA2_ADCLRP;
411b8b88b70SDaniel Drake 		break;
412b8b88b70SDaniel Drake 	case SND_SOC_DAIFMT_IB_NF:
413b8b88b70SDaniel Drake 		serdata1 |= ES8316_SERDATA1_BCLK_INV;
414b8b88b70SDaniel Drake 		break;
415b8b88b70SDaniel Drake 	case SND_SOC_DAIFMT_NB_IF:
416b8b88b70SDaniel Drake 		serdata2 |= ES8316_SERDATA2_ADCLRP;
417b8b88b70SDaniel Drake 		break;
418b8b88b70SDaniel Drake 	default:
419b8b88b70SDaniel Drake 		return -EINVAL;
420b8b88b70SDaniel Drake 	}
421b8b88b70SDaniel Drake 
422b8b88b70SDaniel Drake 	mask = ES8316_SERDATA1_MASTER | ES8316_SERDATA1_BCLK_INV;
423b8b88b70SDaniel Drake 	snd_soc_update_bits(codec, ES8316_SERDATA1, mask, serdata1);
424b8b88b70SDaniel Drake 
425b8b88b70SDaniel Drake 	mask = ES8316_SERDATA2_FMT_MASK | ES8316_SERDATA2_ADCLRP;
426b8b88b70SDaniel Drake 	snd_soc_update_bits(codec, ES8316_SERDATA_ADC, mask, serdata2);
427b8b88b70SDaniel Drake 	snd_soc_update_bits(codec, ES8316_SERDATA_DAC, mask, serdata2);
428b8b88b70SDaniel Drake 
429b8b88b70SDaniel Drake 	/* Enable BCLK and MCLK inputs in slave mode */
430b8b88b70SDaniel Drake 	clksw = ES8316_CLKMGR_CLKSW_MCLK_ON | ES8316_CLKMGR_CLKSW_BCLK_ON;
431b8b88b70SDaniel Drake 	snd_soc_update_bits(codec, ES8316_CLKMGR_CLKSW, clksw, clksw);
432b8b88b70SDaniel Drake 
433b8b88b70SDaniel Drake 	return 0;
434b8b88b70SDaniel Drake }
435b8b88b70SDaniel Drake 
436b8b88b70SDaniel Drake static int es8316_pcm_startup(struct snd_pcm_substream *substream,
437b8b88b70SDaniel Drake 			      struct snd_soc_dai *dai)
438b8b88b70SDaniel Drake {
439b8b88b70SDaniel Drake 	struct snd_soc_codec *codec = dai->codec;
440b8b88b70SDaniel Drake 	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
441b8b88b70SDaniel Drake 
442b8b88b70SDaniel Drake 	if (es8316->sysclk == 0) {
443b8b88b70SDaniel Drake 		dev_err(codec->dev, "No sysclk provided\n");
444b8b88b70SDaniel Drake 		return -EINVAL;
445b8b88b70SDaniel Drake 	}
446b8b88b70SDaniel Drake 
447b8b88b70SDaniel Drake 	/* The set of sample rates that can be supported depends on the
448b8b88b70SDaniel Drake 	 * MCLK supplied to the CODEC.
449b8b88b70SDaniel Drake 	 */
450b8b88b70SDaniel Drake 	snd_pcm_hw_constraint_list(substream->runtime, 0,
451b8b88b70SDaniel Drake 				   SNDRV_PCM_HW_PARAM_RATE,
452b8b88b70SDaniel Drake 				   &es8316->sysclk_constraints);
453b8b88b70SDaniel Drake 
454b8b88b70SDaniel Drake 	return 0;
455b8b88b70SDaniel Drake }
456b8b88b70SDaniel Drake 
457b8b88b70SDaniel Drake static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
458b8b88b70SDaniel Drake 				struct snd_pcm_hw_params *params,
459b8b88b70SDaniel Drake 				struct snd_soc_dai *dai)
460b8b88b70SDaniel Drake {
461b8b88b70SDaniel Drake 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
462b8b88b70SDaniel Drake 	struct snd_soc_codec *codec = rtd->codec;
463b8b88b70SDaniel Drake 	struct es8316_priv *es8316 = snd_soc_codec_get_drvdata(codec);
464b8b88b70SDaniel Drake 	u8 wordlen = 0;
465b8b88b70SDaniel Drake 
466b8b88b70SDaniel Drake 	if (!es8316->sysclk) {
467b8b88b70SDaniel Drake 		dev_err(codec->dev, "No MCLK configured\n");
468b8b88b70SDaniel Drake 		return -EINVAL;
469b8b88b70SDaniel Drake 	}
470b8b88b70SDaniel Drake 
471b8b88b70SDaniel Drake 	switch (params_format(params)) {
472b8b88b70SDaniel Drake 	case SNDRV_PCM_FORMAT_S16_LE:
473b8b88b70SDaniel Drake 		wordlen = ES8316_SERDATA2_LEN_16;
474b8b88b70SDaniel Drake 		break;
475b8b88b70SDaniel Drake 	case SNDRV_PCM_FORMAT_S20_3LE:
476b8b88b70SDaniel Drake 		wordlen = ES8316_SERDATA2_LEN_20;
477b8b88b70SDaniel Drake 		break;
478b8b88b70SDaniel Drake 	case SNDRV_PCM_FORMAT_S24_LE:
479b8b88b70SDaniel Drake 		wordlen = ES8316_SERDATA2_LEN_24;
480b8b88b70SDaniel Drake 		break;
481b8b88b70SDaniel Drake 	case SNDRV_PCM_FORMAT_S32_LE:
482b8b88b70SDaniel Drake 		wordlen = ES8316_SERDATA2_LEN_32;
483b8b88b70SDaniel Drake 		break;
484b8b88b70SDaniel Drake 	default:
485b8b88b70SDaniel Drake 		return -EINVAL;
486b8b88b70SDaniel Drake 	}
487b8b88b70SDaniel Drake 
488b8b88b70SDaniel Drake 	snd_soc_update_bits(codec, ES8316_SERDATA_DAC,
489b8b88b70SDaniel Drake 			    ES8316_SERDATA2_LEN_MASK, wordlen);
490b8b88b70SDaniel Drake 	snd_soc_update_bits(codec, ES8316_SERDATA_ADC,
491b8b88b70SDaniel Drake 			    ES8316_SERDATA2_LEN_MASK, wordlen);
492b8b88b70SDaniel Drake 	return 0;
493b8b88b70SDaniel Drake }
494b8b88b70SDaniel Drake 
495b8b88b70SDaniel Drake static int es8316_mute(struct snd_soc_dai *dai, int mute)
496b8b88b70SDaniel Drake {
497b8b88b70SDaniel Drake 	snd_soc_update_bits(dai->codec, ES8316_DAC_SET1, 0x20,
498b8b88b70SDaniel Drake 			    mute ? 0x20 : 0);
499b8b88b70SDaniel Drake 	return 0;
500b8b88b70SDaniel Drake }
501b8b88b70SDaniel Drake 
502b8b88b70SDaniel Drake #define ES8316_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
503b8b88b70SDaniel Drake 			SNDRV_PCM_FMTBIT_S24_LE)
504b8b88b70SDaniel Drake 
505eb59d73cSArvind Yadav static const struct snd_soc_dai_ops es8316_ops = {
506b8b88b70SDaniel Drake 	.startup = es8316_pcm_startup,
507b8b88b70SDaniel Drake 	.hw_params = es8316_pcm_hw_params,
508b8b88b70SDaniel Drake 	.set_fmt = es8316_set_dai_fmt,
509b8b88b70SDaniel Drake 	.set_sysclk = es8316_set_dai_sysclk,
510b8b88b70SDaniel Drake 	.digital_mute = es8316_mute,
511b8b88b70SDaniel Drake };
512b8b88b70SDaniel Drake 
513b8b88b70SDaniel Drake static struct snd_soc_dai_driver es8316_dai = {
514b8b88b70SDaniel Drake 	.name = "ES8316 HiFi",
515b8b88b70SDaniel Drake 	.playback = {
516b8b88b70SDaniel Drake 		.stream_name = "Playback",
517b8b88b70SDaniel Drake 		.channels_min = 1,
518b8b88b70SDaniel Drake 		.channels_max = 2,
519b8b88b70SDaniel Drake 		.rates = SNDRV_PCM_RATE_8000_48000,
520b8b88b70SDaniel Drake 		.formats = ES8316_FORMATS,
521b8b88b70SDaniel Drake 	},
522b8b88b70SDaniel Drake 	.capture = {
523b8b88b70SDaniel Drake 		.stream_name = "Capture",
524b8b88b70SDaniel Drake 		.channels_min = 1,
525b8b88b70SDaniel Drake 		.channels_max = 2,
526b8b88b70SDaniel Drake 		.rates = SNDRV_PCM_RATE_8000_48000,
527b8b88b70SDaniel Drake 		.formats = ES8316_FORMATS,
528b8b88b70SDaniel Drake 	},
529b8b88b70SDaniel Drake 	.ops = &es8316_ops,
530b8b88b70SDaniel Drake 	.symmetric_rates = 1,
531b8b88b70SDaniel Drake };
532b8b88b70SDaniel Drake 
533b8b88b70SDaniel Drake static int es8316_probe(struct snd_soc_codec *codec)
534b8b88b70SDaniel Drake {
535b8b88b70SDaniel Drake 	/* Reset codec and enable current state machine */
536b8b88b70SDaniel Drake 	snd_soc_write(codec, ES8316_RESET, 0x3f);
537b8b88b70SDaniel Drake 	usleep_range(5000, 5500);
538b8b88b70SDaniel Drake 	snd_soc_write(codec, ES8316_RESET, ES8316_RESET_CSM_ON);
539b8b88b70SDaniel Drake 	msleep(30);
540b8b88b70SDaniel Drake 
541b8b88b70SDaniel Drake 	/*
542b8b88b70SDaniel Drake 	 * Documentation is unclear, but this value from the vendor driver is
543b8b88b70SDaniel Drake 	 * needed otherwise audio output is silent.
544b8b88b70SDaniel Drake 	 */
545b8b88b70SDaniel Drake 	snd_soc_write(codec, ES8316_SYS_VMIDSEL, 0xff);
546b8b88b70SDaniel Drake 
547b8b88b70SDaniel Drake 	/*
548b8b88b70SDaniel Drake 	 * Documentation for this register is unclear and incomplete,
549b8b88b70SDaniel Drake 	 * but here is a vendor-provided value that improves volume
550b8b88b70SDaniel Drake 	 * and quality for Intel CHT platforms.
551b8b88b70SDaniel Drake 	 */
552b8b88b70SDaniel Drake 	snd_soc_write(codec, ES8316_CLKMGR_ADCOSR, 0x32);
553b8b88b70SDaniel Drake 
554b8b88b70SDaniel Drake 	return 0;
555b8b88b70SDaniel Drake }
556b8b88b70SDaniel Drake 
557a180ba45SBhumika Goyal static const struct snd_soc_codec_driver soc_codec_dev_es8316 = {
558b8b88b70SDaniel Drake 	.probe		= es8316_probe,
559b8b88b70SDaniel Drake 	.idle_bias_off	= true,
560b8b88b70SDaniel Drake 
561b8b88b70SDaniel Drake 	.component_driver = {
562b8b88b70SDaniel Drake 		.controls		= es8316_snd_controls,
563b8b88b70SDaniel Drake 		.num_controls		= ARRAY_SIZE(es8316_snd_controls),
564b8b88b70SDaniel Drake 		.dapm_widgets		= es8316_dapm_widgets,
565b8b88b70SDaniel Drake 		.num_dapm_widgets	= ARRAY_SIZE(es8316_dapm_widgets),
566b8b88b70SDaniel Drake 		.dapm_routes		= es8316_dapm_routes,
567b8b88b70SDaniel Drake 		.num_dapm_routes	= ARRAY_SIZE(es8316_dapm_routes),
568b8b88b70SDaniel Drake 	},
569b8b88b70SDaniel Drake };
570b8b88b70SDaniel Drake 
571b8b88b70SDaniel Drake static const struct regmap_config es8316_regmap = {
572b8b88b70SDaniel Drake 	.reg_bits = 8,
573b8b88b70SDaniel Drake 	.val_bits = 8,
574b8b88b70SDaniel Drake 	.max_register = 0x53,
575b8b88b70SDaniel Drake 	.cache_type = REGCACHE_RBTREE,
576b8b88b70SDaniel Drake };
577b8b88b70SDaniel Drake 
578b8b88b70SDaniel Drake static int es8316_i2c_probe(struct i2c_client *i2c_client,
579b8b88b70SDaniel Drake 			    const struct i2c_device_id *id)
580b8b88b70SDaniel Drake {
581b8b88b70SDaniel Drake 	struct es8316_priv *es8316;
582b8b88b70SDaniel Drake 	struct regmap *regmap;
583b8b88b70SDaniel Drake 
584b8b88b70SDaniel Drake 	es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv),
585b8b88b70SDaniel Drake 			      GFP_KERNEL);
586b8b88b70SDaniel Drake 	if (es8316 == NULL)
587b8b88b70SDaniel Drake 		return -ENOMEM;
588b8b88b70SDaniel Drake 
589b8b88b70SDaniel Drake 	i2c_set_clientdata(i2c_client, es8316);
590b8b88b70SDaniel Drake 
591b8b88b70SDaniel Drake 	regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap);
592b8b88b70SDaniel Drake 	if (IS_ERR(regmap))
593b8b88b70SDaniel Drake 		return PTR_ERR(regmap);
594b8b88b70SDaniel Drake 
595b8b88b70SDaniel Drake 	return snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_es8316,
596b8b88b70SDaniel Drake 				      &es8316_dai, 1);
597b8b88b70SDaniel Drake }
598b8b88b70SDaniel Drake 
599b8b88b70SDaniel Drake static int es8316_i2c_remove(struct i2c_client *client)
600b8b88b70SDaniel Drake {
601b8b88b70SDaniel Drake 	snd_soc_unregister_codec(&client->dev);
602b8b88b70SDaniel Drake 	return 0;
603b8b88b70SDaniel Drake }
604b8b88b70SDaniel Drake 
605b8b88b70SDaniel Drake static const struct i2c_device_id es8316_i2c_id[] = {
606b8b88b70SDaniel Drake 	{"es8316", 0 },
607b8b88b70SDaniel Drake 	{}
608b8b88b70SDaniel Drake };
609b8b88b70SDaniel Drake MODULE_DEVICE_TABLE(i2c, es8316_i2c_id);
610b8b88b70SDaniel Drake 
611b8b88b70SDaniel Drake static const struct of_device_id es8316_of_match[] = {
612b8b88b70SDaniel Drake 	{ .compatible = "everest,es8316", },
613b8b88b70SDaniel Drake 	{},
614b8b88b70SDaniel Drake };
615b8b88b70SDaniel Drake MODULE_DEVICE_TABLE(of, es8316_of_match);
616b8b88b70SDaniel Drake 
617b8b88b70SDaniel Drake static const struct acpi_device_id es8316_acpi_match[] = {
618b8b88b70SDaniel Drake 	{"ESSX8316", 0},
619b8b88b70SDaniel Drake 	{},
620b8b88b70SDaniel Drake };
621b8b88b70SDaniel Drake MODULE_DEVICE_TABLE(acpi, es8316_acpi_match);
622b8b88b70SDaniel Drake 
623b8b88b70SDaniel Drake static struct i2c_driver es8316_i2c_driver = {
624b8b88b70SDaniel Drake 	.driver = {
625b8b88b70SDaniel Drake 		.name			= "es8316",
626b8b88b70SDaniel Drake 		.acpi_match_table	= ACPI_PTR(es8316_acpi_match),
627b8b88b70SDaniel Drake 		.of_match_table		= of_match_ptr(es8316_of_match),
628b8b88b70SDaniel Drake 	},
629b8b88b70SDaniel Drake 	.probe		= es8316_i2c_probe,
630b8b88b70SDaniel Drake 	.remove		= es8316_i2c_remove,
631b8b88b70SDaniel Drake 	.id_table	= es8316_i2c_id,
632b8b88b70SDaniel Drake };
633b8b88b70SDaniel Drake module_i2c_driver(es8316_i2c_driver);
634b8b88b70SDaniel Drake 
635b8b88b70SDaniel Drake MODULE_DESCRIPTION("Everest Semi ES8316 ALSA SoC Codec Driver");
636b8b88b70SDaniel Drake MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>");
637b8b88b70SDaniel Drake MODULE_LICENSE("GPL v2");
638