xref: /openbmc/linux/sound/soc/codecs/cs42l56.c (revision e48f7466f9d93232da3f33ca722aa23a0a892f9e)
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;
48*e48f7466SKuninori Morimoto 	struct snd_soc_component *component;
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;
59de06f22fSJavier Martinez Canillas #if IS_ENABLED(CONFIG_INPUT)
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 	{ 3, 0x7f },	/* r03	- Power Ctl 1 */
68272b5eddSBrian Austin 	{ 4, 0xff },	/* r04	- Power Ctl 2 */
69272b5eddSBrian Austin 	{ 5, 0x00 },	/* ro5	- Clocking Ctl 1 */
70272b5eddSBrian Austin 	{ 6, 0x0b },	/* r06	- Clocking Ctl 2 */
71272b5eddSBrian Austin 	{ 7, 0x00 },	/* r07	- Serial Format */
72272b5eddSBrian Austin 	{ 8, 0x05 },	/* r08	- Class H Ctl */
73272b5eddSBrian Austin 	{ 9, 0x0c },	/* r09	- Misc Ctl */
74272b5eddSBrian Austin 	{ 10, 0x80 },	/* r0a	- INT Status */
75272b5eddSBrian Austin 	{ 11, 0x00 },	/* r0b	- Playback Ctl */
76272b5eddSBrian Austin 	{ 12, 0x0c },	/* r0c	- DSP Mute Ctl */
77272b5eddSBrian Austin 	{ 13, 0x00 },	/* r0d	- ADCA Mixer Volume */
78272b5eddSBrian Austin 	{ 14, 0x00 },	/* r0e	- ADCB Mixer Volume */
79272b5eddSBrian Austin 	{ 15, 0x00 },	/* r0f	- PCMA Mixer Volume */
80272b5eddSBrian Austin 	{ 16, 0x00 },	/* r10	- PCMB Mixer Volume */
81272b5eddSBrian Austin 	{ 17, 0x00 },	/* r11	- Analog Input Advisory Volume */
82272b5eddSBrian Austin 	{ 18, 0x00 },	/* r12	- Digital Input Advisory Volume */
83272b5eddSBrian Austin 	{ 19, 0x00 },	/* r13	- Master A Volume */
84272b5eddSBrian Austin 	{ 20, 0x00 },	/* r14	- Master B Volume */
85272b5eddSBrian Austin 	{ 21, 0x00 },	/* r15	- Beep Freq / On Time */
86272b5eddSBrian Austin 	{ 22, 0x00 },	/* r16	- Beep Volume / Off Time */
87272b5eddSBrian Austin 	{ 23, 0x00 },	/* r17	- Beep Tone Ctl */
88272b5eddSBrian Austin 	{ 24, 0x88 },	/* r18	- Tone Ctl */
89272b5eddSBrian Austin 	{ 25, 0x00 },	/* r19	- Channel Mixer & Swap */
90272b5eddSBrian Austin 	{ 26, 0x00 },	/* r1a	- AIN Ref Config / ADC Mux */
91272b5eddSBrian Austin 	{ 27, 0xa0 },	/* r1b	- High-Pass Filter Ctl */
92272b5eddSBrian Austin 	{ 28, 0x00 },	/* r1c	- Misc ADC Ctl */
93272b5eddSBrian Austin 	{ 29, 0x00 },	/* r1d	- Gain & Bias Ctl */
94272b5eddSBrian Austin 	{ 30, 0x00 },	/* r1e	- PGAA Mux & Volume */
95272b5eddSBrian Austin 	{ 31, 0x00 },	/* r1f	- PGAB Mux & Volume */
96272b5eddSBrian Austin 	{ 32, 0x00 },	/* r20	- ADCA Attenuator */
97272b5eddSBrian Austin 	{ 33, 0x00 },	/* r21	- ADCB Attenuator */
98272b5eddSBrian Austin 	{ 34, 0x00 },	/* r22	- ALC Enable & Attack Rate */
99272b5eddSBrian Austin 	{ 35, 0xbf },	/* r23	- ALC Release Rate */
100272b5eddSBrian Austin 	{ 36, 0x00 },	/* r24	- ALC Threshold */
101272b5eddSBrian Austin 	{ 37, 0x00 },	/* r25	- Noise Gate Ctl */
102272b5eddSBrian Austin 	{ 38, 0x00 },	/* r26	- ALC, Limiter, SFT, ZeroCross */
103272b5eddSBrian Austin 	{ 39, 0x00 },	/* r27	- Analog Mute, LO & HP Mux */
104272b5eddSBrian Austin 	{ 40, 0x00 },	/* r28	- HP A Volume */
105272b5eddSBrian Austin 	{ 41, 0x00 },	/* r29	- HP B Volume */
106272b5eddSBrian Austin 	{ 42, 0x00 },	/* r2a	- LINEOUT A Volume */
107272b5eddSBrian Austin 	{ 43, 0x00 },	/* r2b	- LINEOUT B Volume */
108272b5eddSBrian Austin 	{ 44, 0x00 },	/* r2c	- Limit Threshold Ctl */
109272b5eddSBrian Austin 	{ 45, 0x7f },	/* r2d	- Limiter Ctl & Release Rate */
110272b5eddSBrian Austin 	{ 46, 0x00 },	/* r2e	- Limiter Attack Rate */
111272b5eddSBrian Austin };
112272b5eddSBrian Austin 
113272b5eddSBrian Austin static bool cs42l56_readable_register(struct device *dev, unsigned int reg)
114272b5eddSBrian Austin {
115272b5eddSBrian Austin 	switch (reg) {
1167f325bfcSAxel Lin 	case CS42L56_CHIP_ID_1 ... CS42L56_LIM_ATTACK_RATE:
117272b5eddSBrian Austin 		return true;
118272b5eddSBrian Austin 	default:
119272b5eddSBrian Austin 		return false;
120272b5eddSBrian Austin 	}
121272b5eddSBrian Austin }
122272b5eddSBrian Austin 
123272b5eddSBrian Austin static bool cs42l56_volatile_register(struct device *dev, unsigned int reg)
124272b5eddSBrian Austin {
125272b5eddSBrian Austin 	switch (reg) {
126272b5eddSBrian Austin 	case CS42L56_INT_STATUS:
127c2b49ae6SBrian Austin 		return true;
128272b5eddSBrian Austin 	default:
129c2b49ae6SBrian Austin 		return false;
130272b5eddSBrian Austin 	}
131272b5eddSBrian Austin }
132272b5eddSBrian Austin 
133272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(beep_tlv, -5000, 200, 0);
134272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(hl_tlv, -6000, 50, 0);
135272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(adv_tlv, -10200, 50, 0);
136272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, 0);
137272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
138272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0);
139272b5eddSBrian Austin static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
140272b5eddSBrian Austin 
14137879bafSLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(ngnb_tlv,
142272b5eddSBrian Austin 	0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0),
14337879bafSLars-Peter Clausen 	2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0)
14437879bafSLars-Peter Clausen );
14537879bafSLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(ngb_tlv,
146272b5eddSBrian Austin 	0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0),
14737879bafSLars-Peter Clausen 	3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0)
14837879bafSLars-Peter Clausen );
14937879bafSLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(alc_tlv,
150272b5eddSBrian Austin 	0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
15137879bafSLars-Peter Clausen 	3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
15237879bafSLars-Peter Clausen );
153272b5eddSBrian Austin 
154272b5eddSBrian Austin static const char * const beep_config_text[] = {
155272b5eddSBrian Austin 	"Off", "Single", "Multiple", "Continuous"
156272b5eddSBrian Austin };
157272b5eddSBrian Austin 
158272b5eddSBrian Austin static const struct soc_enum beep_config_enum =
159272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 6,
160272b5eddSBrian Austin 			ARRAY_SIZE(beep_config_text), beep_config_text);
161272b5eddSBrian Austin 
162272b5eddSBrian Austin static const char * const beep_pitch_text[] = {
163272b5eddSBrian Austin 	"C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
164272b5eddSBrian Austin 	"C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
165272b5eddSBrian Austin };
166272b5eddSBrian Austin 
167272b5eddSBrian Austin static const struct soc_enum beep_pitch_enum =
168272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 4,
169272b5eddSBrian Austin 			ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
170272b5eddSBrian Austin 
171272b5eddSBrian Austin static const char * const beep_ontime_text[] = {
172272b5eddSBrian Austin 	"86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
173272b5eddSBrian Austin 	"1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
174272b5eddSBrian Austin 	"3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
175272b5eddSBrian Austin };
176272b5eddSBrian Austin 
177272b5eddSBrian Austin static const struct soc_enum beep_ontime_enum =
178272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 0,
179272b5eddSBrian Austin 			ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
180272b5eddSBrian Austin 
181272b5eddSBrian Austin static const char * const beep_offtime_text[] = {
182272b5eddSBrian Austin 	"1.23 s", "2.58 s", "3.90 s", "5.20 s",
183272b5eddSBrian Austin 	"6.60 s", "8.05 s", "9.35 s", "10.80 s"
184272b5eddSBrian Austin };
185272b5eddSBrian Austin 
186272b5eddSBrian Austin static const struct soc_enum beep_offtime_enum =
187272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_OFFTIME, 5,
188272b5eddSBrian Austin 			ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
189272b5eddSBrian Austin 
190272b5eddSBrian Austin static const char * const beep_treble_text[] = {
191272b5eddSBrian Austin 	"5kHz", "7kHz", "10kHz", "15kHz"
192272b5eddSBrian Austin };
193272b5eddSBrian Austin 
194272b5eddSBrian Austin static const struct soc_enum beep_treble_enum =
195272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 3,
196272b5eddSBrian Austin 			ARRAY_SIZE(beep_treble_text), beep_treble_text);
197272b5eddSBrian Austin 
198272b5eddSBrian Austin static const char * const beep_bass_text[] = {
199272b5eddSBrian Austin 	"50Hz", "100Hz", "200Hz", "250Hz"
200272b5eddSBrian Austin };
201272b5eddSBrian Austin 
202272b5eddSBrian Austin static const struct soc_enum beep_bass_enum =
203272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1,
204272b5eddSBrian Austin 			ARRAY_SIZE(beep_bass_text), beep_bass_text);
205272b5eddSBrian Austin 
206272b5eddSBrian Austin static const char * const adc_swap_text[] = {
207272b5eddSBrian Austin 	"None", "A+B/2", "A-B/2", "Swap"
208272b5eddSBrian Austin };
209272b5eddSBrian Austin 
210272b5eddSBrian Austin static const struct soc_enum adc_swap_enum =
211272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3,
212272b5eddSBrian Austin 			ARRAY_SIZE(adc_swap_text), adc_swap_text);
213272b5eddSBrian Austin 
214272b5eddSBrian Austin static const char * const pgaa_mux_text[] = {
215272b5eddSBrian Austin 	"AIN1A", "AIN2A", "AIN3A"};
216272b5eddSBrian Austin 
217272b5eddSBrian Austin static const struct soc_enum pgaa_mux_enum =
218272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_PGAA_MUX_VOLUME, 0,
219272b5eddSBrian Austin 			      ARRAY_SIZE(pgaa_mux_text),
220272b5eddSBrian Austin 			      pgaa_mux_text);
221272b5eddSBrian Austin 
222272b5eddSBrian Austin static const struct snd_kcontrol_new pgaa_mux =
223272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", pgaa_mux_enum);
224272b5eddSBrian Austin 
225272b5eddSBrian Austin static const char * const pgab_mux_text[] = {
226272b5eddSBrian Austin 	"AIN1B", "AIN2B", "AIN3B"};
227272b5eddSBrian Austin 
228272b5eddSBrian Austin static const struct soc_enum pgab_mux_enum =
229272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_PGAB_MUX_VOLUME, 0,
230272b5eddSBrian Austin 			      ARRAY_SIZE(pgab_mux_text),
231272b5eddSBrian Austin 			      pgab_mux_text);
232272b5eddSBrian Austin 
233272b5eddSBrian Austin static const struct snd_kcontrol_new pgab_mux =
234272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", pgab_mux_enum);
235272b5eddSBrian Austin 
236272b5eddSBrian Austin static const char * const adca_mux_text[] = {
237272b5eddSBrian Austin 	"PGAA", "AIN1A", "AIN2A", "AIN3A"};
238272b5eddSBrian Austin 
239272b5eddSBrian Austin static const struct soc_enum adca_mux_enum =
240272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 0,
241272b5eddSBrian Austin 			      ARRAY_SIZE(adca_mux_text),
242272b5eddSBrian Austin 			      adca_mux_text);
243272b5eddSBrian Austin 
244272b5eddSBrian Austin static const struct snd_kcontrol_new adca_mux =
245272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", adca_mux_enum);
246272b5eddSBrian Austin 
247272b5eddSBrian Austin static const char * const adcb_mux_text[] = {
248272b5eddSBrian Austin 	"PGAB", "AIN1B", "AIN2B", "AIN3B"};
249272b5eddSBrian Austin 
250272b5eddSBrian Austin static const struct soc_enum adcb_mux_enum =
251272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 2,
252272b5eddSBrian Austin 			      ARRAY_SIZE(adcb_mux_text),
253272b5eddSBrian Austin 			      adcb_mux_text);
254272b5eddSBrian Austin 
255272b5eddSBrian Austin static const struct snd_kcontrol_new adcb_mux =
256272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", adcb_mux_enum);
257272b5eddSBrian Austin 
258272b5eddSBrian Austin static const char * const left_swap_text[] = {
259272b5eddSBrian Austin 	"Left", "LR 2", "Right"};
260272b5eddSBrian Austin 
261272b5eddSBrian Austin static const char * const right_swap_text[] = {
262272b5eddSBrian Austin 	"Right", "LR 2", "Left"};
263272b5eddSBrian Austin 
264272b5eddSBrian Austin static const unsigned int swap_values[] = { 0, 1, 3 };
265272b5eddSBrian Austin 
266272b5eddSBrian Austin static const struct soc_enum adca_swap_enum =
267272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 0, 3,
268272b5eddSBrian Austin 			      ARRAY_SIZE(left_swap_text),
269272b5eddSBrian Austin 			      left_swap_text,
270272b5eddSBrian Austin 			      swap_values);
271c4324bfaSBrian Austin static const struct snd_kcontrol_new adca_swap_mux =
272c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", adca_swap_enum);
273272b5eddSBrian Austin 
274272b5eddSBrian Austin static const struct soc_enum pcma_swap_enum =
275272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3,
276272b5eddSBrian Austin 			      ARRAY_SIZE(left_swap_text),
277272b5eddSBrian Austin 			      left_swap_text,
278272b5eddSBrian Austin 			      swap_values);
279c4324bfaSBrian Austin static const struct snd_kcontrol_new pcma_swap_mux =
280c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", pcma_swap_enum);
281272b5eddSBrian Austin 
282272b5eddSBrian Austin static const struct soc_enum adcb_swap_enum =
283272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3,
284272b5eddSBrian Austin 			      ARRAY_SIZE(right_swap_text),
285272b5eddSBrian Austin 			      right_swap_text,
286272b5eddSBrian Austin 			      swap_values);
287c4324bfaSBrian Austin static const struct snd_kcontrol_new adcb_swap_mux =
288c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", adcb_swap_enum);
289272b5eddSBrian Austin 
290272b5eddSBrian Austin static const struct soc_enum pcmb_swap_enum =
291272b5eddSBrian Austin 	SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3,
292272b5eddSBrian Austin 			      ARRAY_SIZE(right_swap_text),
293272b5eddSBrian Austin 			      right_swap_text,
294272b5eddSBrian Austin 			      swap_values);
295c4324bfaSBrian Austin static const struct snd_kcontrol_new pcmb_swap_mux =
296c4324bfaSBrian Austin 	SOC_DAPM_ENUM("Route", pcmb_swap_enum);
297272b5eddSBrian Austin 
298272b5eddSBrian Austin static const struct snd_kcontrol_new hpa_switch =
299272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1);
300272b5eddSBrian Austin 
301272b5eddSBrian Austin static const struct snd_kcontrol_new hpb_switch =
302272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 4, 1, 1);
303272b5eddSBrian Austin 
304272b5eddSBrian Austin static const struct snd_kcontrol_new loa_switch =
305272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 2, 1, 1);
306272b5eddSBrian Austin 
307272b5eddSBrian Austin static const struct snd_kcontrol_new lob_switch =
308272b5eddSBrian Austin 	SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 0, 1, 1);
309272b5eddSBrian Austin 
310272b5eddSBrian Austin static const char * const hploa_input_text[] = {
311272b5eddSBrian Austin 	"DACA", "PGAA"};
312272b5eddSBrian Austin 
313272b5eddSBrian Austin static const struct soc_enum lineouta_input_enum =
314272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 2,
315272b5eddSBrian Austin 			      ARRAY_SIZE(hploa_input_text),
316272b5eddSBrian Austin 			      hploa_input_text);
317272b5eddSBrian Austin 
318272b5eddSBrian Austin static const struct snd_kcontrol_new lineouta_input =
319272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", lineouta_input_enum);
320272b5eddSBrian Austin 
321272b5eddSBrian Austin static const struct soc_enum hpa_input_enum =
322272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 0,
323272b5eddSBrian Austin 			      ARRAY_SIZE(hploa_input_text),
324272b5eddSBrian Austin 			      hploa_input_text);
325272b5eddSBrian Austin 
326272b5eddSBrian Austin static const struct snd_kcontrol_new hpa_input =
327272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", hpa_input_enum);
328272b5eddSBrian Austin 
329272b5eddSBrian Austin static const char * const hplob_input_text[] = {
330272b5eddSBrian Austin 	"DACB", "PGAB"};
331272b5eddSBrian Austin 
332272b5eddSBrian Austin static const struct soc_enum lineoutb_input_enum =
333272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 3,
334272b5eddSBrian Austin 			      ARRAY_SIZE(hplob_input_text),
335272b5eddSBrian Austin 			      hplob_input_text);
336272b5eddSBrian Austin 
337272b5eddSBrian Austin static const struct snd_kcontrol_new lineoutb_input =
338272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", lineoutb_input_enum);
339272b5eddSBrian Austin 
340272b5eddSBrian Austin static const struct soc_enum hpb_input_enum =
341272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 1,
342272b5eddSBrian Austin 			      ARRAY_SIZE(hplob_input_text),
343272b5eddSBrian Austin 			      hplob_input_text);
344272b5eddSBrian Austin 
345272b5eddSBrian Austin static const struct snd_kcontrol_new hpb_input =
346272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", hpb_input_enum);
347272b5eddSBrian Austin 
348272b5eddSBrian Austin static const char * const dig_mux_text[] = {
349272b5eddSBrian Austin 	"ADC", "DSP"};
350272b5eddSBrian Austin 
351272b5eddSBrian Austin static const struct soc_enum dig_mux_enum =
352272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_MISC_CTL, 7,
353272b5eddSBrian Austin 			      ARRAY_SIZE(dig_mux_text),
354272b5eddSBrian Austin 			      dig_mux_text);
355272b5eddSBrian Austin 
356272b5eddSBrian Austin static const struct snd_kcontrol_new dig_mux =
357272b5eddSBrian Austin 	SOC_DAPM_ENUM("Route", dig_mux_enum);
358272b5eddSBrian Austin 
359272b5eddSBrian Austin static const char * const hpf_freq_text[] = {
360272b5eddSBrian Austin 	"1.8Hz", "119Hz", "236Hz", "464Hz"
361272b5eddSBrian Austin };
362272b5eddSBrian Austin 
363272b5eddSBrian Austin static const struct soc_enum hpfa_freq_enum =
364272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 0,
365272b5eddSBrian Austin 			ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
366272b5eddSBrian Austin 
367272b5eddSBrian Austin static const struct soc_enum hpfb_freq_enum =
368272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 2,
369272b5eddSBrian Austin 			ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
370272b5eddSBrian Austin 
371272b5eddSBrian Austin static const char * const ng_delay_text[] = {
372272b5eddSBrian Austin 	"50ms", "100ms", "150ms", "200ms"
373272b5eddSBrian Austin };
374272b5eddSBrian Austin 
375272b5eddSBrian Austin static const struct soc_enum ng_delay_enum =
376272b5eddSBrian Austin 	SOC_ENUM_SINGLE(CS42L56_NOISE_GATE_CTL, 0,
377272b5eddSBrian Austin 			ARRAY_SIZE(ng_delay_text), ng_delay_text);
378272b5eddSBrian Austin 
379272b5eddSBrian Austin static const struct snd_kcontrol_new cs42l56_snd_controls[] = {
380272b5eddSBrian Austin 
381272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME,
382a0465587SBrian Austin 			      CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xE4, adv_tlv),
383272b5eddSBrian Austin 	SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1),
384272b5eddSBrian Austin 
385272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME,
386a0465587SBrian Austin 			      CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv),
387272b5eddSBrian Austin 	SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1),
388272b5eddSBrian Austin 
389272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME,
390a0465587SBrian Austin 			      CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv),
391272b5eddSBrian Austin 	SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1),
392272b5eddSBrian Austin 
393272b5eddSBrian Austin 	SOC_SINGLE_TLV("Analog Advisory Volume",
394272b5eddSBrian Austin 			  CS42L56_ANAINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
395272b5eddSBrian Austin 	SOC_SINGLE_TLV("Digital Advisory Volume",
396272b5eddSBrian Austin 			  CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
397272b5eddSBrian Austin 
398272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME,
399a0465587SBrian Austin 			      CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0x24, pga_tlv),
400272b5eddSBrian Austin 	SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR,
401272b5eddSBrian Austin 			      CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv),
402272b5eddSBrian Austin 	SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1),
403272b5eddSBrian Austin 	SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1),
404272b5eddSBrian Austin 
405272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME,
406a0465587SBrian Austin 			      CS42L56_HPB_VOLUME, 0, 0x84, 0x48, hl_tlv),
407272b5eddSBrian Austin 	SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME,
408a0465587SBrian Austin 			      CS42L56_LOB_VOLUME, 0, 0x84, 0x48, hl_tlv),
409272b5eddSBrian Austin 
410272b5eddSBrian Austin 	SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL,
411272b5eddSBrian Austin 			0, 0x00, 1, tone_tlv),
412272b5eddSBrian Austin 	SOC_SINGLE_TLV("Treble Shelving Volume", CS42L56_TONE_CTL,
413272b5eddSBrian Austin 			4, 0x00, 1, tone_tlv),
414272b5eddSBrian Austin 
415272b5eddSBrian Austin 	SOC_DOUBLE_TLV("PGA Preamp Volume", CS42L56_GAIN_BIAS_CTL,
416272b5eddSBrian Austin 			4, 6, 0x02, 1, preamp_tlv),
417272b5eddSBrian Austin 
418272b5eddSBrian Austin 	SOC_SINGLE("DSP Switch", CS42L56_PLAYBACK_CTL, 7, 1, 1),
419272b5eddSBrian Austin 	SOC_SINGLE("Gang Playback Switch", CS42L56_PLAYBACK_CTL, 4, 1, 1),
420272b5eddSBrian Austin 	SOC_SINGLE("Gang ADC Switch", CS42L56_MISC_ADC_CTL, 7, 1, 1),
421272b5eddSBrian Austin 	SOC_SINGLE("Gang PGA Switch", CS42L56_MISC_ADC_CTL, 6, 1, 1),
422272b5eddSBrian Austin 
423272b5eddSBrian Austin 	SOC_SINGLE("PCMA Invert", CS42L56_PLAYBACK_CTL, 2, 1, 1),
424272b5eddSBrian Austin 	SOC_SINGLE("PCMB Invert", CS42L56_PLAYBACK_CTL, 3, 1, 1),
425272b5eddSBrian Austin 	SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1),
426272b5eddSBrian Austin 	SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1),
427272b5eddSBrian Austin 
428272b5eddSBrian Austin 	SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1),
429272b5eddSBrian Austin 	SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1),
430272b5eddSBrian Austin 	SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum),
431272b5eddSBrian Austin 	SOC_ENUM("HPFB Corner Freq", hpfb_freq_enum),
432272b5eddSBrian Austin 
433272b5eddSBrian Austin 	SOC_SINGLE("Analog Soft Ramp", CS42L56_MISC_CTL, 4, 1, 1),
434272b5eddSBrian Austin 	SOC_DOUBLE("Analog Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
435272b5eddSBrian Austin 		7, 5, 1, 1),
436272b5eddSBrian Austin 	SOC_SINGLE("Analog Zero Cross", CS42L56_MISC_CTL, 3, 1, 1),
437272b5eddSBrian Austin 	SOC_DOUBLE("Analog Zero Cross Disable", CS42L56_ALC_LIM_SFT_ZC,
438272b5eddSBrian Austin 		6, 4, 1, 1),
439272b5eddSBrian Austin 	SOC_SINGLE("Digital Soft Ramp", CS42L56_MISC_CTL, 2, 1, 1),
440272b5eddSBrian Austin 	SOC_SINGLE("Digital Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
441272b5eddSBrian Austin 		3, 1, 1),
442272b5eddSBrian Austin 
443272b5eddSBrian Austin 	SOC_SINGLE("HL Deemphasis", CS42L56_PLAYBACK_CTL, 6, 1, 1),
444272b5eddSBrian Austin 
445272b5eddSBrian Austin 	SOC_SINGLE("ALC Switch", CS42L56_ALC_EN_ATTACK_RATE, 6, 1, 1),
446272b5eddSBrian Austin 	SOC_SINGLE("ALC Limit All Switch", CS42L56_ALC_RELEASE_RATE, 7, 1, 1),
447272b5eddSBrian Austin 	SOC_SINGLE_RANGE("ALC Attack", CS42L56_ALC_EN_ATTACK_RATE,
448272b5eddSBrian Austin 			0, 0, 0x3f, 0),
449272b5eddSBrian Austin 	SOC_SINGLE_RANGE("ALC Release", CS42L56_ALC_RELEASE_RATE,
450272b5eddSBrian Austin 			0, 0x3f, 0, 0),
451272b5eddSBrian Austin 	SOC_SINGLE_TLV("ALC MAX", CS42L56_ALC_THRESHOLD,
452272b5eddSBrian Austin 			5, 0x07, 1, alc_tlv),
453272b5eddSBrian Austin 	SOC_SINGLE_TLV("ALC MIN", CS42L56_ALC_THRESHOLD,
454272b5eddSBrian Austin 			2, 0x07, 1, alc_tlv),
455272b5eddSBrian Austin 
456272b5eddSBrian Austin 	SOC_SINGLE("Limiter Switch", CS42L56_LIM_CTL_RELEASE_RATE, 7, 1, 1),
457272b5eddSBrian Austin 	SOC_SINGLE("Limit All Switch", CS42L56_LIM_CTL_RELEASE_RATE, 6, 1, 1),
458272b5eddSBrian Austin 	SOC_SINGLE_RANGE("Limiter Attack", CS42L56_LIM_ATTACK_RATE,
459272b5eddSBrian Austin 			0, 0, 0x3f, 0),
460272b5eddSBrian Austin 	SOC_SINGLE_RANGE("Limiter Release", CS42L56_LIM_CTL_RELEASE_RATE,
461272b5eddSBrian Austin 			0, 0x3f, 0, 0),
462272b5eddSBrian Austin 	SOC_SINGLE_TLV("Limiter MAX", CS42L56_LIM_THRESHOLD_CTL,
463272b5eddSBrian Austin 			5, 0x07, 1, alc_tlv),
464272b5eddSBrian Austin 	SOC_SINGLE_TLV("Limiter Cushion", CS42L56_ALC_THRESHOLD,
465272b5eddSBrian Austin 			2, 0x07, 1, alc_tlv),
466272b5eddSBrian Austin 
467272b5eddSBrian Austin 	SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1),
468272b5eddSBrian Austin 	SOC_SINGLE("NG All Switch", CS42L56_NOISE_GATE_CTL, 7, 1, 1),
469272b5eddSBrian Austin 	SOC_SINGLE("NG Boost Switch", CS42L56_NOISE_GATE_CTL, 5, 1, 1),
470272b5eddSBrian Austin 	SOC_SINGLE_TLV("NG Unboost Threshold", CS42L56_NOISE_GATE_CTL,
471272b5eddSBrian Austin 			2, 0x07, 1, ngnb_tlv),
472272b5eddSBrian Austin 	SOC_SINGLE_TLV("NG Boost Threshold", CS42L56_NOISE_GATE_CTL,
473272b5eddSBrian Austin 			2, 0x07, 1, ngb_tlv),
474272b5eddSBrian Austin 	SOC_ENUM("NG Delay", ng_delay_enum),
475272b5eddSBrian Austin 
476272b5eddSBrian Austin 	SOC_ENUM("Beep Config", beep_config_enum),
477272b5eddSBrian Austin 	SOC_ENUM("Beep Pitch", beep_pitch_enum),
478272b5eddSBrian Austin 	SOC_ENUM("Beep on Time", beep_ontime_enum),
479272b5eddSBrian Austin 	SOC_ENUM("Beep off Time", beep_offtime_enum),
480272b5eddSBrian Austin 	SOC_SINGLE_SX_TLV("Beep Volume", CS42L56_BEEP_FREQ_OFFTIME,
481272b5eddSBrian Austin 			0, 0x07, 0x23, beep_tlv),
482272b5eddSBrian Austin 	SOC_SINGLE("Beep Tone Ctl Switch", CS42L56_BEEP_TONE_CFG, 0, 1, 1),
483272b5eddSBrian Austin 	SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
484272b5eddSBrian Austin 	SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
485272b5eddSBrian Austin 
486272b5eddSBrian Austin };
487272b5eddSBrian Austin 
488272b5eddSBrian Austin static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = {
489272b5eddSBrian Austin 
490272b5eddSBrian Austin 	SND_SOC_DAPM_SIGGEN("Beep"),
491272b5eddSBrian Austin 	SND_SOC_DAPM_SUPPLY("VBUF", CS42L56_PWRCTL_1, 5, 1, NULL, 0),
492272b5eddSBrian Austin 	SND_SOC_DAPM_MICBIAS("MIC1 Bias", CS42L56_PWRCTL_1, 4, 1),
493272b5eddSBrian Austin 	SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L56_PWRCTL_1, 3, 1, NULL, 0),
494272b5eddSBrian Austin 
495272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN1A"),
496272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN2A"),
497272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN1B"),
498272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN2B"),
499272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN3A"),
500272b5eddSBrian Austin 	SND_SOC_DAPM_INPUT("AIN3B"),
501272b5eddSBrian Austin 
502272b5eddSBrian Austin 	SND_SOC_DAPM_AIF_OUT("SDOUT", NULL,  0,
503272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0),
504272b5eddSBrian Austin 
505272b5eddSBrian Austin 	SND_SOC_DAPM_AIF_IN("SDIN", NULL,  0,
506272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0),
507272b5eddSBrian Austin 
508272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("Digital Output Mux", SND_SOC_NOPM,
509272b5eddSBrian Austin 			 0, 0, &dig_mux),
510272b5eddSBrian Austin 
511272b5eddSBrian Austin 	SND_SOC_DAPM_PGA("PGAA", SND_SOC_NOPM, 0, 0, NULL, 0),
512272b5eddSBrian Austin 	SND_SOC_DAPM_PGA("PGAB", SND_SOC_NOPM, 0, 0, NULL, 0),
513272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("PGAA Input Mux",
514272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0, &pgaa_mux),
515272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("PGAB Input Mux",
516272b5eddSBrian Austin 			SND_SOC_NOPM, 0, 0, &pgab_mux),
517272b5eddSBrian Austin 
518272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("ADCA Mux", SND_SOC_NOPM,
519272b5eddSBrian Austin 			 0, 0, &adca_mux),
520272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("ADCB Mux", SND_SOC_NOPM,
521272b5eddSBrian Austin 			 0, 0, &adcb_mux),
522272b5eddSBrian Austin 
523272b5eddSBrian Austin 	SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1),
524272b5eddSBrian Austin 	SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1),
525272b5eddSBrian Austin 
526c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("ADCA Swap Mux", SND_SOC_NOPM, 0, 0,
527c4324bfaSBrian Austin 		&adca_swap_mux),
528c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("ADCB Swap Mux", SND_SOC_NOPM, 0, 0,
529c4324bfaSBrian Austin 		&adcb_swap_mux),
530c4324bfaSBrian Austin 
531c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("PCMA Swap Mux", SND_SOC_NOPM, 0, 0,
532c4324bfaSBrian Austin 		&pcma_swap_mux),
533c4324bfaSBrian Austin 	SND_SOC_DAPM_MUX("PCMB Swap Mux", SND_SOC_NOPM, 0, 0,
534c4324bfaSBrian Austin 		&pcmb_swap_mux),
535c4324bfaSBrian Austin 
536272b5eddSBrian Austin 	SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0),
537272b5eddSBrian Austin 	SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0),
538272b5eddSBrian Austin 
539272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("HPA"),
540272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("LOA"),
541272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("HPB"),
542272b5eddSBrian Austin 	SND_SOC_DAPM_OUTPUT("LOB"),
543272b5eddSBrian Austin 
544272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Headphone Right",
545272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 4, 1, &hpb_switch),
546272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Headphone Left",
547272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 6, 1, &hpa_switch),
548272b5eddSBrian Austin 
549272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Lineout Right",
550272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 0, 1, &lob_switch),
551272b5eddSBrian Austin 	SND_SOC_DAPM_SWITCH("Lineout Left",
552272b5eddSBrian Austin 			    CS42L56_PWRCTL_2, 2, 1, &loa_switch),
553272b5eddSBrian Austin 
554272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("LINEOUTA Input Mux", SND_SOC_NOPM,
555272b5eddSBrian Austin 			 0, 0, &lineouta_input),
556272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("LINEOUTB Input Mux", SND_SOC_NOPM,
557272b5eddSBrian Austin 			 0, 0, &lineoutb_input),
558272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("HPA Input Mux", SND_SOC_NOPM,
559272b5eddSBrian Austin 			 0, 0, &hpa_input),
560272b5eddSBrian Austin 	SND_SOC_DAPM_MUX("HPB Input Mux", SND_SOC_NOPM,
561272b5eddSBrian Austin 			 0, 0, &hpb_input),
562272b5eddSBrian Austin 
563272b5eddSBrian Austin };
564272b5eddSBrian Austin 
565272b5eddSBrian Austin static const struct snd_soc_dapm_route cs42l56_audio_map[] = {
566272b5eddSBrian Austin 
567272b5eddSBrian Austin 	{"HiFi Capture", "DSP", "Digital Output Mux"},
568272b5eddSBrian Austin 	{"HiFi Capture", "ADC", "Digital Output Mux"},
569272b5eddSBrian Austin 
570272b5eddSBrian Austin 	{"Digital Output Mux", NULL, "ADCA"},
571272b5eddSBrian Austin 	{"Digital Output Mux", NULL, "ADCB"},
572272b5eddSBrian Austin 
573c4324bfaSBrian Austin 	{"ADCB", NULL, "ADCB Swap Mux"},
574c4324bfaSBrian Austin 	{"ADCA", NULL, "ADCA Swap Mux"},
575c4324bfaSBrian Austin 
576c4324bfaSBrian Austin 	{"ADCA Swap Mux", NULL, "ADCA"},
577c4324bfaSBrian Austin 	{"ADCB Swap Mux", NULL, "ADCB"},
578c4324bfaSBrian Austin 
579c4324bfaSBrian Austin 	{"DACA", "Left", "ADCA Swap Mux"},
580c4324bfaSBrian Austin 	{"DACA", "LR 2", "ADCA Swap Mux"},
581c4324bfaSBrian Austin 	{"DACA", "Right", "ADCA Swap Mux"},
582c4324bfaSBrian Austin 
583c4324bfaSBrian Austin 	{"DACB", "Left", "ADCB Swap Mux"},
584c4324bfaSBrian Austin 	{"DACB", "LR 2", "ADCB Swap Mux"},
585c4324bfaSBrian Austin 	{"DACB", "Right", "ADCB Swap Mux"},
586272b5eddSBrian Austin 
587272b5eddSBrian Austin 	{"ADCA Mux", NULL, "AIN3A"},
588272b5eddSBrian Austin 	{"ADCA Mux", NULL, "AIN2A"},
589272b5eddSBrian Austin 	{"ADCA Mux", NULL, "AIN1A"},
590272b5eddSBrian Austin 	{"ADCA Mux", NULL, "PGAA"},
591272b5eddSBrian Austin 	{"ADCB Mux", NULL, "AIN3B"},
592272b5eddSBrian Austin 	{"ADCB Mux", NULL, "AIN2B"},
593272b5eddSBrian Austin 	{"ADCB Mux", NULL, "AIN1B"},
594272b5eddSBrian Austin 	{"ADCB Mux", NULL, "PGAB"},
595272b5eddSBrian Austin 
596272b5eddSBrian Austin 	{"PGAA", "AIN1A", "PGAA Input Mux"},
597272b5eddSBrian Austin 	{"PGAA", "AIN2A", "PGAA Input Mux"},
598272b5eddSBrian Austin 	{"PGAA", "AIN3A", "PGAA Input Mux"},
599272b5eddSBrian Austin 	{"PGAB", "AIN1B", "PGAB Input Mux"},
600272b5eddSBrian Austin 	{"PGAB", "AIN2B", "PGAB Input Mux"},
601272b5eddSBrian Austin 	{"PGAB", "AIN3B", "PGAB Input Mux"},
602272b5eddSBrian Austin 
603272b5eddSBrian Austin 	{"PGAA Input Mux", NULL, "AIN1A"},
604272b5eddSBrian Austin 	{"PGAA Input Mux", NULL, "AIN2A"},
605272b5eddSBrian Austin 	{"PGAA Input Mux", NULL, "AIN3A"},
606272b5eddSBrian Austin 	{"PGAB Input Mux", NULL, "AIN1B"},
607272b5eddSBrian Austin 	{"PGAB Input Mux", NULL, "AIN2B"},
608272b5eddSBrian Austin 	{"PGAB Input Mux", NULL, "AIN3B"},
609272b5eddSBrian Austin 
610c4324bfaSBrian Austin 	{"LOB", "Switch", "LINEOUTB Input Mux"},
611c4324bfaSBrian Austin 	{"LOA", "Switch", "LINEOUTA Input Mux"},
612272b5eddSBrian Austin 
613272b5eddSBrian Austin 	{"LINEOUTA Input Mux", "PGAA", "PGAA"},
614272b5eddSBrian Austin 	{"LINEOUTB Input Mux", "PGAB", "PGAB"},
615272b5eddSBrian Austin 	{"LINEOUTA Input Mux", "DACA", "DACA"},
616272b5eddSBrian Austin 	{"LINEOUTB Input Mux", "DACB", "DACB"},
617272b5eddSBrian Austin 
618c4324bfaSBrian Austin 	{"HPA", "Switch", "HPB Input Mux"},
619c4324bfaSBrian Austin 	{"HPB", "Switch", "HPA Input Mux"},
620272b5eddSBrian Austin 
621272b5eddSBrian Austin 	{"HPA Input Mux", "PGAA", "PGAA"},
622272b5eddSBrian Austin 	{"HPB Input Mux", "PGAB", "PGAB"},
623272b5eddSBrian Austin 	{"HPA Input Mux", "DACA", "DACA"},
624272b5eddSBrian Austin 	{"HPB Input Mux", "DACB", "DACB"},
625272b5eddSBrian Austin 
626c4324bfaSBrian Austin 	{"DACA", NULL, "PCMA Swap Mux"},
627c4324bfaSBrian Austin 	{"DACB", NULL, "PCMB Swap Mux"},
628c4324bfaSBrian Austin 
629c4324bfaSBrian Austin 	{"PCMB Swap Mux", "Left", "HiFi Playback"},
630c4324bfaSBrian Austin 	{"PCMB Swap Mux", "LR 2", "HiFi Playback"},
631c4324bfaSBrian Austin 	{"PCMB Swap Mux", "Right", "HiFi Playback"},
632c4324bfaSBrian Austin 
633c4324bfaSBrian Austin 	{"PCMA Swap Mux", "Left", "HiFi Playback"},
634c4324bfaSBrian Austin 	{"PCMA Swap Mux", "LR 2", "HiFi Playback"},
635c4324bfaSBrian Austin 	{"PCMA Swap Mux", "Right", "HiFi Playback"},
636272b5eddSBrian Austin 
637272b5eddSBrian Austin };
638272b5eddSBrian Austin 
639272b5eddSBrian Austin struct cs42l56_clk_para {
640272b5eddSBrian Austin 	u32 mclk;
641272b5eddSBrian Austin 	u32 srate;
642272b5eddSBrian Austin 	u8 ratio;
643272b5eddSBrian Austin };
644272b5eddSBrian Austin 
645272b5eddSBrian Austin static const struct cs42l56_clk_para clk_ratio_table[] = {
646272b5eddSBrian Austin 	/* 8k */
647272b5eddSBrian Austin 	{ 6000000, 8000, CS42L56_MCLK_LRCLK_768 },
648272b5eddSBrian Austin 	{ 6144000, 8000, CS42L56_MCLK_LRCLK_750 },
649272b5eddSBrian Austin 	{ 12000000, 8000, CS42L56_MCLK_LRCLK_768 },
650272b5eddSBrian Austin 	{ 12288000, 8000, CS42L56_MCLK_LRCLK_750 },
651272b5eddSBrian Austin 	{ 24000000, 8000, CS42L56_MCLK_LRCLK_768 },
652272b5eddSBrian Austin 	{ 24576000, 8000, CS42L56_MCLK_LRCLK_750 },
653272b5eddSBrian Austin 	/* 11.025k */
654272b5eddSBrian Austin 	{ 5644800, 11025, CS42L56_MCLK_LRCLK_512},
655272b5eddSBrian Austin 	{ 11289600, 11025, CS42L56_MCLK_LRCLK_512},
656272b5eddSBrian Austin 	{ 22579200, 11025, CS42L56_MCLK_LRCLK_512 },
657272b5eddSBrian Austin 	/* 11.0294k */
658272b5eddSBrian Austin 	{ 6000000, 110294, CS42L56_MCLK_LRCLK_544 },
659272b5eddSBrian Austin 	{ 12000000, 110294, CS42L56_MCLK_LRCLK_544 },
660272b5eddSBrian Austin 	{ 24000000, 110294, CS42L56_MCLK_LRCLK_544 },
661272b5eddSBrian Austin 	/* 12k */
662272b5eddSBrian Austin 	{ 6000000, 12000, CS42L56_MCLK_LRCLK_500 },
663272b5eddSBrian Austin 	{ 6144000, 12000, CS42L56_MCLK_LRCLK_512 },
664272b5eddSBrian Austin 	{ 12000000, 12000, CS42L56_MCLK_LRCLK_500 },
665272b5eddSBrian Austin 	{ 12288000, 12000, CS42L56_MCLK_LRCLK_512 },
666272b5eddSBrian Austin 	{ 24000000, 12000, CS42L56_MCLK_LRCLK_500 },
667272b5eddSBrian Austin 	{ 24576000, 12000, CS42L56_MCLK_LRCLK_512 },
668272b5eddSBrian Austin 	/* 16k */
669272b5eddSBrian Austin 	{ 6000000, 16000, CS42L56_MCLK_LRCLK_375 },
670272b5eddSBrian Austin 	{ 6144000, 16000, CS42L56_MCLK_LRCLK_384 },
671272b5eddSBrian Austin 	{ 12000000, 16000, CS42L56_MCLK_LRCLK_375 },
672272b5eddSBrian Austin 	{ 12288000, 16000, CS42L56_MCLK_LRCLK_384 },
673272b5eddSBrian Austin 	{ 24000000, 16000, CS42L56_MCLK_LRCLK_375 },
674272b5eddSBrian Austin 	{ 24576000, 16000, CS42L56_MCLK_LRCLK_384 },
675272b5eddSBrian Austin 	/* 22.050k */
676272b5eddSBrian Austin 	{ 5644800, 22050, CS42L56_MCLK_LRCLK_256 },
677272b5eddSBrian Austin 	{ 11289600, 22050, CS42L56_MCLK_LRCLK_256 },
678272b5eddSBrian Austin 	{ 22579200, 22050, CS42L56_MCLK_LRCLK_256 },
679272b5eddSBrian Austin 	/* 22.0588k */
680272b5eddSBrian Austin 	{ 6000000, 220588, CS42L56_MCLK_LRCLK_272 },
681272b5eddSBrian Austin 	{ 12000000, 220588, CS42L56_MCLK_LRCLK_272 },
682272b5eddSBrian Austin 	{ 24000000, 220588, CS42L56_MCLK_LRCLK_272 },
683272b5eddSBrian Austin 	/* 24k */
684272b5eddSBrian Austin 	{ 6000000, 24000, CS42L56_MCLK_LRCLK_250 },
685272b5eddSBrian Austin 	{ 6144000, 24000, CS42L56_MCLK_LRCLK_256 },
686272b5eddSBrian Austin 	{ 12000000, 24000, CS42L56_MCLK_LRCLK_250 },
687272b5eddSBrian Austin 	{ 12288000, 24000, CS42L56_MCLK_LRCLK_256 },
688272b5eddSBrian Austin 	{ 24000000, 24000, CS42L56_MCLK_LRCLK_250 },
689272b5eddSBrian Austin 	{ 24576000, 24000, CS42L56_MCLK_LRCLK_256 },
690272b5eddSBrian Austin 	/* 32k */
691272b5eddSBrian Austin 	{ 6000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
692272b5eddSBrian Austin 	{ 6144000, 32000, CS42L56_MCLK_LRCLK_192 },
693272b5eddSBrian Austin 	{ 12000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
694272b5eddSBrian Austin 	{ 12288000, 32000, CS42L56_MCLK_LRCLK_192 },
695272b5eddSBrian Austin 	{ 24000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
696272b5eddSBrian Austin 	{ 24576000, 32000, CS42L56_MCLK_LRCLK_192 },
697272b5eddSBrian Austin 	/* 44.118k */
698272b5eddSBrian Austin 	{ 6000000, 44118, CS42L56_MCLK_LRCLK_136 },
699272b5eddSBrian Austin 	{ 12000000, 44118, CS42L56_MCLK_LRCLK_136 },
700272b5eddSBrian Austin 	{ 24000000, 44118, CS42L56_MCLK_LRCLK_136 },
701272b5eddSBrian Austin 	/* 44.1k */
702272b5eddSBrian Austin 	{ 5644800, 44100, CS42L56_MCLK_LRCLK_128 },
703272b5eddSBrian Austin 	{ 11289600, 44100, CS42L56_MCLK_LRCLK_128 },
704272b5eddSBrian Austin 	{ 22579200, 44100, CS42L56_MCLK_LRCLK_128 },
705272b5eddSBrian Austin 	/* 48k */
706272b5eddSBrian Austin 	{ 6000000, 48000, CS42L56_MCLK_LRCLK_125 },
707272b5eddSBrian Austin 	{ 6144000, 48000, CS42L56_MCLK_LRCLK_128 },
708272b5eddSBrian Austin 	{ 12000000, 48000, CS42L56_MCLK_LRCLK_125 },
709272b5eddSBrian Austin 	{ 12288000, 48000, CS42L56_MCLK_LRCLK_128 },
710272b5eddSBrian Austin 	{ 24000000, 48000, CS42L56_MCLK_LRCLK_125 },
711272b5eddSBrian Austin 	{ 24576000, 48000, CS42L56_MCLK_LRCLK_128 },
712272b5eddSBrian Austin };
713272b5eddSBrian Austin 
714272b5eddSBrian Austin static int cs42l56_get_mclk_ratio(int mclk, int rate)
715272b5eddSBrian Austin {
716272b5eddSBrian Austin 	int i;
717272b5eddSBrian Austin 
718272b5eddSBrian Austin 	for (i = 0; i < ARRAY_SIZE(clk_ratio_table); i++) {
719272b5eddSBrian Austin 		if (clk_ratio_table[i].mclk == mclk &&
720272b5eddSBrian Austin 		    clk_ratio_table[i].srate == rate)
721272b5eddSBrian Austin 			return clk_ratio_table[i].ratio;
722272b5eddSBrian Austin 	}
723272b5eddSBrian Austin 	return -EINVAL;
724272b5eddSBrian Austin }
725272b5eddSBrian Austin 
726272b5eddSBrian Austin static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
727272b5eddSBrian Austin 			int clk_id, unsigned int freq, int dir)
728272b5eddSBrian Austin {
729*e48f7466SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
730*e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
731272b5eddSBrian Austin 
732272b5eddSBrian Austin 	switch (freq) {
733272b5eddSBrian Austin 	case CS42L56_MCLK_5P6448MHZ:
734272b5eddSBrian Austin 	case CS42L56_MCLK_6MHZ:
735272b5eddSBrian Austin 	case CS42L56_MCLK_6P144MHZ:
736272b5eddSBrian Austin 		cs42l56->mclk_div2 = 0;
737272b5eddSBrian Austin 		cs42l56->mclk_prediv = 0;
738272b5eddSBrian Austin 		break;
739272b5eddSBrian Austin 	case CS42L56_MCLK_11P2896MHZ:
740272b5eddSBrian Austin 	case CS42L56_MCLK_12MHZ:
741272b5eddSBrian Austin 	case CS42L56_MCLK_12P288MHZ:
7424641c771SAxel Lin 		cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
743272b5eddSBrian Austin 		cs42l56->mclk_prediv = 0;
744272b5eddSBrian Austin 		break;
745272b5eddSBrian Austin 	case CS42L56_MCLK_22P5792MHZ:
746272b5eddSBrian Austin 	case CS42L56_MCLK_24MHZ:
747272b5eddSBrian Austin 	case CS42L56_MCLK_24P576MHZ:
7484641c771SAxel Lin 		cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
7494641c771SAxel Lin 		cs42l56->mclk_prediv = CS42L56_MCLK_PREDIV;
750272b5eddSBrian Austin 		break;
751272b5eddSBrian Austin 	default:
752272b5eddSBrian Austin 		return -EINVAL;
753272b5eddSBrian Austin 	}
754272b5eddSBrian Austin 	cs42l56->mclk = freq;
755272b5eddSBrian Austin 
756*e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
757272b5eddSBrian Austin 			    CS42L56_MCLK_PREDIV_MASK,
758272b5eddSBrian Austin 				cs42l56->mclk_prediv);
759*e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
760272b5eddSBrian Austin 			    CS42L56_MCLK_DIV2_MASK,
761272b5eddSBrian Austin 				cs42l56->mclk_div2);
762272b5eddSBrian Austin 
763272b5eddSBrian Austin 	return 0;
764272b5eddSBrian Austin }
765272b5eddSBrian Austin 
766272b5eddSBrian Austin static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
767272b5eddSBrian Austin {
768*e48f7466SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
769*e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
770272b5eddSBrian Austin 
771272b5eddSBrian Austin 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
772272b5eddSBrian Austin 	case SND_SOC_DAIFMT_CBM_CFM:
773272b5eddSBrian Austin 		cs42l56->iface = CS42L56_MASTER_MODE;
774272b5eddSBrian Austin 		break;
775272b5eddSBrian Austin 	case SND_SOC_DAIFMT_CBS_CFS:
776272b5eddSBrian Austin 		cs42l56->iface = CS42L56_SLAVE_MODE;
777272b5eddSBrian Austin 		break;
778272b5eddSBrian Austin 	default:
779272b5eddSBrian Austin 		return -EINVAL;
780272b5eddSBrian Austin 	}
781272b5eddSBrian Austin 
782272b5eddSBrian Austin 	 /* interface format */
783272b5eddSBrian Austin 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
784272b5eddSBrian Austin 	case SND_SOC_DAIFMT_I2S:
785272b5eddSBrian Austin 		cs42l56->iface_fmt = CS42L56_DIG_FMT_I2S;
786272b5eddSBrian Austin 		break;
787272b5eddSBrian Austin 	case SND_SOC_DAIFMT_LEFT_J:
788272b5eddSBrian Austin 		cs42l56->iface_fmt = CS42L56_DIG_FMT_LEFT_J;
789272b5eddSBrian Austin 		break;
790272b5eddSBrian Austin 	default:
791272b5eddSBrian Austin 		return -EINVAL;
792272b5eddSBrian Austin 	}
793272b5eddSBrian Austin 
794272b5eddSBrian Austin 	/* sclk inversion */
795272b5eddSBrian Austin 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
796272b5eddSBrian Austin 	case SND_SOC_DAIFMT_NB_NF:
797272b5eddSBrian Austin 		cs42l56->iface_inv = 0;
798272b5eddSBrian Austin 		break;
799272b5eddSBrian Austin 	case SND_SOC_DAIFMT_IB_NF:
800272b5eddSBrian Austin 		cs42l56->iface_inv = CS42L56_SCLK_INV;
801272b5eddSBrian Austin 		break;
802272b5eddSBrian Austin 	default:
803272b5eddSBrian Austin 		return -EINVAL;
804272b5eddSBrian Austin 	}
805272b5eddSBrian Austin 
806*e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
807272b5eddSBrian Austin 			    CS42L56_MS_MODE_MASK, cs42l56->iface);
808*e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_SERIAL_FMT,
809272b5eddSBrian Austin 			    CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt);
810*e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
811272b5eddSBrian Austin 			    CS42L56_SCLK_INV_MASK, cs42l56->iface_inv);
812272b5eddSBrian Austin 	return 0;
813272b5eddSBrian Austin }
814272b5eddSBrian Austin 
815272b5eddSBrian Austin static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute)
816272b5eddSBrian Austin {
817*e48f7466SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
818272b5eddSBrian Austin 
819272b5eddSBrian Austin 	if (mute) {
820272b5eddSBrian Austin 		/* Hit the DSP Mixer first */
821*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_DSP_MUTE_CTL,
822272b5eddSBrian Austin 				    CS42L56_ADCAMIX_MUTE_MASK |
823272b5eddSBrian Austin 				    CS42L56_ADCBMIX_MUTE_MASK |
824272b5eddSBrian Austin 				    CS42L56_PCMAMIX_MUTE_MASK |
825272b5eddSBrian Austin 				    CS42L56_PCMBMIX_MUTE_MASK |
826272b5eddSBrian Austin 				    CS42L56_MSTB_MUTE_MASK |
827272b5eddSBrian Austin 				    CS42L56_MSTA_MUTE_MASK,
8284641c771SAxel Lin 				    CS42L56_MUTE_ALL);
829272b5eddSBrian Austin 		/* Mute ADC's */
830*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_MISC_ADC_CTL,
831272b5eddSBrian Austin 				    CS42L56_ADCA_MUTE_MASK |
832272b5eddSBrian Austin 				    CS42L56_ADCB_MUTE_MASK,
8334641c771SAxel Lin 				    CS42L56_MUTE_ALL);
834272b5eddSBrian Austin 		/* HP And LO */
835*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_HPA_VOLUME,
8364641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
837*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_HPB_VOLUME,
8384641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
839*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_LOA_VOLUME,
8404641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
841*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_LOB_VOLUME,
8424641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
843272b5eddSBrian Austin 	} else {
844*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_DSP_MUTE_CTL,
845272b5eddSBrian Austin 				    CS42L56_ADCAMIX_MUTE_MASK |
846272b5eddSBrian Austin 				    CS42L56_ADCBMIX_MUTE_MASK |
847272b5eddSBrian Austin 				    CS42L56_PCMAMIX_MUTE_MASK |
848272b5eddSBrian Austin 				    CS42L56_PCMBMIX_MUTE_MASK |
849272b5eddSBrian Austin 				    CS42L56_MSTB_MUTE_MASK |
850272b5eddSBrian Austin 				    CS42L56_MSTA_MUTE_MASK,
851272b5eddSBrian Austin 				    CS42L56_UNMUTE);
8524641c771SAxel Lin 
853*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_MISC_ADC_CTL,
854272b5eddSBrian Austin 				    CS42L56_ADCA_MUTE_MASK |
855272b5eddSBrian Austin 				    CS42L56_ADCB_MUTE_MASK,
856272b5eddSBrian Austin 				    CS42L56_UNMUTE);
8574641c771SAxel Lin 
858*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_HPA_VOLUME,
8594641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
860*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_HPB_VOLUME,
8614641c771SAxel Lin 				    CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
862*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_LOA_VOLUME,
8634641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
864*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_LOB_VOLUME,
8654641c771SAxel Lin 				    CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
866272b5eddSBrian Austin 	}
867272b5eddSBrian Austin 	return 0;
868272b5eddSBrian Austin }
869272b5eddSBrian Austin 
870272b5eddSBrian Austin static int cs42l56_pcm_hw_params(struct snd_pcm_substream *substream,
871272b5eddSBrian Austin 				     struct snd_pcm_hw_params *params,
872272b5eddSBrian Austin 				     struct snd_soc_dai *dai)
873272b5eddSBrian Austin {
874*e48f7466SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
875*e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
876272b5eddSBrian Austin 	int ratio;
877272b5eddSBrian Austin 
878272b5eddSBrian Austin 	ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params));
879272b5eddSBrian Austin 	if (ratio >= 0) {
880*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_CLKCTL_2,
881272b5eddSBrian Austin 				    CS42L56_CLK_RATIO_MASK, ratio);
882272b5eddSBrian Austin 	} else {
883*e48f7466SKuninori Morimoto 		dev_err(component->dev, "unsupported mclk/sclk/lrclk ratio\n");
884272b5eddSBrian Austin 		return -EINVAL;
885272b5eddSBrian Austin 	}
886272b5eddSBrian Austin 
887272b5eddSBrian Austin 	return 0;
888272b5eddSBrian Austin }
889272b5eddSBrian Austin 
890*e48f7466SKuninori Morimoto static int cs42l56_set_bias_level(struct snd_soc_component *component,
891272b5eddSBrian Austin 					enum snd_soc_bias_level level)
892272b5eddSBrian Austin {
893*e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
894272b5eddSBrian Austin 	int ret;
895272b5eddSBrian Austin 
896272b5eddSBrian Austin 	switch (level) {
897272b5eddSBrian Austin 	case SND_SOC_BIAS_ON:
898272b5eddSBrian Austin 		break;
899272b5eddSBrian Austin 	case SND_SOC_BIAS_PREPARE:
900*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
901272b5eddSBrian Austin 				    CS42L56_MCLK_DIS_MASK, 0);
902*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
903272b5eddSBrian Austin 				    CS42L56_PDN_ALL_MASK, 0);
904272b5eddSBrian Austin 		break;
905272b5eddSBrian Austin 	case SND_SOC_BIAS_STANDBY:
906*e48f7466SKuninori Morimoto 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
907272b5eddSBrian Austin 			regcache_cache_only(cs42l56->regmap, false);
908272b5eddSBrian Austin 			regcache_sync(cs42l56->regmap);
909272b5eddSBrian Austin 			ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
910272b5eddSBrian Austin 						    cs42l56->supplies);
911272b5eddSBrian Austin 			if (ret != 0) {
912272b5eddSBrian Austin 				dev_err(cs42l56->dev,
913272b5eddSBrian Austin 					"Failed to enable regulators: %d\n",
914272b5eddSBrian Austin 					ret);
915272b5eddSBrian Austin 				return ret;
916272b5eddSBrian Austin 			}
917272b5eddSBrian Austin 		}
918*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
919272b5eddSBrian Austin 				    CS42L56_PDN_ALL_MASK, 1);
920272b5eddSBrian Austin 		break;
921272b5eddSBrian Austin 	case SND_SOC_BIAS_OFF:
922*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_PWRCTL_1,
923272b5eddSBrian Austin 				    CS42L56_PDN_ALL_MASK, 1);
924*e48f7466SKuninori Morimoto 		snd_soc_component_update_bits(component, CS42L56_CLKCTL_1,
925272b5eddSBrian Austin 				    CS42L56_MCLK_DIS_MASK, 1);
926272b5eddSBrian Austin 		regcache_cache_only(cs42l56->regmap, true);
927272b5eddSBrian Austin 		regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
928272b5eddSBrian Austin 						    cs42l56->supplies);
929272b5eddSBrian Austin 		break;
930272b5eddSBrian Austin 	}
931272b5eddSBrian Austin 
932272b5eddSBrian Austin 	return 0;
933272b5eddSBrian Austin }
934272b5eddSBrian Austin 
935272b5eddSBrian Austin #define CS42L56_RATES (SNDRV_PCM_RATE_8000_48000)
936272b5eddSBrian Austin 
937272b5eddSBrian Austin #define CS42L56_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
938272b5eddSBrian Austin 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
939272b5eddSBrian Austin 			SNDRV_PCM_FMTBIT_S32_LE)
940272b5eddSBrian Austin 
941272b5eddSBrian Austin 
94264793047SAxel Lin static const struct snd_soc_dai_ops cs42l56_ops = {
943272b5eddSBrian Austin 	.hw_params	= cs42l56_pcm_hw_params,
944272b5eddSBrian Austin 	.digital_mute	= cs42l56_digital_mute,
945272b5eddSBrian Austin 	.set_fmt	= cs42l56_set_dai_fmt,
946272b5eddSBrian Austin 	.set_sysclk	= cs42l56_set_sysclk,
947272b5eddSBrian Austin };
948272b5eddSBrian Austin 
949272b5eddSBrian Austin static struct snd_soc_dai_driver cs42l56_dai = {
950272b5eddSBrian Austin 		.name = "cs42l56",
951272b5eddSBrian Austin 		.playback = {
952272b5eddSBrian Austin 			.stream_name = "HiFi Playback",
953272b5eddSBrian Austin 			.channels_min = 1,
954272b5eddSBrian Austin 			.channels_max = 2,
955272b5eddSBrian Austin 			.rates = CS42L56_RATES,
956272b5eddSBrian Austin 			.formats = CS42L56_FORMATS,
957272b5eddSBrian Austin 		},
958272b5eddSBrian Austin 		.capture = {
959272b5eddSBrian Austin 			.stream_name = "HiFi Capture",
960272b5eddSBrian Austin 			.channels_min = 1,
961272b5eddSBrian Austin 			.channels_max = 2,
962272b5eddSBrian Austin 			.rates = CS42L56_RATES,
963272b5eddSBrian Austin 			.formats = CS42L56_FORMATS,
964272b5eddSBrian Austin 		},
965272b5eddSBrian Austin 		.ops = &cs42l56_ops,
966272b5eddSBrian Austin };
967272b5eddSBrian Austin 
968272b5eddSBrian Austin static int beep_freq[] = {
969272b5eddSBrian Austin 	261, 522, 585, 667, 706, 774, 889, 1000,
970272b5eddSBrian Austin 	1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
971272b5eddSBrian Austin };
972272b5eddSBrian Austin 
973272b5eddSBrian Austin static void cs42l56_beep_work(struct work_struct *work)
974272b5eddSBrian Austin {
975272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 =
976272b5eddSBrian Austin 		container_of(work, struct cs42l56_private, beep_work);
977*e48f7466SKuninori Morimoto 	struct snd_soc_component *component = cs42l56->component;
978*e48f7466SKuninori Morimoto 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
979272b5eddSBrian Austin 	int i;
980272b5eddSBrian Austin 	int val = 0;
981272b5eddSBrian Austin 	int best = 0;
982272b5eddSBrian Austin 
983272b5eddSBrian Austin 	if (cs42l56->beep_rate) {
984272b5eddSBrian Austin 		for (i = 0; i < ARRAY_SIZE(beep_freq); i++) {
985272b5eddSBrian Austin 			if (abs(cs42l56->beep_rate - beep_freq[i]) <
986272b5eddSBrian Austin 			    abs(cs42l56->beep_rate - beep_freq[best]))
987272b5eddSBrian Austin 				best = i;
988272b5eddSBrian Austin 		}
989272b5eddSBrian Austin 
990*e48f7466SKuninori Morimoto 		dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n",
991272b5eddSBrian Austin 			beep_freq[best], cs42l56->beep_rate);
992272b5eddSBrian Austin 
993272b5eddSBrian Austin 		val = (best << CS42L56_BEEP_RATE_SHIFT);
994272b5eddSBrian Austin 
995272b5eddSBrian Austin 		snd_soc_dapm_enable_pin(dapm, "Beep");
996272b5eddSBrian Austin 	} else {
997*e48f7466SKuninori Morimoto 		dev_dbg(component->dev, "Disabling beep\n");
998272b5eddSBrian Austin 		snd_soc_dapm_disable_pin(dapm, "Beep");
999272b5eddSBrian Austin 	}
1000272b5eddSBrian Austin 
1001*e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_BEEP_FREQ_ONTIME,
1002272b5eddSBrian Austin 			    CS42L56_BEEP_FREQ_MASK, val);
1003272b5eddSBrian Austin 
1004272b5eddSBrian Austin 	snd_soc_dapm_sync(dapm);
1005272b5eddSBrian Austin }
1006272b5eddSBrian Austin 
1007272b5eddSBrian Austin /* For usability define a way of injecting beep events for the device -
1008272b5eddSBrian Austin  * many systems will not have a keyboard.
1009272b5eddSBrian Austin  */
1010272b5eddSBrian Austin static int cs42l56_beep_event(struct input_dev *dev, unsigned int type,
1011272b5eddSBrian Austin 			     unsigned int code, int hz)
1012272b5eddSBrian Austin {
1013*e48f7466SKuninori Morimoto 	struct snd_soc_component *component = input_get_drvdata(dev);
1014*e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
1015272b5eddSBrian Austin 
1016*e48f7466SKuninori Morimoto 	dev_dbg(component->dev, "Beep event %x %x\n", code, hz);
1017272b5eddSBrian Austin 
1018272b5eddSBrian Austin 	switch (code) {
1019272b5eddSBrian Austin 	case SND_BELL:
1020272b5eddSBrian Austin 		if (hz)
1021272b5eddSBrian Austin 			hz = 261;
1022272b5eddSBrian Austin 	case SND_TONE:
1023272b5eddSBrian Austin 		break;
1024272b5eddSBrian Austin 	default:
1025272b5eddSBrian Austin 		return -1;
1026272b5eddSBrian Austin 	}
1027272b5eddSBrian Austin 
1028272b5eddSBrian Austin 	/* Kick the beep from a workqueue */
1029272b5eddSBrian Austin 	cs42l56->beep_rate = hz;
1030272b5eddSBrian Austin 	schedule_work(&cs42l56->beep_work);
1031272b5eddSBrian Austin 	return 0;
1032272b5eddSBrian Austin }
1033272b5eddSBrian Austin 
1034272b5eddSBrian Austin static ssize_t cs42l56_beep_set(struct device *dev,
1035272b5eddSBrian Austin 			       struct device_attribute *attr,
1036272b5eddSBrian Austin 			       const char *buf, size_t count)
1037272b5eddSBrian Austin {
1038272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = dev_get_drvdata(dev);
1039272b5eddSBrian Austin 	long int time;
1040272b5eddSBrian Austin 	int ret;
1041272b5eddSBrian Austin 
1042272b5eddSBrian Austin 	ret = kstrtol(buf, 10, &time);
1043272b5eddSBrian Austin 	if (ret != 0)
1044272b5eddSBrian Austin 		return ret;
1045272b5eddSBrian Austin 
1046272b5eddSBrian Austin 	input_event(cs42l56->beep, EV_SND, SND_TONE, time);
1047272b5eddSBrian Austin 
1048272b5eddSBrian Austin 	return count;
1049272b5eddSBrian Austin }
1050272b5eddSBrian Austin 
1051272b5eddSBrian Austin static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set);
1052272b5eddSBrian Austin 
1053*e48f7466SKuninori Morimoto static void cs42l56_init_beep(struct snd_soc_component *component)
1054272b5eddSBrian Austin {
1055*e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
1056272b5eddSBrian Austin 	int ret;
1057272b5eddSBrian Austin 
1058*e48f7466SKuninori Morimoto 	cs42l56->beep = devm_input_allocate_device(component->dev);
1059272b5eddSBrian Austin 	if (!cs42l56->beep) {
1060*e48f7466SKuninori Morimoto 		dev_err(component->dev, "Failed to allocate beep device\n");
1061272b5eddSBrian Austin 		return;
1062272b5eddSBrian Austin 	}
1063272b5eddSBrian Austin 
1064272b5eddSBrian Austin 	INIT_WORK(&cs42l56->beep_work, cs42l56_beep_work);
1065272b5eddSBrian Austin 	cs42l56->beep_rate = 0;
1066272b5eddSBrian Austin 
1067272b5eddSBrian Austin 	cs42l56->beep->name = "CS42L56 Beep Generator";
1068*e48f7466SKuninori Morimoto 	cs42l56->beep->phys = dev_name(component->dev);
1069272b5eddSBrian Austin 	cs42l56->beep->id.bustype = BUS_I2C;
1070272b5eddSBrian Austin 
1071272b5eddSBrian Austin 	cs42l56->beep->evbit[0] = BIT_MASK(EV_SND);
1072272b5eddSBrian Austin 	cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
1073272b5eddSBrian Austin 	cs42l56->beep->event = cs42l56_beep_event;
1074*e48f7466SKuninori Morimoto 	cs42l56->beep->dev.parent = component->dev;
1075*e48f7466SKuninori Morimoto 	input_set_drvdata(cs42l56->beep, component);
1076272b5eddSBrian Austin 
1077272b5eddSBrian Austin 	ret = input_register_device(cs42l56->beep);
1078272b5eddSBrian Austin 	if (ret != 0) {
1079272b5eddSBrian Austin 		cs42l56->beep = NULL;
1080*e48f7466SKuninori Morimoto 		dev_err(component->dev, "Failed to register beep device\n");
1081272b5eddSBrian Austin 	}
1082272b5eddSBrian Austin 
1083*e48f7466SKuninori Morimoto 	ret = device_create_file(component->dev, &dev_attr_beep);
1084272b5eddSBrian Austin 	if (ret != 0) {
1085*e48f7466SKuninori Morimoto 		dev_err(component->dev, "Failed to create keyclick file: %d\n",
1086272b5eddSBrian Austin 			ret);
1087272b5eddSBrian Austin 	}
1088272b5eddSBrian Austin }
1089272b5eddSBrian Austin 
1090*e48f7466SKuninori Morimoto static void cs42l56_free_beep(struct snd_soc_component *component)
1091272b5eddSBrian Austin {
1092*e48f7466SKuninori Morimoto 	struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
1093272b5eddSBrian Austin 
1094*e48f7466SKuninori Morimoto 	device_remove_file(component->dev, &dev_attr_beep);
1095272b5eddSBrian Austin 	cancel_work_sync(&cs42l56->beep_work);
1096272b5eddSBrian Austin 	cs42l56->beep = NULL;
1097272b5eddSBrian Austin 
1098*e48f7466SKuninori Morimoto 	snd_soc_component_update_bits(component, CS42L56_BEEP_TONE_CFG,
1099272b5eddSBrian Austin 			    CS42L56_BEEP_EN_MASK, 0);
1100272b5eddSBrian Austin }
1101272b5eddSBrian Austin 
1102*e48f7466SKuninori Morimoto static int cs42l56_probe(struct snd_soc_component *component)
1103272b5eddSBrian Austin {
1104*e48f7466SKuninori Morimoto 	cs42l56_init_beep(component);
1105272b5eddSBrian Austin 
1106272b5eddSBrian Austin 	return 0;
1107272b5eddSBrian Austin }
1108272b5eddSBrian Austin 
1109*e48f7466SKuninori Morimoto static void cs42l56_remove(struct snd_soc_component *component)
1110272b5eddSBrian Austin {
1111*e48f7466SKuninori Morimoto 	cs42l56_free_beep(component);
1112272b5eddSBrian Austin }
1113272b5eddSBrian Austin 
1114*e48f7466SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_cs42l56 = {
1115272b5eddSBrian Austin 	.probe			= cs42l56_probe,
1116272b5eddSBrian Austin 	.remove			= cs42l56_remove,
1117272b5eddSBrian Austin 	.set_bias_level		= cs42l56_set_bias_level,
1118561828f8SKuninori Morimoto 	.controls		= cs42l56_snd_controls,
1119561828f8SKuninori Morimoto 	.num_controls		= ARRAY_SIZE(cs42l56_snd_controls),
1120272b5eddSBrian Austin 	.dapm_widgets		= cs42l56_dapm_widgets,
1121272b5eddSBrian Austin 	.num_dapm_widgets	= ARRAY_SIZE(cs42l56_dapm_widgets),
1122272b5eddSBrian Austin 	.dapm_routes		= cs42l56_audio_map,
1123272b5eddSBrian Austin 	.num_dapm_routes	= ARRAY_SIZE(cs42l56_audio_map),
1124*e48f7466SKuninori Morimoto 	.suspend_bias_off	= 1,
1125*e48f7466SKuninori Morimoto 	.idle_bias_on		= 1,
1126*e48f7466SKuninori Morimoto 	.use_pmdown_time	= 1,
1127*e48f7466SKuninori Morimoto 	.endianness		= 1,
1128*e48f7466SKuninori Morimoto 	.non_legacy_dai_naming	= 1,
1129272b5eddSBrian Austin };
1130272b5eddSBrian Austin 
1131cf0efa1cSKrzysztof Kozlowski static const struct regmap_config cs42l56_regmap = {
1132272b5eddSBrian Austin 	.reg_bits = 8,
1133272b5eddSBrian Austin 	.val_bits = 8,
1134272b5eddSBrian Austin 
1135272b5eddSBrian Austin 	.max_register = CS42L56_MAX_REGISTER,
1136272b5eddSBrian Austin 	.reg_defaults = cs42l56_reg_defaults,
1137272b5eddSBrian Austin 	.num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults),
1138272b5eddSBrian Austin 	.readable_reg = cs42l56_readable_register,
1139272b5eddSBrian Austin 	.volatile_reg = cs42l56_volatile_register,
1140272b5eddSBrian Austin 	.cache_type = REGCACHE_RBTREE,
1141272b5eddSBrian Austin };
1142272b5eddSBrian Austin 
1143272b5eddSBrian Austin static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
1144272b5eddSBrian Austin 				    struct cs42l56_platform_data *pdata)
1145272b5eddSBrian Austin {
1146272b5eddSBrian Austin 	struct device_node *np = i2c_client->dev.of_node;
1147272b5eddSBrian Austin 	u32 val32;
1148272b5eddSBrian Austin 
1149272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain1a-reference-cfg"))
1150272b5eddSBrian Austin 		pdata->ain1a_ref_cfg = true;
1151272b5eddSBrian Austin 
1152272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain2a-reference-cfg"))
1153272b5eddSBrian Austin 		pdata->ain2a_ref_cfg = true;
1154272b5eddSBrian Austin 
1155272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain1b-reference-cfg"))
1156272b5eddSBrian Austin 		pdata->ain1b_ref_cfg = true;
1157272b5eddSBrian Austin 
1158272b5eddSBrian Austin 	if (of_property_read_bool(np, "cirrus,ain2b-reference-cfg"))
1159272b5eddSBrian Austin 		pdata->ain2b_ref_cfg = true;
1160272b5eddSBrian Austin 
1161272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,micbias-lvl", &val32) >= 0)
1162272b5eddSBrian Austin 		pdata->micbias_lvl = val32;
1163272b5eddSBrian Austin 
1164272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,chgfreq-divisor", &val32) >= 0)
1165272b5eddSBrian Austin 		pdata->chgfreq = val32;
1166272b5eddSBrian Austin 
1167272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,adaptive-pwr-cfg", &val32) >= 0)
1168272b5eddSBrian Austin 		pdata->adaptive_pwr = val32;
1169272b5eddSBrian Austin 
1170272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
1171272b5eddSBrian Austin 		pdata->hpfa_freq = val32;
1172272b5eddSBrian Austin 
1173272b5eddSBrian Austin 	if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
1174272b5eddSBrian Austin 		pdata->hpfb_freq = val32;
1175272b5eddSBrian Austin 
1176272b5eddSBrian Austin 	pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0);
1177272b5eddSBrian Austin 
1178272b5eddSBrian Austin 	return 0;
1179272b5eddSBrian Austin }
1180272b5eddSBrian Austin 
1181272b5eddSBrian Austin static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
1182272b5eddSBrian Austin 			     const struct i2c_device_id *id)
1183272b5eddSBrian Austin {
1184272b5eddSBrian Austin 	struct cs42l56_private *cs42l56;
1185272b5eddSBrian Austin 	struct cs42l56_platform_data *pdata =
1186272b5eddSBrian Austin 		dev_get_platdata(&i2c_client->dev);
1187272b5eddSBrian Austin 	int ret, i;
1188272b5eddSBrian Austin 	unsigned int devid = 0;
1189272b5eddSBrian Austin 	unsigned int alpha_rev, metal_rev;
1190272b5eddSBrian Austin 	unsigned int reg;
1191272b5eddSBrian Austin 
1192e8d8b98cSMarkus Elfring 	cs42l56 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l56), GFP_KERNEL);
1193272b5eddSBrian Austin 	if (cs42l56 == NULL)
1194272b5eddSBrian Austin 		return -ENOMEM;
1195272b5eddSBrian Austin 	cs42l56->dev = &i2c_client->dev;
1196272b5eddSBrian Austin 
1197272b5eddSBrian Austin 	cs42l56->regmap = devm_regmap_init_i2c(i2c_client, &cs42l56_regmap);
1198272b5eddSBrian Austin 	if (IS_ERR(cs42l56->regmap)) {
1199272b5eddSBrian Austin 		ret = PTR_ERR(cs42l56->regmap);
1200272b5eddSBrian Austin 		dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
1201272b5eddSBrian Austin 		return ret;
1202272b5eddSBrian Austin 	}
1203272b5eddSBrian Austin 
1204272b5eddSBrian Austin 	if (pdata) {
1205272b5eddSBrian Austin 		cs42l56->pdata = *pdata;
1206272b5eddSBrian Austin 	} else {
1207e8d8b98cSMarkus Elfring 		pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
1208272b5eddSBrian Austin 				     GFP_KERNEL);
1209277631ccSMarkus Elfring 		if (!pdata)
1210272b5eddSBrian Austin 			return -ENOMEM;
1211277631ccSMarkus Elfring 
1212272b5eddSBrian Austin 		if (i2c_client->dev.of_node) {
1213272b5eddSBrian Austin 			ret = cs42l56_handle_of_data(i2c_client,
1214272b5eddSBrian Austin 						     &cs42l56->pdata);
1215272b5eddSBrian Austin 			if (ret != 0)
1216272b5eddSBrian Austin 				return ret;
1217272b5eddSBrian Austin 		}
1218272b5eddSBrian Austin 		cs42l56->pdata = *pdata;
1219272b5eddSBrian Austin 	}
1220272b5eddSBrian Austin 
1221272b5eddSBrian Austin 	if (cs42l56->pdata.gpio_nreset) {
1222272b5eddSBrian Austin 		ret = gpio_request_one(cs42l56->pdata.gpio_nreset,
1223272b5eddSBrian Austin 				       GPIOF_OUT_INIT_HIGH, "CS42L56 /RST");
1224272b5eddSBrian Austin 		if (ret < 0) {
1225272b5eddSBrian Austin 			dev_err(&i2c_client->dev,
1226272b5eddSBrian Austin 				"Failed to request /RST %d: %d\n",
1227272b5eddSBrian Austin 				cs42l56->pdata.gpio_nreset, ret);
1228272b5eddSBrian Austin 			return ret;
1229272b5eddSBrian Austin 		}
1230272b5eddSBrian Austin 		gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0);
1231272b5eddSBrian Austin 		gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1);
1232272b5eddSBrian Austin 	}
1233272b5eddSBrian Austin 
1234272b5eddSBrian Austin 
1235272b5eddSBrian Austin 	i2c_set_clientdata(i2c_client, cs42l56);
1236272b5eddSBrian Austin 
1237272b5eddSBrian Austin 	for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++)
1238272b5eddSBrian Austin 		cs42l56->supplies[i].supply = cs42l56_supply_names[i];
1239272b5eddSBrian Austin 
1240272b5eddSBrian Austin 	ret = devm_regulator_bulk_get(&i2c_client->dev,
1241272b5eddSBrian Austin 				      ARRAY_SIZE(cs42l56->supplies),
1242272b5eddSBrian Austin 				      cs42l56->supplies);
1243272b5eddSBrian Austin 	if (ret != 0) {
1244272b5eddSBrian Austin 		dev_err(&i2c_client->dev,
1245272b5eddSBrian Austin 			"Failed to request supplies: %d\n", ret);
1246272b5eddSBrian Austin 		return ret;
1247272b5eddSBrian Austin 	}
1248272b5eddSBrian Austin 
1249272b5eddSBrian Austin 	ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
1250272b5eddSBrian Austin 				    cs42l56->supplies);
1251272b5eddSBrian Austin 	if (ret != 0) {
1252272b5eddSBrian Austin 		dev_err(&i2c_client->dev,
1253272b5eddSBrian Austin 			"Failed to enable supplies: %d\n", ret);
1254272b5eddSBrian Austin 		return ret;
1255272b5eddSBrian Austin 	}
1256272b5eddSBrian Austin 
1257272b5eddSBrian Austin 	ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, &reg);
1258272b5eddSBrian Austin 	devid = reg & CS42L56_CHIP_ID_MASK;
1259272b5eddSBrian Austin 	if (devid != CS42L56_DEVID) {
1260272b5eddSBrian Austin 		dev_err(&i2c_client->dev,
1261272b5eddSBrian Austin 			"CS42L56 Device ID (%X). Expected %X\n",
1262272b5eddSBrian Austin 			devid, CS42L56_DEVID);
1263272b5eddSBrian Austin 		goto err_enable;
1264272b5eddSBrian Austin 	}
1265272b5eddSBrian Austin 	alpha_rev = reg & CS42L56_AREV_MASK;
1266272b5eddSBrian Austin 	metal_rev = reg & CS42L56_MTLREV_MASK;
1267272b5eddSBrian Austin 
1268272b5eddSBrian Austin 	dev_info(&i2c_client->dev, "Cirrus Logic CS42L56 ");
1269272b5eddSBrian Austin 	dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n",
1270272b5eddSBrian Austin 		 alpha_rev, metal_rev);
1271272b5eddSBrian Austin 
1272272b5eddSBrian Austin 	if (cs42l56->pdata.ain1a_ref_cfg)
1273272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
12748c317fafSFlorian Vaussard 				   CS42L56_AIN1A_REF_MASK,
12758c317fafSFlorian Vaussard 				   CS42L56_AIN1A_REF_MASK);
1276272b5eddSBrian Austin 
1277272b5eddSBrian Austin 	if (cs42l56->pdata.ain1b_ref_cfg)
1278272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
12798c317fafSFlorian Vaussard 				   CS42L56_AIN1B_REF_MASK,
12808c317fafSFlorian Vaussard 				   CS42L56_AIN1B_REF_MASK);
1281272b5eddSBrian Austin 
1282272b5eddSBrian Austin 	if (cs42l56->pdata.ain2a_ref_cfg)
1283272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
12848c317fafSFlorian Vaussard 				   CS42L56_AIN2A_REF_MASK,
12858c317fafSFlorian Vaussard 				   CS42L56_AIN2A_REF_MASK);
1286272b5eddSBrian Austin 
1287272b5eddSBrian Austin 	if (cs42l56->pdata.ain2b_ref_cfg)
1288272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
12898c317fafSFlorian Vaussard 				   CS42L56_AIN2B_REF_MASK,
12908c317fafSFlorian Vaussard 				   CS42L56_AIN2B_REF_MASK);
1291272b5eddSBrian Austin 
1292272b5eddSBrian Austin 	if (cs42l56->pdata.micbias_lvl)
1293272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL,
1294272b5eddSBrian Austin 				   CS42L56_MIC_BIAS_MASK,
1295272b5eddSBrian Austin 				cs42l56->pdata.micbias_lvl);
1296272b5eddSBrian Austin 
1297272b5eddSBrian Austin 	if (cs42l56->pdata.chgfreq)
1298272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
1299272b5eddSBrian Austin 				   CS42L56_CHRG_FREQ_MASK,
1300272b5eddSBrian Austin 				cs42l56->pdata.chgfreq);
1301272b5eddSBrian Austin 
1302272b5eddSBrian Austin 	if (cs42l56->pdata.hpfb_freq)
1303272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
1304272b5eddSBrian Austin 				   CS42L56_HPFB_FREQ_MASK,
1305272b5eddSBrian Austin 				cs42l56->pdata.hpfb_freq);
1306272b5eddSBrian Austin 
1307272b5eddSBrian Austin 	if (cs42l56->pdata.hpfa_freq)
1308272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
1309272b5eddSBrian Austin 				   CS42L56_HPFA_FREQ_MASK,
1310272b5eddSBrian Austin 				cs42l56->pdata.hpfa_freq);
1311272b5eddSBrian Austin 
1312272b5eddSBrian Austin 	if (cs42l56->pdata.adaptive_pwr)
1313272b5eddSBrian Austin 		regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
1314272b5eddSBrian Austin 				   CS42L56_ADAPT_PWR_MASK,
1315272b5eddSBrian Austin 				cs42l56->pdata.adaptive_pwr);
1316272b5eddSBrian Austin 
1317*e48f7466SKuninori Morimoto 	ret =  devm_snd_soc_register_component(&i2c_client->dev,
1318*e48f7466SKuninori Morimoto 			&soc_component_dev_cs42l56, &cs42l56_dai, 1);
1319272b5eddSBrian Austin 	if (ret < 0)
1320272b5eddSBrian Austin 		return ret;
1321272b5eddSBrian Austin 
1322272b5eddSBrian Austin 	return 0;
1323272b5eddSBrian Austin 
1324272b5eddSBrian Austin err_enable:
1325272b5eddSBrian Austin 	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
1326272b5eddSBrian Austin 			       cs42l56->supplies);
1327272b5eddSBrian Austin 	return ret;
1328272b5eddSBrian Austin }
1329272b5eddSBrian Austin 
1330272b5eddSBrian Austin static int cs42l56_i2c_remove(struct i2c_client *client)
1331272b5eddSBrian Austin {
1332272b5eddSBrian Austin 	struct cs42l56_private *cs42l56 = i2c_get_clientdata(client);
1333272b5eddSBrian Austin 
1334272b5eddSBrian Austin 	regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
1335272b5eddSBrian Austin 			       cs42l56->supplies);
1336272b5eddSBrian Austin 	return 0;
1337272b5eddSBrian Austin }
1338272b5eddSBrian Austin 
1339272b5eddSBrian Austin static const struct of_device_id cs42l56_of_match[] = {
1340272b5eddSBrian Austin 	{ .compatible = "cirrus,cs42l56", },
1341272b5eddSBrian Austin 	{ }
1342272b5eddSBrian Austin };
1343272b5eddSBrian Austin MODULE_DEVICE_TABLE(of, cs42l56_of_match);
1344272b5eddSBrian Austin 
1345272b5eddSBrian Austin 
1346272b5eddSBrian Austin static const struct i2c_device_id cs42l56_id[] = {
1347272b5eddSBrian Austin 	{ "cs42l56", 0 },
1348272b5eddSBrian Austin 	{ }
1349272b5eddSBrian Austin };
1350272b5eddSBrian Austin MODULE_DEVICE_TABLE(i2c, cs42l56_id);
1351272b5eddSBrian Austin 
1352272b5eddSBrian Austin static struct i2c_driver cs42l56_i2c_driver = {
1353272b5eddSBrian Austin 	.driver = {
1354272b5eddSBrian Austin 		.name = "cs42l56",
1355272b5eddSBrian Austin 		.of_match_table = cs42l56_of_match,
1356272b5eddSBrian Austin 	},
1357272b5eddSBrian Austin 	.id_table = cs42l56_id,
1358272b5eddSBrian Austin 	.probe =    cs42l56_i2c_probe,
1359272b5eddSBrian Austin 	.remove =   cs42l56_i2c_remove,
1360272b5eddSBrian Austin };
1361272b5eddSBrian Austin 
1362272b5eddSBrian Austin module_i2c_driver(cs42l56_i2c_driver);
1363272b5eddSBrian Austin 
1364272b5eddSBrian Austin MODULE_DESCRIPTION("ASoC CS42L56 driver");
1365272b5eddSBrian Austin MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
1366272b5eddSBrian Austin MODULE_LICENSE("GPL");
1367