xref: /openbmc/linux/sound/soc/codecs/cs42l56.c (revision 37879bafc2e0932279ad440d5a81c323e0c5c58c)
1272b5eddSBrian Austin /*
2272b5eddSBrian Austin  * cs42l56.c -- CS42L56 ALSA SoC audio driver
3272b5eddSBrian Austin  *
4272b5eddSBrian Austin  * Copyright 2014 CirrusLogic, Inc.
5272b5eddSBrian Austin  *
6272b5eddSBrian Austin  * Author: Brian Austin <brian.austin@cirrus.com>
7272b5eddSBrian Austin  *
8272b5eddSBrian Austin  * This program is free software; you can redistribute it and/or modify
9272b5eddSBrian Austin  * it under the terms of the GNU General Public License version 2 as
10272b5eddSBrian Austin  * published by the Free Software Foundation.
11272b5eddSBrian Austin  *
12272b5eddSBrian Austin  */
13272b5eddSBrian Austin 
14272b5eddSBrian Austin #include <linux/module.h>
15272b5eddSBrian Austin #include <linux/moduleparam.h>
16272b5eddSBrian Austin #include <linux/kernel.h>
17272b5eddSBrian Austin #include <linux/init.h>
18272b5eddSBrian Austin #include <linux/delay.h>
19272b5eddSBrian Austin #include <linux/pm.h>
20272b5eddSBrian Austin #include <linux/i2c.h>
21272b5eddSBrian Austin #include <linux/input.h>
22272b5eddSBrian Austin #include <linux/regmap.h>
23272b5eddSBrian Austin #include <linux/slab.h>
24272b5eddSBrian Austin #include <linux/workqueue.h>
25272b5eddSBrian Austin #include <linux/platform_device.h>
26272b5eddSBrian Austin #include <linux/regulator/consumer.h>
27272b5eddSBrian Austin #include <linux/of_device.h>
28272b5eddSBrian Austin #include <linux/of_gpio.h>
29272b5eddSBrian Austin #include <sound/core.h>
30272b5eddSBrian Austin #include <sound/pcm.h>
31272b5eddSBrian Austin #include <sound/pcm_params.h>
32272b5eddSBrian Austin #include <sound/soc.h>
33272b5eddSBrian Austin #include <sound/soc-dapm.h>
34272b5eddSBrian Austin #include <sound/initval.h>
35272b5eddSBrian Austin #include <sound/tlv.h>
36272b5eddSBrian Austin #include <sound/cs42l56.h>
37272b5eddSBrian Austin #include "cs42l56.h"
38272b5eddSBrian Austin 
39272b5eddSBrian Austin #define CS42L56_NUM_SUPPLIES 3
40272b5eddSBrian Austin static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = {
41272b5eddSBrian Austin 	"VA",
42272b5eddSBrian Austin 	"VCP",
43272b5eddSBrian Austin 	"VLDO",
44272b5eddSBrian Austin };
45272b5eddSBrian Austin 
46272b5eddSBrian Austin struct  cs42l56_private {
47272b5eddSBrian Austin 	struct regmap *regmap;
48272b5eddSBrian Austin 	struct snd_soc_codec *codec;
49272b5eddSBrian Austin 	struct device *dev;
50272b5eddSBrian Austin 	struct cs42l56_platform_data pdata;
51272b5eddSBrian Austin 	struct regulator_bulk_data supplies[CS42L56_NUM_SUPPLIES];
52272b5eddSBrian Austin 	u32 mclk;
53272b5eddSBrian Austin 	u8 mclk_prediv;
54272b5eddSBrian Austin 	u8 mclk_div2;
55272b5eddSBrian Austin 	u8 mclk_ratio;
56272b5eddSBrian Austin 	u8 iface;
57272b5eddSBrian Austin 	u8 iface_fmt;
58272b5eddSBrian Austin 	u8 iface_inv;
59272b5eddSBrian Austin #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
60272b5eddSBrian Austin 	struct input_dev *beep;
61272b5eddSBrian Austin 	struct work_struct beep_work;
62272b5eddSBrian Austin 	int beep_rate;
63272b5eddSBrian Austin #endif
64272b5eddSBrian Austin };
65272b5eddSBrian Austin 
66272b5eddSBrian Austin static const struct reg_default cs42l56_reg_defaults[] = {
67272b5eddSBrian Austin 	{ 1, 0x56 },	/* r01	- ID 1 */
68272b5eddSBrian Austin 	{ 2, 0x04 },	/* r02	- ID 2 */
69272b5eddSBrian Austin 	{ 3, 0x7f },	/* r03	- Power Ctl 1 */
70272b5eddSBrian Austin 	{ 4, 0xff },	/* r04	- Power Ctl 2 */
71272b5eddSBrian Austin 	{ 5, 0x00 },	/* ro5	- Clocking Ctl 1 */
72272b5eddSBrian Austin 	{ 6, 0x0b },	/* r06	- Clocking Ctl 2 */
73272b5eddSBrian Austin 	{ 7, 0x00 },	/* r07	- Serial Format */
74272b5eddSBrian Austin 	{ 8, 0x05 },	/* r08	- Class H Ctl */
75272b5eddSBrian Austin 	{ 9, 0x0c },	/* r09	- Misc Ctl */
76272b5eddSBrian Austin 	{ 10, 0x80 },	/* r0a	- INT Status */
77272b5eddSBrian Austin 	{ 11, 0x00 },	/* r0b	- Playback Ctl */
78272b5eddSBrian Austin 	{ 12, 0x0c },	/* r0c	- DSP Mute Ctl */
79272b5eddSBrian Austin 	{ 13, 0x00 },	/* r0d	- ADCA Mixer Volume */
80272b5eddSBrian Austin 	{ 14, 0x00 },	/* r0e	- ADCB Mixer Volume */
81272b5eddSBrian Austin 	{ 15, 0x00 },	/* r0f	- PCMA Mixer Volume */
82272b5eddSBrian Austin 	{ 16, 0x00 },	/* r10	- PCMB Mixer Volume */
83272b5eddSBrian Austin 	{ 17, 0x00 },	/* r11	- Analog Input Advisory Volume */
84272b5eddSBrian Austin 	{ 18, 0x00 },	/* r12	- Digital Input Advisory Volume */
85272b5eddSBrian Austin 	{ 19, 0x00 },	/* r13	- Master A Volume */
86272b5eddSBrian Austin 	{ 20, 0x00 },	/* r14	- Master B Volume */
87272b5eddSBrian Austin 	{ 21, 0x00 },	/* r15	- Beep Freq / On Time */
88272b5eddSBrian Austin 	{ 22, 0x00 },	/* r16	- Beep Volume / Off Time */
89272b5eddSBrian Austin 	{ 23, 0x00 },	/* r17	- Beep Tone Ctl */
90272b5eddSBrian Austin 	{ 24, 0x88 },	/* r18	- Tone Ctl */
91272b5eddSBrian Austin 	{ 25, 0x00 },	/* r19	- Channel Mixer & Swap */
92272b5eddSBrian Austin 	{ 26, 0x00 },	/* r1a	- AIN Ref Config / ADC Mux */
93272b5eddSBrian Austin 	{ 27, 0xa0 },	/* r1b	- High-Pass Filter Ctl */
94272b5eddSBrian Austin 	{ 28, 0x00 },	/* r1c	- Misc ADC Ctl */
95272b5eddSBrian Austin 	{ 29, 0x00 },	/* r1d	- Gain & Bias Ctl */
96272b5eddSBrian Austin 	{ 30, 0x00 },	/* r1e	- PGAA Mux & Volume */
97272b5eddSBrian Austin 	{ 31, 0x00 },	/* r1f	- PGAB Mux & Volume */
98272b5eddSBrian Austin 	{ 32, 0x00 },	/* r20	- ADCA Attenuator */
99272b5eddSBrian Austin 	{ 33, 0x00 },	/* r21	- ADCB Attenuator */
100272b5eddSBrian Austin 	{ 34, 0x00 },	/* r22	- ALC Enable & Attack Rate */
101272b5eddSBrian Austin 	{ 35, 0xbf },	/* r23	- ALC Release Rate */
102272b5eddSBrian Austin 	{ 36, 0x00 },	/* r24	- ALC Threshold */
103272b5eddSBrian Austin 	{ 37, 0x00 },	/* r25	- Noise Gate Ctl */
104272b5eddSBrian Austin 	{ 38, 0x00 },	/* r26	- ALC, Limiter, SFT, ZeroCross */
105272b5eddSBrian Austin 	{ 39, 0x00 },	/* r27	- Analog Mute, LO & HP Mux */
106272b5eddSBrian Austin 	{ 40, 0x00 },	/* r28	- HP A Volume */
107272b5eddSBrian Austin 	{ 41, 0x00 },	/* r29	- HP B Volume */
108272b5eddSBrian Austin 	{ 42, 0x00 },	/* r2a	- LINEOUT A Volume */
109272b5eddSBrian Austin 	{ 43, 0x00 },	/* r2b	- LINEOUT B Volume */
110272b5eddSBrian Austin 	{ 44, 0x00 },	/* r2c	- Limit Threshold Ctl */
111272b5eddSBrian Austin 	{ 45, 0x7f },	/* r2d	- Limiter Ctl & Release Rate */
112272b5eddSBrian Austin 	{ 46, 0x00 },	/* r2e	- Limiter Attack Rate */
113272b5eddSBrian Austin };
114272b5eddSBrian Austin 
115272b5eddSBrian Austin static bool cs42l56_readable_register(struct device *dev, unsigned int reg)
116272b5eddSBrian Austin {
117272b5eddSBrian Austin 	switch (reg) {
118272b5eddSBrian Austin 	case CS42L56_CHIP_ID_1:
119272b5eddSBrian Austin 	case CS42L56_CHIP_ID_2:
120272b5eddSBrian Austin 	case CS42L56_PWRCTL_1:
121272b5eddSBrian Austin 	case CS42L56_PWRCTL_2:
122272b5eddSBrian Austin 	case CS42L56_CLKCTL_1:
123272b5eddSBrian Austin 	case CS42L56_CLKCTL_2:
124272b5eddSBrian Austin 	case CS42L56_SERIAL_FMT:
125272b5eddSBrian Austin 	case CS42L56_CLASSH_CTL:
126272b5eddSBrian Austin 	case CS42L56_MISC_CTL:
127272b5eddSBrian Austin 	case CS42L56_INT_STATUS:
128272b5eddSBrian Austin 	case CS42L56_PLAYBACK_CTL:
129272b5eddSBrian Austin 	case CS42L56_DSP_MUTE_CTL:
130272b5eddSBrian Austin 	case CS42L56_ADCA_MIX_VOLUME:
131272b5eddSBrian Austin 	case CS42L56_ADCB_MIX_VOLUME:
132272b5eddSBrian Austin 	case CS42L56_PCMA_MIX_VOLUME:
133272b5eddSBrian Austin 	case CS42L56_PCMB_MIX_VOLUME:
134272b5eddSBrian Austin 	case CS42L56_ANAINPUT_ADV_VOLUME:
135272b5eddSBrian Austin 	case CS42L56_DIGINPUT_ADV_VOLUME:
136272b5eddSBrian Austin 	case CS42L56_MASTER_A_VOLUME:
137272b5eddSBrian Austin 	case CS42L56_MASTER_B_VOLUME:
138272b5eddSBrian Austin 	case CS42L56_BEEP_FREQ_ONTIME:
139272b5eddSBrian Austin 	case CS42L56_BEEP_FREQ_OFFTIME:
140272b5eddSBrian Austin 	case CS42L56_BEEP_TONE_CFG:
141272b5eddSBrian Austin 	case CS42L56_TONE_CTL:
142272b5eddSBrian Austin 	case CS42L56_CHAN_MIX_SWAP:
143272b5eddSBrian Austin 	case CS42L56_AIN_REFCFG_ADC_MUX:
144272b5eddSBrian Austin 	case CS42L56_HPF_CTL:
145272b5eddSBrian Austin 	case CS42L56_MISC_ADC_CTL:
146272b5eddSBrian Austin 	case CS42L56_GAIN_BIAS_CTL:
147272b5eddSBrian Austin 	case CS42L56_PGAA_MUX_VOLUME:
148272b5eddSBrian Austin 	case CS42L56_PGAB_MUX_VOLUME:
149272b5eddSBrian Austin 	case CS42L56_ADCA_ATTENUATOR:
150272b5eddSBrian Austin 	case CS42L56_ADCB_ATTENUATOR:
151272b5eddSBrian Austin 	case CS42L56_ALC_EN_ATTACK_RATE:
152272b5eddSBrian Austin 	case CS42L56_ALC_RELEASE_RATE:
153272b5eddSBrian Austin 	case CS42L56_ALC_THRESHOLD:
154272b5eddSBrian Austin 	case CS42L56_NOISE_GATE_CTL:
155272b5eddSBrian Austin 	case CS42L56_ALC_LIM_SFT_ZC:
156272b5eddSBrian Austin 	case CS42L56_AMUTE_HPLO_MUX:
157272b5eddSBrian Austin 	case CS42L56_HPA_VOLUME:
158272b5eddSBrian Austin 	case CS42L56_HPB_VOLUME:
159272b5eddSBrian Austin 	case CS42L56_LOA_VOLUME:
160272b5eddSBrian Austin 	case CS42L56_LOB_VOLUME:
161272b5eddSBrian Austin 	case CS42L56_LIM_THRESHOLD_CTL:
162272b5eddSBrian Austin 	case CS42L56_LIM_CTL_RELEASE_RATE:
163272b5eddSBrian Austin 	case CS42L56_LIM_ATTACK_RATE:
164272b5eddSBrian Austin 		return true;
165272b5eddSBrian Austin 	default:
166272b5eddSBrian Austin 		return false;
167272b5eddSBrian Austin 	}
168272b5eddSBrian Austin }
169272b5eddSBrian Austin 
170272b5eddSBrian Austin static bool cs42l56_volatile_register(struct device *dev, unsigned int reg)
171272b5eddSBrian Austin {
172272b5eddSBrian Austin 	switch (reg) {
173272b5eddSBrian Austin 	case CS42L56_INT_STATUS:
174c2b49ae6SBrian Austin 		return true;
175272b5eddSBrian Austin 	default:
176c2b49ae6SBrian Austin 		return false;
177272b5eddSBrian Austin 	}
178272b5eddSBrian Austin }
179272b5eddSBrian Austin 
180272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(beep_tlv, -5000, 200, 0);
181272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(hl_tlv, -6000, 50, 0);
182272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(adv_tlv, -10200, 50, 0);
183272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, 0);
184272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
185272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0);
186272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
187272b5eddSBrian Austin 
188*37879bafSLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(ngnb_tlv,
189272b5eddSBrian Austin 	0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0),
190*37879bafSLars-Peter Clausen 	2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0)
191*37879bafSLars-Peter Clausen );
192*37879bafSLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(ngb_tlv,
193272b5eddSBrian Austin 	0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0),
194*37879bafSLars-Peter Clausen 	3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0)
195*37879bafSLars-Peter Clausen );
196*37879bafSLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(alc_tlv,
197272b5eddSBrian Austin 	0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
198*37879bafSLars-Peter Clausen 	3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
199*37879bafSLars-Peter Clausen );
200272b5eddSBrian Austin 
201272b5eddSBrian Austin static const char * const beep_config_text[] = {
202272b5eddSBrian Austin 	"Off", "Single", "Multiple", "Continuous"
203272b5eddSBrian Austin };
204272b5eddSBrian Austin 
205272b5eddSBrian Austin static const struct soc_enum beep_config_enum =
206272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 6,
207272b5eddSBrian Austin 			ARRAY_SIZE(beep_config_text), beep_config_text);
208272b5eddSBrian Austin 
209272b5eddSBrian Austin static const char * const beep_pitch_text[] = {
210272b5eddSBrian Austin 	"C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
211272b5eddSBrian Austin 	"C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
212272b5eddSBrian Austin };
213272b5eddSBrian Austin 
214272b5eddSBrian Austin static const struct soc_enum beep_pitch_enum =
215272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 4,
216272b5eddSBrian Austin 			ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
217272b5eddSBrian Austin 
218272b5eddSBrian Austin static const char * const beep_ontime_text[] = {
219272b5eddSBrian Austin 	"86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
220272b5eddSBrian Austin 	"1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
221272b5eddSBrian Austin 	"3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
222272b5eddSBrian Austin };
223272b5eddSBrian Austin 
224272b5eddSBrian Austin static const struct soc_enum beep_ontime_enum =
225272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 0,
226272b5eddSBrian Austin 			ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
227272b5eddSBrian Austin 
228272b5eddSBrian Austin static const char * const beep_offtime_text[] = {
229272b5eddSBrian Austin 	"1.23 s", "2.58 s", "3.90 s", "5.20 s",
230272b5eddSBrian Austin 	"6.60 s", "8.05 s", "9.35 s", "10.80 s"
231272b5eddSBrian Austin };
232272b5eddSBrian Austin 
233272b5eddSBrian Austin static const struct soc_enum beep_offtime_enum =
234272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_OFFTIME, 5,
235272b5eddSBrian Austin 			ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
236272b5eddSBrian Austin 
237272b5eddSBrian Austin static const char * const beep_treble_text[] = {
238272b5eddSBrian Austin 	"5kHz", "7kHz", "10kHz", "15kHz"
239272b5eddSBrian Austin };
240272b5eddSBrian Austin 
241272b5eddSBrian Austin static const struct soc_enum beep_treble_enum =
242272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 3,
243272b5eddSBrian Austin 			ARRAY_SIZE(beep_treble_text), beep_treble_text);
244272b5eddSBrian Austin 
245272b5eddSBrian Austin static const char * const beep_bass_text[] = {
246272b5eddSBrian Austin 	"50Hz", "100Hz", "200Hz", "250Hz"
247272b5eddSBrian Austin };
248272b5eddSBrian Austin 
249272b5eddSBrian Austin static const struct soc_enum beep_bass_enum =
250272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1,
251272b5eddSBrian Austin 			ARRAY_SIZE(beep_bass_text), beep_bass_text);
252272b5eddSBrian Austin 
253272b5eddSBrian Austin static const char * const adc_swap_text[] = {
254272b5eddSBrian Austin 	"None", "A+B/2", "A-B/2", "Swap"
255272b5eddSBrian Austin };
256272b5eddSBrian Austin 
257272b5eddSBrian Austin static const struct soc_enum adc_swap_enum =
258272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3,
259272b5eddSBrian Austin 			ARRAY_SIZE(adc_swap_text), adc_swap_text);
260272b5eddSBrian Austin 
261272b5eddSBrian Austin static const char * const pgaa_mux_text[] = {
262272b5eddSBrian Austin 	"AIN1A", "AIN2A", "AIN3A"};
263272b5eddSBrian Austin 
264272b5eddSBrian Austin static const struct soc_enum pgaa_mux_enum =
265272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_PGAA_MUX_VOLUME, 0,
266272b5eddSBrian Austin 			      ARRAY_SIZE(pgaa_mux_text),
267272b5eddSBrian Austin 			      pgaa_mux_text);
268272b5eddSBrian Austin 
269272b5eddSBrian Austin static const struct snd_kcontrol_new pgaa_mux =
270272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", pgaa_mux_enum);
271272b5eddSBrian Austin 
272272b5eddSBrian Austin static const char * const pgab_mux_text[] = {
273272b5eddSBrian Austin 	"AIN1B", "AIN2B", "AIN3B"};
274272b5eddSBrian Austin 
275272b5eddSBrian Austin static const struct soc_enum pgab_mux_enum =
276272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_PGAB_MUX_VOLUME, 0,
277272b5eddSBrian Austin 			      ARRAY_SIZE(pgab_mux_text),
278272b5eddSBrian Austin 			      pgab_mux_text);
279272b5eddSBrian Austin 
280272b5eddSBrian Austin static const struct snd_kcontrol_new pgab_mux =
281272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", pgab_mux_enum);
282272b5eddSBrian Austin 
283272b5eddSBrian Austin static const char * const adca_mux_text[] = {
284272b5eddSBrian Austin 	"PGAA", "AIN1A", "AIN2A", "AIN3A"};
285272b5eddSBrian Austin 
286272b5eddSBrian Austin static const struct soc_enum adca_mux_enum =
287272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 0,
288272b5eddSBrian Austin 			      ARRAY_SIZE(adca_mux_text),
289272b5eddSBrian Austin 			      adca_mux_text);
290272b5eddSBrian Austin 
291272b5eddSBrian Austin static const struct snd_kcontrol_new adca_mux =
292272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", adca_mux_enum);
293272b5eddSBrian Austin 
294272b5eddSBrian Austin static const char * const adcb_mux_text[] = {
295272b5eddSBrian Austin 	"PGAB", "AIN1B", "AIN2B", "AIN3B"};
296272b5eddSBrian Austin 
297272b5eddSBrian Austin static const struct soc_enum adcb_mux_enum =
298272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 2,
299272b5eddSBrian Austin 			      ARRAY_SIZE(adcb_mux_text),
300272b5eddSBrian Austin 			      adcb_mux_text);
301272b5eddSBrian Austin 
302272b5eddSBrian Austin static const struct snd_kcontrol_new adcb_mux =
303272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", adcb_mux_enum);
304272b5eddSBrian Austin 
305272b5eddSBrian Austin static const char * const left_swap_text[] = {
306272b5eddSBrian Austin 	"Left", "LR 2", "Right"};
307272b5eddSBrian Austin 
308272b5eddSBrian Austin static const char * const right_swap_text[] = {
309272b5eddSBrian Austin 	"Right", "LR 2", "Left"};
310272b5eddSBrian Austin 
311272b5eddSBrian Austin static const unsigned int swap_values[] = { 0, 1, 3 };
312272b5eddSBrian Austin 
313272b5eddSBrian Austin static const struct soc_enum adca_swap_enum =
314272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 0, 3,
315272b5eddSBrian Austin 			      ARRAY_SIZE(left_swap_text),
316272b5eddSBrian Austin 			      left_swap_text,
317272b5eddSBrian Austin 			      swap_values);
318c4324bfaSBrian Austin static const struct snd_kcontrol_new adca_swap_mux =
319c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", adca_swap_enum);
320272b5eddSBrian Austin 
321272b5eddSBrian Austin static const struct soc_enum pcma_swap_enum =
322272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3,
323272b5eddSBrian Austin 			      ARRAY_SIZE(left_swap_text),
324272b5eddSBrian Austin 			      left_swap_text,
325272b5eddSBrian Austin 			      swap_values);
326c4324bfaSBrian Austin static const struct snd_kcontrol_new pcma_swap_mux =
327c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", pcma_swap_enum);
328272b5eddSBrian Austin 
329272b5eddSBrian Austin static const struct soc_enum adcb_swap_enum =
330272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3,
331272b5eddSBrian Austin 			      ARRAY_SIZE(right_swap_text),
332272b5eddSBrian Austin 			      right_swap_text,
333272b5eddSBrian Austin 			      swap_values);
334c4324bfaSBrian Austin static const struct snd_kcontrol_new adcb_swap_mux =
335c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", adcb_swap_enum);
336272b5eddSBrian Austin 
337272b5eddSBrian Austin static const struct soc_enum pcmb_swap_enum =
338272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3,
339272b5eddSBrian Austin 			      ARRAY_SIZE(right_swap_text),
340272b5eddSBrian Austin 			      right_swap_text,
341272b5eddSBrian Austin 			      swap_values);
342c4324bfaSBrian Austin static const struct snd_kcontrol_new pcmb_swap_mux =
343c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", pcmb_swap_enum);
344272b5eddSBrian Austin 
345272b5eddSBrian Austin static const struct snd_kcontrol_new hpa_switch =
346272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1);
347272b5eddSBrian Austin 
348272b5eddSBrian Austin static const struct snd_kcontrol_new hpb_switch =
349272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 4, 1, 1);
350272b5eddSBrian Austin 
351272b5eddSBrian Austin static const struct snd_kcontrol_new loa_switch =
352272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 2, 1, 1);
353272b5eddSBrian Austin 
354272b5eddSBrian Austin static const struct snd_kcontrol_new lob_switch =
355272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 0, 1, 1);
356272b5eddSBrian Austin 
357272b5eddSBrian Austin static const char * const hploa_input_text[] = {
358272b5eddSBrian Austin 	"DACA", "PGAA"};
359272b5eddSBrian Austin 
360272b5eddSBrian Austin static const struct soc_enum lineouta_input_enum =
361272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 2,
362272b5eddSBrian Austin 			      ARRAY_SIZE(hploa_input_text),
363272b5eddSBrian Austin 			      hploa_input_text);
364272b5eddSBrian Austin 
365272b5eddSBrian Austin static const struct snd_kcontrol_new lineouta_input =
366272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", lineouta_input_enum);
367272b5eddSBrian Austin 
368272b5eddSBrian Austin static const struct soc_enum hpa_input_enum =
369272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 0,
370272b5eddSBrian Austin 			      ARRAY_SIZE(hploa_input_text),
371272b5eddSBrian Austin 			      hploa_input_text);
372272b5eddSBrian Austin 
373272b5eddSBrian Austin static const struct snd_kcontrol_new hpa_input =
374272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", hpa_input_enum);
375272b5eddSBrian Austin 
376272b5eddSBrian Austin static const char * const hplob_input_text[] = {
377272b5eddSBrian Austin 	"DACB", "PGAB"};
378272b5eddSBrian Austin 
379272b5eddSBrian Austin static const struct soc_enum lineoutb_input_enum =
380272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 3,
381272b5eddSBrian Austin 			      ARRAY_SIZE(hplob_input_text),
382272b5eddSBrian Austin 			      hplob_input_text);
383272b5eddSBrian Austin 
384272b5eddSBrian Austin static const struct snd_kcontrol_new lineoutb_input =
385272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", lineoutb_input_enum);
386272b5eddSBrian Austin 
387272b5eddSBrian Austin static const struct soc_enum hpb_input_enum =
388272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 1,
389272b5eddSBrian Austin 			      ARRAY_SIZE(hplob_input_text),
390272b5eddSBrian Austin 			      hplob_input_text);
391272b5eddSBrian Austin 
392272b5eddSBrian Austin static const struct snd_kcontrol_new hpb_input =
393272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", hpb_input_enum);
394272b5eddSBrian Austin 
395272b5eddSBrian Austin static const char * const dig_mux_text[] = {
396272b5eddSBrian Austin 	"ADC", "DSP"};
397272b5eddSBrian Austin 
398272b5eddSBrian Austin static const struct soc_enum dig_mux_enum =
399272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_MISC_CTL, 7,
400272b5eddSBrian Austin 			      ARRAY_SIZE(dig_mux_text),
401272b5eddSBrian Austin 			      dig_mux_text);
402272b5eddSBrian Austin 
403272b5eddSBrian Austin static const struct snd_kcontrol_new dig_mux =
404272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", dig_mux_enum);
405272b5eddSBrian Austin 
406272b5eddSBrian Austin static const char * const hpf_freq_text[] = {
407272b5eddSBrian Austin 	"1.8Hz", "119Hz", "236Hz", "464Hz"
408272b5eddSBrian Austin };
409272b5eddSBrian Austin 
410272b5eddSBrian Austin static const struct soc_enum hpfa_freq_enum =
411272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 0,
412272b5eddSBrian Austin 			ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
413272b5eddSBrian Austin 
414272b5eddSBrian Austin static const struct soc_enum hpfb_freq_enum =
415272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 2,
416272b5eddSBrian Austin 			ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
417272b5eddSBrian Austin 
418272b5eddSBrian Austin static const char * const ng_delay_text[] = {
419272b5eddSBrian Austin 	"50ms", "100ms", "150ms", "200ms"
420272b5eddSBrian Austin };
421272b5eddSBrian Austin 
422272b5eddSBrian Austin static const struct soc_enum ng_delay_enum =
423272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_NOISE_GATE_CTL, 0,
424272b5eddSBrian Austin 			ARRAY_SIZE(ng_delay_text), ng_delay_text);
425272b5eddSBrian Austin 
426272b5eddSBrian Austin static const struct snd_kcontrol_new cs42l56_snd_controls[] = {
427272b5eddSBrian Austin 
428272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME,
429a0465587SBrian Austin 			      CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xE4, adv_tlv),
430272b5eddSBrian Austin 	SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1),
431272b5eddSBrian Austin 
432272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME,
433a0465587SBrian Austin 			      CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv),
434272b5eddSBrian Austin 	SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1),
435272b5eddSBrian Austin 
436272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME,
437a0465587SBrian Austin 			      CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv),
438272b5eddSBrian Austin 	SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1),
439272b5eddSBrian Austin 
440272b5eddSBrian Austin 	SOC_SINGLE_TLV("Analog Advisory Volume",
441272b5eddSBrian Austin 			  CS42L56_ANAINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
442272b5eddSBrian Austin 	SOC_SINGLE_TLV("Digital Advisory Volume",
443272b5eddSBrian Austin 			  CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
444272b5eddSBrian Austin 
445272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME,
446a0465587SBrian Austin 			      CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0x24, pga_tlv),
447272b5eddSBrian Austin 	SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR,
448272b5eddSBrian Austin 			      CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv),
449272b5eddSBrian Austin 	SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1),
450272b5eddSBrian Austin 	SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1),
451272b5eddSBrian Austin 
452272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME,
453a0465587SBrian Austin 			      CS42L56_HPB_VOLUME, 0, 0x84, 0x48, hl_tlv),
454272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME,
455a0465587SBrian Austin 			      CS42L56_LOB_VOLUME, 0, 0x84, 0x48, hl_tlv),
456272b5eddSBrian Austin 
457272b5eddSBrian Austin 	SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL,
458272b5eddSBrian Austin 			0, 0x00, 1, tone_tlv),
459272b5eddSBrian Austin 	SOC_SINGLE_TLV("Treble Shelving Volume", CS42L56_TONE_CTL,
460272b5eddSBrian Austin 			4, 0x00, 1, tone_tlv),
461272b5eddSBrian Austin 
462272b5eddSBrian Austin 	SOC_DOUBLE_TLV("PGA Preamp Volume", CS42L56_GAIN_BIAS_CTL,
463272b5eddSBrian Austin 			4, 6, 0x02, 1, preamp_tlv),
464272b5eddSBrian Austin 
465272b5eddSBrian Austin 	SOC_SINGLE("DSP Switch", CS42L56_PLAYBACK_CTL, 7, 1, 1),
466272b5eddSBrian Austin 	SOC_SINGLE("Gang Playback Switch", CS42L56_PLAYBACK_CTL, 4, 1, 1),
467272b5eddSBrian Austin 	SOC_SINGLE("Gang ADC Switch", CS42L56_MISC_ADC_CTL, 7, 1, 1),
468272b5eddSBrian Austin 	SOC_SINGLE("Gang PGA Switch", CS42L56_MISC_ADC_CTL, 6, 1, 1),
469272b5eddSBrian Austin 
470272b5eddSBrian Austin 	SOC_SINGLE("PCMA Invert", CS42L56_PLAYBACK_CTL, 2, 1, 1),
471272b5eddSBrian Austin 	SOC_SINGLE("PCMB Invert", CS42L56_PLAYBACK_CTL, 3, 1, 1),
472272b5eddSBrian Austin 	SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1),
473272b5eddSBrian Austin 	SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1),
474272b5eddSBrian Austin 
475272b5eddSBrian Austin 	SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1),
476272b5eddSBrian Austin 	SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1),
477272b5eddSBrian Austin 	SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum),
478272b5eddSBrian Austin 	SOC_ENUM("HPFB Corner Freq", hpfb_freq_enum),
479272b5eddSBrian Austin 
480272b5eddSBrian Austin 	SOC_SINGLE("Analog Soft Ramp", CS42L56_MISC_CTL, 4, 1, 1),
481272b5eddSBrian Austin 	SOC_DOUBLE("Analog Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
482272b5eddSBrian Austin 		7, 5, 1, 1),
483272b5eddSBrian Austin 	SOC_SINGLE("Analog Zero Cross", CS42L56_MISC_CTL, 3, 1, 1),
484272b5eddSBrian Austin 	SOC_DOUBLE("Analog Zero Cross Disable", CS42L56_ALC_LIM_SFT_ZC,
485272b5eddSBrian Austin 		6, 4, 1, 1),
486272b5eddSBrian Austin 	SOC_SINGLE("Digital Soft Ramp", CS42L56_MISC_CTL, 2, 1, 1),
487272b5eddSBrian Austin 	SOC_SINGLE("Digital Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
488272b5eddSBrian Austin 		3, 1, 1),
489272b5eddSBrian Austin 
490272b5eddSBrian Austin 	SOC_SINGLE("HL Deemphasis", CS42L56_PLAYBACK_CTL, 6, 1, 1),
491272b5eddSBrian Austin 
492272b5eddSBrian Austin 	SOC_SINGLE("ALC Switch", CS42L56_ALC_EN_ATTACK_RATE, 6, 1, 1),
493272b5eddSBrian Austin 	SOC_SINGLE("ALC Limit All Switch", CS42L56_ALC_RELEASE_RATE, 7, 1, 1),
494272b5eddSBrian Austin 	SOC_SINGLE_RANGE("ALC Attack", CS42L56_ALC_EN_ATTACK_RATE,
495272b5eddSBrian Austin 			0, 0, 0x3f, 0),
496272b5eddSBrian Austin 	SOC_SINGLE_RANGE("ALC Release", CS42L56_ALC_RELEASE_RATE,
497272b5eddSBrian Austin 			0, 0x3f, 0, 0),
498272b5eddSBrian Austin 	SOC_SINGLE_TLV("ALC MAX", CS42L56_ALC_THRESHOLD,
499272b5eddSBrian Austin 			5, 0x07, 1, alc_tlv),
500272b5eddSBrian Austin 	SOC_SINGLE_TLV("ALC MIN", CS42L56_ALC_THRESHOLD,
501272b5eddSBrian Austin 			2, 0x07, 1, alc_tlv),
502272b5eddSBrian Austin 
503272b5eddSBrian Austin 	SOC_SINGLE("Limiter Switch", CS42L56_LIM_CTL_RELEASE_RATE, 7, 1, 1),
504272b5eddSBrian Austin 	SOC_SINGLE("Limit All Switch", CS42L56_LIM_CTL_RELEASE_RATE, 6, 1, 1),
505272b5eddSBrian Austin 	SOC_SINGLE_RANGE("Limiter Attack", CS42L56_LIM_ATTACK_RATE,
506272b5eddSBrian Austin 			0, 0, 0x3f, 0),
507272b5eddSBrian Austin 	SOC_SINGLE_RANGE("Limiter Release", CS42L56_LIM_CTL_RELEASE_RATE,
508272b5eddSBrian Austin 			0, 0x3f, 0, 0),
509272b5eddSBrian Austin 	SOC_SINGLE_TLV("Limiter MAX", CS42L56_LIM_THRESHOLD_CTL,
510272b5eddSBrian Austin 			5, 0x07, 1, alc_tlv),
511272b5eddSBrian Austin 	SOC_SINGLE_TLV("Limiter Cushion", CS42L56_ALC_THRESHOLD,
512272b5eddSBrian Austin 			2, 0x07, 1, alc_tlv),
513272b5eddSBrian Austin 
514272b5eddSBrian Austin 	SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1),
515272b5eddSBrian Austin 	SOC_SINGLE("NG All Switch", CS42L56_NOISE_GATE_CTL, 7, 1, 1),
516272b5eddSBrian Austin 	SOC_SINGLE("NG Boost Switch", CS42L56_NOISE_GATE_CTL, 5, 1, 1),
517272b5eddSBrian Austin 	SOC_SINGLE_TLV("NG Unboost Threshold", CS42L56_NOISE_GATE_CTL,
518272b5eddSBrian Austin 			2, 0x07, 1, ngnb_tlv),
519272b5eddSBrian Austin 	SOC_SINGLE_TLV("NG Boost Threshold", CS42L56_NOISE_GATE_CTL,
520272b5eddSBrian Austin 			2, 0x07, 1, ngb_tlv),
521272b5eddSBrian Austin 	SOC_ENUM("NG Delay", ng_delay_enum),
522272b5eddSBrian Austin 
523272b5eddSBrian Austin 	SOC_ENUM("Beep Config", beep_config_enum),
524272b5eddSBrian Austin 	SOC_ENUM("Beep Pitch", beep_pitch_enum),
525272b5eddSBrian Austin 	SOC_ENUM("Beep on Time", beep_ontime_enum),
526272b5eddSBrian Austin 	SOC_ENUM("Beep off Time", beep_offtime_enum),
527272b5eddSBrian Austin 	SOC_SINGLE_SX_TLV("Beep Volume", CS42L56_BEEP_FREQ_OFFTIME,
528272b5eddSBrian Austin 			0, 0x07, 0x23, beep_tlv),
529272b5eddSBrian Austin 	SOC_SINGLE("Beep Tone Ctl Switch", CS42L56_BEEP_TONE_CFG, 0, 1, 1),
530272b5eddSBrian Austin 	SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
531272b5eddSBrian Austin 	SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
532272b5eddSBrian Austin 
533272b5eddSBrian Austin };
534272b5eddSBrian Austin 
535272b5eddSBrian Austin static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = {
536272b5eddSBrian Austin 
537272b5eddSBrian Austin 	SND_SOC_DAPM_SIGGEN("Beep"),
538272b5eddSBrian Austin 	SND_SOC_DAPM_SUPPLY("VBUF", CS42L56_PWRCTL_1, 5, 1, NULL, 0),
539272b5eddSBrian Austin 	SND_SOC_DAPM_MICBIAS("MIC1 Bias", CS42L56_PWRCTL_1, 4, 1),
540272b5eddSBrian Austin 	SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L56_PWRCTL_1, 3, 1, NULL, 0),
541272b5eddSBrian Austin 
542272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN1A"),
543272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN2A"),
544272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN1B"),
545272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN2B"),
546272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN3A"),
547272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN3B"),
548272b5eddSBrian Austin 
549272b5eddSBrian Austin 	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL,  0,
550272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0),
551272b5eddSBrian Austin 
552272b5eddSBrian Austin 	SND_SOC_DAPM_AIF_IN("SDIN", NULL,  0,
553272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0),
554272b5eddSBrian Austin 
555272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("Digital Output Mux", SND_SOC_NOPM,
556272b5eddSBrian Austin 			 0, 0, &dig_mux),
557272b5eddSBrian Austin 
558272b5eddSBrian Austin 	SND_SOC_DAPM_PGA("PGAA", SND_SOC_NOPM, 0, 0, NULL, 0),
559272b5eddSBrian Austin 	SND_SOC_DAPM_PGA("PGAB", SND_SOC_NOPM, 0, 0, NULL, 0),
560272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("PGAA Input Mux",
561272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0, &pgaa_mux),
562272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("PGAB Input Mux",
563272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0, &pgab_mux),
564272b5eddSBrian Austin 
565272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("ADCA Mux", SND_SOC_NOPM,
566272b5eddSBrian Austin 			 0, 0, &adca_mux),
567272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("ADCB Mux", SND_SOC_NOPM,
568272b5eddSBrian Austin 			 0, 0, &adcb_mux),
569272b5eddSBrian Austin 
570272b5eddSBrian Austin 	SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1),
571272b5eddSBrian Austin 	SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1),
572272b5eddSBrian Austin 
573c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("ADCA Swap Mux", SND_SOC_NOPM, 0, 0,
574c4324bfaSBrian Austin 		&adca_swap_mux),
575c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("ADCB Swap Mux", SND_SOC_NOPM, 0, 0,
576c4324bfaSBrian Austin 		&adcb_swap_mux),
577c4324bfaSBrian Austin 
578c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("PCMA Swap Mux", SND_SOC_NOPM, 0, 0,
579c4324bfaSBrian Austin 		&pcma_swap_mux),
580c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("PCMB Swap Mux", SND_SOC_NOPM, 0, 0,
581c4324bfaSBrian Austin 		&pcmb_swap_mux),
582c4324bfaSBrian Austin 
583272b5eddSBrian Austin 	SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0),
584272b5eddSBrian Austin 	SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0),
585272b5eddSBrian Austin 
586272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("HPA"),
587272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("LOA"),
588272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("HPB"),
589272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("LOB"),
590272b5eddSBrian Austin 
591272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Headphone Right",
592272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 4, 1, &hpb_switch),
593272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Headphone Left",
594272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 6, 1, &hpa_switch),
595272b5eddSBrian Austin 
596272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Lineout Right",
597272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 0, 1, &lob_switch),
598272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Lineout Left",
599272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 2, 1, &loa_switch),
600272b5eddSBrian Austin 
601272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("LINEOUTA Input Mux", SND_SOC_NOPM,
602272b5eddSBrian Austin 			 0, 0, &lineouta_input),
603272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("LINEOUTB Input Mux", SND_SOC_NOPM,
604272b5eddSBrian Austin 			 0, 0, &lineoutb_input),
605272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("HPA Input Mux", SND_SOC_NOPM,
606272b5eddSBrian Austin 			 0, 0, &hpa_input),
607272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("HPB Input Mux", SND_SOC_NOPM,
608272b5eddSBrian Austin 			 0, 0, &hpb_input),
609272b5eddSBrian Austin 
610272b5eddSBrian Austin };
611272b5eddSBrian Austin 
612272b5eddSBrian Austin static const struct snd_soc_dapm_route cs42l56_audio_map[] = {
613272b5eddSBrian Austin 
614272b5eddSBrian Austin 	{"HiFi Capture", "DSP", "Digital Output Mux"},
615272b5eddSBrian Austin 	{"HiFi Capture", "ADC", "Digital Output Mux"},
616272b5eddSBrian Austin 
617272b5eddSBrian Austin 	{"Digital Output Mux", NULL, "ADCA"},
618272b5eddSBrian Austin 	{"Digital Output Mux", NULL, "ADCB"},
619272b5eddSBrian Austin 
620c4324bfaSBrian Austin 	{"ADCB", NULL, "ADCB Swap Mux"},
621c4324bfaSBrian Austin 	{"ADCA", NULL, "ADCA Swap Mux"},
622c4324bfaSBrian Austin 
623c4324bfaSBrian Austin 	{"ADCA Swap Mux", NULL, "ADCA"},
624c4324bfaSBrian Austin 	{"ADCB Swap Mux", NULL, "ADCB"},
625c4324bfaSBrian Austin 
626c4324bfaSBrian Austin 	{"DACA", "Left", "ADCA Swap Mux"},
627c4324bfaSBrian Austin 	{"DACA", "LR 2", "ADCA Swap Mux"},
628c4324bfaSBrian Austin 	{"DACA", "Right", "ADCA Swap Mux"},
629c4324bfaSBrian Austin 
630c4324bfaSBrian Austin 	{"DACB", "Left", "ADCB Swap Mux"},
631c4324bfaSBrian Austin 	{"DACB", "LR 2", "ADCB Swap Mux"},
632c4324bfaSBrian Austin 	{"DACB", "Right", "ADCB Swap Mux"},
633272b5eddSBrian Austin 
634272b5eddSBrian Austin 	{"ADCA Mux", NULL, "AIN3A"},
635272b5eddSBrian Austin 	{"ADCA Mux", NULL, "AIN2A"},
636272b5eddSBrian Austin 	{"ADCA Mux", NULL, "AIN1A"},
637272b5eddSBrian Austin 	{"ADCA Mux", NULL, "PGAA"},
638272b5eddSBrian Austin 	{"ADCB Mux", NULL, "AIN3B"},
639272b5eddSBrian Austin 	{"ADCB Mux", NULL, "AIN2B"},
640272b5eddSBrian Austin 	{"ADCB Mux", NULL, "AIN1B"},
641272b5eddSBrian Austin 	{"ADCB Mux", NULL, "PGAB"},
642272b5eddSBrian Austin 
643272b5eddSBrian Austin 	{"PGAA", "AIN1A", "PGAA Input Mux"},
644272b5eddSBrian Austin 	{"PGAA", "AIN2A", "PGAA Input Mux"},
645272b5eddSBrian Austin 	{"PGAA", "AIN3A", "PGAA Input Mux"},
646272b5eddSBrian Austin 	{"PGAB", "AIN1B", "PGAB Input Mux"},
647272b5eddSBrian Austin 	{"PGAB", "AIN2B", "PGAB Input Mux"},
648272b5eddSBrian Austin 	{"PGAB", "AIN3B", "PGAB Input Mux"},
649272b5eddSBrian Austin 
650272b5eddSBrian Austin 	{"PGAA Input Mux", NULL, "AIN1A"},
651272b5eddSBrian Austin 	{"PGAA Input Mux", NULL, "AIN2A"},
652272b5eddSBrian Austin 	{"PGAA Input Mux", NULL, "AIN3A"},
653272b5eddSBrian Austin 	{"PGAB Input Mux", NULL, "AIN1B"},
654272b5eddSBrian Austin 	{"PGAB Input Mux", NULL, "AIN2B"},
655272b5eddSBrian Austin 	{"PGAB Input Mux", NULL, "AIN3B"},
656272b5eddSBrian Austin 
657c4324bfaSBrian Austin 	{"LOB", "Switch", "LINEOUTB Input Mux"},
658c4324bfaSBrian Austin 	{"LOA", "Switch", "LINEOUTA Input Mux"},
659272b5eddSBrian Austin 
660272b5eddSBrian Austin 	{"LINEOUTA Input Mux", "PGAA", "PGAA"},
661272b5eddSBrian Austin 	{"LINEOUTB Input Mux", "PGAB", "PGAB"},
662272b5eddSBrian Austin 	{"LINEOUTA Input Mux", "DACA", "DACA"},
663272b5eddSBrian Austin 	{"LINEOUTB Input Mux", "DACB", "DACB"},
664272b5eddSBrian Austin 
665c4324bfaSBrian Austin 	{"HPA", "Switch", "HPB Input Mux"},
666c4324bfaSBrian Austin 	{"HPB", "Switch", "HPA Input Mux"},
667272b5eddSBrian Austin 
668272b5eddSBrian Austin 	{"HPA Input Mux", "PGAA", "PGAA"},
669272b5eddSBrian Austin 	{"HPB Input Mux", "PGAB", "PGAB"},
670272b5eddSBrian Austin 	{"HPA Input Mux", "DACA", "DACA"},
671272b5eddSBrian Austin 	{"HPB Input Mux", "DACB", "DACB"},
672272b5eddSBrian Austin 
673c4324bfaSBrian Austin 	{"DACA", NULL, "PCMA Swap Mux"},
674c4324bfaSBrian Austin 	{"DACB", NULL, "PCMB Swap Mux"},
675c4324bfaSBrian Austin 
676c4324bfaSBrian Austin 	{"PCMB Swap Mux", "Left", "HiFi Playback"},
677c4324bfaSBrian Austin 	{"PCMB Swap Mux", "LR 2", "HiFi Playback"},
678c4324bfaSBrian Austin 	{"PCMB Swap Mux", "Right", "HiFi Playback"},
679c4324bfaSBrian Austin 
680c4324bfaSBrian Austin 	{"PCMA Swap Mux", "Left", "HiFi Playback"},
681c4324bfaSBrian Austin 	{"PCMA Swap Mux", "LR 2", "HiFi Playback"},
682c4324bfaSBrian Austin 	{"PCMA Swap Mux", "Right", "HiFi Playback"},
683272b5eddSBrian Austin 
684272b5eddSBrian Austin };
685272b5eddSBrian Austin 
686272b5eddSBrian Austin struct cs42l56_clk_para {
687272b5eddSBrian Austin 	u32 mclk;
688272b5eddSBrian Austin 	u32 srate;
689272b5eddSBrian Austin 	u8 ratio;
690272b5eddSBrian Austin };
691272b5eddSBrian Austin 
692272b5eddSBrian Austin static const struct cs42l56_clk_para clk_ratio_table[] = {
693272b5eddSBrian Austin 	/* 8k */
694272b5eddSBrian Austin 	{ 6000000, 8000, CS42L56_MCLK_LRCLK_768 },
695272b5eddSBrian Austin 	{ 6144000, 8000, CS42L56_MCLK_LRCLK_750 },
696272b5eddSBrian Austin 	{ 12000000, 8000, CS42L56_MCLK_LRCLK_768 },
697272b5eddSBrian Austin 	{ 12288000, 8000, CS42L56_MCLK_LRCLK_750 },
698272b5eddSBrian Austin 	{ 24000000, 8000, CS42L56_MCLK_LRCLK_768 },
699272b5eddSBrian Austin 	{ 24576000, 8000, CS42L56_MCLK_LRCLK_750 },
700272b5eddSBrian Austin 	/* 11.025k */
701272b5eddSBrian Austin 	{ 5644800, 11025, CS42L56_MCLK_LRCLK_512},
702272b5eddSBrian Austin 	{ 11289600, 11025, CS42L56_MCLK_LRCLK_512},
703272b5eddSBrian Austin 	{ 22579200, 11025, CS42L56_MCLK_LRCLK_512 },
704272b5eddSBrian Austin 	/* 11.0294k */
705272b5eddSBrian Austin 	{ 6000000, 110294, CS42L56_MCLK_LRCLK_544 },
706272b5eddSBrian Austin 	{ 12000000, 110294, CS42L56_MCLK_LRCLK_544 },
707272b5eddSBrian Austin 	{ 24000000, 110294, CS42L56_MCLK_LRCLK_544 },
708272b5eddSBrian Austin 	/* 12k */
709272b5eddSBrian Austin 	{ 6000000, 12000, CS42L56_MCLK_LRCLK_500 },
710272b5eddSBrian Austin 	{ 6144000, 12000, CS42L56_MCLK_LRCLK_512 },
711272b5eddSBrian Austin 	{ 12000000, 12000, CS42L56_MCLK_LRCLK_500 },
712272b5eddSBrian Austin 	{ 12288000, 12000, CS42L56_MCLK_LRCLK_512 },
713272b5eddSBrian Austin 	{ 24000000, 12000, CS42L56_MCLK_LRCLK_500 },
714272b5eddSBrian Austin 	{ 24576000, 12000, CS42L56_MCLK_LRCLK_512 },
715272b5eddSBrian Austin 	/* 16k */
716272b5eddSBrian Austin 	{ 6000000, 16000, CS42L56_MCLK_LRCLK_375 },
717272b5eddSBrian Austin 	{ 6144000, 16000, CS42L56_MCLK_LRCLK_384 },
718272b5eddSBrian Austin 	{ 12000000, 16000, CS42L56_MCLK_LRCLK_375 },
719272b5eddSBrian Austin 	{ 12288000, 16000, CS42L56_MCLK_LRCLK_384 },
720272b5eddSBrian Austin 	{ 24000000, 16000, CS42L56_MCLK_LRCLK_375 },
721272b5eddSBrian Austin 	{ 24576000, 16000, CS42L56_MCLK_LRCLK_384 },
722272b5eddSBrian Austin 	/* 22.050k */
723272b5eddSBrian Austin 	{ 5644800, 22050, CS42L56_MCLK_LRCLK_256 },
724272b5eddSBrian Austin 	{ 11289600, 22050, CS42L56_MCLK_LRCLK_256 },
725272b5eddSBrian Austin 	{ 22579200, 22050, CS42L56_MCLK_LRCLK_256 },
726272b5eddSBrian Austin 	/* 22.0588k */
727272b5eddSBrian Austin 	{ 6000000, 220588, CS42L56_MCLK_LRCLK_272 },
728272b5eddSBrian Austin 	{ 12000000, 220588, CS42L56_MCLK_LRCLK_272 },
729272b5eddSBrian Austin 	{ 24000000, 220588, CS42L56_MCLK_LRCLK_272 },
730272b5eddSBrian Austin 	/* 24k */
731272b5eddSBrian Austin 	{ 6000000, 24000, CS42L56_MCLK_LRCLK_250 },
732272b5eddSBrian Austin 	{ 6144000, 24000, CS42L56_MCLK_LRCLK_256 },
733272b5eddSBrian Austin 	{ 12000000, 24000, CS42L56_MCLK_LRCLK_250 },
734272b5eddSBrian Austin 	{ 12288000, 24000, CS42L56_MCLK_LRCLK_256 },
735272b5eddSBrian Austin 	{ 24000000, 24000, CS42L56_MCLK_LRCLK_250 },
736272b5eddSBrian Austin 	{ 24576000, 24000, CS42L56_MCLK_LRCLK_256 },
737272b5eddSBrian Austin 	/* 32k */
738272b5eddSBrian Austin 	{ 6000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
739272b5eddSBrian Austin 	{ 6144000, 32000, CS42L56_MCLK_LRCLK_192 },
740272b5eddSBrian Austin 	{ 12000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
741272b5eddSBrian Austin 	{ 12288000, 32000, CS42L56_MCLK_LRCLK_192 },
742272b5eddSBrian Austin 	{ 24000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
743272b5eddSBrian Austin 	{ 24576000, 32000, CS42L56_MCLK_LRCLK_192 },
744272b5eddSBrian Austin 	/* 44.118k */
745272b5eddSBrian Austin 	{ 6000000, 44118, CS42L56_MCLK_LRCLK_136 },
746272b5eddSBrian Austin 	{ 12000000, 44118, CS42L56_MCLK_LRCLK_136 },
747272b5eddSBrian Austin 	{ 24000000, 44118, CS42L56_MCLK_LRCLK_136 },
748272b5eddSBrian Austin 	/* 44.1k */
749272b5eddSBrian Austin 	{ 5644800, 44100, CS42L56_MCLK_LRCLK_128 },
750272b5eddSBrian Austin 	{ 11289600, 44100, CS42L56_MCLK_LRCLK_128 },
751272b5eddSBrian Austin 	{ 22579200, 44100, CS42L56_MCLK_LRCLK_128 },
752272b5eddSBrian Austin 	/* 48k */
753272b5eddSBrian Austin 	{ 6000000, 48000, CS42L56_MCLK_LRCLK_125 },
754272b5eddSBrian Austin 	{ 6144000, 48000, CS42L56_MCLK_LRCLK_128 },
755272b5eddSBrian Austin 	{ 12000000, 48000, CS42L56_MCLK_LRCLK_125 },
756272b5eddSBrian Austin 	{ 12288000, 48000, CS42L56_MCLK_LRCLK_128 },
757272b5eddSBrian Austin 	{ 24000000, 48000, CS42L56_MCLK_LRCLK_125 },
758272b5eddSBrian Austin 	{ 24576000, 48000, CS42L56_MCLK_LRCLK_128 },
759272b5eddSBrian Austin };
760272b5eddSBrian Austin 
761272b5eddSBrian Austin static int cs42l56_get_mclk_ratio(int mclk, int rate)
762272b5eddSBrian Austin {
763272b5eddSBrian Austin 	int i;
764272b5eddSBrian Austin 
765272b5eddSBrian Austin 	for (i = 0; i < ARRAY_SIZE(clk_ratio_table); i++) {
766272b5eddSBrian Austin 		if (clk_ratio_table[i].mclk == mclk &&
767272b5eddSBrian Austin 		    clk_ratio_table[i].srate == rate)
768272b5eddSBrian Austin 			return clk_ratio_table[i].ratio;
769272b5eddSBrian Austin 	}
770272b5eddSBrian Austin 	return -EINVAL;
771272b5eddSBrian Austin }
772272b5eddSBrian Austin 
773272b5eddSBrian Austin static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
774272b5eddSBrian Austin 			int clk_id, unsigned int freq, int dir)
775272b5eddSBrian Austin {
776272b5eddSBrian Austin 	struct snd_soc_codec *codec = codec_dai->codec;
777272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
778272b5eddSBrian Austin 
779272b5eddSBrian Austin 	switch (freq) {
780272b5eddSBrian Austin 	case CS42L56_MCLK_5P6448MHZ:
781272b5eddSBrian Austin 	case CS42L56_MCLK_6MHZ:
782272b5eddSBrian Austin 	case CS42L56_MCLK_6P144MHZ:
783272b5eddSBrian Austin 		cs42l56->mclk_div2 = 0;
784272b5eddSBrian Austin 		cs42l56->mclk_prediv = 0;
785272b5eddSBrian Austin 		break;
786272b5eddSBrian Austin 	case CS42L56_MCLK_11P2896MHZ:
787272b5eddSBrian Austin 	case CS42L56_MCLK_12MHZ:
788272b5eddSBrian Austin 	case CS42L56_MCLK_12P288MHZ:
7894641c771SAxel Lin 		cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
790272b5eddSBrian Austin 		cs42l56->mclk_prediv = 0;
791272b5eddSBrian Austin 		break;
792272b5eddSBrian Austin 	case CS42L56_MCLK_22P5792MHZ:
793272b5eddSBrian Austin 	case CS42L56_MCLK_24MHZ:
794272b5eddSBrian Austin 	case CS42L56_MCLK_24P576MHZ:
7954641c771SAxel Lin 		cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
7964641c771SAxel Lin 		cs42l56->mclk_prediv = CS42L56_MCLK_PREDIV;
797272b5eddSBrian Austin 		break;
798272b5eddSBrian Austin 	default:
799272b5eddSBrian Austin 		return -EINVAL;
800272b5eddSBrian Austin 	}
801272b5eddSBrian Austin 	cs42l56->mclk = freq;
802272b5eddSBrian Austin 
803272b5eddSBrian Austin 	snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
804272b5eddSBrian Austin 			    CS42L56_MCLK_PREDIV_MASK,
805272b5eddSBrian Austin 				cs42l56->mclk_prediv);
806272b5eddSBrian Austin 	snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
807272b5eddSBrian Austin 			    CS42L56_MCLK_DIV2_MASK,
808272b5eddSBrian Austin 				cs42l56->mclk_div2);
809272b5eddSBrian Austin 
810272b5eddSBrian Austin 	return 0;
811272b5eddSBrian Austin }
812272b5eddSBrian Austin 
813272b5eddSBrian Austin static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
814272b5eddSBrian Austin {
815272b5eddSBrian Austin 	struct snd_soc_codec *codec = codec_dai->codec;
816272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
817272b5eddSBrian Austin 
818272b5eddSBrian Austin 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
819272b5eddSBrian Austin 	case SND_SOC_DAIFMT_CBM_CFM:
820272b5eddSBrian Austin 		cs42l56->iface = CS42L56_MASTER_MODE;
821272b5eddSBrian Austin 		break;
822272b5eddSBrian Austin 	case SND_SOC_DAIFMT_CBS_CFS:
823272b5eddSBrian Austin 		cs42l56->iface = CS42L56_SLAVE_MODE;
824272b5eddSBrian Austin 		break;
825272b5eddSBrian Austin 	default:
826272b5eddSBrian Austin 		return -EINVAL;
827272b5eddSBrian Austin 	}
828272b5eddSBrian Austin 
829272b5eddSBrian Austin 	 /* interface format */
830272b5eddSBrian Austin 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
831272b5eddSBrian Austin 	case SND_SOC_DAIFMT_I2S:
832272b5eddSBrian Austin 		cs42l56->iface_fmt = CS42L56_DIG_FMT_I2S;
833272b5eddSBrian Austin 		break;
834272b5eddSBrian Austin 	case SND_SOC_DAIFMT_LEFT_J:
835272b5eddSBrian Austin 		cs42l56->iface_fmt = CS42L56_DIG_FMT_LEFT_J;
836272b5eddSBrian Austin 		break;
837272b5eddSBrian Austin 	default:
838272b5eddSBrian Austin 		return -EINVAL;
839272b5eddSBrian Austin 	}
840272b5eddSBrian Austin 
841272b5eddSBrian Austin 	/* sclk inversion */
842272b5eddSBrian Austin 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
843272b5eddSBrian Austin 	case SND_SOC_DAIFMT_NB_NF:
844272b5eddSBrian Austin 		cs42l56->iface_inv = 0;
845272b5eddSBrian Austin 		break;
846272b5eddSBrian Austin 	case SND_SOC_DAIFMT_IB_NF:
847272b5eddSBrian Austin 		cs42l56->iface_inv = CS42L56_SCLK_INV;
848272b5eddSBrian Austin 		break;
849272b5eddSBrian Austin 	default:
850272b5eddSBrian Austin 		return -EINVAL;
851272b5eddSBrian Austin 	}
852272b5eddSBrian Austin 
853272b5eddSBrian Austin 	snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
854272b5eddSBrian Austin 			    CS42L56_MS_MODE_MASK, cs42l56->iface);
855272b5eddSBrian Austin 	snd_soc_update_bits(codec, CS42L56_SERIAL_FMT,
856272b5eddSBrian Austin 			    CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt);
857272b5eddSBrian Austin 	snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
858272b5eddSBrian Austin 			    CS42L56_SCLK_INV_MASK, cs42l56->iface_inv);
859272b5eddSBrian Austin 	return 0;
860272b5eddSBrian Austin }
861272b5eddSBrian Austin 
862272b5eddSBrian Austin static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute)
863272b5eddSBrian Austin {
864272b5eddSBrian Austin 	struct snd_soc_codec *codec = dai->codec;
865272b5eddSBrian Austin 
866272b5eddSBrian Austin 	if (mute) {
867272b5eddSBrian Austin 		/* Hit the DSP Mixer first */
868272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
869272b5eddSBrian Austin 				    CS42L56_ADCAMIX_MUTE_MASK |
870272b5eddSBrian Austin 				    CS42L56_ADCBMIX_MUTE_MASK |
871272b5eddSBrian Austin 				    CS42L56_PCMAMIX_MUTE_MASK |
872272b5eddSBrian Austin 				    CS42L56_PCMBMIX_MUTE_MASK |
873272b5eddSBrian Austin 				    CS42L56_MSTB_MUTE_MASK |
874272b5eddSBrian Austin 				    CS42L56_MSTA_MUTE_MASK,
8754641c771SAxel Lin 				    CS42L56_MUTE_ALL);
876272b5eddSBrian Austin 		/* Mute ADC's */
877272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
878272b5eddSBrian Austin 				    CS42L56_ADCA_MUTE_MASK |
879272b5eddSBrian Austin 				    CS42L56_ADCB_MUTE_MASK,
8804641c771SAxel Lin 				    CS42L56_MUTE_ALL);
881272b5eddSBrian Austin 		/* HP And LO */
882272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
8834641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
884272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
8854641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
886272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
8874641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
888272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
8894641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
890272b5eddSBrian Austin 	} else {
891272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
892272b5eddSBrian Austin 				    CS42L56_ADCAMIX_MUTE_MASK |
893272b5eddSBrian Austin 				    CS42L56_ADCBMIX_MUTE_MASK |
894272b5eddSBrian Austin 				    CS42L56_PCMAMIX_MUTE_MASK |
895272b5eddSBrian Austin 				    CS42L56_PCMBMIX_MUTE_MASK |
896272b5eddSBrian Austin 				    CS42L56_MSTB_MUTE_MASK |
897272b5eddSBrian Austin 				    CS42L56_MSTA_MUTE_MASK,
898272b5eddSBrian Austin 				    CS42L56_UNMUTE);
8994641c771SAxel Lin 
900272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
901272b5eddSBrian Austin 				    CS42L56_ADCA_MUTE_MASK |
902272b5eddSBrian Austin 				    CS42L56_ADCB_MUTE_MASK,
903272b5eddSBrian Austin 				    CS42L56_UNMUTE);
9044641c771SAxel Lin 
905272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
9064641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
907272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
9084641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
909272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
9104641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
911272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
9124641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
913272b5eddSBrian Austin 	}
914272b5eddSBrian Austin 	return 0;
915272b5eddSBrian Austin }
916272b5eddSBrian Austin 
917272b5eddSBrian Austin static int cs42l56_pcm_hw_params(struct snd_pcm_substream *substream,
918272b5eddSBrian Austin 				     struct snd_pcm_hw_params *params,
919272b5eddSBrian Austin 				     struct snd_soc_dai *dai)
920272b5eddSBrian Austin {
921272b5eddSBrian Austin 	struct snd_soc_codec *codec = dai->codec;
922272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
923272b5eddSBrian Austin 	int ratio;
924272b5eddSBrian Austin 
925272b5eddSBrian Austin 	ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params));
926272b5eddSBrian Austin 	if (ratio >= 0) {
927272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_CLKCTL_2,
928272b5eddSBrian Austin 				    CS42L56_CLK_RATIO_MASK, ratio);
929272b5eddSBrian Austin 	} else {
930272b5eddSBrian Austin 		dev_err(codec->dev, "unsupported mclk/sclk/lrclk ratio\n");
931272b5eddSBrian Austin 		return -EINVAL;
932272b5eddSBrian Austin 	}
933272b5eddSBrian Austin 
934272b5eddSBrian Austin 	return 0;
935272b5eddSBrian Austin }
936272b5eddSBrian Austin 
937272b5eddSBrian Austin static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
938272b5eddSBrian Austin 					enum snd_soc_bias_level level)
939272b5eddSBrian Austin {
940272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
941272b5eddSBrian Austin 	int ret;
942272b5eddSBrian Austin 
943272b5eddSBrian Austin 	switch (level) {
944272b5eddSBrian Austin 	case SND_SOC_BIAS_ON:
945272b5eddSBrian Austin 		break;
946272b5eddSBrian Austin 	case SND_SOC_BIAS_PREPARE:
947272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
948272b5eddSBrian Austin 				    CS42L56_MCLK_DIS_MASK, 0);
949272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
950272b5eddSBrian Austin 				    CS42L56_PDN_ALL_MASK, 0);
951272b5eddSBrian Austin 		break;
952272b5eddSBrian Austin 	case SND_SOC_BIAS_STANDBY:
95346a35b0dSLars-Peter Clausen 		if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
954272b5eddSBrian Austin 			regcache_cache_only(cs42l56->regmap, false);
955272b5eddSBrian Austin 			regcache_sync(cs42l56->regmap);
956272b5eddSBrian Austin 			ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
957272b5eddSBrian Austin 						    cs42l56->supplies);
958272b5eddSBrian Austin 			if (ret != 0) {
959272b5eddSBrian Austin 				dev_err(cs42l56->dev,
960272b5eddSBrian Austin 					"Failed to enable regulators: %d\n",
961272b5eddSBrian Austin 					ret);
962272b5eddSBrian Austin 				return ret;
963272b5eddSBrian Austin 			}
964272b5eddSBrian Austin 		}
965272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
966272b5eddSBrian Austin 				    CS42L56_PDN_ALL_MASK, 1);
967272b5eddSBrian Austin 		break;
968272b5eddSBrian Austin 	case SND_SOC_BIAS_OFF:
969272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
970272b5eddSBrian Austin 				    CS42L56_PDN_ALL_MASK, 1);
971272b5eddSBrian Austin 		snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
972272b5eddSBrian Austin 				    CS42L56_MCLK_DIS_MASK, 1);
973272b5eddSBrian Austin 		regcache_cache_only(cs42l56->regmap, true);
974272b5eddSBrian Austin 		regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
975272b5eddSBrian Austin 						    cs42l56->supplies);
976272b5eddSBrian Austin 		break;
977272b5eddSBrian Austin 	}
978272b5eddSBrian Austin 
979272b5eddSBrian Austin 	return 0;
980272b5eddSBrian Austin }
981272b5eddSBrian Austin 
982272b5eddSBrian Austin #define CS42L56_RATES (SNDRV_PCM_RATE_8000_48000)
983272b5eddSBrian Austin 
984272b5eddSBrian Austin #define CS42L56_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
985272b5eddSBrian Austin 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
986272b5eddSBrian Austin 			SNDRV_PCM_FMTBIT_S32_LE)
987272b5eddSBrian Austin 
988272b5eddSBrian Austin 
989272b5eddSBrian Austin static struct snd_soc_dai_ops cs42l56_ops = {
990272b5eddSBrian Austin 	.hw_params	= cs42l56_pcm_hw_params,
991272b5eddSBrian Austin 	.digital_mute	= cs42l56_digital_mute,
992272b5eddSBrian Austin 	.set_fmt	= cs42l56_set_dai_fmt,
993272b5eddSBrian Austin 	.set_sysclk	= cs42l56_set_sysclk,
994272b5eddSBrian Austin };
995272b5eddSBrian Austin 
996272b5eddSBrian Austin static struct snd_soc_dai_driver cs42l56_dai = {
997272b5eddSBrian Austin 		.name = "cs42l56",
998272b5eddSBrian Austin 		.playback = {
999272b5eddSBrian Austin 			.stream_name = "HiFi Playback",
1000272b5eddSBrian Austin 			.channels_min = 1,
1001272b5eddSBrian Austin 			.channels_max = 2,
1002272b5eddSBrian Austin 			.rates = CS42L56_RATES,
1003272b5eddSBrian Austin 			.formats = CS42L56_FORMATS,
1004272b5eddSBrian Austin 		},
1005272b5eddSBrian Austin 		.capture = {
1006272b5eddSBrian Austin 			.stream_name = "HiFi Capture",
1007272b5eddSBrian Austin 			.channels_min = 1,
1008272b5eddSBrian Austin 			.channels_max = 2,
1009272b5eddSBrian Austin 			.rates = CS42L56_RATES,
1010272b5eddSBrian Austin 			.formats = CS42L56_FORMATS,
1011272b5eddSBrian Austin 		},
1012272b5eddSBrian Austin 		.ops = &cs42l56_ops,
1013272b5eddSBrian Austin };
1014272b5eddSBrian Austin 
1015272b5eddSBrian Austin static int beep_freq[] = {
1016272b5eddSBrian Austin 	261, 522, 585, 667, 706, 774, 889, 1000,
1017272b5eddSBrian Austin 	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
1018272b5eddSBrian Austin };
1019272b5eddSBrian Austin 
1020272b5eddSBrian Austin static void cs42l56_beep_work(struct work_struct *work)
1021272b5eddSBrian Austin {
1022272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 =
1023272b5eddSBrian Austin 		container_of(work, struct cs42l56_private, beep_work);
1024272b5eddSBrian Austin 	struct snd_soc_codec *codec = cs42l56->codec;
102546a35b0dSLars-Peter Clausen 	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
1026272b5eddSBrian Austin 	int i;
1027272b5eddSBrian Austin 	int val = 0;
1028272b5eddSBrian Austin 	int best = 0;
1029272b5eddSBrian Austin 
1030272b5eddSBrian Austin 	if (cs42l56->beep_rate) {
1031272b5eddSBrian Austin 		for (i = 0; i < ARRAY_SIZE(beep_freq); i++) {
1032272b5eddSBrian Austin 			if (abs(cs42l56->beep_rate - beep_freq[i]) <
1033272b5eddSBrian Austin 			    abs(cs42l56->beep_rate - beep_freq[best]))
1034272b5eddSBrian Austin 				best = i;
1035272b5eddSBrian Austin 		}
1036272b5eddSBrian Austin 
1037272b5eddSBrian Austin 		dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
1038272b5eddSBrian Austin 			beep_freq[best], cs42l56->beep_rate);
1039272b5eddSBrian Austin 
1040272b5eddSBrian Austin 		val = (best << CS42L56_BEEP_RATE_SHIFT);
1041272b5eddSBrian Austin 
1042272b5eddSBrian Austin 		snd_soc_dapm_enable_pin(dapm, "Beep");
1043272b5eddSBrian Austin 	} else {
1044272b5eddSBrian Austin 		dev_dbg(codec->dev, "Disabling beep\n");
1045272b5eddSBrian Austin 		snd_soc_dapm_disable_pin(dapm, "Beep");
1046272b5eddSBrian Austin 	}
1047272b5eddSBrian Austin 
1048272b5eddSBrian Austin 	snd_soc_update_bits(codec, CS42L56_BEEP_FREQ_ONTIME,
1049272b5eddSBrian Austin 			    CS42L56_BEEP_FREQ_MASK, val);
1050272b5eddSBrian Austin 
1051272b5eddSBrian Austin 	snd_soc_dapm_sync(dapm);
1052272b5eddSBrian Austin }
1053272b5eddSBrian Austin 
1054272b5eddSBrian Austin /* For usability define a way of injecting beep events for the device -
1055272b5eddSBrian Austin  * many systems will not have a keyboard.
1056272b5eddSBrian Austin  */
1057272b5eddSBrian Austin static int cs42l56_beep_event(struct input_dev *dev, unsigned int type,
1058272b5eddSBrian Austin 			     unsigned int code, int hz)
1059272b5eddSBrian Austin {
1060272b5eddSBrian Austin 	struct snd_soc_codec *codec = input_get_drvdata(dev);
1061272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
1062272b5eddSBrian Austin 
1063272b5eddSBrian Austin 	dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
1064272b5eddSBrian Austin 
1065272b5eddSBrian Austin 	switch (code) {
1066272b5eddSBrian Austin 	case SND_BELL:
1067272b5eddSBrian Austin 		if (hz)
1068272b5eddSBrian Austin 			hz = 261;
1069272b5eddSBrian Austin 	case SND_TONE:
1070272b5eddSBrian Austin 		break;
1071272b5eddSBrian Austin 	default:
1072272b5eddSBrian Austin 		return -1;
1073272b5eddSBrian Austin 	}
1074272b5eddSBrian Austin 
1075272b5eddSBrian Austin 	/* Kick the beep from a workqueue */
1076272b5eddSBrian Austin 	cs42l56->beep_rate = hz;
1077272b5eddSBrian Austin 	schedule_work(&cs42l56->beep_work);
1078272b5eddSBrian Austin 	return 0;
1079272b5eddSBrian Austin }
1080272b5eddSBrian Austin 
1081272b5eddSBrian Austin static ssize_t cs42l56_beep_set(struct device *dev,
1082272b5eddSBrian Austin 			       struct device_attribute *attr,
1083272b5eddSBrian Austin 			       const char *buf, size_t count)
1084272b5eddSBrian Austin {
1085272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = dev_get_drvdata(dev);
1086272b5eddSBrian Austin 	long int time;
1087272b5eddSBrian Austin 	int ret;
1088272b5eddSBrian Austin 
1089272b5eddSBrian Austin 	ret = kstrtol(buf, 10, &time);
1090272b5eddSBrian Austin 	if (ret != 0)
1091272b5eddSBrian Austin 		return ret;
1092272b5eddSBrian Austin 
1093272b5eddSBrian Austin 	input_event(cs42l56->beep, EV_SND, SND_TONE, time);
1094272b5eddSBrian Austin 
1095272b5eddSBrian Austin 	return count;
1096272b5eddSBrian Austin }
1097272b5eddSBrian Austin 
1098272b5eddSBrian Austin static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set);
1099272b5eddSBrian Austin 
1100272b5eddSBrian Austin static void cs42l56_init_beep(struct snd_soc_codec *codec)
1101272b5eddSBrian Austin {
1102272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
1103272b5eddSBrian Austin 	int ret;
1104272b5eddSBrian Austin 
1105272b5eddSBrian Austin 	cs42l56->beep = devm_input_allocate_device(codec->dev);
1106272b5eddSBrian Austin 	if (!cs42l56->beep) {
1107272b5eddSBrian Austin 		dev_err(codec->dev, "Failed to allocate beep device\n");
1108272b5eddSBrian Austin 		return;
1109272b5eddSBrian Austin 	}
1110272b5eddSBrian Austin 
1111272b5eddSBrian Austin 	INIT_WORK(&cs42l56->beep_work, cs42l56_beep_work);
1112272b5eddSBrian Austin 	cs42l56->beep_rate = 0;
1113272b5eddSBrian Austin 
1114272b5eddSBrian Austin 	cs42l56->beep->name = "CS42L56 Beep Generator";
1115272b5eddSBrian Austin 	cs42l56->beep->phys = dev_name(codec->dev);
1116272b5eddSBrian Austin 	cs42l56->beep->id.bustype = BUS_I2C;
1117272b5eddSBrian Austin 
1118272b5eddSBrian Austin 	cs42l56->beep->evbit[0] = BIT_MASK(EV_SND);
1119272b5eddSBrian Austin 	cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
1120272b5eddSBrian Austin 	cs42l56->beep->event = cs42l56_beep_event;
1121272b5eddSBrian Austin 	cs42l56->beep->dev.parent = codec->dev;
1122272b5eddSBrian Austin 	input_set_drvdata(cs42l56->beep, codec);
1123272b5eddSBrian Austin 
1124272b5eddSBrian Austin 	ret = input_register_device(cs42l56->beep);
1125272b5eddSBrian Austin 	if (ret != 0) {
1126272b5eddSBrian Austin 		cs42l56->beep = NULL;
1127272b5eddSBrian Austin 		dev_err(codec->dev, "Failed to register beep device\n");
1128272b5eddSBrian Austin 	}
1129272b5eddSBrian Austin 
1130272b5eddSBrian Austin 	ret = device_create_file(codec->dev, &dev_attr_beep);
1131272b5eddSBrian Austin 	if (ret != 0) {
1132272b5eddSBrian Austin 		dev_err(codec->dev, "Failed to create keyclick file: %d\n",
1133272b5eddSBrian Austin 			ret);
1134272b5eddSBrian Austin 	}
1135272b5eddSBrian Austin }
1136272b5eddSBrian Austin 
1137272b5eddSBrian Austin static void cs42l56_free_beep(struct snd_soc_codec *codec)
1138272b5eddSBrian Austin {
1139272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
1140272b5eddSBrian Austin 
1141272b5eddSBrian Austin 	device_remove_file(codec->dev, &dev_attr_beep);
1142272b5eddSBrian Austin 	cancel_work_sync(&cs42l56->beep_work);
1143272b5eddSBrian Austin 	cs42l56->beep = NULL;
1144272b5eddSBrian Austin 
1145272b5eddSBrian Austin 	snd_soc_update_bits(codec, CS42L56_BEEP_TONE_CFG,
1146272b5eddSBrian Austin 			    CS42L56_BEEP_EN_MASK, 0);
1147272b5eddSBrian Austin }
1148272b5eddSBrian Austin 
1149272b5eddSBrian Austin static int cs42l56_probe(struct snd_soc_codec *codec)
1150272b5eddSBrian Austin {
1151272b5eddSBrian Austin 	cs42l56_init_beep(codec);
1152272b5eddSBrian Austin 
1153272b5eddSBrian Austin 	return 0;
1154272b5eddSBrian Austin }
1155272b5eddSBrian Austin 
1156272b5eddSBrian Austin static int cs42l56_remove(struct snd_soc_codec *codec)
1157272b5eddSBrian Austin {
1158272b5eddSBrian Austin 	cs42l56_free_beep(codec);
1159272b5eddSBrian Austin 
1160272b5eddSBrian Austin 	return 0;
1161272b5eddSBrian Austin }
1162272b5eddSBrian Austin 
1163cf0efa1cSKrzysztof Kozlowski static const struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
1164272b5eddSBrian Austin 	.probe = cs42l56_probe,
1165272b5eddSBrian Austin 	.remove = cs42l56_remove,
1166272b5eddSBrian Austin 	.set_bias_level = cs42l56_set_bias_level,
11672a4bc751SLars-Peter Clausen 	.suspend_bias_off = true,
1168272b5eddSBrian Austin 
1169272b5eddSBrian Austin 	.dapm_widgets = cs42l56_dapm_widgets,
1170272b5eddSBrian Austin 	.num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets),
1171272b5eddSBrian Austin 	.dapm_routes = cs42l56_audio_map,
1172272b5eddSBrian Austin 	.num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map),
1173272b5eddSBrian Austin 
1174272b5eddSBrian Austin 	.controls = cs42l56_snd_controls,
1175272b5eddSBrian Austin 	.num_controls = ARRAY_SIZE(cs42l56_snd_controls),
1176272b5eddSBrian Austin };
1177272b5eddSBrian Austin 
1178cf0efa1cSKrzysztof Kozlowski static const struct regmap_config cs42l56_regmap = {
1179272b5eddSBrian Austin 	.reg_bits = 8,
1180272b5eddSBrian Austin 	.val_bits = 8,
1181272b5eddSBrian Austin 
1182272b5eddSBrian Austin 	.max_register = CS42L56_MAX_REGISTER,
1183272b5eddSBrian Austin 	.reg_defaults = cs42l56_reg_defaults,
1184272b5eddSBrian Austin 	.num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults),
1185272b5eddSBrian Austin 	.readable_reg = cs42l56_readable_register,
1186272b5eddSBrian Austin 	.volatile_reg = cs42l56_volatile_register,
1187272b5eddSBrian Austin 	.cache_type = REGCACHE_RBTREE,
1188272b5eddSBrian Austin };
1189272b5eddSBrian Austin 
1190272b5eddSBrian Austin static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
1191272b5eddSBrian Austin 				    struct cs42l56_platform_data *pdata)
1192272b5eddSBrian Austin {
1193272b5eddSBrian Austin 	struct device_node *np = i2c_client->dev.of_node;
1194272b5eddSBrian Austin 	u32 val32;
1195272b5eddSBrian Austin 
1196272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain1a-reference-cfg"))
1197272b5eddSBrian Austin 		pdata->ain1a_ref_cfg = true;
1198272b5eddSBrian Austin 
1199272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain2a-reference-cfg"))
1200272b5eddSBrian Austin 		pdata->ain2a_ref_cfg = true;
1201272b5eddSBrian Austin 
1202272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain1b-reference-cfg"))
1203272b5eddSBrian Austin 		pdata->ain1b_ref_cfg = true;
1204272b5eddSBrian Austin 
1205272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain2b-reference-cfg"))
1206272b5eddSBrian Austin 		pdata->ain2b_ref_cfg = true;
1207272b5eddSBrian Austin 
1208272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,micbias-lvl", &val32) >= 0)
1209272b5eddSBrian Austin 		pdata->micbias_lvl = val32;
1210272b5eddSBrian Austin 
1211272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,chgfreq-divisor", &val32) >= 0)
1212272b5eddSBrian Austin 		pdata->chgfreq = val32;
1213272b5eddSBrian Austin 
1214272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,adaptive-pwr-cfg", &val32) >= 0)
1215272b5eddSBrian Austin 		pdata->adaptive_pwr = val32;
1216272b5eddSBrian Austin 
1217272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
1218272b5eddSBrian Austin 		pdata->hpfa_freq = val32;
1219272b5eddSBrian Austin 
1220272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
1221272b5eddSBrian Austin 		pdata->hpfb_freq = val32;
1222272b5eddSBrian Austin 
1223272b5eddSBrian Austin 	pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0);
1224272b5eddSBrian Austin 
1225272b5eddSBrian Austin 	return 0;
1226272b5eddSBrian Austin }
1227272b5eddSBrian Austin 
1228272b5eddSBrian Austin static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
1229272b5eddSBrian Austin 			     const struct i2c_device_id *id)
1230272b5eddSBrian Austin {
1231272b5eddSBrian Austin 	struct cs42l56_private *cs42l56;
1232272b5eddSBrian Austin 	struct cs42l56_platform_data *pdata =
1233272b5eddSBrian Austin 		dev_get_platdata(&i2c_client->dev);
1234272b5eddSBrian Austin 	int ret, i;
1235272b5eddSBrian Austin 	unsigned int devid = 0;
1236272b5eddSBrian Austin 	unsigned int alpha_rev, metal_rev;
1237272b5eddSBrian Austin 	unsigned int reg;
1238272b5eddSBrian Austin 
1239272b5eddSBrian Austin 	cs42l56 = devm_kzalloc(&i2c_client->dev,
1240272b5eddSBrian Austin 			       sizeof(struct cs42l56_private),
1241272b5eddSBrian Austin 			       GFP_KERNEL);
1242272b5eddSBrian Austin 	if (cs42l56 == NULL)
1243272b5eddSBrian Austin 		return -ENOMEM;
1244272b5eddSBrian Austin 	cs42l56->dev = &i2c_client->dev;
1245272b5eddSBrian Austin 
1246272b5eddSBrian Austin 	cs42l56->regmap = devm_regmap_init_i2c(i2c_client, &cs42l56_regmap);
1247272b5eddSBrian Austin 	if (IS_ERR(cs42l56->regmap)) {
1248272b5eddSBrian Austin 		ret = PTR_ERR(cs42l56->regmap);
1249272b5eddSBrian Austin 		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
1250272b5eddSBrian Austin 		return ret;
1251272b5eddSBrian Austin 	}
1252272b5eddSBrian Austin 
1253272b5eddSBrian Austin 	if (pdata) {
1254272b5eddSBrian Austin 		cs42l56->pdata = *pdata;
1255272b5eddSBrian Austin 	} else {
1256272b5eddSBrian Austin 		pdata = devm_kzalloc(&i2c_client->dev,
1257272b5eddSBrian Austin 				     sizeof(struct cs42l56_platform_data),
1258272b5eddSBrian Austin 				     GFP_KERNEL);
1259272b5eddSBrian Austin 		if (!pdata) {
1260272b5eddSBrian Austin 			dev_err(&i2c_client->dev,
1261272b5eddSBrian Austin 				"could not allocate pdata\n");
1262272b5eddSBrian Austin 			return -ENOMEM;
1263272b5eddSBrian Austin 		}
1264272b5eddSBrian Austin 		if (i2c_client->dev.of_node) {
1265272b5eddSBrian Austin 			ret = cs42l56_handle_of_data(i2c_client,
1266272b5eddSBrian Austin 						     &cs42l56->pdata);
1267272b5eddSBrian Austin 			if (ret != 0)
1268272b5eddSBrian Austin 				return ret;
1269272b5eddSBrian Austin 		}
1270272b5eddSBrian Austin 		cs42l56->pdata = *pdata;
1271272b5eddSBrian Austin 	}
1272272b5eddSBrian Austin 
1273272b5eddSBrian Austin 	if (cs42l56->pdata.gpio_nreset) {
1274272b5eddSBrian Austin 		ret = gpio_request_one(cs42l56->pdata.gpio_nreset,
1275272b5eddSBrian Austin 				       GPIOF_OUT_INIT_HIGH, "CS42L56 /RST");
1276272b5eddSBrian Austin 		if (ret < 0) {
1277272b5eddSBrian Austin 			dev_err(&i2c_client->dev,
1278272b5eddSBrian Austin 				"Failed to request /RST %d: %d\n",
1279272b5eddSBrian Austin 				cs42l56->pdata.gpio_nreset, ret);
1280272b5eddSBrian Austin 			return ret;
1281272b5eddSBrian Austin 		}
1282272b5eddSBrian Austin 		gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0);
1283272b5eddSBrian Austin 		gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1);
1284272b5eddSBrian Austin 	}
1285272b5eddSBrian Austin 
1286272b5eddSBrian Austin 
1287272b5eddSBrian Austin 	i2c_set_clientdata(i2c_client, cs42l56);
1288272b5eddSBrian Austin 
1289272b5eddSBrian Austin 	for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++)
1290272b5eddSBrian Austin 		cs42l56->supplies[i].supply = cs42l56_supply_names[i];
1291272b5eddSBrian Austin 
1292272b5eddSBrian Austin 	ret = devm_regulator_bulk_get(&i2c_client->dev,
1293272b5eddSBrian Austin 				      ARRAY_SIZE(cs42l56->supplies),
1294272b5eddSBrian Austin 				      cs42l56->supplies);
1295272b5eddSBrian Austin 	if (ret != 0) {
1296272b5eddSBrian Austin 		dev_err(&i2c_client->dev,
1297272b5eddSBrian Austin 			"Failed to request supplies: %d\n", ret);
1298272b5eddSBrian Austin 		return ret;
1299272b5eddSBrian Austin 	}
1300272b5eddSBrian Austin 
1301272b5eddSBrian Austin 	ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
1302272b5eddSBrian Austin 				    cs42l56->supplies);
1303272b5eddSBrian Austin 	if (ret != 0) {
1304272b5eddSBrian Austin 		dev_err(&i2c_client->dev,
1305272b5eddSBrian Austin 			"Failed to enable supplies: %d\n", ret);
1306272b5eddSBrian Austin 		return ret;
1307272b5eddSBrian Austin 	}
1308272b5eddSBrian Austin 
1309272b5eddSBrian Austin 	regcache_cache_bypass(cs42l56->regmap, true);
1310272b5eddSBrian Austin 
1311272b5eddSBrian Austin 	ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, &reg);
1312272b5eddSBrian Austin 	devid = reg & CS42L56_CHIP_ID_MASK;
1313272b5eddSBrian Austin 	if (devid != CS42L56_DEVID) {
1314272b5eddSBrian Austin 		dev_err(&i2c_client->dev,
1315272b5eddSBrian Austin 			"CS42L56 Device ID (%X). Expected %X\n",
1316272b5eddSBrian Austin 			devid, CS42L56_DEVID);
1317272b5eddSBrian Austin 		goto err_enable;
1318272b5eddSBrian Austin 	}
1319272b5eddSBrian Austin 	alpha_rev = reg & CS42L56_AREV_MASK;
1320272b5eddSBrian Austin 	metal_rev = reg & CS42L56_MTLREV_MASK;
1321272b5eddSBrian Austin 
1322272b5eddSBrian Austin 	dev_info(&i2c_client->dev, "Cirrus Logic CS42L56 ");
1323272b5eddSBrian Austin 	dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n",
1324272b5eddSBrian Austin 		 alpha_rev, metal_rev);
1325272b5eddSBrian Austin 
1326272b5eddSBrian Austin 	regcache_cache_bypass(cs42l56->regmap, false);
1327272b5eddSBrian Austin 
1328272b5eddSBrian Austin 	if (cs42l56->pdata.ain1a_ref_cfg)
1329272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
1330272b5eddSBrian Austin 				   CS42L56_AIN1A_REF_MASK, 1);
1331272b5eddSBrian Austin 
1332272b5eddSBrian Austin 	if (cs42l56->pdata.ain1b_ref_cfg)
1333272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
1334272b5eddSBrian Austin 				   CS42L56_AIN1B_REF_MASK, 1);
1335272b5eddSBrian Austin 
1336272b5eddSBrian Austin 	if (cs42l56->pdata.ain2a_ref_cfg)
1337272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
1338272b5eddSBrian Austin 				   CS42L56_AIN2A_REF_MASK, 1);
1339272b5eddSBrian Austin 
1340272b5eddSBrian Austin 	if (cs42l56->pdata.ain2b_ref_cfg)
1341272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
1342272b5eddSBrian Austin 				   CS42L56_AIN2B_REF_MASK, 1);
1343272b5eddSBrian Austin 
1344272b5eddSBrian Austin 	if (cs42l56->pdata.micbias_lvl)
1345272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL,
1346272b5eddSBrian Austin 				   CS42L56_MIC_BIAS_MASK,
1347272b5eddSBrian Austin 				cs42l56->pdata.micbias_lvl);
1348272b5eddSBrian Austin 
1349272b5eddSBrian Austin 	if (cs42l56->pdata.chgfreq)
1350272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
1351272b5eddSBrian Austin 				   CS42L56_CHRG_FREQ_MASK,
1352272b5eddSBrian Austin 				cs42l56->pdata.chgfreq);
1353272b5eddSBrian Austin 
1354272b5eddSBrian Austin 	if (cs42l56->pdata.hpfb_freq)
1355272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
1356272b5eddSBrian Austin 				   CS42L56_HPFB_FREQ_MASK,
1357272b5eddSBrian Austin 				cs42l56->pdata.hpfb_freq);
1358272b5eddSBrian Austin 
1359272b5eddSBrian Austin 	if (cs42l56->pdata.hpfa_freq)
1360272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
1361272b5eddSBrian Austin 				   CS42L56_HPFA_FREQ_MASK,
1362272b5eddSBrian Austin 				cs42l56->pdata.hpfa_freq);
1363272b5eddSBrian Austin 
1364272b5eddSBrian Austin 	if (cs42l56->pdata.adaptive_pwr)
1365272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
1366272b5eddSBrian Austin 				   CS42L56_ADAPT_PWR_MASK,
1367272b5eddSBrian Austin 				cs42l56->pdata.adaptive_pwr);
1368272b5eddSBrian Austin 
1369272b5eddSBrian Austin 	ret =  snd_soc_register_codec(&i2c_client->dev,
1370272b5eddSBrian Austin 			&soc_codec_dev_cs42l56, &cs42l56_dai, 1);
1371272b5eddSBrian Austin 	if (ret < 0)
1372272b5eddSBrian Austin 		return ret;
1373272b5eddSBrian Austin 
1374272b5eddSBrian Austin 	return 0;
1375272b5eddSBrian Austin 
1376272b5eddSBrian Austin err_enable:
1377272b5eddSBrian Austin 	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
1378272b5eddSBrian Austin 			       cs42l56->supplies);
1379272b5eddSBrian Austin 	return ret;
1380272b5eddSBrian Austin }
1381272b5eddSBrian Austin 
1382272b5eddSBrian Austin static int cs42l56_i2c_remove(struct i2c_client *client)
1383272b5eddSBrian Austin {
1384272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = i2c_get_clientdata(client);
1385272b5eddSBrian Austin 
1386272b5eddSBrian Austin 	snd_soc_unregister_codec(&client->dev);
1387272b5eddSBrian Austin 	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
1388272b5eddSBrian Austin 			       cs42l56->supplies);
1389272b5eddSBrian Austin 	return 0;
1390272b5eddSBrian Austin }
1391272b5eddSBrian Austin 
1392272b5eddSBrian Austin static const struct of_device_id cs42l56_of_match[] = {
1393272b5eddSBrian Austin 	{ .compatible = "cirrus,cs42l56", },
1394272b5eddSBrian Austin 	{ }
1395272b5eddSBrian Austin };
1396272b5eddSBrian Austin MODULE_DEVICE_TABLE(of, cs42l56_of_match);
1397272b5eddSBrian Austin 
1398272b5eddSBrian Austin 
1399272b5eddSBrian Austin static const struct i2c_device_id cs42l56_id[] = {
1400272b5eddSBrian Austin 	{ "cs42l56", 0 },
1401272b5eddSBrian Austin 	{ }
1402272b5eddSBrian Austin };
1403272b5eddSBrian Austin MODULE_DEVICE_TABLE(i2c, cs42l56_id);
1404272b5eddSBrian Austin 
1405272b5eddSBrian Austin static struct i2c_driver cs42l56_i2c_driver = {
1406272b5eddSBrian Austin 	.driver = {
1407272b5eddSBrian Austin 		.name = "cs42l56",
1408272b5eddSBrian Austin 		.owner = THIS_MODULE,
1409272b5eddSBrian Austin 		.of_match_table = cs42l56_of_match,
1410272b5eddSBrian Austin 	},
1411272b5eddSBrian Austin 	.id_table = cs42l56_id,
1412272b5eddSBrian Austin 	.probe =    cs42l56_i2c_probe,
1413272b5eddSBrian Austin 	.remove =   cs42l56_i2c_remove,
1414272b5eddSBrian Austin };
1415272b5eddSBrian Austin 
1416272b5eddSBrian Austin module_i2c_driver(cs42l56_i2c_driver);
1417272b5eddSBrian Austin 
1418272b5eddSBrian Austin MODULE_DESCRIPTION("ASoC CS42L56 driver");
1419272b5eddSBrian Austin MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
1420272b5eddSBrian Austin MODULE_LICENSE("GPL");
1421