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