blob: e88a559e04b937badfc16ef6583864b13e1f08f6 [file] [log] [blame]
Brian Austin272b5ed2014-05-05 15:09:08 -05001/*
2 * cs42l56.c -- CS42L56 ALSA SoC audio driver
3 *
4 * Copyright 2014 CirrusLogic, Inc.
5 *
6 * Author: Brian Austin <brian.austin@cirrus.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/delay.h>
19#include <linux/pm.h>
20#include <linux/i2c.h>
21#include <linux/input.h>
22#include <linux/regmap.h>
23#include <linux/slab.h>
24#include <linux/workqueue.h>
25#include <linux/platform_device.h>
26#include <linux/regulator/consumer.h>
27#include <linux/of_device.h>
28#include <linux/of_gpio.h>
29#include <sound/core.h>
30#include <sound/pcm.h>
31#include <sound/pcm_params.h>
32#include <sound/soc.h>
33#include <sound/soc-dapm.h>
34#include <sound/initval.h>
35#include <sound/tlv.h>
36#include <sound/cs42l56.h>
37#include "cs42l56.h"
38
39#define CS42L56_NUM_SUPPLIES 3
40static const char *const cs42l56_supply_names[CS42L56_NUM_SUPPLIES] = {
41 "VA",
42 "VCP",
43 "VLDO",
44};
45
46struct cs42l56_private {
47 struct regmap *regmap;
48 struct snd_soc_codec *codec;
49 struct device *dev;
50 struct cs42l56_platform_data pdata;
51 struct regulator_bulk_data supplies[CS42L56_NUM_SUPPLIES];
52 u32 mclk;
53 u8 mclk_prediv;
54 u8 mclk_div2;
55 u8 mclk_ratio;
56 u8 iface;
57 u8 iface_fmt;
58 u8 iface_inv;
59#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
60 struct input_dev *beep;
61 struct work_struct beep_work;
62 int beep_rate;
63#endif
64};
65
66static const struct reg_default cs42l56_reg_defaults[] = {
67 { 1, 0x56 }, /* r01 - ID 1 */
68 { 2, 0x04 }, /* r02 - ID 2 */
69 { 3, 0x7f }, /* r03 - Power Ctl 1 */
70 { 4, 0xff }, /* r04 - Power Ctl 2 */
71 { 5, 0x00 }, /* ro5 - Clocking Ctl 1 */
72 { 6, 0x0b }, /* r06 - Clocking Ctl 2 */
73 { 7, 0x00 }, /* r07 - Serial Format */
74 { 8, 0x05 }, /* r08 - Class H Ctl */
75 { 9, 0x0c }, /* r09 - Misc Ctl */
76 { 10, 0x80 }, /* r0a - INT Status */
77 { 11, 0x00 }, /* r0b - Playback Ctl */
78 { 12, 0x0c }, /* r0c - DSP Mute Ctl */
79 { 13, 0x00 }, /* r0d - ADCA Mixer Volume */
80 { 14, 0x00 }, /* r0e - ADCB Mixer Volume */
81 { 15, 0x00 }, /* r0f - PCMA Mixer Volume */
82 { 16, 0x00 }, /* r10 - PCMB Mixer Volume */
83 { 17, 0x00 }, /* r11 - Analog Input Advisory Volume */
84 { 18, 0x00 }, /* r12 - Digital Input Advisory Volume */
85 { 19, 0x00 }, /* r13 - Master A Volume */
86 { 20, 0x00 }, /* r14 - Master B Volume */
87 { 21, 0x00 }, /* r15 - Beep Freq / On Time */
88 { 22, 0x00 }, /* r16 - Beep Volume / Off Time */
89 { 23, 0x00 }, /* r17 - Beep Tone Ctl */
90 { 24, 0x88 }, /* r18 - Tone Ctl */
91 { 25, 0x00 }, /* r19 - Channel Mixer & Swap */
92 { 26, 0x00 }, /* r1a - AIN Ref Config / ADC Mux */
93 { 27, 0xa0 }, /* r1b - High-Pass Filter Ctl */
94 { 28, 0x00 }, /* r1c - Misc ADC Ctl */
95 { 29, 0x00 }, /* r1d - Gain & Bias Ctl */
96 { 30, 0x00 }, /* r1e - PGAA Mux & Volume */
97 { 31, 0x00 }, /* r1f - PGAB Mux & Volume */
98 { 32, 0x00 }, /* r20 - ADCA Attenuator */
99 { 33, 0x00 }, /* r21 - ADCB Attenuator */
100 { 34, 0x00 }, /* r22 - ALC Enable & Attack Rate */
101 { 35, 0xbf }, /* r23 - ALC Release Rate */
102 { 36, 0x00 }, /* r24 - ALC Threshold */
103 { 37, 0x00 }, /* r25 - Noise Gate Ctl */
104 { 38, 0x00 }, /* r26 - ALC, Limiter, SFT, ZeroCross */
105 { 39, 0x00 }, /* r27 - Analog Mute, LO & HP Mux */
106 { 40, 0x00 }, /* r28 - HP A Volume */
107 { 41, 0x00 }, /* r29 - HP B Volume */
108 { 42, 0x00 }, /* r2a - LINEOUT A Volume */
109 { 43, 0x00 }, /* r2b - LINEOUT B Volume */
110 { 44, 0x00 }, /* r2c - Limit Threshold Ctl */
111 { 45, 0x7f }, /* r2d - Limiter Ctl & Release Rate */
112 { 46, 0x00 }, /* r2e - Limiter Attack Rate */
113};
114
115static bool cs42l56_readable_register(struct device *dev, unsigned int reg)
116{
117 switch (reg) {
118 case CS42L56_CHIP_ID_1:
119 case CS42L56_CHIP_ID_2:
120 case CS42L56_PWRCTL_1:
121 case CS42L56_PWRCTL_2:
122 case CS42L56_CLKCTL_1:
123 case CS42L56_CLKCTL_2:
124 case CS42L56_SERIAL_FMT:
125 case CS42L56_CLASSH_CTL:
126 case CS42L56_MISC_CTL:
127 case CS42L56_INT_STATUS:
128 case CS42L56_PLAYBACK_CTL:
129 case CS42L56_DSP_MUTE_CTL:
130 case CS42L56_ADCA_MIX_VOLUME:
131 case CS42L56_ADCB_MIX_VOLUME:
132 case CS42L56_PCMA_MIX_VOLUME:
133 case CS42L56_PCMB_MIX_VOLUME:
134 case CS42L56_ANAINPUT_ADV_VOLUME:
135 case CS42L56_DIGINPUT_ADV_VOLUME:
136 case CS42L56_MASTER_A_VOLUME:
137 case CS42L56_MASTER_B_VOLUME:
138 case CS42L56_BEEP_FREQ_ONTIME:
139 case CS42L56_BEEP_FREQ_OFFTIME:
140 case CS42L56_BEEP_TONE_CFG:
141 case CS42L56_TONE_CTL:
142 case CS42L56_CHAN_MIX_SWAP:
143 case CS42L56_AIN_REFCFG_ADC_MUX:
144 case CS42L56_HPF_CTL:
145 case CS42L56_MISC_ADC_CTL:
146 case CS42L56_GAIN_BIAS_CTL:
147 case CS42L56_PGAA_MUX_VOLUME:
148 case CS42L56_PGAB_MUX_VOLUME:
149 case CS42L56_ADCA_ATTENUATOR:
150 case CS42L56_ADCB_ATTENUATOR:
151 case CS42L56_ALC_EN_ATTACK_RATE:
152 case CS42L56_ALC_RELEASE_RATE:
153 case CS42L56_ALC_THRESHOLD:
154 case CS42L56_NOISE_GATE_CTL:
155 case CS42L56_ALC_LIM_SFT_ZC:
156 case CS42L56_AMUTE_HPLO_MUX:
157 case CS42L56_HPA_VOLUME:
158 case CS42L56_HPB_VOLUME:
159 case CS42L56_LOA_VOLUME:
160 case CS42L56_LOB_VOLUME:
161 case CS42L56_LIM_THRESHOLD_CTL:
162 case CS42L56_LIM_CTL_RELEASE_RATE:
163 case CS42L56_LIM_ATTACK_RATE:
164 return true;
165 default:
166 return false;
167 }
168}
169
170static bool cs42l56_volatile_register(struct device *dev, unsigned int reg)
171{
172 switch (reg) {
173 case CS42L56_INT_STATUS:
Brian Austinc2b49ae2014-08-28 10:02:42 -0500174 return true;
Brian Austin272b5ed2014-05-05 15:09:08 -0500175 default:
Brian Austinc2b49ae2014-08-28 10:02:42 -0500176 return false;
Brian Austin272b5ed2014-05-05 15:09:08 -0500177 }
178}
179
180static DECLARE_TLV_DB_SCALE(beep_tlv, -5000, 200, 0);
181static DECLARE_TLV_DB_SCALE(hl_tlv, -6000, 50, 0);
182static DECLARE_TLV_DB_SCALE(adv_tlv, -10200, 50, 0);
183static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, 0);
184static DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
185static DECLARE_TLV_DB_SCALE(preamp_tlv, 0, 1000, 0);
186static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
187
Lars-Peter Clausen37879ba2015-08-02 17:19:35 +0200188static const DECLARE_TLV_DB_RANGE(ngnb_tlv,
Brian Austin272b5ed2014-05-05 15:09:08 -0500189 0, 1, TLV_DB_SCALE_ITEM(-8200, 600, 0),
Lars-Peter Clausen37879ba2015-08-02 17:19:35 +0200190 2, 5, TLV_DB_SCALE_ITEM(-7600, 300, 0)
191);
192static const DECLARE_TLV_DB_RANGE(ngb_tlv,
Brian Austin272b5ed2014-05-05 15:09:08 -0500193 0, 2, TLV_DB_SCALE_ITEM(-6400, 600, 0),
Lars-Peter Clausen37879ba2015-08-02 17:19:35 +0200194 3, 7, TLV_DB_SCALE_ITEM(-4600, 300, 0)
195);
196static const DECLARE_TLV_DB_RANGE(alc_tlv,
Brian Austin272b5ed2014-05-05 15:09:08 -0500197 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
Lars-Peter Clausen37879ba2015-08-02 17:19:35 +0200198 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
199);
Brian Austin272b5ed2014-05-05 15:09:08 -0500200
201static const char * const beep_config_text[] = {
202 "Off", "Single", "Multiple", "Continuous"
203};
204
205static const struct soc_enum beep_config_enum =
206 SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 6,
207 ARRAY_SIZE(beep_config_text), beep_config_text);
208
209static const char * const beep_pitch_text[] = {
210 "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
211 "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
212};
213
214static const struct soc_enum beep_pitch_enum =
215 SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 4,
216 ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
217
218static const char * const beep_ontime_text[] = {
219 "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
220 "1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
221 "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
222};
223
224static const struct soc_enum beep_ontime_enum =
225 SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_ONTIME, 0,
226 ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
227
228static const char * const beep_offtime_text[] = {
229 "1.23 s", "2.58 s", "3.90 s", "5.20 s",
230 "6.60 s", "8.05 s", "9.35 s", "10.80 s"
231};
232
233static const struct soc_enum beep_offtime_enum =
234 SOC_ENUM_SINGLE(CS42L56_BEEP_FREQ_OFFTIME, 5,
235 ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
236
237static const char * const beep_treble_text[] = {
238 "5kHz", "7kHz", "10kHz", "15kHz"
239};
240
241static const struct soc_enum beep_treble_enum =
242 SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 3,
243 ARRAY_SIZE(beep_treble_text), beep_treble_text);
244
245static const char * const beep_bass_text[] = {
246 "50Hz", "100Hz", "200Hz", "250Hz"
247};
248
249static const struct soc_enum beep_bass_enum =
250 SOC_ENUM_SINGLE(CS42L56_BEEP_TONE_CFG, 1,
251 ARRAY_SIZE(beep_bass_text), beep_bass_text);
252
253static const char * const adc_swap_text[] = {
254 "None", "A+B/2", "A-B/2", "Swap"
255};
256
257static const struct soc_enum adc_swap_enum =
258 SOC_ENUM_SINGLE(CS42L56_MISC_ADC_CTL, 3,
259 ARRAY_SIZE(adc_swap_text), adc_swap_text);
260
261static const char * const pgaa_mux_text[] = {
262 "AIN1A", "AIN2A", "AIN3A"};
263
264static const struct soc_enum pgaa_mux_enum =
265 SOC_ENUM_SINGLE(CS42L56_PGAA_MUX_VOLUME, 0,
266 ARRAY_SIZE(pgaa_mux_text),
267 pgaa_mux_text);
268
269static const struct snd_kcontrol_new pgaa_mux =
270 SOC_DAPM_ENUM("Route", pgaa_mux_enum);
271
272static const char * const pgab_mux_text[] = {
273 "AIN1B", "AIN2B", "AIN3B"};
274
275static const struct soc_enum pgab_mux_enum =
276 SOC_ENUM_SINGLE(CS42L56_PGAB_MUX_VOLUME, 0,
277 ARRAY_SIZE(pgab_mux_text),
278 pgab_mux_text);
279
280static const struct snd_kcontrol_new pgab_mux =
281 SOC_DAPM_ENUM("Route", pgab_mux_enum);
282
283static const char * const adca_mux_text[] = {
284 "PGAA", "AIN1A", "AIN2A", "AIN3A"};
285
286static const struct soc_enum adca_mux_enum =
287 SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 0,
288 ARRAY_SIZE(adca_mux_text),
289 adca_mux_text);
290
291static const struct snd_kcontrol_new adca_mux =
292 SOC_DAPM_ENUM("Route", adca_mux_enum);
293
294static const char * const adcb_mux_text[] = {
295 "PGAB", "AIN1B", "AIN2B", "AIN3B"};
296
297static const struct soc_enum adcb_mux_enum =
298 SOC_ENUM_SINGLE(CS42L56_AIN_REFCFG_ADC_MUX, 2,
299 ARRAY_SIZE(adcb_mux_text),
300 adcb_mux_text);
301
302static const struct snd_kcontrol_new adcb_mux =
303 SOC_DAPM_ENUM("Route", adcb_mux_enum);
304
305static const char * const left_swap_text[] = {
306 "Left", "LR 2", "Right"};
307
308static const char * const right_swap_text[] = {
309 "Right", "LR 2", "Left"};
310
311static const unsigned int swap_values[] = { 0, 1, 3 };
312
313static const struct soc_enum adca_swap_enum =
314 SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 0, 3,
315 ARRAY_SIZE(left_swap_text),
316 left_swap_text,
317 swap_values);
Brian Austinc4324bf2014-07-08 09:56:35 -0500318static const struct snd_kcontrol_new adca_swap_mux =
319 SOC_DAPM_ENUM("Route", adca_swap_enum);
Brian Austin272b5ed2014-05-05 15:09:08 -0500320
321static const struct soc_enum pcma_swap_enum =
322 SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 4, 3,
323 ARRAY_SIZE(left_swap_text),
324 left_swap_text,
325 swap_values);
Brian Austinc4324bf2014-07-08 09:56:35 -0500326static const struct snd_kcontrol_new pcma_swap_mux =
327 SOC_DAPM_ENUM("Route", pcma_swap_enum);
Brian Austin272b5ed2014-05-05 15:09:08 -0500328
329static const struct soc_enum adcb_swap_enum =
330 SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 2, 3,
331 ARRAY_SIZE(right_swap_text),
332 right_swap_text,
333 swap_values);
Brian Austinc4324bf2014-07-08 09:56:35 -0500334static const struct snd_kcontrol_new adcb_swap_mux =
335 SOC_DAPM_ENUM("Route", adcb_swap_enum);
Brian Austin272b5ed2014-05-05 15:09:08 -0500336
337static const struct soc_enum pcmb_swap_enum =
338 SOC_VALUE_ENUM_SINGLE(CS42L56_CHAN_MIX_SWAP, 6, 3,
339 ARRAY_SIZE(right_swap_text),
340 right_swap_text,
341 swap_values);
Brian Austinc4324bf2014-07-08 09:56:35 -0500342static const struct snd_kcontrol_new pcmb_swap_mux =
343 SOC_DAPM_ENUM("Route", pcmb_swap_enum);
Brian Austin272b5ed2014-05-05 15:09:08 -0500344
345static const struct snd_kcontrol_new hpa_switch =
346 SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 6, 1, 1);
347
348static const struct snd_kcontrol_new hpb_switch =
349 SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 4, 1, 1);
350
351static const struct snd_kcontrol_new loa_switch =
352 SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 2, 1, 1);
353
354static const struct snd_kcontrol_new lob_switch =
355 SOC_DAPM_SINGLE("Switch", CS42L56_PWRCTL_2, 0, 1, 1);
356
357static const char * const hploa_input_text[] = {
358 "DACA", "PGAA"};
359
360static const struct soc_enum lineouta_input_enum =
361 SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 2,
362 ARRAY_SIZE(hploa_input_text),
363 hploa_input_text);
364
365static const struct snd_kcontrol_new lineouta_input =
366 SOC_DAPM_ENUM("Route", lineouta_input_enum);
367
368static const struct soc_enum hpa_input_enum =
369 SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 0,
370 ARRAY_SIZE(hploa_input_text),
371 hploa_input_text);
372
373static const struct snd_kcontrol_new hpa_input =
374 SOC_DAPM_ENUM("Route", hpa_input_enum);
375
376static const char * const hplob_input_text[] = {
377 "DACB", "PGAB"};
378
379static const struct soc_enum lineoutb_input_enum =
380 SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 3,
381 ARRAY_SIZE(hplob_input_text),
382 hplob_input_text);
383
384static const struct snd_kcontrol_new lineoutb_input =
385 SOC_DAPM_ENUM("Route", lineoutb_input_enum);
386
387static const struct soc_enum hpb_input_enum =
388 SOC_ENUM_SINGLE(CS42L56_AMUTE_HPLO_MUX, 1,
389 ARRAY_SIZE(hplob_input_text),
390 hplob_input_text);
391
392static const struct snd_kcontrol_new hpb_input =
393 SOC_DAPM_ENUM("Route", hpb_input_enum);
394
395static const char * const dig_mux_text[] = {
396 "ADC", "DSP"};
397
398static const struct soc_enum dig_mux_enum =
399 SOC_ENUM_SINGLE(CS42L56_MISC_CTL, 7,
400 ARRAY_SIZE(dig_mux_text),
401 dig_mux_text);
402
403static const struct snd_kcontrol_new dig_mux =
404 SOC_DAPM_ENUM("Route", dig_mux_enum);
405
406static const char * const hpf_freq_text[] = {
407 "1.8Hz", "119Hz", "236Hz", "464Hz"
408};
409
410static const struct soc_enum hpfa_freq_enum =
411 SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 0,
412 ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
413
414static const struct soc_enum hpfb_freq_enum =
415 SOC_ENUM_SINGLE(CS42L56_HPF_CTL, 2,
416 ARRAY_SIZE(hpf_freq_text), hpf_freq_text);
417
418static const char * const ng_delay_text[] = {
419 "50ms", "100ms", "150ms", "200ms"
420};
421
422static const struct soc_enum ng_delay_enum =
423 SOC_ENUM_SINGLE(CS42L56_NOISE_GATE_CTL, 0,
424 ARRAY_SIZE(ng_delay_text), ng_delay_text);
425
426static const struct snd_kcontrol_new cs42l56_snd_controls[] = {
427
428 SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L56_MASTER_A_VOLUME,
Brian Austina0465582014-07-17 13:16:55 -0500429 CS42L56_MASTER_B_VOLUME, 0, 0x34, 0xE4, adv_tlv),
Brian Austin272b5ed2014-05-05 15:09:08 -0500430 SOC_DOUBLE("Master Mute Switch", CS42L56_DSP_MUTE_CTL, 0, 1, 1, 1),
431
432 SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", CS42L56_ADCA_MIX_VOLUME,
Brian Austina0465582014-07-17 13:16:55 -0500433 CS42L56_ADCB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv),
Brian Austin272b5ed2014-05-05 15:09:08 -0500434 SOC_DOUBLE("ADC Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 6, 7, 1, 1),
435
436 SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume", CS42L56_PCMA_MIX_VOLUME,
Brian Austina0465582014-07-17 13:16:55 -0500437 CS42L56_PCMB_MIX_VOLUME, 0, 0x88, 0x90, hl_tlv),
Brian Austin272b5ed2014-05-05 15:09:08 -0500438 SOC_DOUBLE("PCM Mixer Mute Switch", CS42L56_DSP_MUTE_CTL, 4, 5, 1, 1),
439
440 SOC_SINGLE_TLV("Analog Advisory Volume",
441 CS42L56_ANAINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
442 SOC_SINGLE_TLV("Digital Advisory Volume",
443 CS42L56_DIGINPUT_ADV_VOLUME, 0, 0x00, 1, adv_tlv),
444
445 SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L56_PGAA_MUX_VOLUME,
Brian Austina0465582014-07-17 13:16:55 -0500446 CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0x24, pga_tlv),
Brian Austin272b5ed2014-05-05 15:09:08 -0500447 SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR,
448 CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv),
449 SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1),
450 SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1),
451
452 SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME,
Brian Austina0465582014-07-17 13:16:55 -0500453 CS42L56_HPB_VOLUME, 0, 0x84, 0x48, hl_tlv),
Brian Austin272b5ed2014-05-05 15:09:08 -0500454 SOC_DOUBLE_R_SX_TLV("LineOut Volume", CS42L56_LOA_VOLUME,
Brian Austina0465582014-07-17 13:16:55 -0500455 CS42L56_LOB_VOLUME, 0, 0x84, 0x48, hl_tlv),
Brian Austin272b5ed2014-05-05 15:09:08 -0500456
457 SOC_SINGLE_TLV("Bass Shelving Volume", CS42L56_TONE_CTL,
458 0, 0x00, 1, tone_tlv),
459 SOC_SINGLE_TLV("Treble Shelving Volume", CS42L56_TONE_CTL,
460 4, 0x00, 1, tone_tlv),
461
462 SOC_DOUBLE_TLV("PGA Preamp Volume", CS42L56_GAIN_BIAS_CTL,
463 4, 6, 0x02, 1, preamp_tlv),
464
465 SOC_SINGLE("DSP Switch", CS42L56_PLAYBACK_CTL, 7, 1, 1),
466 SOC_SINGLE("Gang Playback Switch", CS42L56_PLAYBACK_CTL, 4, 1, 1),
467 SOC_SINGLE("Gang ADC Switch", CS42L56_MISC_ADC_CTL, 7, 1, 1),
468 SOC_SINGLE("Gang PGA Switch", CS42L56_MISC_ADC_CTL, 6, 1, 1),
469
470 SOC_SINGLE("PCMA Invert", CS42L56_PLAYBACK_CTL, 2, 1, 1),
471 SOC_SINGLE("PCMB Invert", CS42L56_PLAYBACK_CTL, 3, 1, 1),
472 SOC_SINGLE("ADCA Invert", CS42L56_MISC_ADC_CTL, 2, 1, 1),
473 SOC_SINGLE("ADCB Invert", CS42L56_MISC_ADC_CTL, 3, 1, 1),
474
Brian Austin272b5ed2014-05-05 15:09:08 -0500475 SOC_DOUBLE("HPF Switch", CS42L56_HPF_CTL, 5, 7, 1, 1),
476 SOC_DOUBLE("HPF Freeze Switch", CS42L56_HPF_CTL, 4, 6, 1, 1),
477 SOC_ENUM("HPFA Corner Freq", hpfa_freq_enum),
478 SOC_ENUM("HPFB Corner Freq", hpfb_freq_enum),
479
480 SOC_SINGLE("Analog Soft Ramp", CS42L56_MISC_CTL, 4, 1, 1),
481 SOC_DOUBLE("Analog Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
482 7, 5, 1, 1),
483 SOC_SINGLE("Analog Zero Cross", CS42L56_MISC_CTL, 3, 1, 1),
484 SOC_DOUBLE("Analog Zero Cross Disable", CS42L56_ALC_LIM_SFT_ZC,
485 6, 4, 1, 1),
486 SOC_SINGLE("Digital Soft Ramp", CS42L56_MISC_CTL, 2, 1, 1),
487 SOC_SINGLE("Digital Soft Ramp Disable", CS42L56_ALC_LIM_SFT_ZC,
488 3, 1, 1),
489
490 SOC_SINGLE("HL Deemphasis", CS42L56_PLAYBACK_CTL, 6, 1, 1),
491
492 SOC_SINGLE("ALC Switch", CS42L56_ALC_EN_ATTACK_RATE, 6, 1, 1),
493 SOC_SINGLE("ALC Limit All Switch", CS42L56_ALC_RELEASE_RATE, 7, 1, 1),
494 SOC_SINGLE_RANGE("ALC Attack", CS42L56_ALC_EN_ATTACK_RATE,
495 0, 0, 0x3f, 0),
496 SOC_SINGLE_RANGE("ALC Release", CS42L56_ALC_RELEASE_RATE,
497 0, 0x3f, 0, 0),
498 SOC_SINGLE_TLV("ALC MAX", CS42L56_ALC_THRESHOLD,
499 5, 0x07, 1, alc_tlv),
500 SOC_SINGLE_TLV("ALC MIN", CS42L56_ALC_THRESHOLD,
501 2, 0x07, 1, alc_tlv),
502
503 SOC_SINGLE("Limiter Switch", CS42L56_LIM_CTL_RELEASE_RATE, 7, 1, 1),
504 SOC_SINGLE("Limit All Switch", CS42L56_LIM_CTL_RELEASE_RATE, 6, 1, 1),
505 SOC_SINGLE_RANGE("Limiter Attack", CS42L56_LIM_ATTACK_RATE,
506 0, 0, 0x3f, 0),
507 SOC_SINGLE_RANGE("Limiter Release", CS42L56_LIM_CTL_RELEASE_RATE,
508 0, 0x3f, 0, 0),
509 SOC_SINGLE_TLV("Limiter MAX", CS42L56_LIM_THRESHOLD_CTL,
510 5, 0x07, 1, alc_tlv),
511 SOC_SINGLE_TLV("Limiter Cushion", CS42L56_ALC_THRESHOLD,
512 2, 0x07, 1, alc_tlv),
513
514 SOC_SINGLE("NG Switch", CS42L56_NOISE_GATE_CTL, 6, 1, 1),
515 SOC_SINGLE("NG All Switch", CS42L56_NOISE_GATE_CTL, 7, 1, 1),
516 SOC_SINGLE("NG Boost Switch", CS42L56_NOISE_GATE_CTL, 5, 1, 1),
517 SOC_SINGLE_TLV("NG Unboost Threshold", CS42L56_NOISE_GATE_CTL,
518 2, 0x07, 1, ngnb_tlv),
519 SOC_SINGLE_TLV("NG Boost Threshold", CS42L56_NOISE_GATE_CTL,
520 2, 0x07, 1, ngb_tlv),
521 SOC_ENUM("NG Delay", ng_delay_enum),
522
523 SOC_ENUM("Beep Config", beep_config_enum),
524 SOC_ENUM("Beep Pitch", beep_pitch_enum),
525 SOC_ENUM("Beep on Time", beep_ontime_enum),
526 SOC_ENUM("Beep off Time", beep_offtime_enum),
527 SOC_SINGLE_SX_TLV("Beep Volume", CS42L56_BEEP_FREQ_OFFTIME,
528 0, 0x07, 0x23, beep_tlv),
529 SOC_SINGLE("Beep Tone Ctl Switch", CS42L56_BEEP_TONE_CFG, 0, 1, 1),
530 SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
531 SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
532
533};
534
535static const struct snd_soc_dapm_widget cs42l56_dapm_widgets[] = {
536
537 SND_SOC_DAPM_SIGGEN("Beep"),
538 SND_SOC_DAPM_SUPPLY("VBUF", CS42L56_PWRCTL_1, 5, 1, NULL, 0),
539 SND_SOC_DAPM_MICBIAS("MIC1 Bias", CS42L56_PWRCTL_1, 4, 1),
540 SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L56_PWRCTL_1, 3, 1, NULL, 0),
541
542 SND_SOC_DAPM_INPUT("AIN1A"),
543 SND_SOC_DAPM_INPUT("AIN2A"),
544 SND_SOC_DAPM_INPUT("AIN1B"),
545 SND_SOC_DAPM_INPUT("AIN2B"),
546 SND_SOC_DAPM_INPUT("AIN3A"),
547 SND_SOC_DAPM_INPUT("AIN3B"),
548
549 SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0,
550 SND_SOC_NOPM, 0, 0),
551
552 SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0,
553 SND_SOC_NOPM, 0, 0),
554
555 SND_SOC_DAPM_MUX("Digital Output Mux", SND_SOC_NOPM,
556 0, 0, &dig_mux),
557
558 SND_SOC_DAPM_PGA("PGAA", SND_SOC_NOPM, 0, 0, NULL, 0),
559 SND_SOC_DAPM_PGA("PGAB", SND_SOC_NOPM, 0, 0, NULL, 0),
560 SND_SOC_DAPM_MUX("PGAA Input Mux",
561 SND_SOC_NOPM, 0, 0, &pgaa_mux),
562 SND_SOC_DAPM_MUX("PGAB Input Mux",
563 SND_SOC_NOPM, 0, 0, &pgab_mux),
564
565 SND_SOC_DAPM_MUX("ADCA Mux", SND_SOC_NOPM,
566 0, 0, &adca_mux),
567 SND_SOC_DAPM_MUX("ADCB Mux", SND_SOC_NOPM,
568 0, 0, &adcb_mux),
569
570 SND_SOC_DAPM_ADC("ADCA", NULL, CS42L56_PWRCTL_1, 1, 1),
571 SND_SOC_DAPM_ADC("ADCB", NULL, CS42L56_PWRCTL_1, 2, 1),
572
Brian Austinc4324bf2014-07-08 09:56:35 -0500573 SND_SOC_DAPM_MUX("ADCA Swap Mux", SND_SOC_NOPM, 0, 0,
574 &adca_swap_mux),
575 SND_SOC_DAPM_MUX("ADCB Swap Mux", SND_SOC_NOPM, 0, 0,
576 &adcb_swap_mux),
577
578 SND_SOC_DAPM_MUX("PCMA Swap Mux", SND_SOC_NOPM, 0, 0,
579 &pcma_swap_mux),
580 SND_SOC_DAPM_MUX("PCMB Swap Mux", SND_SOC_NOPM, 0, 0,
581 &pcmb_swap_mux),
582
Brian Austin272b5ed2014-05-05 15:09:08 -0500583 SND_SOC_DAPM_DAC("DACA", NULL, SND_SOC_NOPM, 0, 0),
584 SND_SOC_DAPM_DAC("DACB", NULL, SND_SOC_NOPM, 0, 0),
585
586 SND_SOC_DAPM_OUTPUT("HPA"),
587 SND_SOC_DAPM_OUTPUT("LOA"),
588 SND_SOC_DAPM_OUTPUT("HPB"),
589 SND_SOC_DAPM_OUTPUT("LOB"),
590
591 SND_SOC_DAPM_SWITCH("Headphone Right",
592 CS42L56_PWRCTL_2, 4, 1, &hpb_switch),
593 SND_SOC_DAPM_SWITCH("Headphone Left",
594 CS42L56_PWRCTL_2, 6, 1, &hpa_switch),
595
596 SND_SOC_DAPM_SWITCH("Lineout Right",
597 CS42L56_PWRCTL_2, 0, 1, &lob_switch),
598 SND_SOC_DAPM_SWITCH("Lineout Left",
599 CS42L56_PWRCTL_2, 2, 1, &loa_switch),
600
601 SND_SOC_DAPM_MUX("LINEOUTA Input Mux", SND_SOC_NOPM,
602 0, 0, &lineouta_input),
603 SND_SOC_DAPM_MUX("LINEOUTB Input Mux", SND_SOC_NOPM,
604 0, 0, &lineoutb_input),
605 SND_SOC_DAPM_MUX("HPA Input Mux", SND_SOC_NOPM,
606 0, 0, &hpa_input),
607 SND_SOC_DAPM_MUX("HPB Input Mux", SND_SOC_NOPM,
608 0, 0, &hpb_input),
609
610};
611
612static const struct snd_soc_dapm_route cs42l56_audio_map[] = {
613
614 {"HiFi Capture", "DSP", "Digital Output Mux"},
615 {"HiFi Capture", "ADC", "Digital Output Mux"},
616
617 {"Digital Output Mux", NULL, "ADCA"},
618 {"Digital Output Mux", NULL, "ADCB"},
619
Brian Austinc4324bf2014-07-08 09:56:35 -0500620 {"ADCB", NULL, "ADCB Swap Mux"},
621 {"ADCA", NULL, "ADCA Swap Mux"},
622
623 {"ADCA Swap Mux", NULL, "ADCA"},
624 {"ADCB Swap Mux", NULL, "ADCB"},
625
626 {"DACA", "Left", "ADCA Swap Mux"},
627 {"DACA", "LR 2", "ADCA Swap Mux"},
628 {"DACA", "Right", "ADCA Swap Mux"},
629
630 {"DACB", "Left", "ADCB Swap Mux"},
631 {"DACB", "LR 2", "ADCB Swap Mux"},
632 {"DACB", "Right", "ADCB Swap Mux"},
Brian Austin272b5ed2014-05-05 15:09:08 -0500633
634 {"ADCA Mux", NULL, "AIN3A"},
635 {"ADCA Mux", NULL, "AIN2A"},
636 {"ADCA Mux", NULL, "AIN1A"},
637 {"ADCA Mux", NULL, "PGAA"},
638 {"ADCB Mux", NULL, "AIN3B"},
639 {"ADCB Mux", NULL, "AIN2B"},
640 {"ADCB Mux", NULL, "AIN1B"},
641 {"ADCB Mux", NULL, "PGAB"},
642
643 {"PGAA", "AIN1A", "PGAA Input Mux"},
644 {"PGAA", "AIN2A", "PGAA Input Mux"},
645 {"PGAA", "AIN3A", "PGAA Input Mux"},
646 {"PGAB", "AIN1B", "PGAB Input Mux"},
647 {"PGAB", "AIN2B", "PGAB Input Mux"},
648 {"PGAB", "AIN3B", "PGAB Input Mux"},
649
650 {"PGAA Input Mux", NULL, "AIN1A"},
651 {"PGAA Input Mux", NULL, "AIN2A"},
652 {"PGAA Input Mux", NULL, "AIN3A"},
653 {"PGAB Input Mux", NULL, "AIN1B"},
654 {"PGAB Input Mux", NULL, "AIN2B"},
655 {"PGAB Input Mux", NULL, "AIN3B"},
656
Brian Austinc4324bf2014-07-08 09:56:35 -0500657 {"LOB", "Switch", "LINEOUTB Input Mux"},
658 {"LOA", "Switch", "LINEOUTA Input Mux"},
Brian Austin272b5ed2014-05-05 15:09:08 -0500659
660 {"LINEOUTA Input Mux", "PGAA", "PGAA"},
661 {"LINEOUTB Input Mux", "PGAB", "PGAB"},
662 {"LINEOUTA Input Mux", "DACA", "DACA"},
663 {"LINEOUTB Input Mux", "DACB", "DACB"},
664
Brian Austinc4324bf2014-07-08 09:56:35 -0500665 {"HPA", "Switch", "HPB Input Mux"},
666 {"HPB", "Switch", "HPA Input Mux"},
Brian Austin272b5ed2014-05-05 15:09:08 -0500667
668 {"HPA Input Mux", "PGAA", "PGAA"},
669 {"HPB Input Mux", "PGAB", "PGAB"},
670 {"HPA Input Mux", "DACA", "DACA"},
671 {"HPB Input Mux", "DACB", "DACB"},
672
Brian Austinc4324bf2014-07-08 09:56:35 -0500673 {"DACA", NULL, "PCMA Swap Mux"},
674 {"DACB", NULL, "PCMB Swap Mux"},
675
676 {"PCMB Swap Mux", "Left", "HiFi Playback"},
677 {"PCMB Swap Mux", "LR 2", "HiFi Playback"},
678 {"PCMB Swap Mux", "Right", "HiFi Playback"},
679
680 {"PCMA Swap Mux", "Left", "HiFi Playback"},
681 {"PCMA Swap Mux", "LR 2", "HiFi Playback"},
682 {"PCMA Swap Mux", "Right", "HiFi Playback"},
Brian Austin272b5ed2014-05-05 15:09:08 -0500683
684};
685
686struct cs42l56_clk_para {
687 u32 mclk;
688 u32 srate;
689 u8 ratio;
690};
691
692static const struct cs42l56_clk_para clk_ratio_table[] = {
693 /* 8k */
694 { 6000000, 8000, CS42L56_MCLK_LRCLK_768 },
695 { 6144000, 8000, CS42L56_MCLK_LRCLK_750 },
696 { 12000000, 8000, CS42L56_MCLK_LRCLK_768 },
697 { 12288000, 8000, CS42L56_MCLK_LRCLK_750 },
698 { 24000000, 8000, CS42L56_MCLK_LRCLK_768 },
699 { 24576000, 8000, CS42L56_MCLK_LRCLK_750 },
700 /* 11.025k */
701 { 5644800, 11025, CS42L56_MCLK_LRCLK_512},
702 { 11289600, 11025, CS42L56_MCLK_LRCLK_512},
703 { 22579200, 11025, CS42L56_MCLK_LRCLK_512 },
704 /* 11.0294k */
705 { 6000000, 110294, CS42L56_MCLK_LRCLK_544 },
706 { 12000000, 110294, CS42L56_MCLK_LRCLK_544 },
707 { 24000000, 110294, CS42L56_MCLK_LRCLK_544 },
708 /* 12k */
709 { 6000000, 12000, CS42L56_MCLK_LRCLK_500 },
710 { 6144000, 12000, CS42L56_MCLK_LRCLK_512 },
711 { 12000000, 12000, CS42L56_MCLK_LRCLK_500 },
712 { 12288000, 12000, CS42L56_MCLK_LRCLK_512 },
713 { 24000000, 12000, CS42L56_MCLK_LRCLK_500 },
714 { 24576000, 12000, CS42L56_MCLK_LRCLK_512 },
715 /* 16k */
716 { 6000000, 16000, CS42L56_MCLK_LRCLK_375 },
717 { 6144000, 16000, CS42L56_MCLK_LRCLK_384 },
718 { 12000000, 16000, CS42L56_MCLK_LRCLK_375 },
719 { 12288000, 16000, CS42L56_MCLK_LRCLK_384 },
720 { 24000000, 16000, CS42L56_MCLK_LRCLK_375 },
721 { 24576000, 16000, CS42L56_MCLK_LRCLK_384 },
722 /* 22.050k */
723 { 5644800, 22050, CS42L56_MCLK_LRCLK_256 },
724 { 11289600, 22050, CS42L56_MCLK_LRCLK_256 },
725 { 22579200, 22050, CS42L56_MCLK_LRCLK_256 },
726 /* 22.0588k */
727 { 6000000, 220588, CS42L56_MCLK_LRCLK_272 },
728 { 12000000, 220588, CS42L56_MCLK_LRCLK_272 },
729 { 24000000, 220588, CS42L56_MCLK_LRCLK_272 },
730 /* 24k */
731 { 6000000, 24000, CS42L56_MCLK_LRCLK_250 },
732 { 6144000, 24000, CS42L56_MCLK_LRCLK_256 },
733 { 12000000, 24000, CS42L56_MCLK_LRCLK_250 },
734 { 12288000, 24000, CS42L56_MCLK_LRCLK_256 },
735 { 24000000, 24000, CS42L56_MCLK_LRCLK_250 },
736 { 24576000, 24000, CS42L56_MCLK_LRCLK_256 },
737 /* 32k */
738 { 6000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
739 { 6144000, 32000, CS42L56_MCLK_LRCLK_192 },
740 { 12000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
741 { 12288000, 32000, CS42L56_MCLK_LRCLK_192 },
742 { 24000000, 32000, CS42L56_MCLK_LRCLK_187P5 },
743 { 24576000, 32000, CS42L56_MCLK_LRCLK_192 },
744 /* 44.118k */
745 { 6000000, 44118, CS42L56_MCLK_LRCLK_136 },
746 { 12000000, 44118, CS42L56_MCLK_LRCLK_136 },
747 { 24000000, 44118, CS42L56_MCLK_LRCLK_136 },
748 /* 44.1k */
749 { 5644800, 44100, CS42L56_MCLK_LRCLK_128 },
750 { 11289600, 44100, CS42L56_MCLK_LRCLK_128 },
751 { 22579200, 44100, CS42L56_MCLK_LRCLK_128 },
752 /* 48k */
753 { 6000000, 48000, CS42L56_MCLK_LRCLK_125 },
754 { 6144000, 48000, CS42L56_MCLK_LRCLK_128 },
755 { 12000000, 48000, CS42L56_MCLK_LRCLK_125 },
756 { 12288000, 48000, CS42L56_MCLK_LRCLK_128 },
757 { 24000000, 48000, CS42L56_MCLK_LRCLK_125 },
758 { 24576000, 48000, CS42L56_MCLK_LRCLK_128 },
759};
760
761static int cs42l56_get_mclk_ratio(int mclk, int rate)
762{
763 int i;
764
765 for (i = 0; i < ARRAY_SIZE(clk_ratio_table); i++) {
766 if (clk_ratio_table[i].mclk == mclk &&
767 clk_ratio_table[i].srate == rate)
768 return clk_ratio_table[i].ratio;
769 }
770 return -EINVAL;
771}
772
773static int cs42l56_set_sysclk(struct snd_soc_dai *codec_dai,
774 int clk_id, unsigned int freq, int dir)
775{
776 struct snd_soc_codec *codec = codec_dai->codec;
777 struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
778
779 switch (freq) {
780 case CS42L56_MCLK_5P6448MHZ:
781 case CS42L56_MCLK_6MHZ:
782 case CS42L56_MCLK_6P144MHZ:
783 cs42l56->mclk_div2 = 0;
784 cs42l56->mclk_prediv = 0;
785 break;
786 case CS42L56_MCLK_11P2896MHZ:
787 case CS42L56_MCLK_12MHZ:
788 case CS42L56_MCLK_12P288MHZ:
Axel Lin4641c772014-05-23 13:05:31 +0800789 cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
Brian Austin272b5ed2014-05-05 15:09:08 -0500790 cs42l56->mclk_prediv = 0;
791 break;
792 case CS42L56_MCLK_22P5792MHZ:
793 case CS42L56_MCLK_24MHZ:
794 case CS42L56_MCLK_24P576MHZ:
Axel Lin4641c772014-05-23 13:05:31 +0800795 cs42l56->mclk_div2 = CS42L56_MCLK_DIV2;
796 cs42l56->mclk_prediv = CS42L56_MCLK_PREDIV;
Brian Austin272b5ed2014-05-05 15:09:08 -0500797 break;
798 default:
799 return -EINVAL;
800 }
801 cs42l56->mclk = freq;
802
803 snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
804 CS42L56_MCLK_PREDIV_MASK,
805 cs42l56->mclk_prediv);
806 snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
807 CS42L56_MCLK_DIV2_MASK,
808 cs42l56->mclk_div2);
809
810 return 0;
811}
812
813static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
814{
815 struct snd_soc_codec *codec = codec_dai->codec;
816 struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
817
818 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
819 case SND_SOC_DAIFMT_CBM_CFM:
820 cs42l56->iface = CS42L56_MASTER_MODE;
821 break;
822 case SND_SOC_DAIFMT_CBS_CFS:
823 cs42l56->iface = CS42L56_SLAVE_MODE;
824 break;
825 default:
826 return -EINVAL;
827 }
828
829 /* interface format */
830 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
831 case SND_SOC_DAIFMT_I2S:
832 cs42l56->iface_fmt = CS42L56_DIG_FMT_I2S;
833 break;
834 case SND_SOC_DAIFMT_LEFT_J:
835 cs42l56->iface_fmt = CS42L56_DIG_FMT_LEFT_J;
836 break;
837 default:
838 return -EINVAL;
839 }
840
841 /* sclk inversion */
842 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
843 case SND_SOC_DAIFMT_NB_NF:
844 cs42l56->iface_inv = 0;
845 break;
846 case SND_SOC_DAIFMT_IB_NF:
847 cs42l56->iface_inv = CS42L56_SCLK_INV;
848 break;
849 default:
850 return -EINVAL;
851 }
852
853 snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
854 CS42L56_MS_MODE_MASK, cs42l56->iface);
855 snd_soc_update_bits(codec, CS42L56_SERIAL_FMT,
856 CS42L56_DIG_FMT_MASK, cs42l56->iface_fmt);
857 snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
858 CS42L56_SCLK_INV_MASK, cs42l56->iface_inv);
859 return 0;
860}
861
862static int cs42l56_digital_mute(struct snd_soc_dai *dai, int mute)
863{
864 struct snd_soc_codec *codec = dai->codec;
865
866 if (mute) {
867 /* Hit the DSP Mixer first */
868 snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
869 CS42L56_ADCAMIX_MUTE_MASK |
Axel Lin4641c772014-05-23 13:05:31 +0800870 CS42L56_ADCBMIX_MUTE_MASK |
871 CS42L56_PCMAMIX_MUTE_MASK |
872 CS42L56_PCMBMIX_MUTE_MASK |
873 CS42L56_MSTB_MUTE_MASK |
874 CS42L56_MSTA_MUTE_MASK,
875 CS42L56_MUTE_ALL);
Brian Austin272b5ed2014-05-05 15:09:08 -0500876 /* Mute ADC's */
877 snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
Axel Lin4641c772014-05-23 13:05:31 +0800878 CS42L56_ADCA_MUTE_MASK |
879 CS42L56_ADCB_MUTE_MASK,
880 CS42L56_MUTE_ALL);
Brian Austin272b5ed2014-05-05 15:09:08 -0500881 /* HP And LO */
882 snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
Axel Lin4641c772014-05-23 13:05:31 +0800883 CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
Brian Austin272b5ed2014-05-05 15:09:08 -0500884 snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
Axel Lin4641c772014-05-23 13:05:31 +0800885 CS42L56_HP_MUTE_MASK, CS42L56_MUTE_ALL);
Brian Austin272b5ed2014-05-05 15:09:08 -0500886 snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
Axel Lin4641c772014-05-23 13:05:31 +0800887 CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
Brian Austin272b5ed2014-05-05 15:09:08 -0500888 snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
Axel Lin4641c772014-05-23 13:05:31 +0800889 CS42L56_LO_MUTE_MASK, CS42L56_MUTE_ALL);
Brian Austin272b5ed2014-05-05 15:09:08 -0500890 } else {
891 snd_soc_update_bits(codec, CS42L56_DSP_MUTE_CTL,
892 CS42L56_ADCAMIX_MUTE_MASK |
Axel Lin4641c772014-05-23 13:05:31 +0800893 CS42L56_ADCBMIX_MUTE_MASK |
894 CS42L56_PCMAMIX_MUTE_MASK |
895 CS42L56_PCMBMIX_MUTE_MASK |
896 CS42L56_MSTB_MUTE_MASK |
897 CS42L56_MSTA_MUTE_MASK,
898 CS42L56_UNMUTE);
899
Brian Austin272b5ed2014-05-05 15:09:08 -0500900 snd_soc_update_bits(codec, CS42L56_MISC_ADC_CTL,
Axel Lin4641c772014-05-23 13:05:31 +0800901 CS42L56_ADCA_MUTE_MASK |
902 CS42L56_ADCB_MUTE_MASK,
903 CS42L56_UNMUTE);
904
Brian Austin272b5ed2014-05-05 15:09:08 -0500905 snd_soc_update_bits(codec, CS42L56_HPA_VOLUME,
Axel Lin4641c772014-05-23 13:05:31 +0800906 CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
Brian Austin272b5ed2014-05-05 15:09:08 -0500907 snd_soc_update_bits(codec, CS42L56_HPB_VOLUME,
Axel Lin4641c772014-05-23 13:05:31 +0800908 CS42L56_HP_MUTE_MASK, CS42L56_UNMUTE);
Brian Austin272b5ed2014-05-05 15:09:08 -0500909 snd_soc_update_bits(codec, CS42L56_LOA_VOLUME,
Axel Lin4641c772014-05-23 13:05:31 +0800910 CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
Brian Austin272b5ed2014-05-05 15:09:08 -0500911 snd_soc_update_bits(codec, CS42L56_LOB_VOLUME,
Axel Lin4641c772014-05-23 13:05:31 +0800912 CS42L56_LO_MUTE_MASK, CS42L56_UNMUTE);
Brian Austin272b5ed2014-05-05 15:09:08 -0500913 }
914 return 0;
915}
916
917static int cs42l56_pcm_hw_params(struct snd_pcm_substream *substream,
918 struct snd_pcm_hw_params *params,
919 struct snd_soc_dai *dai)
920{
921 struct snd_soc_codec *codec = dai->codec;
922 struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
923 int ratio;
924
925 ratio = cs42l56_get_mclk_ratio(cs42l56->mclk, params_rate(params));
926 if (ratio >= 0) {
927 snd_soc_update_bits(codec, CS42L56_CLKCTL_2,
928 CS42L56_CLK_RATIO_MASK, ratio);
929 } else {
930 dev_err(codec->dev, "unsupported mclk/sclk/lrclk ratio\n");
931 return -EINVAL;
932 }
933
934 return 0;
935}
936
937static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
938 enum snd_soc_bias_level level)
939{
940 struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
941 int ret;
942
943 switch (level) {
944 case SND_SOC_BIAS_ON:
945 break;
946 case SND_SOC_BIAS_PREPARE:
947 snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
948 CS42L56_MCLK_DIS_MASK, 0);
949 snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
950 CS42L56_PDN_ALL_MASK, 0);
951 break;
952 case SND_SOC_BIAS_STANDBY:
Lars-Peter Clausen46a35b02015-06-01 10:10:21 +0200953 if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
Brian Austin272b5ed2014-05-05 15:09:08 -0500954 regcache_cache_only(cs42l56->regmap, false);
955 regcache_sync(cs42l56->regmap);
956 ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
957 cs42l56->supplies);
958 if (ret != 0) {
959 dev_err(cs42l56->dev,
960 "Failed to enable regulators: %d\n",
961 ret);
962 return ret;
963 }
964 }
965 snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
966 CS42L56_PDN_ALL_MASK, 1);
967 break;
968 case SND_SOC_BIAS_OFF:
969 snd_soc_update_bits(codec, CS42L56_PWRCTL_1,
970 CS42L56_PDN_ALL_MASK, 1);
971 snd_soc_update_bits(codec, CS42L56_CLKCTL_1,
972 CS42L56_MCLK_DIS_MASK, 1);
973 regcache_cache_only(cs42l56->regmap, true);
974 regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
975 cs42l56->supplies);
976 break;
977 }
Brian Austin272b5ed2014-05-05 15:09:08 -0500978
979 return 0;
980}
981
982#define CS42L56_RATES (SNDRV_PCM_RATE_8000_48000)
983
984#define CS42L56_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
985 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
986 SNDRV_PCM_FMTBIT_S32_LE)
987
988
989static struct snd_soc_dai_ops cs42l56_ops = {
990 .hw_params = cs42l56_pcm_hw_params,
991 .digital_mute = cs42l56_digital_mute,
992 .set_fmt = cs42l56_set_dai_fmt,
993 .set_sysclk = cs42l56_set_sysclk,
994};
995
996static struct snd_soc_dai_driver cs42l56_dai = {
997 .name = "cs42l56",
998 .playback = {
999 .stream_name = "HiFi Playback",
1000 .channels_min = 1,
1001 .channels_max = 2,
1002 .rates = CS42L56_RATES,
1003 .formats = CS42L56_FORMATS,
1004 },
1005 .capture = {
1006 .stream_name = "HiFi Capture",
1007 .channels_min = 1,
1008 .channels_max = 2,
1009 .rates = CS42L56_RATES,
1010 .formats = CS42L56_FORMATS,
1011 },
1012 .ops = &cs42l56_ops,
1013};
1014
Brian Austin272b5ed2014-05-05 15:09:08 -05001015static int beep_freq[] = {
1016 261, 522, 585, 667, 706, 774, 889, 1000,
1017 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
1018};
1019
1020static void cs42l56_beep_work(struct work_struct *work)
1021{
1022 struct cs42l56_private *cs42l56 =
1023 container_of(work, struct cs42l56_private, beep_work);
1024 struct snd_soc_codec *codec = cs42l56->codec;
Lars-Peter Clausen46a35b02015-06-01 10:10:21 +02001025 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Brian Austin272b5ed2014-05-05 15:09:08 -05001026 int i;
1027 int val = 0;
1028 int best = 0;
1029
1030 if (cs42l56->beep_rate) {
1031 for (i = 0; i < ARRAY_SIZE(beep_freq); i++) {
1032 if (abs(cs42l56->beep_rate - beep_freq[i]) <
1033 abs(cs42l56->beep_rate - beep_freq[best]))
1034 best = i;
1035 }
1036
1037 dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
1038 beep_freq[best], cs42l56->beep_rate);
1039
1040 val = (best << CS42L56_BEEP_RATE_SHIFT);
1041
1042 snd_soc_dapm_enable_pin(dapm, "Beep");
1043 } else {
1044 dev_dbg(codec->dev, "Disabling beep\n");
1045 snd_soc_dapm_disable_pin(dapm, "Beep");
1046 }
1047
1048 snd_soc_update_bits(codec, CS42L56_BEEP_FREQ_ONTIME,
1049 CS42L56_BEEP_FREQ_MASK, val);
1050
1051 snd_soc_dapm_sync(dapm);
1052}
1053
1054/* For usability define a way of injecting beep events for the device -
1055 * many systems will not have a keyboard.
1056 */
1057static int cs42l56_beep_event(struct input_dev *dev, unsigned int type,
1058 unsigned int code, int hz)
1059{
1060 struct snd_soc_codec *codec = input_get_drvdata(dev);
1061 struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
1062
1063 dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
1064
1065 switch (code) {
1066 case SND_BELL:
1067 if (hz)
1068 hz = 261;
1069 case SND_TONE:
1070 break;
1071 default:
1072 return -1;
1073 }
1074
1075 /* Kick the beep from a workqueue */
1076 cs42l56->beep_rate = hz;
1077 schedule_work(&cs42l56->beep_work);
1078 return 0;
1079}
1080
1081static ssize_t cs42l56_beep_set(struct device *dev,
1082 struct device_attribute *attr,
1083 const char *buf, size_t count)
1084{
1085 struct cs42l56_private *cs42l56 = dev_get_drvdata(dev);
1086 long int time;
1087 int ret;
1088
1089 ret = kstrtol(buf, 10, &time);
1090 if (ret != 0)
1091 return ret;
1092
1093 input_event(cs42l56->beep, EV_SND, SND_TONE, time);
1094
1095 return count;
1096}
1097
1098static DEVICE_ATTR(beep, 0200, NULL, cs42l56_beep_set);
1099
1100static void cs42l56_init_beep(struct snd_soc_codec *codec)
1101{
1102 struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
1103 int ret;
1104
1105 cs42l56->beep = devm_input_allocate_device(codec->dev);
1106 if (!cs42l56->beep) {
1107 dev_err(codec->dev, "Failed to allocate beep device\n");
1108 return;
1109 }
1110
1111 INIT_WORK(&cs42l56->beep_work, cs42l56_beep_work);
1112 cs42l56->beep_rate = 0;
1113
1114 cs42l56->beep->name = "CS42L56 Beep Generator";
1115 cs42l56->beep->phys = dev_name(codec->dev);
1116 cs42l56->beep->id.bustype = BUS_I2C;
1117
1118 cs42l56->beep->evbit[0] = BIT_MASK(EV_SND);
1119 cs42l56->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
1120 cs42l56->beep->event = cs42l56_beep_event;
1121 cs42l56->beep->dev.parent = codec->dev;
1122 input_set_drvdata(cs42l56->beep, codec);
1123
1124 ret = input_register_device(cs42l56->beep);
1125 if (ret != 0) {
1126 cs42l56->beep = NULL;
1127 dev_err(codec->dev, "Failed to register beep device\n");
1128 }
1129
1130 ret = device_create_file(codec->dev, &dev_attr_beep);
1131 if (ret != 0) {
1132 dev_err(codec->dev, "Failed to create keyclick file: %d\n",
1133 ret);
1134 }
1135}
1136
1137static void cs42l56_free_beep(struct snd_soc_codec *codec)
1138{
1139 struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
1140
1141 device_remove_file(codec->dev, &dev_attr_beep);
1142 cancel_work_sync(&cs42l56->beep_work);
1143 cs42l56->beep = NULL;
1144
1145 snd_soc_update_bits(codec, CS42L56_BEEP_TONE_CFG,
1146 CS42L56_BEEP_EN_MASK, 0);
1147}
1148
1149static int cs42l56_probe(struct snd_soc_codec *codec)
1150{
1151 cs42l56_init_beep(codec);
1152
Brian Austin272b5ed2014-05-05 15:09:08 -05001153 return 0;
1154}
1155
1156static int cs42l56_remove(struct snd_soc_codec *codec)
1157{
Brian Austin272b5ed2014-05-05 15:09:08 -05001158 cs42l56_free_beep(codec);
Brian Austin272b5ed2014-05-05 15:09:08 -05001159
1160 return 0;
1161}
1162
Krzysztof Kozlowskicf0efa12015-01-05 10:18:24 +01001163static const struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
Brian Austin272b5ed2014-05-05 15:09:08 -05001164 .probe = cs42l56_probe,
1165 .remove = cs42l56_remove,
Brian Austin272b5ed2014-05-05 15:09:08 -05001166 .set_bias_level = cs42l56_set_bias_level,
Lars-Peter Clausen2a4bc752014-09-09 20:42:41 +02001167 .suspend_bias_off = true,
Brian Austin272b5ed2014-05-05 15:09:08 -05001168
1169 .dapm_widgets = cs42l56_dapm_widgets,
1170 .num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets),
1171 .dapm_routes = cs42l56_audio_map,
1172 .num_dapm_routes = ARRAY_SIZE(cs42l56_audio_map),
1173
1174 .controls = cs42l56_snd_controls,
1175 .num_controls = ARRAY_SIZE(cs42l56_snd_controls),
1176};
1177
Krzysztof Kozlowskicf0efa12015-01-05 10:18:24 +01001178static const struct regmap_config cs42l56_regmap = {
Brian Austin272b5ed2014-05-05 15:09:08 -05001179 .reg_bits = 8,
1180 .val_bits = 8,
1181
1182 .max_register = CS42L56_MAX_REGISTER,
1183 .reg_defaults = cs42l56_reg_defaults,
1184 .num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults),
1185 .readable_reg = cs42l56_readable_register,
1186 .volatile_reg = cs42l56_volatile_register,
1187 .cache_type = REGCACHE_RBTREE,
1188};
1189
1190static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
1191 struct cs42l56_platform_data *pdata)
1192{
1193 struct device_node *np = i2c_client->dev.of_node;
1194 u32 val32;
1195
1196 if (of_property_read_bool(np, "cirrus,ain1a-reference-cfg"))
1197 pdata->ain1a_ref_cfg = true;
1198
1199 if (of_property_read_bool(np, "cirrus,ain2a-reference-cfg"))
1200 pdata->ain2a_ref_cfg = true;
1201
1202 if (of_property_read_bool(np, "cirrus,ain1b-reference-cfg"))
1203 pdata->ain1b_ref_cfg = true;
1204
1205 if (of_property_read_bool(np, "cirrus,ain2b-reference-cfg"))
1206 pdata->ain2b_ref_cfg = true;
1207
1208 if (of_property_read_u32(np, "cirrus,micbias-lvl", &val32) >= 0)
1209 pdata->micbias_lvl = val32;
1210
1211 if (of_property_read_u32(np, "cirrus,chgfreq-divisor", &val32) >= 0)
1212 pdata->chgfreq = val32;
1213
1214 if (of_property_read_u32(np, "cirrus,adaptive-pwr-cfg", &val32) >= 0)
1215 pdata->adaptive_pwr = val32;
1216
1217 if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
1218 pdata->hpfa_freq = val32;
1219
1220 if (of_property_read_u32(np, "cirrus,hpf-left-freq", &val32) >= 0)
1221 pdata->hpfb_freq = val32;
1222
1223 pdata->gpio_nreset = of_get_named_gpio(np, "cirrus,gpio-nreset", 0);
1224
1225 return 0;
1226}
1227
1228static int cs42l56_i2c_probe(struct i2c_client *i2c_client,
1229 const struct i2c_device_id *id)
1230{
1231 struct cs42l56_private *cs42l56;
1232 struct cs42l56_platform_data *pdata =
1233 dev_get_platdata(&i2c_client->dev);
1234 int ret, i;
1235 unsigned int devid = 0;
1236 unsigned int alpha_rev, metal_rev;
1237 unsigned int reg;
1238
1239 cs42l56 = devm_kzalloc(&i2c_client->dev,
1240 sizeof(struct cs42l56_private),
1241 GFP_KERNEL);
1242 if (cs42l56 == NULL)
1243 return -ENOMEM;
1244 cs42l56->dev = &i2c_client->dev;
1245
1246 cs42l56->regmap = devm_regmap_init_i2c(i2c_client, &cs42l56_regmap);
1247 if (IS_ERR(cs42l56->regmap)) {
1248 ret = PTR_ERR(cs42l56->regmap);
1249 dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
1250 return ret;
1251 }
1252
1253 if (pdata) {
1254 cs42l56->pdata = *pdata;
1255 } else {
1256 pdata = devm_kzalloc(&i2c_client->dev,
1257 sizeof(struct cs42l56_platform_data),
1258 GFP_KERNEL);
1259 if (!pdata) {
1260 dev_err(&i2c_client->dev,
1261 "could not allocate pdata\n");
1262 return -ENOMEM;
1263 }
1264 if (i2c_client->dev.of_node) {
1265 ret = cs42l56_handle_of_data(i2c_client,
1266 &cs42l56->pdata);
1267 if (ret != 0)
1268 return ret;
1269 }
1270 cs42l56->pdata = *pdata;
1271 }
1272
1273 if (cs42l56->pdata.gpio_nreset) {
1274 ret = gpio_request_one(cs42l56->pdata.gpio_nreset,
1275 GPIOF_OUT_INIT_HIGH, "CS42L56 /RST");
1276 if (ret < 0) {
1277 dev_err(&i2c_client->dev,
1278 "Failed to request /RST %d: %d\n",
1279 cs42l56->pdata.gpio_nreset, ret);
1280 return ret;
1281 }
1282 gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 0);
1283 gpio_set_value_cansleep(cs42l56->pdata.gpio_nreset, 1);
1284 }
1285
1286
1287 i2c_set_clientdata(i2c_client, cs42l56);
1288
1289 for (i = 0; i < ARRAY_SIZE(cs42l56->supplies); i++)
1290 cs42l56->supplies[i].supply = cs42l56_supply_names[i];
1291
1292 ret = devm_regulator_bulk_get(&i2c_client->dev,
1293 ARRAY_SIZE(cs42l56->supplies),
1294 cs42l56->supplies);
1295 if (ret != 0) {
1296 dev_err(&i2c_client->dev,
1297 "Failed to request supplies: %d\n", ret);
1298 return ret;
1299 }
1300
1301 ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
1302 cs42l56->supplies);
1303 if (ret != 0) {
1304 dev_err(&i2c_client->dev,
1305 "Failed to enable supplies: %d\n", ret);
1306 return ret;
1307 }
1308
1309 regcache_cache_bypass(cs42l56->regmap, true);
1310
1311 ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, &reg);
1312 devid = reg & CS42L56_CHIP_ID_MASK;
1313 if (devid != CS42L56_DEVID) {
1314 dev_err(&i2c_client->dev,
1315 "CS42L56 Device ID (%X). Expected %X\n",
1316 devid, CS42L56_DEVID);
1317 goto err_enable;
1318 }
1319 alpha_rev = reg & CS42L56_AREV_MASK;
1320 metal_rev = reg & CS42L56_MTLREV_MASK;
1321
1322 dev_info(&i2c_client->dev, "Cirrus Logic CS42L56 ");
1323 dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n",
1324 alpha_rev, metal_rev);
1325
1326 regcache_cache_bypass(cs42l56->regmap, false);
1327
1328 if (cs42l56->pdata.ain1a_ref_cfg)
1329 regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
1330 CS42L56_AIN1A_REF_MASK, 1);
1331
1332 if (cs42l56->pdata.ain1b_ref_cfg)
1333 regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
1334 CS42L56_AIN1B_REF_MASK, 1);
1335
1336 if (cs42l56->pdata.ain2a_ref_cfg)
1337 regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
1338 CS42L56_AIN2A_REF_MASK, 1);
1339
1340 if (cs42l56->pdata.ain2b_ref_cfg)
1341 regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX,
1342 CS42L56_AIN2B_REF_MASK, 1);
1343
1344 if (cs42l56->pdata.micbias_lvl)
1345 regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL,
1346 CS42L56_MIC_BIAS_MASK,
1347 cs42l56->pdata.micbias_lvl);
1348
1349 if (cs42l56->pdata.chgfreq)
1350 regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
1351 CS42L56_CHRG_FREQ_MASK,
1352 cs42l56->pdata.chgfreq);
1353
1354 if (cs42l56->pdata.hpfb_freq)
1355 regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
1356 CS42L56_HPFB_FREQ_MASK,
1357 cs42l56->pdata.hpfb_freq);
1358
1359 if (cs42l56->pdata.hpfa_freq)
1360 regmap_update_bits(cs42l56->regmap, CS42L56_HPF_CTL,
1361 CS42L56_HPFA_FREQ_MASK,
1362 cs42l56->pdata.hpfa_freq);
1363
1364 if (cs42l56->pdata.adaptive_pwr)
1365 regmap_update_bits(cs42l56->regmap, CS42L56_CLASSH_CTL,
1366 CS42L56_ADAPT_PWR_MASK,
1367 cs42l56->pdata.adaptive_pwr);
1368
1369 ret = snd_soc_register_codec(&i2c_client->dev,
1370 &soc_codec_dev_cs42l56, &cs42l56_dai, 1);
1371 if (ret < 0)
1372 return ret;
1373
1374 return 0;
1375
1376err_enable:
1377 regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
1378 cs42l56->supplies);
1379 return ret;
1380}
1381
1382static int cs42l56_i2c_remove(struct i2c_client *client)
1383{
1384 struct cs42l56_private *cs42l56 = i2c_get_clientdata(client);
1385
1386 snd_soc_unregister_codec(&client->dev);
1387 regulator_bulk_disable(ARRAY_SIZE(cs42l56->supplies),
1388 cs42l56->supplies);
1389 return 0;
1390}
1391
1392static const struct of_device_id cs42l56_of_match[] = {
1393 { .compatible = "cirrus,cs42l56", },
1394 { }
1395};
1396MODULE_DEVICE_TABLE(of, cs42l56_of_match);
1397
1398
1399static const struct i2c_device_id cs42l56_id[] = {
1400 { "cs42l56", 0 },
1401 { }
1402};
1403MODULE_DEVICE_TABLE(i2c, cs42l56_id);
1404
1405static struct i2c_driver cs42l56_i2c_driver = {
1406 .driver = {
1407 .name = "cs42l56",
1408 .owner = THIS_MODULE,
1409 .of_match_table = cs42l56_of_match,
1410 },
1411 .id_table = cs42l56_id,
1412 .probe = cs42l56_i2c_probe,
1413 .remove = cs42l56_i2c_remove,
1414};
1415
1416module_i2c_driver(cs42l56_i2c_driver);
1417
1418MODULE_DESCRIPTION("ASoC CS42L56 driver");
1419MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
1420MODULE_LICENSE("GPL");