xref: /openbmc/linux/sound/soc/codecs/cs42l56.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2272b5eddSBrian Austin /*
3272b5eddSBrian Austin  * cs42l56.c -- CS42L56 ALSA SoC audio driver
4272b5eddSBrian Austin  *
5272b5eddSBrian Austin  * Copyright 2014 CirrusLogic, Inc.
6272b5eddSBrian Austin  *
7272b5eddSBrian Austin  * Author: Brian Austin <brian.austin@cirrus.com>
8272b5eddSBrian Austin  */
9272b5eddSBrian Austin 
10272b5eddSBrian Austin #include <linux/module.h>
11272b5eddSBrian Austin #include <linux/moduleparam.h>
12272b5eddSBrian Austin #include <linux/kernel.h>
13272b5eddSBrian Austin #include <linux/init.h>
14272b5eddSBrian Austin #include <linux/delay.h>
15272b5eddSBrian Austin #include <linux/pm.h>
16272b5eddSBrian Austin #include <linux/i2c.h>
17272b5eddSBrian Austin #include <linux/input.h>
18272b5eddSBrian Austin #include <linux/regmap.h>
19272b5eddSBrian Austin #include <linux/slab.h>
20272b5eddSBrian Austin #include <linux/workqueue.h>
21272b5eddSBrian Austin #include <linux/platform_device.h>
22272b5eddSBrian Austin #include <linux/regulator/consumer.h>
23272b5eddSBrian Austin #include <linux/of_device.h>
24272b5eddSBrian Austin #include <linux/of_gpio.h>
25272b5eddSBrian Austin #include <sound/core.h>
26272b5eddSBrian Austin #include <sound/pcm.h>
27272b5eddSBrian Austin #include <sound/pcm_params.h>
28272b5eddSBrian Austin #include <sound/soc.h>
29272b5eddSBrian Austin #include <sound/soc-dapm.h>
30272b5eddSBrian Austin #include <sound/initval.h>
31272b5eddSBrian Austin #include <sound/tlv.h>
32272b5eddSBrian Austin #include <sound/cs42l56.h>
33272b5eddSBrian Austin #include "cs42l56.h"
34272b5eddSBrian Austin 
35272b5eddSBrian Austin #define CS42L56_NUM_SUPPLIES 3
36272b5eddSBrian Austin static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = {
37272b5eddSBrian Austin 	"VA",
38272b5eddSBrian Austin 	"VCP",
39272b5eddSBrian Austin 	"VLDO",
40272b5eddSBrian Austin };
41272b5eddSBrian Austin 
42272b5eddSBrian Austin struct  cs42l56_private {
43272b5eddSBrian Austin 	struct regmap *regmap;
44e48f7466SKuninori Morimoto 	struct snd_soc_component *component;
45272b5eddSBrian Austin 	struct device *dev;
46272b5eddSBrian Austin 	struct cs42l56_platform_data pdata;
47272b5eddSBrian Austin 	struct regulator_bulk_data supplies[CS42L56_NUM_SUPPLIES];
48272b5eddSBrian Austin 	u32 mclk;
49272b5eddSBrian Austin 	u8 mclk_prediv;
50272b5eddSBrian Austin 	u8 mclk_div2;
51272b5eddSBrian Austin 	u8 mclk_ratio;
52272b5eddSBrian Austin 	u8 iface;
53272b5eddSBrian Austin 	u8 iface_fmt;
54272b5eddSBrian Austin 	u8 iface_inv;
55de06f22fSJavier Martinez Canillas #if IS_ENABLED(CONFIG_INPUT)
56272b5eddSBrian Austin 	struct input_dev *beep;
57272b5eddSBrian Austin 	struct work_struct beep_work;
58272b5eddSBrian Austin 	int beep_rate;
59272b5eddSBrian Austin #endif
60272b5eddSBrian Austin };
61272b5eddSBrian Austin 
62272b5eddSBrian Austin static const struct reg_default cs42l56_reg_defaults[] = {
63272b5eddSBrian Austin 	{ 3, 0x7f },	/* r03	- Power Ctl 1 */
64272b5eddSBrian Austin 	{ 4, 0xff },	/* r04	- Power Ctl 2 */
65272b5eddSBrian Austin 	{ 5, 0x00 },	/* ro5	- Clocking Ctl 1 */
66272b5eddSBrian Austin 	{ 6, 0x0b },	/* r06	- Clocking Ctl 2 */
67272b5eddSBrian Austin 	{ 7, 0x00 },	/* r07	- Serial Format */
68272b5eddSBrian Austin 	{ 8, 0x05 },	/* r08	- Class H Ctl */
69272b5eddSBrian Austin 	{ 9, 0x0c },	/* r09	- Misc Ctl */
70272b5eddSBrian Austin 	{ 10, 0x80 },	/* r0a	- INT Status */
71272b5eddSBrian Austin 	{ 11, 0x00 },	/* r0b	- Playback Ctl */
72272b5eddSBrian Austin 	{ 12, 0x0c },	/* r0c	- DSP Mute Ctl */
73272b5eddSBrian Austin 	{ 13, 0x00 },	/* r0d	- ADCA Mixer Volume */
74272b5eddSBrian Austin 	{ 14, 0x00 },	/* r0e	- ADCB Mixer Volume */
75272b5eddSBrian Austin 	{ 15, 0x00 },	/* r0f	- PCMA Mixer Volume */
76272b5eddSBrian Austin 	{ 16, 0x00 },	/* r10	- PCMB Mixer Volume */
77272b5eddSBrian Austin 	{ 17, 0x00 },	/* r11	- Analog Input Advisory Volume */
78272b5eddSBrian Austin 	{ 18, 0x00 },	/* r12	- Digital Input Advisory Volume */
79272b5eddSBrian Austin 	{ 19, 0x00 },	/* r13	- Master A Volume */
80272b5eddSBrian Austin 	{ 20, 0x00 },	/* r14	- Master B Volume */
81272b5eddSBrian Austin 	{ 21, 0x00 },	/* r15	- Beep Freq / On Time */
82272b5eddSBrian Austin 	{ 22, 0x00 },	/* r16	- Beep Volume / Off Time */
83272b5eddSBrian Austin 	{ 23, 0x00 },	/* r17	- Beep Tone Ctl */
84272b5eddSBrian Austin 	{ 24, 0x88 },	/* r18	- Tone Ctl */
85272b5eddSBrian Austin 	{ 25, 0x00 },	/* r19	- Channel Mixer & Swap */
86272b5eddSBrian Austin 	{ 26, 0x00 },	/* r1a	- AIN Ref Config / ADC Mux */
87272b5eddSBrian Austin 	{ 27, 0xa0 },	/* r1b	- High-Pass Filter Ctl */
88272b5eddSBrian Austin 	{ 28, 0x00 },	/* r1c	- Misc ADC Ctl */
89272b5eddSBrian Austin 	{ 29, 0x00 },	/* r1d	- Gain & Bias Ctl */
90272b5eddSBrian Austin 	{ 30, 0x00 },	/* r1e	- PGAA Mux & Volume */
91272b5eddSBrian Austin 	{ 31, 0x00 },	/* r1f	- PGAB Mux & Volume */
92272b5eddSBrian Austin 	{ 32, 0x00 },	/* r20	- ADCA Attenuator */
93272b5eddSBrian Austin 	{ 33, 0x00 },	/* r21	- ADCB Attenuator */
94272b5eddSBrian Austin 	{ 34, 0x00 },	/* r22	- ALC Enable & Attack Rate */
95272b5eddSBrian Austin 	{ 35, 0xbf },	/* r23	- ALC Release Rate */
96272b5eddSBrian Austin 	{ 36, 0x00 },	/* r24	- ALC Threshold */
97272b5eddSBrian Austin 	{ 37, 0x00 },	/* r25	- Noise Gate Ctl */
98272b5eddSBrian Austin 	{ 38, 0x00 },	/* r26	- ALC, Limiter, SFT, ZeroCross */
99272b5eddSBrian Austin 	{ 39, 0x00 },	/* r27	- Analog Mute, LO & HP Mux */
100272b5eddSBrian Austin 	{ 40, 0x00 },	/* r28	- HP A Volume */
101272b5eddSBrian Austin 	{ 41, 0x00 },	/* r29	- HP B Volume */
102272b5eddSBrian Austin 	{ 42, 0x00 },	/* r2a	- LINEOUT A Volume */
103272b5eddSBrian Austin 	{ 43, 0x00 },	/* r2b	- LINEOUT B Volume */
104272b5eddSBrian Austin 	{ 44, 0x00 },	/* r2c	- Limit Threshold Ctl */
105272b5eddSBrian Austin 	{ 45, 0x7f },	/* r2d	- Limiter Ctl & Release Rate */
106272b5eddSBrian Austin 	{ 46, 0x00 },	/* r2e	- Limiter Attack Rate */
107272b5eddSBrian Austin };
108272b5eddSBrian Austin 
cs42l56_readable_register(struct device * dev,unsigned int reg)109272b5eddSBrian Austin static bool cs42l56_readable_register(struct device *dev, unsigned int reg)
110272b5eddSBrian Austin {
111272b5eddSBrian Austin 	switch (reg) {
1127f325bfcSAxel Lin 	case CS42L56_CHIP_ID_1 ... CS42L56_LIM_ATTACK_RATE:
113272b5eddSBrian Austin 		return true;
114272b5eddSBrian Austin 	default:
115272b5eddSBrian Austin 		return false;
116272b5eddSBrian Austin 	}
117272b5eddSBrian Austin }
118272b5eddSBrian Austin 
cs42l56_volatile_register(struct device * dev,unsigned int reg)119272b5eddSBrian Austin static bool cs42l56_volatile_register(struct device *dev, unsigned int reg)
120272b5eddSBrian Austin {
121272b5eddSBrian Austin 	switch (reg) {
122272b5eddSBrian Austin 	case CS42L56_INT_STATUS:
123c2b49ae6SBrian Austin 		return true;
124272b5eddSBrian Austin 	default:
125c2b49ae6SBrian Austin 		return false;
126272b5eddSBrian Austin 	}
127272b5eddSBrian Austin }
128272b5eddSBrian Austin 
129272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(beep_tlv, -5000, 200, 0);
130272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(hl_tlv, -6000, 50, 0);
131272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(adv_tlv, -10200, 50, 0);
132272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, 0);
133272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
134272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0);
135272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
136272b5eddSBrian Austin 
13737879bafSLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(ngnb_tlv,
138272b5eddSBrian Austin 	0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0),
13937879bafSLars-Peter Clausen 	2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0)
14037879bafSLars-Peter Clausen );
14137879bafSLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(ngb_tlv,
142272b5eddSBrian Austin 	0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0),
14337879bafSLars-Peter Clausen 	3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0)
14437879bafSLars-Peter Clausen );
14537879bafSLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(alc_tlv,
146272b5eddSBrian Austin 	0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
14737879bafSLars-Peter Clausen 	3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
14837879bafSLars-Peter Clausen );
149272b5eddSBrian Austin 
150272b5eddSBrian Austin static const char * const beep_config_text[] = {
151272b5eddSBrian Austin 	"Off", "Single", "Multiple", "Continuous"
152272b5eddSBrian Austin };
153272b5eddSBrian Austin 
154272b5eddSBrian Austin static const struct soc_enum beep_config_enum =
155272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 6,
156272b5eddSBrian Austin 			ARRAY_SIZE(beep_config_text), beep_config_text);
157272b5eddSBrian Austin 
158272b5eddSBrian Austin static const char * const beep_pitch_text[] = {
159272b5eddSBrian Austin 	"C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
160272b5eddSBrian Austin 	"C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
161272b5eddSBrian Austin };
162272b5eddSBrian Austin 
163272b5eddSBrian Austin static const struct soc_enum beep_pitch_enum =
164272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 4,
165272b5eddSBrian Austin 			ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
166272b5eddSBrian Austin 
167272b5eddSBrian Austin static const char * const beep_ontime_text[] = {
168272b5eddSBrian Austin 	"86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
169272b5eddSBrian Austin 	"1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
170272b5eddSBrian Austin 	"3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
171272b5eddSBrian Austin };
172272b5eddSBrian Austin 
173272b5eddSBrian Austin static const struct soc_enum beep_ontime_enum =
174272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 0,
175272b5eddSBrian Austin 			ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
176272b5eddSBrian Austin 
177272b5eddSBrian Austin static const char * const beep_offtime_text[] = {
178272b5eddSBrian Austin 	"1.23 s", "2.58 s", "3.90 s", "5.20 s",
179272b5eddSBrian Austin 	"6.60 s", "8.05 s", "9.35 s", "10.80 s"
180272b5eddSBrian Austin };
181272b5eddSBrian Austin 
182272b5eddSBrian Austin static const struct soc_enum beep_offtime_enum =
183272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_OFFTIME, 5,
184272b5eddSBrian Austin 			ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
185272b5eddSBrian Austin 
186272b5eddSBrian Austin static const char * const beep_treble_text[] = {
187272b5eddSBrian Austin 	"5kHz", "7kHz", "10kHz", "15kHz"
188272b5eddSBrian Austin };
189272b5eddSBrian Austin 
190272b5eddSBrian Austin static const struct soc_enum beep_treble_enum =
191272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 3,
192272b5eddSBrian Austin 			ARRAY_SIZE(beep_treble_text), beep_treble_text);
193272b5eddSBrian Austin 
194272b5eddSBrian Austin static const char * const beep_bass_text[] = {
195272b5eddSBrian Austin 	"50Hz", "100Hz", "200Hz", "250Hz"
196272b5eddSBrian Austin };
197272b5eddSBrian Austin 
198272b5eddSBrian Austin static const struct soc_enum beep_bass_enum =
199272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1,
200272b5eddSBrian Austin 			ARRAY_SIZE(beep_bass_text), beep_bass_text);
201272b5eddSBrian Austin 
202272b5eddSBrian Austin static const char * const pgaa_mux_text[] = {
203272b5eddSBrian Austin 	"AIN1A", "AIN2A", "AIN3A"};
204272b5eddSBrian Austin 
205272b5eddSBrian Austin static const struct soc_enum pgaa_mux_enum =
206272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_PGAA_MUX_VOLUME, 0,
207272b5eddSBrian Austin 			      ARRAY_SIZE(pgaa_mux_text),
208272b5eddSBrian Austin 			      pgaa_mux_text);
209272b5eddSBrian Austin 
210272b5eddSBrian Austin static const struct snd_kcontrol_new pgaa_mux =
211272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", pgaa_mux_enum);
212272b5eddSBrian Austin 
213272b5eddSBrian Austin static const char * const pgab_mux_text[] = {
214272b5eddSBrian Austin 	"AIN1B", "AIN2B", "AIN3B"};
215272b5eddSBrian Austin 
216272b5eddSBrian Austin static const struct soc_enum pgab_mux_enum =
217272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_PGAB_MUX_VOLUME, 0,
218272b5eddSBrian Austin 			      ARRAY_SIZE(pgab_mux_text),
219272b5eddSBrian Austin 			      pgab_mux_text);
220272b5eddSBrian Austin 
221272b5eddSBrian Austin static const struct snd_kcontrol_new pgab_mux =
222272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", pgab_mux_enum);
223272b5eddSBrian Austin 
224272b5eddSBrian Austin static const char * const adca_mux_text[] = {
225272b5eddSBrian Austin 	"PGAA", "AIN1A", "AIN2A", "AIN3A"};
226272b5eddSBrian Austin 
227272b5eddSBrian Austin static const struct soc_enum adca_mux_enum =
228272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 0,
229272b5eddSBrian Austin 			      ARRAY_SIZE(adca_mux_text),
230272b5eddSBrian Austin 			      adca_mux_text);
231272b5eddSBrian Austin 
232272b5eddSBrian Austin static const struct snd_kcontrol_new adca_mux =
233272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", adca_mux_enum);
234272b5eddSBrian Austin 
235272b5eddSBrian Austin static const char * const adcb_mux_text[] = {
236272b5eddSBrian Austin 	"PGAB", "AIN1B", "AIN2B", "AIN3B"};
237272b5eddSBrian Austin 
238272b5eddSBrian Austin static const struct soc_enum adcb_mux_enum =
239272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 2,
240272b5eddSBrian Austin 			      ARRAY_SIZE(adcb_mux_text),
241272b5eddSBrian Austin 			      adcb_mux_text);
242272b5eddSBrian Austin 
243272b5eddSBrian Austin static const struct snd_kcontrol_new adcb_mux =
244272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", adcb_mux_enum);
245272b5eddSBrian Austin 
246272b5eddSBrian Austin static const char * const left_swap_text[] = {
247272b5eddSBrian Austin 	"Left", "LR 2", "Right"};
248272b5eddSBrian Austin 
249272b5eddSBrian Austin static const char * const right_swap_text[] = {
250272b5eddSBrian Austin 	"Right", "LR 2", "Left"};
251272b5eddSBrian Austin 
252272b5eddSBrian Austin static const unsigned int swap_values[] = { 0, 1, 3 };
253272b5eddSBrian Austin 
254272b5eddSBrian Austin static const struct soc_enum adca_swap_enum =
255272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 0, 3,
256272b5eddSBrian Austin 			      ARRAY_SIZE(left_swap_text),
257272b5eddSBrian Austin 			      left_swap_text,
258272b5eddSBrian Austin 			      swap_values);
259c4324bfaSBrian Austin static const struct snd_kcontrol_new adca_swap_mux =
260c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", adca_swap_enum);
261272b5eddSBrian Austin 
262272b5eddSBrian Austin static const struct soc_enum pcma_swap_enum =
263272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3,
264272b5eddSBrian Austin 			      ARRAY_SIZE(left_swap_text),
265272b5eddSBrian Austin 			      left_swap_text,
266272b5eddSBrian Austin 			      swap_values);
267c4324bfaSBrian Austin static const struct snd_kcontrol_new pcma_swap_mux =
268c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", pcma_swap_enum);
269272b5eddSBrian Austin 
270272b5eddSBrian Austin static const struct soc_enum adcb_swap_enum =
271272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3,
272272b5eddSBrian Austin 			      ARRAY_SIZE(right_swap_text),
273272b5eddSBrian Austin 			      right_swap_text,
274272b5eddSBrian Austin 			      swap_values);
275c4324bfaSBrian Austin static const struct snd_kcontrol_new adcb_swap_mux =
276c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", adcb_swap_enum);
277272b5eddSBrian Austin 
278272b5eddSBrian Austin static const struct soc_enum pcmb_swap_enum =
279272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3,
280272b5eddSBrian Austin 			      ARRAY_SIZE(right_swap_text),
281272b5eddSBrian Austin 			      right_swap_text,
282272b5eddSBrian Austin 			      swap_values);
283c4324bfaSBrian Austin static const struct snd_kcontrol_new pcmb_swap_mux =
284c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", pcmb_swap_enum);
285272b5eddSBrian Austin 
286272b5eddSBrian Austin static const struct snd_kcontrol_new hpa_switch =
287272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1);
288272b5eddSBrian Austin 
289272b5eddSBrian Austin static const struct snd_kcontrol_new hpb_switch =
290272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 4, 1, 1);
291272b5eddSBrian Austin 
292272b5eddSBrian Austin static const struct snd_kcontrol_new loa_switch =
293272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 2, 1, 1);
294272b5eddSBrian Austin 
295272b5eddSBrian Austin static const struct snd_kcontrol_new lob_switch =
296272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 0, 1, 1);
297272b5eddSBrian Austin 
298272b5eddSBrian Austin static const char * const hploa_input_text[] = {
299272b5eddSBrian Austin 	"DACA", "PGAA"};
300272b5eddSBrian Austin 
301272b5eddSBrian Austin static const struct soc_enum lineouta_input_enum =
302272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 2,
303272b5eddSBrian Austin 			      ARRAY_SIZE(hploa_input_text),
304272b5eddSBrian Austin 			      hploa_input_text);
305272b5eddSBrian Austin 
306272b5eddSBrian Austin static const struct snd_kcontrol_new lineouta_input =
307272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", lineouta_input_enum);
308272b5eddSBrian Austin 
309272b5eddSBrian Austin static const struct soc_enum hpa_input_enum =
310272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 0,
311272b5eddSBrian Austin 			      ARRAY_SIZE(hploa_input_text),
312272b5eddSBrian Austin 			      hploa_input_text);
313272b5eddSBrian Austin 
314272b5eddSBrian Austin static const struct snd_kcontrol_new hpa_input =
315272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", hpa_input_enum);
316272b5eddSBrian Austin 
317272b5eddSBrian Austin static const char * const hplob_input_text[] = {
318272b5eddSBrian Austin 	"DACB", "PGAB"};
319272b5eddSBrian Austin 
320272b5eddSBrian Austin static const struct soc_enum lineoutb_input_enum =
321272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 3,
322272b5eddSBrian Austin 			      ARRAY_SIZE(hplob_input_text),
323272b5eddSBrian Austin 			      hplob_input_text);
324272b5eddSBrian Austin 
325272b5eddSBrian Austin static const struct snd_kcontrol_new lineoutb_input =
326272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", lineoutb_input_enum);
327272b5eddSBrian Austin 
328272b5eddSBrian Austin static const struct soc_enum hpb_input_enum =
329272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 1,
330272b5eddSBrian Austin 			      ARRAY_SIZE(hplob_input_text),
331272b5eddSBrian Austin 			      hplob_input_text);
332272b5eddSBrian Austin 
333272b5eddSBrian Austin static const struct snd_kcontrol_new hpb_input =
334272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", hpb_input_enum);
335272b5eddSBrian Austin 
336272b5eddSBrian Austin static const char * const dig_mux_text[] = {
337272b5eddSBrian Austin 	"ADC", "DSP"};
338272b5eddSBrian Austin 
339272b5eddSBrian Austin static const struct soc_enum dig_mux_enum =
340272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_MISC_CTL, 7,
341272b5eddSBrian Austin 			      ARRAY_SIZE(dig_mux_text),
342272b5eddSBrian Austin 			      dig_mux_text);
343272b5eddSBrian Austin 
344272b5eddSBrian Austin static const struct snd_kcontrol_new dig_mux =
345272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", dig_mux_enum);
346272b5eddSBrian Austin 
347272b5eddSBrian Austin static const char * const hpf_freq_text[] = {
348272b5eddSBrian Austin 	"1.8Hz", "119Hz", "236Hz", "464Hz"
349272b5eddSBrian Austin };
350272b5eddSBrian Austin 
351272b5eddSBrian Austin static const struct soc_enum hpfa_freq_enum =
352272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 0,
353272b5eddSBrian Austin 			ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
354272b5eddSBrian Austin 
355272b5eddSBrian Austin static const struct soc_enum hpfb_freq_enum =
356272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 2,
357272b5eddSBrian Austin 			ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
358272b5eddSBrian Austin 
359272b5eddSBrian Austin static const char * const ng_delay_text[] = {
360272b5eddSBrian Austin 	"50ms", "100ms", "150ms", "200ms"
361272b5eddSBrian Austin };
362272b5eddSBrian Austin 
363272b5eddSBrian Austin static const struct soc_enum ng_delay_enum =
364272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_NOISE_GATE_CTL, 0,
365272b5eddSBrian Austin 			ARRAY_SIZE(ng_delay_text), ng_delay_text);
366272b5eddSBrian Austin 
367272b5eddSBrian Austin static const struct snd_kcontrol_new cs42l56_snd_controls[] = {
368272b5eddSBrian Austin 
369272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME,
370a0465587SBrian Austin 			      CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xE4, adv_tlv),
371272b5eddSBrian Austin 	SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1),
372272b5eddSBrian Austin 
373272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME,
374a0465587SBrian Austin 			      CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv),
375272b5eddSBrian Austin 	SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1),
376272b5eddSBrian Austin 
377272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME,
378a0465587SBrian Austin 			      CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv),
379272b5eddSBrian Austin 	SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1),
380272b5eddSBrian Austin 
381272b5eddSBrian Austin 	SOC_SINGLE_TLV("Analog Advisory Volume",
382272b5eddSBrian Austin 			  CS42L56_ANAINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
383272b5eddSBrian Austin 	SOC_SINGLE_TLV("Digital Advisory Volume",
384272b5eddSBrian Austin 			  CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
385272b5eddSBrian Austin 
386272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME,
387a0465587SBrian Austin 			      CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0x24, pga_tlv),
388272b5eddSBrian Austin 	SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR,
389272b5eddSBrian Austin 			      CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv),
390272b5eddSBrian Austin 	SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1),
391272b5eddSBrian Austin 	SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1),
392272b5eddSBrian Austin 
393272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME,
394a8928adaSCharles Keepax 			      CS42L56_HPB_VOLUME, 0, 0x44, 0x48, hl_tlv),
395272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME,
396a8928adaSCharles Keepax 			      CS42L56_LOB_VOLUME, 0, 0x44, 0x48, hl_tlv),
397272b5eddSBrian Austin 
398272b5eddSBrian Austin 	SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL,
399272b5eddSBrian Austin 			0, 0x00, 1, tone_tlv),
400272b5eddSBrian Austin 	SOC_SINGLE_TLV("Treble Shelving Volume", CS42L56_TONE_CTL,
401272b5eddSBrian Austin 			4, 0x00, 1, tone_tlv),
402272b5eddSBrian Austin 
403272b5eddSBrian Austin 	SOC_DOUBLE_TLV("PGA Preamp Volume", CS42L56_GAIN_BIAS_CTL,
404272b5eddSBrian Austin 			4, 6, 0x02, 1, preamp_tlv),
405272b5eddSBrian Austin 
406272b5eddSBrian Austin 	SOC_SINGLE("DSP Switch", CS42L56_PLAYBACK_CTL, 7, 1, 1),
407272b5eddSBrian Austin 	SOC_SINGLE("Gang Playback Switch", CS42L56_PLAYBACK_CTL, 4, 1, 1),
408272b5eddSBrian Austin 	SOC_SINGLE("Gang ADC Switch", CS42L56_MISC_ADC_CTL, 7, 1, 1),
409272b5eddSBrian Austin 	SOC_SINGLE("Gang PGA Switch", CS42L56_MISC_ADC_CTL, 6, 1, 1),
410272b5eddSBrian Austin 
411272b5eddSBrian Austin 	SOC_SINGLE("PCMA Invert", CS42L56_PLAYBACK_CTL, 2, 1, 1),
412272b5eddSBrian Austin 	SOC_SINGLE("PCMB Invert", CS42L56_PLAYBACK_CTL, 3, 1, 1),
413272b5eddSBrian Austin 	SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1),
414272b5eddSBrian Austin 	SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1),
415272b5eddSBrian Austin 
416272b5eddSBrian Austin 	SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1),
417272b5eddSBrian Austin 	SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1),
418272b5eddSBrian Austin 	SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum),
419272b5eddSBrian Austin 	SOC_ENUM("HPFB Corner Freq", hpfb_freq_enum),
420272b5eddSBrian Austin 
421272b5eddSBrian Austin 	SOC_SINGLE("Analog Soft Ramp", CS42L56_MISC_CTL, 4, 1, 1),
422272b5eddSBrian Austin 	SOC_DOUBLE("Analog Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
423272b5eddSBrian Austin 		7, 5, 1, 1),
424272b5eddSBrian Austin 	SOC_SINGLE("Analog Zero Cross", CS42L56_MISC_CTL, 3, 1, 1),
425272b5eddSBrian Austin 	SOC_DOUBLE("Analog Zero Cross Disable", CS42L56_ALC_LIM_SFT_ZC,
426272b5eddSBrian Austin 		6, 4, 1, 1),
427272b5eddSBrian Austin 	SOC_SINGLE("Digital Soft Ramp", CS42L56_MISC_CTL, 2, 1, 1),
428272b5eddSBrian Austin 	SOC_SINGLE("Digital Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
429272b5eddSBrian Austin 		3, 1, 1),
430272b5eddSBrian Austin 
431272b5eddSBrian Austin 	SOC_SINGLE("HL Deemphasis", CS42L56_PLAYBACK_CTL, 6, 1, 1),
432272b5eddSBrian Austin 
433272b5eddSBrian Austin 	SOC_SINGLE("ALC Switch", CS42L56_ALC_EN_ATTACK_RATE, 6, 1, 1),
434272b5eddSBrian Austin 	SOC_SINGLE("ALC Limit All Switch", CS42L56_ALC_RELEASE_RATE, 7, 1, 1),
435272b5eddSBrian Austin 	SOC_SINGLE_RANGE("ALC Attack", CS42L56_ALC_EN_ATTACK_RATE,
436272b5eddSBrian Austin 			0, 0, 0x3f, 0),
437272b5eddSBrian Austin 	SOC_SINGLE_RANGE("ALC Release", CS42L56_ALC_RELEASE_RATE,
438272b5eddSBrian Austin 			0, 0x3f, 0, 0),
439272b5eddSBrian Austin 	SOC_SINGLE_TLV("ALC MAX", CS42L56_ALC_THRESHOLD,
440272b5eddSBrian Austin 			5, 0x07, 1, alc_tlv),
441272b5eddSBrian Austin 	SOC_SINGLE_TLV("ALC MIN", CS42L56_ALC_THRESHOLD,
442272b5eddSBrian Austin 			2, 0x07, 1, alc_tlv),
443272b5eddSBrian Austin 
444272b5eddSBrian Austin 	SOC_SINGLE("Limiter Switch", CS42L56_LIM_CTL_RELEASE_RATE, 7, 1, 1),
445272b5eddSBrian Austin 	SOC_SINGLE("Limit All Switch", CS42L56_LIM_CTL_RELEASE_RATE, 6, 1, 1),
446272b5eddSBrian Austin 	SOC_SINGLE_RANGE("Limiter Attack", CS42L56_LIM_ATTACK_RATE,
447272b5eddSBrian Austin 			0, 0, 0x3f, 0),
448272b5eddSBrian Austin 	SOC_SINGLE_RANGE("Limiter Release", CS42L56_LIM_CTL_RELEASE_RATE,
449272b5eddSBrian Austin 			0, 0x3f, 0, 0),
450272b5eddSBrian Austin 	SOC_SINGLE_TLV("Limiter MAX", CS42L56_LIM_THRESHOLD_CTL,
451272b5eddSBrian Austin 			5, 0x07, 1, alc_tlv),
452272b5eddSBrian Austin 	SOC_SINGLE_TLV("Limiter Cushion", CS42L56_ALC_THRESHOLD,
453272b5eddSBrian Austin 			2, 0x07, 1, alc_tlv),
454272b5eddSBrian Austin 
455272b5eddSBrian Austin 	SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1),
456272b5eddSBrian Austin 	SOC_SINGLE("NG All Switch", CS42L56_NOISE_GATE_CTL, 7, 1, 1),
457272b5eddSBrian Austin 	SOC_SINGLE("NG Boost Switch", CS42L56_NOISE_GATE_CTL, 5, 1, 1),
458272b5eddSBrian Austin 	SOC_SINGLE_TLV("NG Unboost Threshold", CS42L56_NOISE_GATE_CTL,
459272b5eddSBrian Austin 			2, 0x07, 1, ngnb_tlv),
460272b5eddSBrian Austin 	SOC_SINGLE_TLV("NG Boost Threshold", CS42L56_NOISE_GATE_CTL,
461272b5eddSBrian Austin 			2, 0x07, 1, ngb_tlv),
462272b5eddSBrian Austin 	SOC_ENUM("NG Delay", ng_delay_enum),
463272b5eddSBrian Austin 
464272b5eddSBrian Austin 	SOC_ENUM("Beep Config", beep_config_enum),
465272b5eddSBrian Austin 	SOC_ENUM("Beep Pitch", beep_pitch_enum),
466272b5eddSBrian Austin 	SOC_ENUM("Beep on Time", beep_ontime_enum),
467272b5eddSBrian Austin 	SOC_ENUM("Beep off Time", beep_offtime_enum),
468272b5eddSBrian Austin 	SOC_SINGLE_SX_TLV("Beep Volume", CS42L56_BEEP_FREQ_OFFTIME,
469272b5eddSBrian Austin 			0, 0x07, 0x23, beep_tlv),
470272b5eddSBrian Austin 	SOC_SINGLE("Beep Tone Ctl Switch", CS42L56_BEEP_TONE_CFG, 0, 1, 1),
471272b5eddSBrian Austin 	SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
472272b5eddSBrian Austin 	SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
473272b5eddSBrian Austin 
474272b5eddSBrian Austin };
475272b5eddSBrian Austin 
476272b5eddSBrian Austin static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = {
477272b5eddSBrian Austin 
478272b5eddSBrian Austin 	SND_SOC_DAPM_SIGGEN("Beep"),
479272b5eddSBrian Austin 	SND_SOC_DAPM_SUPPLY("VBUF", CS42L56_PWRCTL_1, 5, 1, NULL, 0),
480272b5eddSBrian Austin 	SND_SOC_DAPM_MICBIAS("MIC1 Bias", CS42L56_PWRCTL_1, 4, 1),
481272b5eddSBrian Austin 	SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L56_PWRCTL_1, 3, 1, NULL, 0),
482272b5eddSBrian Austin 
483272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN1A"),
484272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN2A"),
485272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN1B"),
486272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN2B"),
487272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN3A"),
488272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN3B"),
489272b5eddSBrian Austin 
490272b5eddSBrian Austin 	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL,  0,
491272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0),
492272b5eddSBrian Austin 
493272b5eddSBrian Austin 	SND_SOC_DAPM_AIF_IN("SDIN", NULL,  0,
494272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0),
495272b5eddSBrian Austin 
496272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("Digital Output Mux", SND_SOC_NOPM,
497272b5eddSBrian Austin 			 0, 0, &dig_mux),
498272b5eddSBrian Austin 
499272b5eddSBrian Austin 	SND_SOC_DAPM_PGA("PGAA", SND_SOC_NOPM, 0, 0, NULL, 0),
500272b5eddSBrian Austin 	SND_SOC_DAPM_PGA("PGAB", SND_SOC_NOPM, 0, 0, NULL, 0),
501272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("PGAA Input Mux",
502272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0, &pgaa_mux),
503272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("PGAB Input Mux",
504272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0, &pgab_mux),
505272b5eddSBrian Austin 
506272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("ADCA Mux", SND_SOC_NOPM,
507272b5eddSBrian Austin 			 0, 0, &adca_mux),
508272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("ADCB Mux", SND_SOC_NOPM,
509272b5eddSBrian Austin 			 0, 0, &adcb_mux),
510272b5eddSBrian Austin 
511272b5eddSBrian Austin 	SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1),
512272b5eddSBrian Austin 	SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1),
513272b5eddSBrian Austin 
514c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("ADCA Swap Mux", SND_SOC_NOPM, 0, 0,
515c4324bfaSBrian Austin 		&adca_swap_mux),
516c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("ADCB Swap Mux", SND_SOC_NOPM, 0, 0,
517c4324bfaSBrian Austin 		&adcb_swap_mux),
518c4324bfaSBrian Austin 
519c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("PCMA Swap Mux", SND_SOC_NOPM, 0, 0,
520c4324bfaSBrian Austin 		&pcma_swap_mux),
521c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("PCMB Swap Mux", SND_SOC_NOPM, 0, 0,
522c4324bfaSBrian Austin 		&pcmb_swap_mux),
523c4324bfaSBrian Austin 
524272b5eddSBrian Austin 	SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0),
525272b5eddSBrian Austin 	SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0),
526272b5eddSBrian Austin 
527272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("HPA"),
528272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("LOA"),
529272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("HPB"),
530272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("LOB"),
531272b5eddSBrian Austin 
532272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Headphone Right",
533272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 4, 1, &hpb_switch),
534272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Headphone Left",
535272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 6, 1, &hpa_switch),
536272b5eddSBrian Austin 
537272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Lineout Right",
538272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 0, 1, &lob_switch),
539272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Lineout Left",
540272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 2, 1, &loa_switch),
541272b5eddSBrian Austin 
542272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("LINEOUTA Input Mux", SND_SOC_NOPM,
543272b5eddSBrian Austin 			 0, 0, &lineouta_input),
544272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("LINEOUTB Input Mux", SND_SOC_NOPM,
545272b5eddSBrian Austin 			 0, 0, &lineoutb_input),
546272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("HPA Input Mux", SND_SOC_NOPM,
547272b5eddSBrian Austin 			 0, 0, &hpa_input),
548272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("HPB Input Mux", SND_SOC_NOPM,
549272b5eddSBrian Austin 			 0, 0, &hpb_input),
550272b5eddSBrian Austin 
551272b5eddSBrian Austin };
552272b5eddSBrian Austin 
553272b5eddSBrian Austin static const struct snd_soc_dapm_route cs42l56_audio_map[] = {
554272b5eddSBrian Austin 
555272b5eddSBrian Austin 	{"HiFi Capture", "DSP", "Digital Output Mux"},
556272b5eddSBrian Austin 	{"HiFi Capture", "ADC", "Digital Output Mux"},
557272b5eddSBrian Austin 
558272b5eddSBrian Austin 	{"Digital Output Mux", NULL, "ADCA"},
559272b5eddSBrian Austin 	{"Digital Output Mux", NULL, "ADCB"},
560272b5eddSBrian Austin 
561c4324bfaSBrian Austin 	{"ADCB", NULL, "ADCB Swap Mux"},
562c4324bfaSBrian Austin 	{"ADCA", NULL, "ADCA Swap Mux"},
563c4324bfaSBrian Austin 
564c4324bfaSBrian Austin 	{"ADCA Swap Mux", NULL, "ADCA"},
565c4324bfaSBrian Austin 	{"ADCB Swap Mux", NULL, "ADCB"},
566c4324bfaSBrian Austin 
567c4324bfaSBrian Austin 	{"DACA", "Left", "ADCA Swap Mux"},
568c4324bfaSBrian Austin 	{"DACA", "LR 2", "ADCA Swap Mux"},
569c4324bfaSBrian Austin 	{"DACA", "Right", "ADCA Swap Mux"},
570c4324bfaSBrian Austin 
571c4324bfaSBrian Austin 	{"DACB", "Left", "ADCB Swap Mux"},
572c4324bfaSBrian Austin 	{"DACB", "LR 2", "ADCB Swap Mux"},
573c4324bfaSBrian Austin 	{"DACB", "Right", "ADCB Swap Mux"},
574272b5eddSBrian Austin 
575272b5eddSBrian Austin 	{"ADCA Mux", NULL, "AIN3A"},
576272b5eddSBrian Austin 	{"ADCA Mux", NULL, "AIN2A"},
577272b5eddSBrian Austin 	{"ADCA Mux", NULL, "AIN1A"},
578272b5eddSBrian Austin 	{"ADCA Mux", NULL, "PGAA"},
579272b5eddSBrian Austin 	{"ADCB Mux", NULL, "AIN3B"},
580272b5eddSBrian Austin 	{"ADCB Mux", NULL, "AIN2B"},
581272b5eddSBrian Austin 	{"ADCB Mux", NULL, "AIN1B"},
582272b5eddSBrian Austin 	{"ADCB Mux", NULL, "PGAB"},
583272b5eddSBrian Austin 
584272b5eddSBrian Austin 	{"PGAA", "AIN1A", "PGAA Input Mux"},
585272b5eddSBrian Austin 	{"PGAA", "AIN2A", "PGAA Input Mux"},
586272b5eddSBrian Austin 	{"PGAA", "AIN3A", "PGAA Input Mux"},
587272b5eddSBrian Austin 	{"PGAB", "AIN1B", "PGAB Input Mux"},
588272b5eddSBrian Austin 	{"PGAB", "AIN2B", "PGAB Input Mux"},
589272b5eddSBrian Austin 	{"PGAB", "AIN3B", "PGAB Input Mux"},
590272b5eddSBrian Austin 
591272b5eddSBrian Austin 	{"PGAA Input Mux", NULL, "AIN1A"},
592272b5eddSBrian Austin 	{"PGAA Input Mux", NULL, "AIN2A"},
593272b5eddSBrian Austin 	{"PGAA Input Mux", NULL, "AIN3A"},
594272b5eddSBrian Austin 	{"PGAB Input Mux", NULL, "AIN1B"},
595272b5eddSBrian Austin 	{"PGAB Input Mux", NULL, "AIN2B"},
596272b5eddSBrian Austin 	{"PGAB Input Mux", NULL, "AIN3B"},
597272b5eddSBrian Austin 
598c4324bfaSBrian Austin 	{"LOB", "Switch", "LINEOUTB Input Mux"},
599c4324bfaSBrian Austin 	{"LOA", "Switch", "LINEOUTA Input Mux"},
600272b5eddSBrian Austin 
601272b5eddSBrian Austin 	{"LINEOUTA Input Mux", "PGAA", "PGAA"},
602272b5eddSBrian Austin 	{"LINEOUTB Input Mux", "PGAB", "PGAB"},
603272b5eddSBrian Austin 	{"LINEOUTA Input Mux", "DACA", "DACA"},
604272b5eddSBrian Austin 	{"LINEOUTB Input Mux", "DACB", "DACB"},
605272b5eddSBrian Austin 
606c4324bfaSBrian Austin 	{"HPA", "Switch", "HPB Input Mux"},
607c4324bfaSBrian Austin 	{"HPB", "Switch", "HPA Input Mux"},
608272b5eddSBrian Austin 
609272b5eddSBrian Austin 	{"HPA Input Mux", "PGAA", "PGAA"},
610272b5eddSBrian Austin 	{"HPB Input Mux", "PGAB", "PGAB"},
611272b5eddSBrian Austin 	{"HPA Input Mux", "DACA", "DACA"},
612272b5eddSBrian Austin 	{"HPB Input Mux", "DACB", "DACB"},
613272b5eddSBrian Austin 
614c4324bfaSBrian Austin 	{"DACA", NULL, "PCMA Swap Mux"},
615c4324bfaSBrian Austin 	{"DACB", NULL, "PCMB Swap Mux"},
616c4324bfaSBrian Austin 
617c4324bfaSBrian Austin 	{"PCMB Swap Mux", "Left", "HiFi Playback"},
618c4324bfaSBrian Austin 	{"PCMB Swap Mux", "LR 2", "HiFi Playback"},
619c4324bfaSBrian Austin 	{"PCMB Swap Mux", "Right", "HiFi Playback"},
620c4324bfaSBrian Austin 
621c4324bfaSBrian Austin 	{"PCMA Swap Mux", "Left", "HiFi Playback"},
622c4324bfaSBrian Austin 	{"PCMA Swap Mux", "LR 2", "HiFi Playback"},
623c4324bfaSBrian Austin 	{"PCMA Swap Mux", "Right", "HiFi Playback"},
624272b5eddSBrian Austin 
625272b5eddSBrian Austin };
626272b5eddSBrian Austin 
627272b5eddSBrian Austin struct cs42l56_clk_para {
628272b5eddSBrian Austin 	u32 mclk;
629272b5eddSBrian Austin 	u32 srate;
630272b5eddSBrian Austin 	u8 ratio;
631272b5eddSBrian Austin };
632272b5eddSBrian Austin 
633272b5eddSBrian Austin static const struct cs42l56_clk_para clk_ratio_table[] = {
634272b5eddSBrian Austin 	/* 8k */
635272b5eddSBrian Austin 	{ 6000000, 8000, CS42L56_MCLK_LRCLK_768 },
636272b5eddSBrian Austin 	{ 6144000, 8000, CS42L56_MCLK_LRCLK_750 },
637272b5eddSBrian Austin 	{ 12000000, 8000, CS42L56_MCLK_LRCLK_768 },
638272b5eddSBrian Austin 	{ 12288000, 8000, CS42L56_MCLK_LRCLK_750 },
639272b5eddSBrian Austin 	{ 24000000, 8000, CS42L56_MCLK_LRCLK_768 },
640272b5eddSBrian Austin 	{ 24576000, 8000, CS42L56_MCLK_LRCLK_750 },
641272b5eddSBrian Austin 	/* 11.025k */
642272b5eddSBrian Austin 	{ 5644800, 11025, CS42L56_MCLK_LRCLK_512},
643272b5eddSBrian Austin 	{ 11289600, 11025, CS42L56_MCLK_LRCLK_512},
644272b5eddSBrian Austin 	{ 22579200, 11025, CS42L56_MCLK_LRCLK_512 },
645272b5eddSBrian Austin 	/* 11.0294k */
646272b5eddSBrian Austin 	{ 6000000, 110294, CS42L56_MCLK_LRCLK_544 },
647272b5eddSBrian Austin 	{ 12000000, 110294, CS42L56_MCLK_LRCLK_544 },
648272b5eddSBrian Austin 	{ 24000000, 110294, CS42L56_MCLK_LRCLK_544 },
649272b5eddSBrian Austin 	/* 12k */
650272b5eddSBrian Austin 	{ 6000000, 12000, CS42L56_MCLK_LRCLK_500 },
651272b5eddSBrian Austin 	{ 6144000, 12000, CS42L56_MCLK_LRCLK_512 },
652272b5eddSBrian Austin 	{ 12000000, 12000, CS42L56_MCLK_LRCLK_500 },
653272b5eddSBrian Austin 	{ 12288000, 12000, CS42L56_MCLK_LRCLK_512 },
654272b5eddSBrian Austin 	{ 24000000, 12000, CS42L56_MCLK_LRCLK_500 },
655272b5eddSBrian Austin 	{ 24576000, 12000, CS42L56_MCLK_LRCLK_512 },
656272b5eddSBrian Austin 	/* 16k */
657272b5eddSBrian Austin 	{ 6000000, 16000, CS42L56_MCLK_LRCLK_375 },
658272b5eddSBrian Austin 	{ 6144000, 16000, CS42L56_MCLK_LRCLK_384 },
659272b5eddSBrian Austin 	{ 12000000, 16000, CS42L56_MCLK_LRCLK_375 },
660272b5eddSBrian Austin 	{ 12288000, 16000, CS42L56_MCLK_LRCLK_384 },
661272b5eddSBrian Austin 	{ 24000000, 16000, CS42L56_MCLK_LRCLK_375 },
662272b5eddSBrian Austin 	{ 24576000, 16000, CS42L56_MCLK_LRCLK_384 },
663272b5eddSBrian Austin 	/* 22.050k */
664272b5eddSBrian Austin 	{ 5644800, 22050, CS42L56_MCLK_LRCLK_256 },
665272b5eddSBrian Austin 	{ 11289600, 22050, CS42L56_MCLK_LRCLK_256 },
666272b5eddSBrian Austin 	{ 22579200, 22050, CS42L56_MCLK_LRCLK_256 },
667272b5eddSBrian Austin 	/* 22.0588k */
668272b5eddSBrian Austin 	{ 6000000, 220588, CS42L56_MCLK_LRCLK_272 },
669272b5eddSBrian Austin 	{ 12000000, 220588, CS42L56_MCLK_LRCLK_272 },
670272b5eddSBrian Austin 	{ 24000000, 220588, CS42L56_MCLK_LRCLK_272 },
671272b5eddSBrian Austin 	/* 24k */
672272b5eddSBrian Austin 	{ 6000000, 24000, CS42L56_MCLK_LRCLK_250 },
673272b5eddSBrian Austin 	{ 6144000, 24000, CS42L56_MCLK_LRCLK_256 },
674272b5eddSBrian Austin 	{ 12000000, 24000, CS42L56_MCLK_LRCLK_250 },
675272b5eddSBrian Austin 	{ 12288000, 24000, CS42L56_MCLK_LRCLK_256 },
676272b5eddSBrian Austin 	{ 24000000, 24000, CS42L56_MCLK_LRCLK_250 },
677272b5eddSBrian Austin 	{ 24576000, 24000, CS42L56_MCLK_LRCLK_256 },
678272b5eddSBrian Austin 	/* 32k */
679272b5eddSBrian Austin 	{ 6000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
680272b5eddSBrian Austin 	{ 6144000, 32000, CS42L56_MCLK_LRCLK_192 },
681272b5eddSBrian Austin 	{ 12000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
682272b5eddSBrian Austin 	{ 12288000, 32000, CS42L56_MCLK_LRCLK_192 },
683272b5eddSBrian Austin 	{ 24000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
684272b5eddSBrian Austin 	{ 24576000, 32000, CS42L56_MCLK_LRCLK_192 },
685272b5eddSBrian Austin 	/* 44.118k */
686272b5eddSBrian Austin 	{ 6000000, 44118, CS42L56_MCLK_LRCLK_136 },
687272b5eddSBrian Austin 	{ 12000000, 44118, CS42L56_MCLK_LRCLK_136 },
688272b5eddSBrian Austin 	{ 24000000, 44118, CS42L56_MCLK_LRCLK_136 },
689272b5eddSBrian Austin 	/* 44.1k */
690272b5eddSBrian Austin 	{ 5644800, 44100, CS42L56_MCLK_LRCLK_128 },
691272b5eddSBrian Austin 	{ 11289600, 44100, CS42L56_MCLK_LRCLK_128 },
692272b5eddSBrian Austin 	{ 22579200, 44100, CS42L56_MCLK_LRCLK_128 },
693272b5eddSBrian Austin 	/* 48k */
694272b5eddSBrian Austin 	{ 6000000, 48000, CS42L56_MCLK_LRCLK_125 },
695272b5eddSBrian Austin 	{ 6144000, 48000, CS42L56_MCLK_LRCLK_128 },
696272b5eddSBrian Austin 	{ 12000000, 48000, CS42L56_MCLK_LRCLK_125 },
697272b5eddSBrian Austin 	{ 12288000, 48000, CS42L56_MCLK_LRCLK_128 },
698272b5eddSBrian Austin 	{ 24000000, 48000, CS42L56_MCLK_LRCLK_125 },
699272b5eddSBrian Austin 	{ 24576000, 48000, CS42L56_MCLK_LRCLK_128 },
700272b5eddSBrian Austin };
701272b5eddSBrian Austin 
cs42l56_get_mclk_ratio(int mclk,int rate)702272b5eddSBrian Austin static int cs42l56_get_mclk_ratio(int mclk, int rate)
703272b5eddSBrian Austin {
704272b5eddSBrian Austin 	int i;
705272b5eddSBrian Austin 
706272b5eddSBrian Austin 	for (i = 0; i < ARRAY_SIZE(clk_ratio_table); i++) {
707272b5eddSBrian Austin 		if (clk_ratio_table[i].mclk == mclk &&
708272b5eddSBrian Austin 		    clk_ratio_table[i].srate == rate)
709272b5eddSBrian Austin 			return clk_ratio_table[i].ratio;
710272b5eddSBrian Austin 	}
711272b5eddSBrian Austin 	return -EINVAL;
712272b5eddSBrian Austin }
713272b5eddSBrian Austin 
cs42l56_set_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)714272b5eddSBrian Austin static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
715272b5eddSBrian Austin 			int clk_id, unsigned int freq, int dir)
716272b5eddSBrian Austin {
717e48f7466SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
718e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
719272b5eddSBrian Austin 
720272b5eddSBrian Austin 	switch (freq) {
721272b5eddSBrian Austin 	case CS42L56_MCLK_5P6448MHZ:
722272b5eddSBrian Austin 	case CS42L56_MCLK_6MHZ:
723272b5eddSBrian Austin 	case CS42L56_MCLK_6P144MHZ:
724272b5eddSBrian Austin 		cs42l56->mclk_div2 = 0;
725272b5eddSBrian Austin 		cs42l56->mclk_prediv = 0;
726272b5eddSBrian Austin 		break;
727272b5eddSBrian Austin 	case CS42L56_MCLK_11P2896MHZ:
728272b5eddSBrian Austin 	case CS42L56_MCLK_12MHZ:
729272b5eddSBrian Austin 	case CS42L56_MCLK_12P288MHZ:
7304641c771SAxel Lin 		cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
731272b5eddSBrian Austin 		cs42l56->mclk_prediv = 0;
732272b5eddSBrian Austin 		break;
733272b5eddSBrian Austin 	case CS42L56_MCLK_22P5792MHZ:
734272b5eddSBrian Austin 	case CS42L56_MCLK_24MHZ:
735272b5eddSBrian Austin 	case CS42L56_MCLK_24P576MHZ:
7364641c771SAxel Lin 		cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
7374641c771SAxel Lin 		cs42l56->mclk_prediv = CS42L56_MCLK_PREDIV;
738272b5eddSBrian Austin 		break;
739272b5eddSBrian Austin 	default:
740272b5eddSBrian Austin 		return -EINVAL;
741272b5eddSBrian Austin 	}
742272b5eddSBrian Austin 	cs42l56->mclk = freq;
743272b5eddSBrian Austin 
744e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
745272b5eddSBrian Austin 			    CS42L56_MCLK_PREDIV_MASK,
746272b5eddSBrian Austin 				cs42l56->mclk_prediv);
747e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
748272b5eddSBrian Austin 			    CS42L56_MCLK_DIV2_MASK,
749272b5eddSBrian Austin 				cs42l56->mclk_div2);
750272b5eddSBrian Austin 
751272b5eddSBrian Austin 	return 0;
752272b5eddSBrian Austin }
753272b5eddSBrian Austin 
cs42l56_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)754272b5eddSBrian Austin static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
755272b5eddSBrian Austin {
756e48f7466SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
757e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
758272b5eddSBrian Austin 
759272b5eddSBrian Austin 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
760272b5eddSBrian Austin 	case SND_SOC_DAIFMT_CBM_CFM:
761272b5eddSBrian Austin 		cs42l56->iface = CS42L56_MASTER_MODE;
762272b5eddSBrian Austin 		break;
763272b5eddSBrian Austin 	case SND_SOC_DAIFMT_CBS_CFS:
764272b5eddSBrian Austin 		cs42l56->iface = CS42L56_SLAVE_MODE;
765272b5eddSBrian Austin 		break;
766272b5eddSBrian Austin 	default:
767272b5eddSBrian Austin 		return -EINVAL;
768272b5eddSBrian Austin 	}
769272b5eddSBrian Austin 
770272b5eddSBrian Austin 	 /* interface format */
771272b5eddSBrian Austin 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
772272b5eddSBrian Austin 	case SND_SOC_DAIFMT_I2S:
773272b5eddSBrian Austin 		cs42l56->iface_fmt = CS42L56_DIG_FMT_I2S;
774272b5eddSBrian Austin 		break;
775272b5eddSBrian Austin 	case SND_SOC_DAIFMT_LEFT_J:
776272b5eddSBrian Austin 		cs42l56->iface_fmt = CS42L56_DIG_FMT_LEFT_J;
777272b5eddSBrian Austin 		break;
778272b5eddSBrian Austin 	default:
779272b5eddSBrian Austin 		return -EINVAL;
780272b5eddSBrian Austin 	}
781272b5eddSBrian Austin 
782272b5eddSBrian Austin 	/* sclk inversion */
783272b5eddSBrian Austin 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
784272b5eddSBrian Austin 	case SND_SOC_DAIFMT_NB_NF:
785272b5eddSBrian Austin 		cs42l56->iface_inv = 0;
786272b5eddSBrian Austin 		break;
787272b5eddSBrian Austin 	case SND_SOC_DAIFMT_IB_NF:
788272b5eddSBrian Austin 		cs42l56->iface_inv = CS42L56_SCLK_INV;
789272b5eddSBrian Austin 		break;
790272b5eddSBrian Austin 	default:
791272b5eddSBrian Austin 		return -EINVAL;
792272b5eddSBrian Austin 	}
793272b5eddSBrian Austin 
794e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
795272b5eddSBrian Austin 			    CS42L56_MS_MODE_MASK, cs42l56->iface);
796e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_SERIAL_FMT,
797272b5eddSBrian Austin 			    CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt);
798e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
799272b5eddSBrian Austin 			    CS42L56_SCLK_INV_MASK, cs42l56->iface_inv);
800272b5eddSBrian Austin 	return 0;
801272b5eddSBrian Austin }
802272b5eddSBrian Austin 
cs42l56_mute(struct snd_soc_dai * dai,int mute,int direction)80303c0f1b5SKuninori Morimoto static int cs42l56_mute(struct snd_soc_dai *dai, int mute, int direction)
804272b5eddSBrian Austin {
805e48f7466SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
806272b5eddSBrian Austin 
807272b5eddSBrian Austin 	if (mute) {
808272b5eddSBrian Austin 		/* Hit the DSP Mixer first */
809e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_DSP_MUTE_CTL,
810272b5eddSBrian Austin 				    CS42L56_ADCAMIX_MUTE_MASK |
811272b5eddSBrian Austin 				    CS42L56_ADCBMIX_MUTE_MASK |
812272b5eddSBrian Austin 				    CS42L56_PCMAMIX_MUTE_MASK |
813272b5eddSBrian Austin 				    CS42L56_PCMBMIX_MUTE_MASK |
814272b5eddSBrian Austin 				    CS42L56_MSTB_MUTE_MASK |
815272b5eddSBrian Austin 				    CS42L56_MSTA_MUTE_MASK,
8164641c771SAxel Lin 				    CS42L56_MUTE_ALL);
817272b5eddSBrian Austin 		/* Mute ADC's */
818e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_MISC_ADC_CTL,
819272b5eddSBrian Austin 				    CS42L56_ADCA_MUTE_MASK |
820272b5eddSBrian Austin 				    CS42L56_ADCB_MUTE_MASK,
8214641c771SAxel Lin 				    CS42L56_MUTE_ALL);
822272b5eddSBrian Austin 		/* HP And LO */
823e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_HPA_VOLUME,
8244641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
825e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_HPB_VOLUME,
8264641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
827e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_LOA_VOLUME,
8284641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
829e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_LOB_VOLUME,
8304641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
831272b5eddSBrian Austin 	} else {
832e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_DSP_MUTE_CTL,
833272b5eddSBrian Austin 				    CS42L56_ADCAMIX_MUTE_MASK |
834272b5eddSBrian Austin 				    CS42L56_ADCBMIX_MUTE_MASK |
835272b5eddSBrian Austin 				    CS42L56_PCMAMIX_MUTE_MASK |
836272b5eddSBrian Austin 				    CS42L56_PCMBMIX_MUTE_MASK |
837272b5eddSBrian Austin 				    CS42L56_MSTB_MUTE_MASK |
838272b5eddSBrian Austin 				    CS42L56_MSTA_MUTE_MASK,
839272b5eddSBrian Austin 				    CS42L56_UNMUTE);
8404641c771SAxel Lin 
841e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_MISC_ADC_CTL,
842272b5eddSBrian Austin 				    CS42L56_ADCA_MUTE_MASK |
843272b5eddSBrian Austin 				    CS42L56_ADCB_MUTE_MASK,
844272b5eddSBrian Austin 				    CS42L56_UNMUTE);
8454641c771SAxel Lin 
846e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_HPA_VOLUME,
8474641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
848e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_HPB_VOLUME,
8494641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
850e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_LOA_VOLUME,
8514641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
852e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_LOB_VOLUME,
8534641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
854272b5eddSBrian Austin 	}
855272b5eddSBrian Austin 	return 0;
856272b5eddSBrian Austin }
857272b5eddSBrian Austin 
cs42l56_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)858272b5eddSBrian Austin static int cs42l56_pcm_hw_params(struct snd_pcm_substream *substream,
859272b5eddSBrian Austin 				     struct snd_pcm_hw_params *params,
860272b5eddSBrian Austin 				     struct snd_soc_dai *dai)
861272b5eddSBrian Austin {
862e48f7466SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
863e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
864272b5eddSBrian Austin 	int ratio;
865272b5eddSBrian Austin 
866272b5eddSBrian Austin 	ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params));
867272b5eddSBrian Austin 	if (ratio >= 0) {
868e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_CLKCTL_2,
869272b5eddSBrian Austin 				    CS42L56_CLK_RATIO_MASK, ratio);
870272b5eddSBrian Austin 	} else {
871e48f7466SKuninori Morimoto 		dev_err(component->dev, "unsupported mclk/sclk/lrclk ratio\n");
872272b5eddSBrian Austin 		return -EINVAL;
873272b5eddSBrian Austin 	}
874272b5eddSBrian Austin 
875272b5eddSBrian Austin 	return 0;
876272b5eddSBrian Austin }
877272b5eddSBrian Austin 
cs42l56_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)878e48f7466SKuninori Morimoto static int cs42l56_set_bias_level(struct snd_soc_component *component,
879272b5eddSBrian Austin 					enum snd_soc_bias_level level)
880272b5eddSBrian Austin {
881e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
882272b5eddSBrian Austin 	int ret;
883272b5eddSBrian Austin 
884272b5eddSBrian Austin 	switch (level) {
885272b5eddSBrian Austin 	case SND_SOC_BIAS_ON:
886272b5eddSBrian Austin 		break;
887272b5eddSBrian Austin 	case SND_SOC_BIAS_PREPARE:
888e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
889272b5eddSBrian Austin 				    CS42L56_MCLK_DIS_MASK, 0);
890e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
891272b5eddSBrian Austin 				    CS42L56_PDN_ALL_MASK, 0);
892272b5eddSBrian Austin 		break;
893272b5eddSBrian Austin 	case SND_SOC_BIAS_STANDBY:
894e48f7466SKuninori Morimoto 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
895272b5eddSBrian Austin 			regcache_cache_only(cs42l56->regmap, false);
896272b5eddSBrian Austin 			regcache_sync(cs42l56->regmap);
897272b5eddSBrian Austin 			ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
898272b5eddSBrian Austin 						    cs42l56->supplies);
899272b5eddSBrian Austin 			if (ret != 0) {
900272b5eddSBrian Austin 				dev_err(cs42l56->dev,
901272b5eddSBrian Austin 					"Failed to enable regulators: %d\n",
902272b5eddSBrian Austin 					ret);
903272b5eddSBrian Austin 				return ret;
904272b5eddSBrian Austin 			}
905272b5eddSBrian Austin 		}
906e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
907272b5eddSBrian Austin 				    CS42L56_PDN_ALL_MASK, 1);
908272b5eddSBrian Austin 		break;
909272b5eddSBrian Austin 	case SND_SOC_BIAS_OFF:
910e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
911272b5eddSBrian Austin 				    CS42L56_PDN_ALL_MASK, 1);
912e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
913272b5eddSBrian Austin 				    CS42L56_MCLK_DIS_MASK, 1);
914272b5eddSBrian Austin 		regcache_cache_only(cs42l56->regmap, true);
915272b5eddSBrian Austin 		regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
916272b5eddSBrian Austin 						    cs42l56->supplies);
917272b5eddSBrian Austin 		break;
918272b5eddSBrian Austin 	}
919272b5eddSBrian Austin 
920272b5eddSBrian Austin 	return 0;
921272b5eddSBrian Austin }
922272b5eddSBrian Austin 
923272b5eddSBrian Austin #define CS42L56_RATES (SNDRV_PCM_RATE_8000_48000)
924272b5eddSBrian Austin 
925272b5eddSBrian Austin #define CS42L56_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
926272b5eddSBrian Austin 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
927272b5eddSBrian Austin 			SNDRV_PCM_FMTBIT_S32_LE)
928272b5eddSBrian Austin 
929272b5eddSBrian Austin 
93064793047SAxel Lin static const struct snd_soc_dai_ops cs42l56_ops = {
931272b5eddSBrian Austin 	.hw_params	= cs42l56_pcm_hw_params,
93203c0f1b5SKuninori Morimoto 	.mute_stream	= cs42l56_mute,
933272b5eddSBrian Austin 	.set_fmt	= cs42l56_set_dai_fmt,
934272b5eddSBrian Austin 	.set_sysclk	= cs42l56_set_sysclk,
93503c0f1b5SKuninori Morimoto 	.no_capture_mute = 1,
936272b5eddSBrian Austin };
937272b5eddSBrian Austin 
938272b5eddSBrian Austin static struct snd_soc_dai_driver cs42l56_dai = {
939272b5eddSBrian Austin 		.name = "cs42l56",
940272b5eddSBrian Austin 		.playback = {
941272b5eddSBrian Austin 			.stream_name = "HiFi Playback",
942272b5eddSBrian Austin 			.channels_min = 1,
943272b5eddSBrian Austin 			.channels_max = 2,
944272b5eddSBrian Austin 			.rates = CS42L56_RATES,
945272b5eddSBrian Austin 			.formats = CS42L56_FORMATS,
946272b5eddSBrian Austin 		},
947272b5eddSBrian Austin 		.capture = {
948272b5eddSBrian Austin 			.stream_name = "HiFi Capture",
949272b5eddSBrian Austin 			.channels_min = 1,
950272b5eddSBrian Austin 			.channels_max = 2,
951272b5eddSBrian Austin 			.rates = CS42L56_RATES,
952272b5eddSBrian Austin 			.formats = CS42L56_FORMATS,
953272b5eddSBrian Austin 		},
954272b5eddSBrian Austin 		.ops = &cs42l56_ops,
955272b5eddSBrian Austin };
956272b5eddSBrian Austin 
957272b5eddSBrian Austin static int beep_freq[] = {
958272b5eddSBrian Austin 	261, 522, 585, 667, 706, 774, 889, 1000,
959272b5eddSBrian Austin 	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
960272b5eddSBrian Austin };
961272b5eddSBrian Austin 
cs42l56_beep_work(struct work_struct * work)962272b5eddSBrian Austin static void cs42l56_beep_work(struct work_struct *work)
963272b5eddSBrian Austin {
964272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 =
965272b5eddSBrian Austin 		container_of(work, struct cs42l56_private, beep_work);
966e48f7466SKuninori Morimoto 	struct snd_soc_component *component = cs42l56->component;
967e48f7466SKuninori Morimoto 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
968272b5eddSBrian Austin 	int i;
969272b5eddSBrian Austin 	int val = 0;
970272b5eddSBrian Austin 	int best = 0;
971272b5eddSBrian Austin 
972272b5eddSBrian Austin 	if (cs42l56->beep_rate) {
973272b5eddSBrian Austin 		for (i = 0; i < ARRAY_SIZE(beep_freq); i++) {
974272b5eddSBrian Austin 			if (abs(cs42l56->beep_rate - beep_freq[i]) <
975272b5eddSBrian Austin 			    abs(cs42l56->beep_rate - beep_freq[best]))
976272b5eddSBrian Austin 				best = i;
977272b5eddSBrian Austin 		}
978272b5eddSBrian Austin 
979e48f7466SKuninori Morimoto 		dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n",
980272b5eddSBrian Austin 			beep_freq[best], cs42l56->beep_rate);
981272b5eddSBrian Austin 
982272b5eddSBrian Austin 		val = (best << CS42L56_BEEP_RATE_SHIFT);
983272b5eddSBrian Austin 
984272b5eddSBrian Austin 		snd_soc_dapm_enable_pin(dapm, "Beep");
985272b5eddSBrian Austin 	} else {
986e48f7466SKuninori Morimoto 		dev_dbg(component->dev, "Disabling beep\n");
987272b5eddSBrian Austin 		snd_soc_dapm_disable_pin(dapm, "Beep");
988272b5eddSBrian Austin 	}
989272b5eddSBrian Austin 
990e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_BEEP_FREQ_ONTIME,
991272b5eddSBrian Austin 			    CS42L56_BEEP_FREQ_MASK, val);
992272b5eddSBrian Austin 
993272b5eddSBrian Austin 	snd_soc_dapm_sync(dapm);
994272b5eddSBrian Austin }
995272b5eddSBrian Austin 
996272b5eddSBrian Austin /* For usability define a way of injecting beep events for the device -
997272b5eddSBrian Austin  * many systems will not have a keyboard.
998272b5eddSBrian Austin  */
cs42l56_beep_event(struct input_dev * dev,unsigned int type,unsigned int code,int hz)999272b5eddSBrian Austin static int cs42l56_beep_event(struct input_dev *dev, unsigned int type,
1000272b5eddSBrian Austin 			     unsigned int code, int hz)
1001272b5eddSBrian Austin {
1002e48f7466SKuninori Morimoto 	struct snd_soc_component *component = input_get_drvdata(dev);
1003e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
1004272b5eddSBrian Austin 
1005e48f7466SKuninori Morimoto 	dev_dbg(component->dev, "Beep event %x %x\n", code, hz);
1006272b5eddSBrian Austin 
1007272b5eddSBrian Austin 	switch (code) {
1008272b5eddSBrian Austin 	case SND_BELL:
1009272b5eddSBrian Austin 		if (hz)
1010272b5eddSBrian Austin 			hz = 261;
10113371c6f9SGustavo A. R. Silva 		break;
1012272b5eddSBrian Austin 	case SND_TONE:
1013272b5eddSBrian Austin 		break;
1014272b5eddSBrian Austin 	default:
1015272b5eddSBrian Austin 		return -1;
1016272b5eddSBrian Austin 	}
1017272b5eddSBrian Austin 
1018272b5eddSBrian Austin 	/* Kick the beep from a workqueue */
1019272b5eddSBrian Austin 	cs42l56->beep_rate = hz;
1020272b5eddSBrian Austin 	schedule_work(&cs42l56->beep_work);
1021272b5eddSBrian Austin 	return 0;
1022272b5eddSBrian Austin }
1023272b5eddSBrian Austin 
beep_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)10243ef6253cSYueHaibing static ssize_t beep_store(struct device *dev, struct device_attribute *attr,
1025272b5eddSBrian Austin 			  const char *buf, size_t count)
1026272b5eddSBrian Austin {
1027272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = dev_get_drvdata(dev);
1028272b5eddSBrian Austin 	long int time;
1029272b5eddSBrian Austin 	int ret;
1030272b5eddSBrian Austin 
1031272b5eddSBrian Austin 	ret = kstrtol(buf, 10, &time);
1032272b5eddSBrian Austin 	if (ret != 0)
1033272b5eddSBrian Austin 		return ret;
1034272b5eddSBrian Austin 
1035272b5eddSBrian Austin 	input_event(cs42l56->beep, EV_SND, SND_TONE, time);
1036272b5eddSBrian Austin 
1037272b5eddSBrian Austin 	return count;
1038272b5eddSBrian Austin }
1039272b5eddSBrian Austin 
10403ef6253cSYueHaibing static DEVICE_ATTR_WO(beep);
1041272b5eddSBrian Austin 
cs42l56_init_beep(struct snd_soc_component * component)1042e48f7466SKuninori Morimoto static void cs42l56_init_beep(struct snd_soc_component *component)
1043272b5eddSBrian Austin {
1044e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
1045272b5eddSBrian Austin 	int ret;
1046272b5eddSBrian Austin 
1047e48f7466SKuninori Morimoto 	cs42l56->beep = devm_input_allocate_device(component->dev);
1048272b5eddSBrian Austin 	if (!cs42l56->beep) {
1049e48f7466SKuninori Morimoto 		dev_err(component->dev, "Failed to allocate beep device\n");
1050272b5eddSBrian Austin 		return;
1051272b5eddSBrian Austin 	}
1052272b5eddSBrian Austin 
1053272b5eddSBrian Austin 	INIT_WORK(&cs42l56->beep_work, cs42l56_beep_work);
1054272b5eddSBrian Austin 	cs42l56->beep_rate = 0;
1055272b5eddSBrian Austin 
1056272b5eddSBrian Austin 	cs42l56->beep->name = "CS42L56 Beep Generator";
1057e48f7466SKuninori Morimoto 	cs42l56->beep->phys = dev_name(component->dev);
1058272b5eddSBrian Austin 	cs42l56->beep->id.bustype = BUS_I2C;
1059272b5eddSBrian Austin 
1060272b5eddSBrian Austin 	cs42l56->beep->evbit[0] = BIT_MASK(EV_SND);
1061272b5eddSBrian Austin 	cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
1062272b5eddSBrian Austin 	cs42l56->beep->event = cs42l56_beep_event;
1063e48f7466SKuninori Morimoto 	cs42l56->beep->dev.parent = component->dev;
1064e48f7466SKuninori Morimoto 	input_set_drvdata(cs42l56->beep, component);
1065272b5eddSBrian Austin 
1066272b5eddSBrian Austin 	ret = input_register_device(cs42l56->beep);
1067272b5eddSBrian Austin 	if (ret != 0) {
1068272b5eddSBrian Austin 		cs42l56->beep = NULL;
1069e48f7466SKuninori Morimoto 		dev_err(component->dev, "Failed to register beep device\n");
1070272b5eddSBrian Austin 	}
1071272b5eddSBrian Austin 
1072e48f7466SKuninori Morimoto 	ret = device_create_file(component->dev, &dev_attr_beep);
1073272b5eddSBrian Austin 	if (ret != 0) {
1074e48f7466SKuninori Morimoto 		dev_err(component->dev, "Failed to create keyclick file: %d\n",
1075272b5eddSBrian Austin 			ret);
1076272b5eddSBrian Austin 	}
1077272b5eddSBrian Austin }
1078272b5eddSBrian Austin 
cs42l56_free_beep(struct snd_soc_component * component)1079e48f7466SKuninori Morimoto static void cs42l56_free_beep(struct snd_soc_component *component)
1080272b5eddSBrian Austin {
1081e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
1082272b5eddSBrian Austin 
1083e48f7466SKuninori Morimoto 	device_remove_file(component->dev, &dev_attr_beep);
1084272b5eddSBrian Austin 	cancel_work_sync(&cs42l56->beep_work);
1085272b5eddSBrian Austin 	cs42l56->beep = NULL;
1086272b5eddSBrian Austin 
1087e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_BEEP_TONE_CFG,
1088272b5eddSBrian Austin 			    CS42L56_BEEP_EN_MASK, 0);
1089272b5eddSBrian Austin }
1090272b5eddSBrian Austin 
cs42l56_probe(struct snd_soc_component * component)1091e48f7466SKuninori Morimoto static int cs42l56_probe(struct snd_soc_component *component)
1092272b5eddSBrian Austin {
1093e48f7466SKuninori Morimoto 	cs42l56_init_beep(component);
1094272b5eddSBrian Austin 
1095272b5eddSBrian Austin 	return 0;
1096272b5eddSBrian Austin }
1097272b5eddSBrian Austin 
cs42l56_remove(struct snd_soc_component * component)1098e48f7466SKuninori Morimoto static void cs42l56_remove(struct snd_soc_component *component)
1099272b5eddSBrian Austin {
1100e48f7466SKuninori Morimoto 	cs42l56_free_beep(component);
1101272b5eddSBrian Austin }
1102272b5eddSBrian Austin 
1103e48f7466SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_cs42l56 = {
1104272b5eddSBrian Austin 	.probe			= cs42l56_probe,
1105272b5eddSBrian Austin 	.remove			= cs42l56_remove,
1106272b5eddSBrian Austin 	.set_bias_level		= cs42l56_set_bias_level,
1107561828f8SKuninori Morimoto 	.controls		= cs42l56_snd_controls,
1108561828f8SKuninori Morimoto 	.num_controls		= ARRAY_SIZE(cs42l56_snd_controls),
1109272b5eddSBrian Austin 	.dapm_widgets		= cs42l56_dapm_widgets,
1110272b5eddSBrian Austin 	.num_dapm_widgets	= ARRAY_SIZE(cs42l56_dapm_widgets),
1111272b5eddSBrian Austin 	.dapm_routes		= cs42l56_audio_map,
1112272b5eddSBrian Austin 	.num_dapm_routes	= ARRAY_SIZE(cs42l56_audio_map),
1113e48f7466SKuninori Morimoto 	.suspend_bias_off	= 1,
1114e48f7466SKuninori Morimoto 	.idle_bias_on		= 1,
1115e48f7466SKuninori Morimoto 	.use_pmdown_time	= 1,
1116e48f7466SKuninori Morimoto 	.endianness		= 1,
1117272b5eddSBrian Austin };
1118272b5eddSBrian Austin 
1119cf0efa1cSKrzysztof Kozlowski static const struct regmap_config cs42l56_regmap = {
1120272b5eddSBrian Austin 	.reg_bits = 8,
1121272b5eddSBrian Austin 	.val_bits = 8,
1122272b5eddSBrian Austin 
1123272b5eddSBrian Austin 	.max_register = CS42L56_MAX_REGISTER,
1124272b5eddSBrian Austin 	.reg_defaults = cs42l56_reg_defaults,
1125272b5eddSBrian Austin 	.num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults),
1126272b5eddSBrian Austin 	.readable_reg = cs42l56_readable_register,
1127272b5eddSBrian Austin 	.volatile_reg = cs42l56_volatile_register,
1128*cb8ac265SMark Brown 	.cache_type = REGCACHE_MAPLE,
1129272b5eddSBrian Austin };
1130272b5eddSBrian Austin 
cs42l56_handle_of_data(struct i2c_client * i2c_client,struct cs42l56_platform_data * pdata)1131272b5eddSBrian Austin static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
1132272b5eddSBrian Austin 				    struct cs42l56_platform_data *pdata)
1133272b5eddSBrian Austin {
1134272b5eddSBrian Austin 	struct device_node *np = i2c_client->dev.of_node;
1135272b5eddSBrian Austin 	u32 val32;
1136272b5eddSBrian Austin 
1137272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain1a-reference-cfg"))
1138272b5eddSBrian Austin 		pdata->ain1a_ref_cfg = true;
1139272b5eddSBrian Austin 
1140272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain2a-reference-cfg"))
1141272b5eddSBrian Austin 		pdata->ain2a_ref_cfg = true;
1142272b5eddSBrian Austin 
1143272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain1b-reference-cfg"))
1144272b5eddSBrian Austin 		pdata->ain1b_ref_cfg = true;
1145272b5eddSBrian Austin 
1146272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain2b-reference-cfg"))
1147272b5eddSBrian Austin 		pdata->ain2b_ref_cfg = true;
1148272b5eddSBrian Austin 
1149272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,micbias-lvl", &val32) >= 0)
1150272b5eddSBrian Austin 		pdata->micbias_lvl = val32;
1151272b5eddSBrian Austin 
1152272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,chgfreq-divisor", &val32) >= 0)
1153272b5eddSBrian Austin 		pdata->chgfreq = val32;
1154272b5eddSBrian Austin 
1155272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,adaptive-pwr-cfg", &val32) >= 0)
1156272b5eddSBrian Austin 		pdata->adaptive_pwr = val32;
1157272b5eddSBrian Austin 
1158272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
1159272b5eddSBrian Austin 		pdata->hpfa_freq = val32;
1160272b5eddSBrian Austin 
1161272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
1162272b5eddSBrian Austin 		pdata->hpfb_freq = val32;
1163272b5eddSBrian Austin 
1164272b5eddSBrian Austin 	pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0);
1165272b5eddSBrian Austin 
1166272b5eddSBrian Austin 	return 0;
1167272b5eddSBrian Austin }
1168272b5eddSBrian Austin 
cs42l56_i2c_probe(struct i2c_client * i2c_client)11694a404345SStephen Kitt static int cs42l56_i2c_probe(struct i2c_client *i2c_client)
1170272b5eddSBrian Austin {
1171272b5eddSBrian Austin 	struct cs42l56_private *cs42l56;
1172272b5eddSBrian Austin 	struct cs42l56_platform_data *pdata =
1173272b5eddSBrian Austin 		dev_get_platdata(&i2c_client->dev);
1174272b5eddSBrian Austin 	int ret, i;
11750e49a4deSCharles Keepax 	unsigned int devid;
1176272b5eddSBrian Austin 	unsigned int alpha_rev, metal_rev;
1177272b5eddSBrian Austin 	unsigned int reg;
1178272b5eddSBrian Austin 
1179e8d8b98cSMarkus Elfring 	cs42l56 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l56), GFP_KERNEL);
1180272b5eddSBrian Austin 	if (cs42l56 == NULL)
1181272b5eddSBrian Austin 		return -ENOMEM;
1182272b5eddSBrian Austin 	cs42l56->dev = &i2c_client->dev;
1183272b5eddSBrian Austin 
1184272b5eddSBrian Austin 	cs42l56->regmap = devm_regmap_init_i2c(i2c_client, &cs42l56_regmap);
1185272b5eddSBrian Austin 	if (IS_ERR(cs42l56->regmap)) {
1186272b5eddSBrian Austin 		ret = PTR_ERR(cs42l56->regmap);
1187272b5eddSBrian Austin 		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
1188272b5eddSBrian Austin 		return ret;
1189272b5eddSBrian Austin 	}
1190272b5eddSBrian Austin 
1191272b5eddSBrian Austin 	if (pdata) {
1192272b5eddSBrian Austin 		cs42l56->pdata = *pdata;
1193272b5eddSBrian Austin 	} else {
1194272b5eddSBrian Austin 		if (i2c_client->dev.of_node) {
1195272b5eddSBrian Austin 			ret = cs42l56_handle_of_data(i2c_client,
1196272b5eddSBrian Austin 						     &cs42l56->pdata);
1197272b5eddSBrian Austin 			if (ret != 0)
1198272b5eddSBrian Austin 				return ret;
1199272b5eddSBrian Austin 		}
1200272b5eddSBrian Austin 	}
1201272b5eddSBrian Austin 
1202272b5eddSBrian Austin 	if (cs42l56->pdata.gpio_nreset) {
1203272b5eddSBrian Austin 		ret = gpio_request_one(cs42l56->pdata.gpio_nreset,
1204272b5eddSBrian Austin 				       GPIOF_OUT_INIT_HIGH, "CS42L56 /RST");
1205272b5eddSBrian Austin 		if (ret < 0) {
1206272b5eddSBrian Austin 			dev_err(&i2c_client->dev,
1207272b5eddSBrian Austin 				"Failed to request /RST %d: %d\n",
1208272b5eddSBrian Austin 				cs42l56->pdata.gpio_nreset, ret);
1209272b5eddSBrian Austin 			return ret;
1210272b5eddSBrian Austin 		}
1211272b5eddSBrian Austin 		gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0);
1212272b5eddSBrian Austin 		gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1);
1213272b5eddSBrian Austin 	}
1214272b5eddSBrian Austin 
1215272b5eddSBrian Austin 
1216272b5eddSBrian Austin 	i2c_set_clientdata(i2c_client, cs42l56);
1217272b5eddSBrian Austin 
1218272b5eddSBrian Austin 	for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++)
1219272b5eddSBrian Austin 		cs42l56->supplies[i].supply = cs42l56_supply_names[i];
1220272b5eddSBrian Austin 
1221272b5eddSBrian Austin 	ret = devm_regulator_bulk_get(&i2c_client->dev,
1222272b5eddSBrian Austin 				      ARRAY_SIZE(cs42l56->supplies),
1223272b5eddSBrian Austin 				      cs42l56->supplies);
1224272b5eddSBrian Austin 	if (ret != 0) {
1225272b5eddSBrian Austin 		dev_err(&i2c_client->dev,
1226272b5eddSBrian Austin 			"Failed to request supplies: %d\n", ret);
1227272b5eddSBrian Austin 		return ret;
1228272b5eddSBrian Austin 	}
1229272b5eddSBrian Austin 
1230272b5eddSBrian Austin 	ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
1231272b5eddSBrian Austin 				    cs42l56->supplies);
1232272b5eddSBrian Austin 	if (ret != 0) {
1233272b5eddSBrian Austin 		dev_err(&i2c_client->dev,
1234272b5eddSBrian Austin 			"Failed to enable supplies: %d\n", ret);
1235272b5eddSBrian Austin 		return ret;
1236272b5eddSBrian Austin 	}
1237272b5eddSBrian Austin 
1238272b5eddSBrian Austin 	ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, &reg);
12390e49a4deSCharles Keepax 	if (ret) {
12400e49a4deSCharles Keepax 		dev_err(&i2c_client->dev, "Failed to read chip ID: %d\n", ret);
12411a9fa954SZheyu Ma 		goto err_enable;
12420e49a4deSCharles Keepax 	}
12430e49a4deSCharles Keepax 
1244272b5eddSBrian Austin 	devid = reg & CS42L56_CHIP_ID_MASK;
1245272b5eddSBrian Austin 	if (devid != CS42L56_DEVID) {
1246272b5eddSBrian Austin 		dev_err(&i2c_client->dev,
1247272b5eddSBrian Austin 			"CS42L56 Device ID (%X). Expected %X\n",
1248272b5eddSBrian Austin 			devid, CS42L56_DEVID);
1249856fe64dSDan Carpenter 		ret = -EINVAL;
1250272b5eddSBrian Austin 		goto err_enable;
1251272b5eddSBrian Austin 	}
1252272b5eddSBrian Austin 	alpha_rev = reg & CS42L56_AREV_MASK;
1253272b5eddSBrian Austin 	metal_rev = reg & CS42L56_MTLREV_MASK;
1254272b5eddSBrian Austin 
1255272b5eddSBrian Austin 	dev_info(&i2c_client->dev, "Cirrus Logic CS42L56 ");
1256272b5eddSBrian Austin 	dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n",
1257272b5eddSBrian Austin 		 alpha_rev, metal_rev);
1258272b5eddSBrian Austin 
1259272b5eddSBrian Austin 	if (cs42l56->pdata.ain1a_ref_cfg)
1260272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
12618c317fafSFlorian Vaussard 				   CS42L56_AIN1A_REF_MASK,
12628c317fafSFlorian Vaussard 				   CS42L56_AIN1A_REF_MASK);
1263272b5eddSBrian Austin 
1264272b5eddSBrian Austin 	if (cs42l56->pdata.ain1b_ref_cfg)
1265272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
12668c317fafSFlorian Vaussard 				   CS42L56_AIN1B_REF_MASK,
12678c317fafSFlorian Vaussard 				   CS42L56_AIN1B_REF_MASK);
1268272b5eddSBrian Austin 
1269272b5eddSBrian Austin 	if (cs42l56->pdata.ain2a_ref_cfg)
1270272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
12718c317fafSFlorian Vaussard 				   CS42L56_AIN2A_REF_MASK,
12728c317fafSFlorian Vaussard 				   CS42L56_AIN2A_REF_MASK);
1273272b5eddSBrian Austin 
1274272b5eddSBrian Austin 	if (cs42l56->pdata.ain2b_ref_cfg)
1275272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
12768c317fafSFlorian Vaussard 				   CS42L56_AIN2B_REF_MASK,
12778c317fafSFlorian Vaussard 				   CS42L56_AIN2B_REF_MASK);
1278272b5eddSBrian Austin 
1279272b5eddSBrian Austin 	if (cs42l56->pdata.micbias_lvl)
1280272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL,
1281272b5eddSBrian Austin 				   CS42L56_MIC_BIAS_MASK,
1282272b5eddSBrian Austin 				cs42l56->pdata.micbias_lvl);
1283272b5eddSBrian Austin 
1284272b5eddSBrian Austin 	if (cs42l56->pdata.chgfreq)
1285272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
1286272b5eddSBrian Austin 				   CS42L56_CHRG_FREQ_MASK,
1287272b5eddSBrian Austin 				cs42l56->pdata.chgfreq);
1288272b5eddSBrian Austin 
1289272b5eddSBrian Austin 	if (cs42l56->pdata.hpfb_freq)
1290272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
1291272b5eddSBrian Austin 				   CS42L56_HPFB_FREQ_MASK,
1292272b5eddSBrian Austin 				cs42l56->pdata.hpfb_freq);
1293272b5eddSBrian Austin 
1294272b5eddSBrian Austin 	if (cs42l56->pdata.hpfa_freq)
1295272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
1296272b5eddSBrian Austin 				   CS42L56_HPFA_FREQ_MASK,
1297272b5eddSBrian Austin 				cs42l56->pdata.hpfa_freq);
1298272b5eddSBrian Austin 
1299272b5eddSBrian Austin 	if (cs42l56->pdata.adaptive_pwr)
1300272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
1301272b5eddSBrian Austin 				   CS42L56_ADAPT_PWR_MASK,
1302272b5eddSBrian Austin 				cs42l56->pdata.adaptive_pwr);
1303272b5eddSBrian Austin 
1304e48f7466SKuninori Morimoto 	ret =  devm_snd_soc_register_component(&i2c_client->dev,
1305e48f7466SKuninori Morimoto 			&soc_component_dev_cs42l56, &cs42l56_dai, 1);
1306272b5eddSBrian Austin 	if (ret < 0)
1307856fe64dSDan Carpenter 		goto err_enable;
1308272b5eddSBrian Austin 
1309272b5eddSBrian Austin 	return 0;
1310272b5eddSBrian Austin 
1311272b5eddSBrian Austin err_enable:
1312272b5eddSBrian Austin 	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
1313272b5eddSBrian Austin 			       cs42l56->supplies);
1314272b5eddSBrian Austin 	return ret;
1315272b5eddSBrian Austin }
1316272b5eddSBrian Austin 
cs42l56_i2c_remove(struct i2c_client * client)1317ed5c2f5fSUwe Kleine-König static void cs42l56_i2c_remove(struct i2c_client *client)
1318272b5eddSBrian Austin {
1319272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = i2c_get_clientdata(client);
1320272b5eddSBrian Austin 
1321272b5eddSBrian Austin 	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
1322272b5eddSBrian Austin 			       cs42l56->supplies);
1323272b5eddSBrian Austin }
1324272b5eddSBrian Austin 
1325272b5eddSBrian Austin static const struct of_device_id cs42l56_of_match[] = {
1326272b5eddSBrian Austin 	{ .compatible = "cirrus,cs42l56", },
1327272b5eddSBrian Austin 	{ }
1328272b5eddSBrian Austin };
1329272b5eddSBrian Austin MODULE_DEVICE_TABLE(of, cs42l56_of_match);
1330272b5eddSBrian Austin 
1331272b5eddSBrian Austin 
1332272b5eddSBrian Austin static const struct i2c_device_id cs42l56_id[] = {
1333272b5eddSBrian Austin 	{ "cs42l56", 0 },
1334272b5eddSBrian Austin 	{ }
1335272b5eddSBrian Austin };
1336272b5eddSBrian Austin MODULE_DEVICE_TABLE(i2c, cs42l56_id);
1337272b5eddSBrian Austin 
1338272b5eddSBrian Austin static struct i2c_driver cs42l56_i2c_driver = {
1339272b5eddSBrian Austin 	.driver = {
1340272b5eddSBrian Austin 		.name = "cs42l56",
1341272b5eddSBrian Austin 		.of_match_table = cs42l56_of_match,
1342272b5eddSBrian Austin 	},
1343272b5eddSBrian Austin 	.id_table = cs42l56_id,
13449abcd240SUwe Kleine-König 	.probe =    cs42l56_i2c_probe,
1345272b5eddSBrian Austin 	.remove =   cs42l56_i2c_remove,
1346272b5eddSBrian Austin };
1347272b5eddSBrian Austin 
1348272b5eddSBrian Austin module_i2c_driver(cs42l56_i2c_driver);
1349272b5eddSBrian Austin 
1350272b5eddSBrian Austin MODULE_DESCRIPTION("ASoC CS42L56 driver");
1351272b5eddSBrian Austin MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
1352272b5eddSBrian Austin MODULE_LICENSE("GPL");
1353