1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2dfe0f98bSBrian Austin /*
3dfe0f98bSBrian Austin * cs42l52.c -- CS42L52 ALSA SoC audio driver
4dfe0f98bSBrian Austin *
5dfe0f98bSBrian Austin * Copyright 2012 CirrusLogic, Inc.
6dfe0f98bSBrian Austin *
7dfe0f98bSBrian Austin * Author: Georgi Vlaev <joe@nucleusys.com>
8dfe0f98bSBrian Austin * Author: Brian Austin <brian.austin@cirrus.com>
9dfe0f98bSBrian Austin */
10dfe0f98bSBrian Austin
11dfe0f98bSBrian Austin #include <linux/module.h>
12dfe0f98bSBrian Austin #include <linux/moduleparam.h>
13dfe0f98bSBrian Austin #include <linux/kernel.h>
14dfe0f98bSBrian Austin #include <linux/init.h>
15dfe0f98bSBrian Austin #include <linux/delay.h>
16391fc59dSBrian Austin #include <linux/of_gpio.h>
17dfe0f98bSBrian Austin #include <linux/pm.h>
18dfe0f98bSBrian Austin #include <linux/i2c.h>
19dfe0f98bSBrian Austin #include <linux/input.h>
20dfe0f98bSBrian Austin #include <linux/regmap.h>
21dfe0f98bSBrian Austin #include <linux/slab.h>
22dfe0f98bSBrian Austin #include <linux/workqueue.h>
23dfe0f98bSBrian Austin #include <linux/platform_device.h>
24dfe0f98bSBrian Austin #include <sound/core.h>
25dfe0f98bSBrian Austin #include <sound/pcm.h>
26dfe0f98bSBrian Austin #include <sound/pcm_params.h>
27dfe0f98bSBrian Austin #include <sound/soc.h>
28dfe0f98bSBrian Austin #include <sound/soc-dapm.h>
29dfe0f98bSBrian Austin #include <sound/initval.h>
30dfe0f98bSBrian Austin #include <sound/tlv.h>
31dfe0f98bSBrian Austin #include <sound/cs42l52.h>
32dfe0f98bSBrian Austin #include "cs42l52.h"
33dfe0f98bSBrian Austin
34dfe0f98bSBrian Austin struct sp_config {
35dfe0f98bSBrian Austin u8 spc, format, spfs;
36dfe0f98bSBrian Austin u32 srate;
37dfe0f98bSBrian Austin };
38dfe0f98bSBrian Austin
39dfe0f98bSBrian Austin struct cs42l52_private {
40dfe0f98bSBrian Austin struct regmap *regmap;
419665a749SKuninori Morimoto struct snd_soc_component *component;
42dfe0f98bSBrian Austin struct device *dev;
43dfe0f98bSBrian Austin struct sp_config config;
44dfe0f98bSBrian Austin struct cs42l52_platform_data pdata;
45dfe0f98bSBrian Austin u32 sysclk;
46dfe0f98bSBrian Austin u8 mclksel;
47dfe0f98bSBrian Austin u32 mclk;
48dfe0f98bSBrian Austin u8 flags;
49dfe0f98bSBrian Austin struct input_dev *beep;
50dfe0f98bSBrian Austin struct work_struct beep_work;
51dfe0f98bSBrian Austin int beep_rate;
52dfe0f98bSBrian Austin };
53dfe0f98bSBrian Austin
54dfe0f98bSBrian Austin static const struct reg_default cs42l52_reg_defaults[] = {
55dfe0f98bSBrian Austin { CS42L52_PWRCTL1, 0x9F }, /* r02 PWRCTL 1 */
56dfe0f98bSBrian Austin { CS42L52_PWRCTL2, 0x07 }, /* r03 PWRCTL 2 */
57dfe0f98bSBrian Austin { CS42L52_PWRCTL3, 0xFF }, /* r04 PWRCTL 3 */
58dfe0f98bSBrian Austin { CS42L52_CLK_CTL, 0xA0 }, /* r05 Clocking Ctl */
59dfe0f98bSBrian Austin { CS42L52_IFACE_CTL1, 0x00 }, /* r06 Interface Ctl 1 */
60dfe0f98bSBrian Austin { CS42L52_ADC_PGA_A, 0x80 }, /* r08 Input A Select */
61dfe0f98bSBrian Austin { CS42L52_ADC_PGA_B, 0x80 }, /* r09 Input B Select */
62dfe0f98bSBrian Austin { CS42L52_ANALOG_HPF_CTL, 0xA5 }, /* r0A Analog HPF Ctl */
63dfe0f98bSBrian Austin { CS42L52_ADC_HPF_FREQ, 0x00 }, /* r0B ADC HPF Corner Freq */
64dfe0f98bSBrian Austin { CS42L52_ADC_MISC_CTL, 0x00 }, /* r0C Misc. ADC Ctl */
65dfe0f98bSBrian Austin { CS42L52_PB_CTL1, 0x60 }, /* r0D Playback Ctl 1 */
66dfe0f98bSBrian Austin { CS42L52_MISC_CTL, 0x02 }, /* r0E Misc. Ctl */
67dfe0f98bSBrian Austin { CS42L52_PB_CTL2, 0x00 }, /* r0F Playback Ctl 2 */
68dfe0f98bSBrian Austin { CS42L52_MICA_CTL, 0x00 }, /* r10 MICA Amp Ctl */
69dfe0f98bSBrian Austin { CS42L52_MICB_CTL, 0x00 }, /* r11 MICB Amp Ctl */
70dfe0f98bSBrian Austin { CS42L52_PGAA_CTL, 0x00 }, /* r12 PGAA Vol, Misc. */
71dfe0f98bSBrian Austin { CS42L52_PGAB_CTL, 0x00 }, /* r13 PGAB Vol, Misc. */
72dfe0f98bSBrian Austin { CS42L52_PASSTHRUA_VOL, 0x00 }, /* r14 Bypass A Vol */
73dfe0f98bSBrian Austin { CS42L52_PASSTHRUB_VOL, 0x00 }, /* r15 Bypass B Vol */
74dfe0f98bSBrian Austin { CS42L52_ADCA_VOL, 0x00 }, /* r16 ADCA Volume */
75dfe0f98bSBrian Austin { CS42L52_ADCB_VOL, 0x00 }, /* r17 ADCB Volume */
76dfe0f98bSBrian Austin { CS42L52_ADCA_MIXER_VOL, 0x80 }, /* r18 ADCA Mixer Volume */
77dfe0f98bSBrian Austin { CS42L52_ADCB_MIXER_VOL, 0x80 }, /* r19 ADCB Mixer Volume */
78dfe0f98bSBrian Austin { CS42L52_PCMA_MIXER_VOL, 0x00 }, /* r1A PCMA Mixer Volume */
79dfe0f98bSBrian Austin { CS42L52_PCMB_MIXER_VOL, 0x00 }, /* r1B PCMB Mixer Volume */
80dfe0f98bSBrian Austin { CS42L52_BEEP_FREQ, 0x00 }, /* r1C Beep Freq on Time */
81dfe0f98bSBrian Austin { CS42L52_BEEP_VOL, 0x00 }, /* r1D Beep Volume off Time */
82dfe0f98bSBrian Austin { CS42L52_BEEP_TONE_CTL, 0x00 }, /* r1E Beep Tone Cfg. */
83dfe0f98bSBrian Austin { CS42L52_TONE_CTL, 0x00 }, /* r1F Tone Ctl */
8404d245b7SNicolas Schichan { CS42L52_MASTERA_VOL, 0x00 }, /* r20 Master A Volume */
85dfe0f98bSBrian Austin { CS42L52_MASTERB_VOL, 0x00 }, /* r21 Master B Volume */
86dfe0f98bSBrian Austin { CS42L52_HPA_VOL, 0x00 }, /* r22 Headphone A Volume */
87dfe0f98bSBrian Austin { CS42L52_HPB_VOL, 0x00 }, /* r23 Headphone B Volume */
88dfe0f98bSBrian Austin { CS42L52_SPKA_VOL, 0x00 }, /* r24 Speaker A Volume */
89dfe0f98bSBrian Austin { CS42L52_SPKB_VOL, 0x00 }, /* r25 Speaker B Volume */
90dfe0f98bSBrian Austin { CS42L52_ADC_PCM_MIXER, 0x00 }, /* r26 Channel Mixer and Swap */
91dfe0f98bSBrian Austin { CS42L52_LIMITER_CTL1, 0x00 }, /* r27 Limit Ctl 1 Thresholds */
92dfe0f98bSBrian Austin { CS42L52_LIMITER_CTL2, 0x7F }, /* r28 Limit Ctl 2 Release Rate */
93dfe0f98bSBrian Austin { CS42L52_LIMITER_AT_RATE, 0xC0 }, /* r29 Limiter Attack Rate */
94dfe0f98bSBrian Austin { CS42L52_ALC_CTL, 0x00 }, /* r2A ALC Ctl 1 Attack Rate */
95dfe0f98bSBrian Austin { CS42L52_ALC_RATE, 0x3F }, /* r2B ALC Release Rate */
96dfe0f98bSBrian Austin { CS42L52_ALC_THRESHOLD, 0x3f }, /* r2C ALC Thresholds */
97dfe0f98bSBrian Austin { CS42L52_NOISE_GATE_CTL, 0x00 }, /* r2D Noise Gate Ctl */
98dfe0f98bSBrian Austin { CS42L52_CLK_STATUS, 0x00 }, /* r2E Overflow and Clock Status */
99dfe0f98bSBrian Austin { CS42L52_BATT_COMPEN, 0x00 }, /* r2F battery Compensation */
100dfe0f98bSBrian Austin { CS42L52_BATT_LEVEL, 0x00 }, /* r30 VP Battery Level */
101dfe0f98bSBrian Austin { CS42L52_SPK_STATUS, 0x00 }, /* r31 Speaker Status */
102dfe0f98bSBrian Austin { CS42L52_TEM_CTL, 0x3B }, /* r32 Temp Ctl */
103dfe0f98bSBrian Austin { CS42L52_THE_FOLDBACK, 0x00 }, /* r33 Foldback */
104dfe0f98bSBrian Austin };
105dfe0f98bSBrian Austin
cs42l52_readable_register(struct device * dev,unsigned int reg)106dfe0f98bSBrian Austin static bool cs42l52_readable_register(struct device *dev, unsigned int reg)
107dfe0f98bSBrian Austin {
108dfe0f98bSBrian Austin switch (reg) {
1094caae954SAxel Lin case CS42L52_CHIP ... CS42L52_CHARGE_PUMP:
110dfe0f98bSBrian Austin return true;
111dfe0f98bSBrian Austin default:
112dfe0f98bSBrian Austin return false;
113dfe0f98bSBrian Austin }
114dfe0f98bSBrian Austin }
115dfe0f98bSBrian Austin
cs42l52_volatile_register(struct device * dev,unsigned int reg)116dfe0f98bSBrian Austin static bool cs42l52_volatile_register(struct device *dev, unsigned int reg)
117dfe0f98bSBrian Austin {
118dfe0f98bSBrian Austin switch (reg) {
119dfe0f98bSBrian Austin case CS42L52_IFACE_CTL2:
120dfe0f98bSBrian Austin case CS42L52_CLK_STATUS:
121dfe0f98bSBrian Austin case CS42L52_BATT_LEVEL:
122dfe0f98bSBrian Austin case CS42L52_SPK_STATUS:
123dfe0f98bSBrian Austin case CS42L52_CHARGE_PUMP:
1245c216cc3SBrian Austin return true;
125dfe0f98bSBrian Austin default:
1265c216cc3SBrian Austin return false;
127dfe0f98bSBrian Austin }
128dfe0f98bSBrian Austin }
129dfe0f98bSBrian Austin
130dfe0f98bSBrian Austin static DECLARE_TLV_DB_SCALE(hl_tlv, -10200, 50, 0);
131dfe0f98bSBrian Austin
132dfe0f98bSBrian Austin static DECLARE_TLV_DB_SCALE(hpd_tlv, -9600, 50, 1);
133dfe0f98bSBrian Austin
134dfe0f98bSBrian Austin static DECLARE_TLV_DB_SCALE(ipd_tlv, -9600, 100, 0);
135dfe0f98bSBrian Austin
136dfe0f98bSBrian Austin static DECLARE_TLV_DB_SCALE(mic_tlv, 1600, 100, 0);
137dfe0f98bSBrian Austin
138dfe0f98bSBrian Austin static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
139dfe0f98bSBrian Austin
14091e90c71SCharles Keepax static DECLARE_TLV_DB_SCALE(pass_tlv, -6000, 50, 0);
14191e90c71SCharles Keepax
1428bf5aabfSCharles Keepax static DECLARE_TLV_DB_SCALE(mix_tlv, -5150, 50, 0);
1438ac60a68SNicolas Schichan
1448806d96dSBrian Austin static DECLARE_TLV_DB_SCALE(beep_tlv, -56, 200, 0);
1458806d96dSBrian Austin
1460a017768SLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(limiter_tlv,
147dfe0f98bSBrian Austin 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
1480a017768SLars-Peter Clausen 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
1490a017768SLars-Peter Clausen );
150dfe0f98bSBrian Austin
151dfe0f98bSBrian Austin static const char * const cs42l52_adca_text[] = {
152dfe0f98bSBrian Austin "Input1A", "Input2A", "Input3A", "Input4A", "PGA Input Left"};
153dfe0f98bSBrian Austin
154dfe0f98bSBrian Austin static const char * const cs42l52_adcb_text[] = {
155dfe0f98bSBrian Austin "Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"};
156dfe0f98bSBrian Austin
1574682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(adca_enum,
1584682a0a2STakashi Iwai CS42L52_ADC_PGA_A, 5, cs42l52_adca_text);
159dfe0f98bSBrian Austin
1604682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(adcb_enum,
1614682a0a2STakashi Iwai CS42L52_ADC_PGA_B, 5, cs42l52_adcb_text);
162dfe0f98bSBrian Austin
163dfe0f98bSBrian Austin static const struct snd_kcontrol_new adca_mux =
164dfe0f98bSBrian Austin SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum);
165dfe0f98bSBrian Austin
166dfe0f98bSBrian Austin static const struct snd_kcontrol_new adcb_mux =
167dfe0f98bSBrian Austin SOC_DAPM_ENUM("Right ADC Input Capture Mux", adcb_enum);
168dfe0f98bSBrian Austin
169dfe0f98bSBrian Austin static const char * const mic_bias_level_text[] = {
170dfe0f98bSBrian Austin "0.5 +VA", "0.6 +VA", "0.7 +VA",
171dfe0f98bSBrian Austin "0.8 +VA", "0.83 +VA", "0.91 +VA"
172dfe0f98bSBrian Austin };
173dfe0f98bSBrian Austin
1744682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(mic_bias_level_enum,
1754682a0a2STakashi Iwai CS42L52_IFACE_CTL2, 0, mic_bias_level_text);
176dfe0f98bSBrian Austin
177a3d36bc2SBrian Austin static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" };
178dfe0f98bSBrian Austin
1794682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(mica_enum,
1804682a0a2STakashi Iwai CS42L52_MICA_CTL, 5, cs42l52_mic_text);
181dfe0f98bSBrian Austin
1824682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(micb_enum,
1834682a0a2STakashi Iwai CS42L52_MICB_CTL, 5, cs42l52_mic_text);
184dfe0f98bSBrian Austin
185dfe0f98bSBrian Austin static const char * const digital_output_mux_text[] = {"ADC", "DSP"};
186dfe0f98bSBrian Austin
1874682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(digital_output_mux_enum,
1884682a0a2STakashi Iwai CS42L52_ADC_MISC_CTL, 6,
189dfe0f98bSBrian Austin digital_output_mux_text);
190dfe0f98bSBrian Austin
191dfe0f98bSBrian Austin static const struct snd_kcontrol_new digital_output_mux =
192dfe0f98bSBrian Austin SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum);
193dfe0f98bSBrian Austin
194dfe0f98bSBrian Austin static const char * const hp_gain_num_text[] = {
195dfe0f98bSBrian Austin "0.3959", "0.4571", "0.5111", "0.6047",
196dfe0f98bSBrian Austin "0.7099", "0.8399", "1.000", "1.1430"
197dfe0f98bSBrian Austin };
198dfe0f98bSBrian Austin
1994682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(hp_gain_enum,
2004682a0a2STakashi Iwai CS42L52_PB_CTL1, 5,
2014682a0a2STakashi Iwai hp_gain_num_text);
202dfe0f98bSBrian Austin
203dfe0f98bSBrian Austin static const char * const beep_pitch_text[] = {
204dfe0f98bSBrian Austin "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
205dfe0f98bSBrian Austin "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
206dfe0f98bSBrian Austin };
207dfe0f98bSBrian Austin
2084682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(beep_pitch_enum,
2094682a0a2STakashi Iwai CS42L52_BEEP_FREQ, 4,
2104682a0a2STakashi Iwai beep_pitch_text);
211dfe0f98bSBrian Austin
212dfe0f98bSBrian Austin static const char * const beep_ontime_text[] = {
213dfe0f98bSBrian Austin "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
214dfe0f98bSBrian Austin "1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
215dfe0f98bSBrian Austin "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
216dfe0f98bSBrian Austin };
217dfe0f98bSBrian Austin
2184682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(beep_ontime_enum,
2194682a0a2STakashi Iwai CS42L52_BEEP_FREQ, 0,
2204682a0a2STakashi Iwai beep_ontime_text);
221dfe0f98bSBrian Austin
222dfe0f98bSBrian Austin static const char * const beep_offtime_text[] = {
223dfe0f98bSBrian Austin "1.23 s", "2.58 s", "3.90 s", "5.20 s",
224dfe0f98bSBrian Austin "6.60 s", "8.05 s", "9.35 s", "10.80 s"
225dfe0f98bSBrian Austin };
226dfe0f98bSBrian Austin
2274682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(beep_offtime_enum,
2284682a0a2STakashi Iwai CS42L52_BEEP_VOL, 5,
2294682a0a2STakashi Iwai beep_offtime_text);
230dfe0f98bSBrian Austin
231dfe0f98bSBrian Austin static const char * const beep_config_text[] = {
232dfe0f98bSBrian Austin "Off", "Single", "Multiple", "Continuous"
233dfe0f98bSBrian Austin };
234dfe0f98bSBrian Austin
2354682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(beep_config_enum,
2364682a0a2STakashi Iwai CS42L52_BEEP_TONE_CTL, 6,
2374682a0a2STakashi Iwai beep_config_text);
238dfe0f98bSBrian Austin
239dfe0f98bSBrian Austin static const char * const beep_bass_text[] = {
240dfe0f98bSBrian Austin "50 Hz", "100 Hz", "200 Hz", "250 Hz"
241dfe0f98bSBrian Austin };
242dfe0f98bSBrian Austin
2434682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(beep_bass_enum,
2444682a0a2STakashi Iwai CS42L52_BEEP_TONE_CTL, 1,
2454682a0a2STakashi Iwai beep_bass_text);
246dfe0f98bSBrian Austin
247dfe0f98bSBrian Austin static const char * const beep_treble_text[] = {
248dfe0f98bSBrian Austin "5 kHz", "7 kHz", "10 kHz", " 15 kHz"
249dfe0f98bSBrian Austin };
250dfe0f98bSBrian Austin
2514682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(beep_treble_enum,
2524682a0a2STakashi Iwai CS42L52_BEEP_TONE_CTL, 3,
2534682a0a2STakashi Iwai beep_treble_text);
254dfe0f98bSBrian Austin
255dfe0f98bSBrian Austin static const char * const ng_threshold_text[] = {
256dfe0f98bSBrian Austin "-34dB", "-37dB", "-40dB", "-43dB",
257dfe0f98bSBrian Austin "-46dB", "-52dB", "-58dB", "-64dB"
258dfe0f98bSBrian Austin };
259dfe0f98bSBrian Austin
2604682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(ng_threshold_enum,
2614682a0a2STakashi Iwai CS42L52_NOISE_GATE_CTL, 2,
2624682a0a2STakashi Iwai ng_threshold_text);
263dfe0f98bSBrian Austin
264dfe0f98bSBrian Austin static const char * const cs42l52_ng_delay_text[] = {
265dfe0f98bSBrian Austin "50ms", "100ms", "150ms", "200ms"};
266dfe0f98bSBrian Austin
2674682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(ng_delay_enum,
2684682a0a2STakashi Iwai CS42L52_NOISE_GATE_CTL, 0,
2694682a0a2STakashi Iwai cs42l52_ng_delay_text);
270dfe0f98bSBrian Austin
271dfe0f98bSBrian Austin static const char * const cs42l52_ng_type_text[] = {
272dfe0f98bSBrian Austin "Apply Specific", "Apply All"
273dfe0f98bSBrian Austin };
274dfe0f98bSBrian Austin
2754682a0a2STakashi Iwai static SOC_ENUM_SINGLE_DECL(ng_type_enum,
2764682a0a2STakashi Iwai CS42L52_NOISE_GATE_CTL, 6,
2774682a0a2STakashi Iwai cs42l52_ng_type_text);
278dfe0f98bSBrian Austin
279dfe0f98bSBrian Austin static const char * const left_swap_text[] = {
280dfe0f98bSBrian Austin "Left", "LR 2", "Right"};
281dfe0f98bSBrian Austin
282dfe0f98bSBrian Austin static const char * const right_swap_text[] = {
283dfe0f98bSBrian Austin "Right", "LR 2", "Left"};
284dfe0f98bSBrian Austin
285dfe0f98bSBrian Austin static const unsigned int swap_values[] = { 0, 1, 3 };
286dfe0f98bSBrian Austin
287dfe0f98bSBrian Austin static const struct soc_enum adca_swap_enum =
288d31a33ddSBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 3,
289dfe0f98bSBrian Austin ARRAY_SIZE(left_swap_text),
290dfe0f98bSBrian Austin left_swap_text,
291dfe0f98bSBrian Austin swap_values);
292dfe0f98bSBrian Austin
293dfe0f98bSBrian Austin static const struct snd_kcontrol_new adca_mixer =
294dfe0f98bSBrian Austin SOC_DAPM_ENUM("Route", adca_swap_enum);
295dfe0f98bSBrian Austin
296dfe0f98bSBrian Austin static const struct soc_enum pcma_swap_enum =
297d31a33ddSBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 3,
298dfe0f98bSBrian Austin ARRAY_SIZE(left_swap_text),
299dfe0f98bSBrian Austin left_swap_text,
300dfe0f98bSBrian Austin swap_values);
301dfe0f98bSBrian Austin
302dfe0f98bSBrian Austin static const struct snd_kcontrol_new pcma_mixer =
303dfe0f98bSBrian Austin SOC_DAPM_ENUM("Route", pcma_swap_enum);
304dfe0f98bSBrian Austin
305dfe0f98bSBrian Austin static const struct soc_enum adcb_swap_enum =
306d31a33ddSBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 3,
307dfe0f98bSBrian Austin ARRAY_SIZE(right_swap_text),
308dfe0f98bSBrian Austin right_swap_text,
309dfe0f98bSBrian Austin swap_values);
310dfe0f98bSBrian Austin
311dfe0f98bSBrian Austin static const struct snd_kcontrol_new adcb_mixer =
312dfe0f98bSBrian Austin SOC_DAPM_ENUM("Route", adcb_swap_enum);
313dfe0f98bSBrian Austin
314dfe0f98bSBrian Austin static const struct soc_enum pcmb_swap_enum =
315d31a33ddSBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 3,
316dfe0f98bSBrian Austin ARRAY_SIZE(right_swap_text),
317dfe0f98bSBrian Austin right_swap_text,
318dfe0f98bSBrian Austin swap_values);
319dfe0f98bSBrian Austin
320dfe0f98bSBrian Austin static const struct snd_kcontrol_new pcmb_mixer =
321dfe0f98bSBrian Austin SOC_DAPM_ENUM("Route", pcmb_swap_enum);
322dfe0f98bSBrian Austin
323dfe0f98bSBrian Austin
324dfe0f98bSBrian Austin static const struct snd_kcontrol_new passthrul_ctl =
325dfe0f98bSBrian Austin SOC_DAPM_SINGLE("Switch", CS42L52_MISC_CTL, 6, 1, 0);
326dfe0f98bSBrian Austin
327dfe0f98bSBrian Austin static const struct snd_kcontrol_new passthrur_ctl =
328dfe0f98bSBrian Austin SOC_DAPM_SINGLE("Switch", CS42L52_MISC_CTL, 7, 1, 0);
329dfe0f98bSBrian Austin
330dfe0f98bSBrian Austin static const struct snd_kcontrol_new spkl_ctl =
331dfe0f98bSBrian Austin SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 0, 1, 1);
332dfe0f98bSBrian Austin
333dfe0f98bSBrian Austin static const struct snd_kcontrol_new spkr_ctl =
334dfe0f98bSBrian Austin SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 2, 1, 1);
335dfe0f98bSBrian Austin
336dfe0f98bSBrian Austin static const struct snd_kcontrol_new hpl_ctl =
337dfe0f98bSBrian Austin SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 4, 1, 1);
338dfe0f98bSBrian Austin
339dfe0f98bSBrian Austin static const struct snd_kcontrol_new hpr_ctl =
340dfe0f98bSBrian Austin SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 6, 1, 1);
341dfe0f98bSBrian Austin
342dfe0f98bSBrian Austin static const struct snd_kcontrol_new cs42l52_snd_controls[] = {
343dfe0f98bSBrian Austin
344dfe0f98bSBrian Austin SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L52_MASTERA_VOL,
345dfe0f98bSBrian Austin CS42L52_MASTERB_VOL, 0, 0x34, 0xE4, hl_tlv),
346dfe0f98bSBrian Austin
347dfe0f98bSBrian Austin SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L52_HPA_VOL,
348a0465587SBrian Austin CS42L52_HPB_VOL, 0, 0x34, 0xC0, hpd_tlv),
349dfe0f98bSBrian Austin
350dfe0f98bSBrian Austin SOC_ENUM("Headphone Analog Gain", hp_gain_enum),
351dfe0f98bSBrian Austin
352dfe0f98bSBrian Austin SOC_DOUBLE_R_SX_TLV("Speaker Volume", CS42L52_SPKA_VOL,
353a0465587SBrian Austin CS42L52_SPKB_VOL, 0, 0x40, 0xC0, hl_tlv),
354dfe0f98bSBrian Austin
355dfe0f98bSBrian Austin SOC_DOUBLE_R_SX_TLV("Bypass Volume", CS42L52_PASSTHRUA_VOL,
35691e90c71SCharles Keepax CS42L52_PASSTHRUB_VOL, 0, 0x88, 0x90, pass_tlv),
357dfe0f98bSBrian Austin
358dfe0f98bSBrian Austin SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0),
359dfe0f98bSBrian Austin
360dfe0f98bSBrian Austin SOC_DOUBLE_R_TLV("MIC Gain Volume", CS42L52_MICA_CTL,
361dfe0f98bSBrian Austin CS42L52_MICB_CTL, 0, 0x10, 0, mic_tlv),
362dfe0f98bSBrian Austin
363dfe0f98bSBrian Austin SOC_ENUM("MIC Bias Level", mic_bias_level_enum),
364dfe0f98bSBrian Austin
365dfe0f98bSBrian Austin SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L52_ADCA_VOL,
366a0465587SBrian Austin CS42L52_ADCB_VOL, 0, 0xA0, 0x78, ipd_tlv),
367dfe0f98bSBrian Austin SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
368dfe0f98bSBrian Austin CS42L52_ADCA_MIXER_VOL, CS42L52_ADCB_MIXER_VOL,
3698bf5aabfSCharles Keepax 0, 0x19, 0x7F, mix_tlv),
370dfe0f98bSBrian Austin
371dfe0f98bSBrian Austin SOC_DOUBLE("ADC Switch", CS42L52_ADC_MISC_CTL, 0, 1, 1, 0),
372dfe0f98bSBrian Austin
373dfe0f98bSBrian Austin SOC_DOUBLE_R("ADC Mixer Switch", CS42L52_ADCA_MIXER_VOL,
374dfe0f98bSBrian Austin CS42L52_ADCB_MIXER_VOL, 7, 1, 1),
375dfe0f98bSBrian Austin
376dfe0f98bSBrian Austin SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L52_PGAA_CTL,
377a0465587SBrian Austin CS42L52_PGAB_CTL, 0, 0x28, 0x24, pga_tlv),
378dfe0f98bSBrian Austin
379dfe0f98bSBrian Austin SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume",
380dfe0f98bSBrian Austin CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL,
381a0465587SBrian Austin 0, 0x19, 0x7f, mix_tlv),
382dfe0f98bSBrian Austin SOC_DOUBLE_R("PCM Mixer Switch",
383dfe0f98bSBrian Austin CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, 7, 1, 1),
384dfe0f98bSBrian Austin
385dfe0f98bSBrian Austin SOC_ENUM("Beep Config", beep_config_enum),
386dfe0f98bSBrian Austin SOC_ENUM("Beep Pitch", beep_pitch_enum),
387dfe0f98bSBrian Austin SOC_ENUM("Beep on Time", beep_ontime_enum),
388dfe0f98bSBrian Austin SOC_ENUM("Beep off Time", beep_offtime_enum),
3898806d96dSBrian Austin SOC_SINGLE_SX_TLV("Beep Volume", CS42L52_BEEP_VOL,
3908806d96dSBrian Austin 0, 0x07, 0x1f, beep_tlv),
391dfe0f98bSBrian Austin SOC_SINGLE("Beep Mixer Switch", CS42L52_BEEP_TONE_CTL, 5, 1, 1),
392dfe0f98bSBrian Austin SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
393dfe0f98bSBrian Austin SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
394dfe0f98bSBrian Austin
395dfe0f98bSBrian Austin SOC_SINGLE("Tone Control Switch", CS42L52_BEEP_TONE_CTL, 0, 1, 1),
396dfe0f98bSBrian Austin SOC_SINGLE_TLV("Treble Gain Volume",
397dfe0f98bSBrian Austin CS42L52_TONE_CTL, 4, 15, 1, hl_tlv),
398dfe0f98bSBrian Austin SOC_SINGLE_TLV("Bass Gain Volume",
399dfe0f98bSBrian Austin CS42L52_TONE_CTL, 0, 15, 1, hl_tlv),
400dfe0f98bSBrian Austin
401dfe0f98bSBrian Austin /* Limiter */
402dfe0f98bSBrian Austin SOC_SINGLE_TLV("Limiter Max Threshold Volume",
403dfe0f98bSBrian Austin CS42L52_LIMITER_CTL1, 5, 7, 0, limiter_tlv),
404dfe0f98bSBrian Austin SOC_SINGLE_TLV("Limiter Cushion Threshold Volume",
405dfe0f98bSBrian Austin CS42L52_LIMITER_CTL1, 2, 7, 0, limiter_tlv),
406dfe0f98bSBrian Austin SOC_SINGLE_TLV("Limiter Release Rate Volume",
407dfe0f98bSBrian Austin CS42L52_LIMITER_CTL2, 0, 63, 0, limiter_tlv),
408dfe0f98bSBrian Austin SOC_SINGLE_TLV("Limiter Attack Rate Volume",
409dfe0f98bSBrian Austin CS42L52_LIMITER_AT_RATE, 0, 63, 0, limiter_tlv),
410dfe0f98bSBrian Austin
411dfe0f98bSBrian Austin SOC_SINGLE("Limiter SR Switch", CS42L52_LIMITER_CTL1, 1, 1, 0),
412dfe0f98bSBrian Austin SOC_SINGLE("Limiter ZC Switch", CS42L52_LIMITER_CTL1, 0, 1, 0),
413dfe0f98bSBrian Austin SOC_SINGLE("Limiter Switch", CS42L52_LIMITER_CTL2, 7, 1, 0),
414dfe0f98bSBrian Austin
415dfe0f98bSBrian Austin /* ALC */
416dfe0f98bSBrian Austin SOC_SINGLE_TLV("ALC Attack Rate Volume", CS42L52_ALC_CTL,
417dfe0f98bSBrian Austin 0, 63, 0, limiter_tlv),
418dfe0f98bSBrian Austin SOC_SINGLE_TLV("ALC Release Rate Volume", CS42L52_ALC_RATE,
419dfe0f98bSBrian Austin 0, 63, 0, limiter_tlv),
420dfe0f98bSBrian Austin SOC_SINGLE_TLV("ALC Max Threshold Volume", CS42L52_ALC_THRESHOLD,
421dfe0f98bSBrian Austin 5, 7, 0, limiter_tlv),
422dfe0f98bSBrian Austin SOC_SINGLE_TLV("ALC Min Threshold Volume", CS42L52_ALC_THRESHOLD,
423dfe0f98bSBrian Austin 2, 7, 0, limiter_tlv),
424dfe0f98bSBrian Austin
425dfe0f98bSBrian Austin SOC_DOUBLE_R("ALC SR Capture Switch", CS42L52_PGAA_CTL,
426dfe0f98bSBrian Austin CS42L52_PGAB_CTL, 7, 1, 1),
427dfe0f98bSBrian Austin SOC_DOUBLE_R("ALC ZC Capture Switch", CS42L52_PGAA_CTL,
428dfe0f98bSBrian Austin CS42L52_PGAB_CTL, 6, 1, 1),
429dfe0f98bSBrian Austin SOC_DOUBLE("ALC Capture Switch", CS42L52_ALC_CTL, 6, 7, 1, 0),
430dfe0f98bSBrian Austin
431dfe0f98bSBrian Austin /* Noise gate */
432dfe0f98bSBrian Austin SOC_ENUM("NG Type Switch", ng_type_enum),
433dfe0f98bSBrian Austin SOC_SINGLE("NG Enable Switch", CS42L52_NOISE_GATE_CTL, 6, 1, 0),
434dfe0f98bSBrian Austin SOC_SINGLE("NG Boost Switch", CS42L52_NOISE_GATE_CTL, 5, 1, 1),
435dfe0f98bSBrian Austin SOC_ENUM("NG Threshold", ng_threshold_enum),
436dfe0f98bSBrian Austin SOC_ENUM("NG Delay", ng_delay_enum),
437dfe0f98bSBrian Austin
438dfe0f98bSBrian Austin SOC_DOUBLE("HPF Switch", CS42L52_ANALOG_HPF_CTL, 5, 7, 1, 0),
439dfe0f98bSBrian Austin
440dfe0f98bSBrian Austin SOC_DOUBLE("Analog SR Switch", CS42L52_ANALOG_HPF_CTL, 1, 3, 1, 1),
441dfe0f98bSBrian Austin SOC_DOUBLE("Analog ZC Switch", CS42L52_ANALOG_HPF_CTL, 0, 2, 1, 1),
442dfe0f98bSBrian Austin SOC_SINGLE("Digital SR Switch", CS42L52_MISC_CTL, 1, 1, 0),
443dfe0f98bSBrian Austin SOC_SINGLE("Digital ZC Switch", CS42L52_MISC_CTL, 0, 1, 0),
444dfe0f98bSBrian Austin SOC_SINGLE("Deemphasis Switch", CS42L52_MISC_CTL, 2, 1, 0),
445dfe0f98bSBrian Austin
446dfe0f98bSBrian Austin SOC_SINGLE("Batt Compensation Switch", CS42L52_BATT_COMPEN, 7, 1, 0),
447dfe0f98bSBrian Austin SOC_SINGLE("Batt VP Monitor Switch", CS42L52_BATT_COMPEN, 6, 1, 0),
448dfe0f98bSBrian Austin SOC_SINGLE("Batt VP ref", CS42L52_BATT_COMPEN, 0, 0x0f, 0),
449dfe0f98bSBrian Austin
450dfe0f98bSBrian Austin SOC_SINGLE("PGA AIN1L Switch", CS42L52_ADC_PGA_A, 0, 1, 0),
451dfe0f98bSBrian Austin SOC_SINGLE("PGA AIN1R Switch", CS42L52_ADC_PGA_B, 0, 1, 0),
452dfe0f98bSBrian Austin SOC_SINGLE("PGA AIN2L Switch", CS42L52_ADC_PGA_A, 1, 1, 0),
453dfe0f98bSBrian Austin SOC_SINGLE("PGA AIN2R Switch", CS42L52_ADC_PGA_B, 1, 1, 0),
454dfe0f98bSBrian Austin
455dfe0f98bSBrian Austin SOC_SINGLE("PGA AIN3L Switch", CS42L52_ADC_PGA_A, 2, 1, 0),
456dfe0f98bSBrian Austin SOC_SINGLE("PGA AIN3R Switch", CS42L52_ADC_PGA_B, 2, 1, 0),
457dfe0f98bSBrian Austin
458dfe0f98bSBrian Austin SOC_SINGLE("PGA AIN4L Switch", CS42L52_ADC_PGA_A, 3, 1, 0),
459dfe0f98bSBrian Austin SOC_SINGLE("PGA AIN4R Switch", CS42L52_ADC_PGA_B, 3, 1, 0),
460dfe0f98bSBrian Austin
461dfe0f98bSBrian Austin SOC_SINGLE("PGA MICA Switch", CS42L52_ADC_PGA_A, 4, 1, 0),
462dfe0f98bSBrian Austin SOC_SINGLE("PGA MICB Switch", CS42L52_ADC_PGA_B, 4, 1, 0),
463dfe0f98bSBrian Austin
464dfe0f98bSBrian Austin };
465dfe0f98bSBrian Austin
46644b2ed54SBrian Austin static const struct snd_kcontrol_new cs42l52_mica_controls[] = {
46744b2ed54SBrian Austin SOC_ENUM("MICA Select", mica_enum),
46844b2ed54SBrian Austin };
46944b2ed54SBrian Austin
47044b2ed54SBrian Austin static const struct snd_kcontrol_new cs42l52_micb_controls[] = {
47144b2ed54SBrian Austin SOC_ENUM("MICB Select", micb_enum),
47244b2ed54SBrian Austin };
47344b2ed54SBrian Austin
cs42l52_add_mic_controls(struct snd_soc_component * component)4749665a749SKuninori Morimoto static int cs42l52_add_mic_controls(struct snd_soc_component *component)
47544b2ed54SBrian Austin {
4769665a749SKuninori Morimoto struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
47744b2ed54SBrian Austin struct cs42l52_platform_data *pdata = &cs42l52->pdata;
47844b2ed54SBrian Austin
47944b2ed54SBrian Austin if (!pdata->mica_diff_cfg)
4809665a749SKuninori Morimoto snd_soc_add_component_controls(component, cs42l52_mica_controls,
48144b2ed54SBrian Austin ARRAY_SIZE(cs42l52_mica_controls));
48244b2ed54SBrian Austin
48344b2ed54SBrian Austin if (!pdata->micb_diff_cfg)
4849665a749SKuninori Morimoto snd_soc_add_component_controls(component, cs42l52_micb_controls,
48544b2ed54SBrian Austin ARRAY_SIZE(cs42l52_micb_controls));
48644b2ed54SBrian Austin
48744b2ed54SBrian Austin return 0;
48844b2ed54SBrian Austin }
48944b2ed54SBrian Austin
490dfe0f98bSBrian Austin static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
491dfe0f98bSBrian Austin
492dfe0f98bSBrian Austin SND_SOC_DAPM_INPUT("AIN1L"),
493dfe0f98bSBrian Austin SND_SOC_DAPM_INPUT("AIN1R"),
494dfe0f98bSBrian Austin SND_SOC_DAPM_INPUT("AIN2L"),
495dfe0f98bSBrian Austin SND_SOC_DAPM_INPUT("AIN2R"),
496dfe0f98bSBrian Austin SND_SOC_DAPM_INPUT("AIN3L"),
497dfe0f98bSBrian Austin SND_SOC_DAPM_INPUT("AIN3R"),
498dfe0f98bSBrian Austin SND_SOC_DAPM_INPUT("AIN4L"),
499dfe0f98bSBrian Austin SND_SOC_DAPM_INPUT("AIN4R"),
500dfe0f98bSBrian Austin SND_SOC_DAPM_INPUT("MICA"),
501dfe0f98bSBrian Austin SND_SOC_DAPM_INPUT("MICB"),
502dfe0f98bSBrian Austin SND_SOC_DAPM_SIGGEN("Beep"),
503dfe0f98bSBrian Austin
504dfe0f98bSBrian Austin SND_SOC_DAPM_AIF_OUT("AIFOUTL", NULL, 0,
505dfe0f98bSBrian Austin SND_SOC_NOPM, 0, 0),
506dfe0f98bSBrian Austin SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL, 0,
507dfe0f98bSBrian Austin SND_SOC_NOPM, 0, 0),
508dfe0f98bSBrian Austin
509dfe0f98bSBrian Austin SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1),
510dfe0f98bSBrian Austin SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1),
511dfe0f98bSBrian Austin SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0),
512dfe0f98bSBrian Austin SND_SOC_DAPM_PGA("PGA Right", CS42L52_PWRCTL1, 4, 1, NULL, 0),
513dfe0f98bSBrian Austin
514dfe0f98bSBrian Austin SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adca_mux),
515dfe0f98bSBrian Austin SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcb_mux),
516dfe0f98bSBrian Austin
517dfe0f98bSBrian Austin SND_SOC_DAPM_MUX("ADC Left Swap", SND_SOC_NOPM,
518dfe0f98bSBrian Austin 0, 0, &adca_mixer),
519dfe0f98bSBrian Austin SND_SOC_DAPM_MUX("ADC Right Swap", SND_SOC_NOPM,
520dfe0f98bSBrian Austin 0, 0, &adcb_mixer),
521dfe0f98bSBrian Austin
522dfe0f98bSBrian Austin SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM,
523dfe0f98bSBrian Austin 0, 0, &digital_output_mux),
524dfe0f98bSBrian Austin
525dfe0f98bSBrian Austin SND_SOC_DAPM_PGA("PGA MICA", CS42L52_PWRCTL2, 1, 1, NULL, 0),
526dfe0f98bSBrian Austin SND_SOC_DAPM_PGA("PGA MICB", CS42L52_PWRCTL2, 2, 1, NULL, 0),
527dfe0f98bSBrian Austin
528dfe0f98bSBrian Austin SND_SOC_DAPM_SUPPLY("Mic Bias", CS42L52_PWRCTL2, 0, 1, NULL, 0),
529dfe0f98bSBrian Austin SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L52_PWRCTL1, 7, 1, NULL, 0),
530dfe0f98bSBrian Austin
531dfe0f98bSBrian Austin SND_SOC_DAPM_AIF_IN("AIFINL", NULL, 0,
532dfe0f98bSBrian Austin SND_SOC_NOPM, 0, 0),
533dfe0f98bSBrian Austin SND_SOC_DAPM_AIF_IN("AIFINR", NULL, 0,
534dfe0f98bSBrian Austin SND_SOC_NOPM, 0, 0),
535dfe0f98bSBrian Austin
536dfe0f98bSBrian Austin SND_SOC_DAPM_DAC("DAC Left", NULL, SND_SOC_NOPM, 0, 0),
537dfe0f98bSBrian Austin SND_SOC_DAPM_DAC("DAC Right", NULL, SND_SOC_NOPM, 0, 0),
538dfe0f98bSBrian Austin
539dfe0f98bSBrian Austin SND_SOC_DAPM_SWITCH("Bypass Left", CS42L52_MISC_CTL,
540dfe0f98bSBrian Austin 6, 0, &passthrul_ctl),
541dfe0f98bSBrian Austin SND_SOC_DAPM_SWITCH("Bypass Right", CS42L52_MISC_CTL,
542dfe0f98bSBrian Austin 7, 0, &passthrur_ctl),
543dfe0f98bSBrian Austin
544dfe0f98bSBrian Austin SND_SOC_DAPM_MUX("PCM Left Swap", SND_SOC_NOPM,
545dfe0f98bSBrian Austin 0, 0, &pcma_mixer),
546dfe0f98bSBrian Austin SND_SOC_DAPM_MUX("PCM Right Swap", SND_SOC_NOPM,
547dfe0f98bSBrian Austin 0, 0, &pcmb_mixer),
548dfe0f98bSBrian Austin
549dfe0f98bSBrian Austin SND_SOC_DAPM_SWITCH("HP Left Amp", SND_SOC_NOPM, 0, 0, &hpl_ctl),
550dfe0f98bSBrian Austin SND_SOC_DAPM_SWITCH("HP Right Amp", SND_SOC_NOPM, 0, 0, &hpr_ctl),
551dfe0f98bSBrian Austin
552dfe0f98bSBrian Austin SND_SOC_DAPM_SWITCH("SPK Left Amp", SND_SOC_NOPM, 0, 0, &spkl_ctl),
553dfe0f98bSBrian Austin SND_SOC_DAPM_SWITCH("SPK Right Amp", SND_SOC_NOPM, 0, 0, &spkr_ctl),
554dfe0f98bSBrian Austin
555dfe0f98bSBrian Austin SND_SOC_DAPM_OUTPUT("HPOUTA"),
556dfe0f98bSBrian Austin SND_SOC_DAPM_OUTPUT("HPOUTB"),
557dfe0f98bSBrian Austin SND_SOC_DAPM_OUTPUT("SPKOUTA"),
558dfe0f98bSBrian Austin SND_SOC_DAPM_OUTPUT("SPKOUTB"),
559dfe0f98bSBrian Austin
560dfe0f98bSBrian Austin };
561dfe0f98bSBrian Austin
562dfe0f98bSBrian Austin static const struct snd_soc_dapm_route cs42l52_audio_map[] = {
563dfe0f98bSBrian Austin
564dfe0f98bSBrian Austin {"Capture", NULL, "AIFOUTL"},
565dfe0f98bSBrian Austin {"Capture", NULL, "AIFOUTL"},
566dfe0f98bSBrian Austin
567dfe0f98bSBrian Austin {"AIFOUTL", NULL, "Output Mux"},
568dfe0f98bSBrian Austin {"AIFOUTR", NULL, "Output Mux"},
569dfe0f98bSBrian Austin
570dfe0f98bSBrian Austin {"Output Mux", "ADC", "ADC Left"},
571dfe0f98bSBrian Austin {"Output Mux", "ADC", "ADC Right"},
572dfe0f98bSBrian Austin
573dfe0f98bSBrian Austin {"ADC Left", NULL, "Charge Pump"},
574dfe0f98bSBrian Austin {"ADC Right", NULL, "Charge Pump"},
575dfe0f98bSBrian Austin
576dfe0f98bSBrian Austin {"Charge Pump", NULL, "ADC Left Mux"},
577dfe0f98bSBrian Austin {"Charge Pump", NULL, "ADC Right Mux"},
578dfe0f98bSBrian Austin
579dfe0f98bSBrian Austin {"ADC Left Mux", "Input1A", "AIN1L"},
580dfe0f98bSBrian Austin {"ADC Right Mux", "Input1B", "AIN1R"},
581dfe0f98bSBrian Austin {"ADC Left Mux", "Input2A", "AIN2L"},
582dfe0f98bSBrian Austin {"ADC Right Mux", "Input2B", "AIN2R"},
583dfe0f98bSBrian Austin {"ADC Left Mux", "Input3A", "AIN3L"},
584dfe0f98bSBrian Austin {"ADC Right Mux", "Input3B", "AIN3R"},
585dfe0f98bSBrian Austin {"ADC Left Mux", "Input4A", "AIN4L"},
586dfe0f98bSBrian Austin {"ADC Right Mux", "Input4B", "AIN4R"},
587dfe0f98bSBrian Austin {"ADC Left Mux", "PGA Input Left", "PGA Left"},
588dfe0f98bSBrian Austin {"ADC Right Mux", "PGA Input Right" , "PGA Right"},
589dfe0f98bSBrian Austin
590dfe0f98bSBrian Austin {"PGA Left", "Switch", "AIN1L"},
591dfe0f98bSBrian Austin {"PGA Right", "Switch", "AIN1R"},
592dfe0f98bSBrian Austin {"PGA Left", "Switch", "AIN2L"},
593dfe0f98bSBrian Austin {"PGA Right", "Switch", "AIN2R"},
594dfe0f98bSBrian Austin {"PGA Left", "Switch", "AIN3L"},
595dfe0f98bSBrian Austin {"PGA Right", "Switch", "AIN3R"},
596dfe0f98bSBrian Austin {"PGA Left", "Switch", "AIN4L"},
597dfe0f98bSBrian Austin {"PGA Right", "Switch", "AIN4R"},
598dfe0f98bSBrian Austin
599dfe0f98bSBrian Austin {"PGA Left", "Switch", "PGA MICA"},
600dfe0f98bSBrian Austin {"PGA MICA", NULL, "MICA"},
601dfe0f98bSBrian Austin
602dfe0f98bSBrian Austin {"PGA Right", "Switch", "PGA MICB"},
603dfe0f98bSBrian Austin {"PGA MICB", NULL, "MICB"},
604dfe0f98bSBrian Austin
605dfe0f98bSBrian Austin {"HPOUTA", NULL, "HP Left Amp"},
606dfe0f98bSBrian Austin {"HPOUTB", NULL, "HP Right Amp"},
607dfe0f98bSBrian Austin {"HP Left Amp", NULL, "Bypass Left"},
608dfe0f98bSBrian Austin {"HP Right Amp", NULL, "Bypass Right"},
609dfe0f98bSBrian Austin {"Bypass Left", "Switch", "PGA Left"},
610dfe0f98bSBrian Austin {"Bypass Right", "Switch", "PGA Right"},
611dfe0f98bSBrian Austin {"HP Left Amp", "Switch", "DAC Left"},
612dfe0f98bSBrian Austin {"HP Right Amp", "Switch", "DAC Right"},
613dfe0f98bSBrian Austin
614dfe0f98bSBrian Austin {"SPKOUTA", NULL, "SPK Left Amp"},
615dfe0f98bSBrian Austin {"SPKOUTB", NULL, "SPK Right Amp"},
616dfe0f98bSBrian Austin
617dfe0f98bSBrian Austin {"SPK Left Amp", NULL, "Beep"},
618dfe0f98bSBrian Austin {"SPK Right Amp", NULL, "Beep"},
619dfe0f98bSBrian Austin {"SPK Left Amp", "Switch", "Playback"},
620dfe0f98bSBrian Austin {"SPK Right Amp", "Switch", "Playback"},
621dfe0f98bSBrian Austin
622dfe0f98bSBrian Austin {"DAC Left", NULL, "Beep"},
623dfe0f98bSBrian Austin {"DAC Right", NULL, "Beep"},
624dfe0f98bSBrian Austin {"DAC Left", NULL, "Playback"},
625dfe0f98bSBrian Austin {"DAC Right", NULL, "Playback"},
626dfe0f98bSBrian Austin
627dfe0f98bSBrian Austin {"Output Mux", "DSP", "Playback"},
628dfe0f98bSBrian Austin {"Output Mux", "DSP", "Playback"},
629dfe0f98bSBrian Austin
630dfe0f98bSBrian Austin {"AIFINL", NULL, "Playback"},
631dfe0f98bSBrian Austin {"AIFINR", NULL, "Playback"},
632dfe0f98bSBrian Austin
633dfe0f98bSBrian Austin };
634dfe0f98bSBrian Austin
635dfe0f98bSBrian Austin struct cs42l52_clk_para {
636dfe0f98bSBrian Austin u32 mclk;
637dfe0f98bSBrian Austin u32 rate;
638dfe0f98bSBrian Austin u8 speed;
639dfe0f98bSBrian Austin u8 group;
640dfe0f98bSBrian Austin u8 videoclk;
641dfe0f98bSBrian Austin u8 ratio;
642dfe0f98bSBrian Austin u8 mclkdiv2;
643dfe0f98bSBrian Austin };
644dfe0f98bSBrian Austin
645dfe0f98bSBrian Austin static const struct cs42l52_clk_para clk_map_table[] = {
646dfe0f98bSBrian Austin /*8k*/
647dfe0f98bSBrian Austin {12288000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
648dfe0f98bSBrian Austin {18432000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
649dfe0f98bSBrian Austin {12000000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
650dfe0f98bSBrian Austin {24000000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
651dfe0f98bSBrian Austin {27000000, 8000, CLK_QS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 0},
652dfe0f98bSBrian Austin
653dfe0f98bSBrian Austin /*11.025k*/
654dfe0f98bSBrian Austin {11289600, 11025, CLK_QS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
655dfe0f98bSBrian Austin {16934400, 11025, CLK_QS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
656dfe0f98bSBrian Austin
657dfe0f98bSBrian Austin /*16k*/
658dfe0f98bSBrian Austin {12288000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
659dfe0f98bSBrian Austin {18432000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
660dfe0f98bSBrian Austin {12000000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
661dfe0f98bSBrian Austin {24000000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
662dfe0f98bSBrian Austin {27000000, 16000, CLK_HS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 1},
663dfe0f98bSBrian Austin
664dfe0f98bSBrian Austin /*22.05k*/
665dfe0f98bSBrian Austin {11289600, 22050, CLK_HS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
666dfe0f98bSBrian Austin {16934400, 22050, CLK_HS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
667dfe0f98bSBrian Austin
668dfe0f98bSBrian Austin /* 32k */
669dfe0f98bSBrian Austin {12288000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
670dfe0f98bSBrian Austin {18432000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
671dfe0f98bSBrian Austin {12000000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
672dfe0f98bSBrian Austin {24000000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
673dfe0f98bSBrian Austin {27000000, 32000, CLK_SS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 0},
674dfe0f98bSBrian Austin
675dfe0f98bSBrian Austin /* 44.1k */
676dfe0f98bSBrian Austin {11289600, 44100, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
677dfe0f98bSBrian Austin {16934400, 44100, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
678dfe0f98bSBrian Austin
679dfe0f98bSBrian Austin /* 48k */
680dfe0f98bSBrian Austin {12288000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
681dfe0f98bSBrian Austin {18432000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
682dfe0f98bSBrian Austin {12000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 0},
683dfe0f98bSBrian Austin {24000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 1},
684dfe0f98bSBrian Austin {27000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_27M_MCLK, CLK_R_125, 1},
685dfe0f98bSBrian Austin
686dfe0f98bSBrian Austin /* 88.2k */
687dfe0f98bSBrian Austin {11289600, 88200, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
688dfe0f98bSBrian Austin {16934400, 88200, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
689dfe0f98bSBrian Austin
690dfe0f98bSBrian Austin /* 96k */
691dfe0f98bSBrian Austin {12288000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
692dfe0f98bSBrian Austin {18432000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
693dfe0f98bSBrian Austin {12000000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 0},
694dfe0f98bSBrian Austin {24000000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 1},
695dfe0f98bSBrian Austin };
696dfe0f98bSBrian Austin
cs42l52_get_clk(int mclk,int rate)697dfe0f98bSBrian Austin static int cs42l52_get_clk(int mclk, int rate)
698dfe0f98bSBrian Austin {
6993271a4fcSAxel Lin int i, ret = -EINVAL;
700dfe0f98bSBrian Austin u_int mclk1, mclk2 = 0;
701dfe0f98bSBrian Austin
702dfe0f98bSBrian Austin for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
703dfe0f98bSBrian Austin if (clk_map_table[i].rate == rate) {
704dfe0f98bSBrian Austin mclk1 = clk_map_table[i].mclk;
705dfe0f98bSBrian Austin if (abs(mclk - mclk1) < abs(mclk - mclk2)) {
706dfe0f98bSBrian Austin mclk2 = mclk1;
707dfe0f98bSBrian Austin ret = i;
708dfe0f98bSBrian Austin }
709dfe0f98bSBrian Austin }
710dfe0f98bSBrian Austin }
711dfe0f98bSBrian Austin return ret;
712dfe0f98bSBrian Austin }
713dfe0f98bSBrian Austin
cs42l52_set_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)714dfe0f98bSBrian Austin static int cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
715dfe0f98bSBrian Austin int clk_id, unsigned int freq, int dir)
716dfe0f98bSBrian Austin {
7179665a749SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
7189665a749SKuninori Morimoto struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
719dfe0f98bSBrian Austin
720dfe0f98bSBrian Austin if ((freq >= CS42L52_MIN_CLK) && (freq <= CS42L52_MAX_CLK)) {
721dfe0f98bSBrian Austin cs42l52->sysclk = freq;
722dfe0f98bSBrian Austin } else {
7239665a749SKuninori Morimoto dev_err(component->dev, "Invalid freq parameter\n");
724dfe0f98bSBrian Austin return -EINVAL;
725dfe0f98bSBrian Austin }
726dfe0f98bSBrian Austin return 0;
727dfe0f98bSBrian Austin }
728dfe0f98bSBrian Austin
cs42l52_set_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)729dfe0f98bSBrian Austin static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
730dfe0f98bSBrian Austin {
7319665a749SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
7329665a749SKuninori Morimoto struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
733dfe0f98bSBrian Austin u8 iface = 0;
734dfe0f98bSBrian Austin
735dfe0f98bSBrian Austin switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
736dfe0f98bSBrian Austin case SND_SOC_DAIFMT_CBM_CFM:
737dfe0f98bSBrian Austin iface = CS42L52_IFACE_CTL1_MASTER;
738dfe0f98bSBrian Austin break;
739dfe0f98bSBrian Austin case SND_SOC_DAIFMT_CBS_CFS:
740dfe0f98bSBrian Austin iface = CS42L52_IFACE_CTL1_SLAVE;
741dfe0f98bSBrian Austin break;
742dfe0f98bSBrian Austin default:
743dfe0f98bSBrian Austin return -EINVAL;
744dfe0f98bSBrian Austin }
745dfe0f98bSBrian Austin
746dfe0f98bSBrian Austin /* interface format */
747dfe0f98bSBrian Austin switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
748dfe0f98bSBrian Austin case SND_SOC_DAIFMT_I2S:
749dfe0f98bSBrian Austin iface |= CS42L52_IFACE_CTL1_ADC_FMT_I2S |
750dfe0f98bSBrian Austin CS42L52_IFACE_CTL1_DAC_FMT_I2S;
751dfe0f98bSBrian Austin break;
752dfe0f98bSBrian Austin case SND_SOC_DAIFMT_RIGHT_J:
753dfe0f98bSBrian Austin iface |= CS42L52_IFACE_CTL1_DAC_FMT_RIGHT_J;
754dfe0f98bSBrian Austin break;
755dfe0f98bSBrian Austin case SND_SOC_DAIFMT_LEFT_J:
756dfe0f98bSBrian Austin iface |= CS42L52_IFACE_CTL1_ADC_FMT_LEFT_J |
757dfe0f98bSBrian Austin CS42L52_IFACE_CTL1_DAC_FMT_LEFT_J;
758dfe0f98bSBrian Austin break;
759dfe0f98bSBrian Austin case SND_SOC_DAIFMT_DSP_A:
760dfe0f98bSBrian Austin iface |= CS42L52_IFACE_CTL1_DSP_MODE_EN;
761dfe0f98bSBrian Austin break;
762dfe0f98bSBrian Austin case SND_SOC_DAIFMT_DSP_B:
763dfe0f98bSBrian Austin break;
764dfe0f98bSBrian Austin default:
765dfe0f98bSBrian Austin return -EINVAL;
766dfe0f98bSBrian Austin }
767dfe0f98bSBrian Austin
768dfe0f98bSBrian Austin /* clock inversion */
769dfe0f98bSBrian Austin switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
770dfe0f98bSBrian Austin case SND_SOC_DAIFMT_NB_NF:
771dfe0f98bSBrian Austin break;
772dfe0f98bSBrian Austin case SND_SOC_DAIFMT_IB_IF:
773dfe0f98bSBrian Austin iface |= CS42L52_IFACE_CTL1_INV_SCLK;
774dfe0f98bSBrian Austin break;
775dfe0f98bSBrian Austin case SND_SOC_DAIFMT_IB_NF:
776dfe0f98bSBrian Austin iface |= CS42L52_IFACE_CTL1_INV_SCLK;
777dfe0f98bSBrian Austin break;
778dfe0f98bSBrian Austin case SND_SOC_DAIFMT_NB_IF:
779dfe0f98bSBrian Austin break;
780dfe0f98bSBrian Austin default:
7815c855c8eSWei Yongjun return -EINVAL;
782dfe0f98bSBrian Austin }
783dfe0f98bSBrian Austin cs42l52->config.format = iface;
7849665a749SKuninori Morimoto snd_soc_component_write(component, CS42L52_IFACE_CTL1, cs42l52->config.format);
785dfe0f98bSBrian Austin
786dfe0f98bSBrian Austin return 0;
787dfe0f98bSBrian Austin }
788dfe0f98bSBrian Austin
cs42l52_mute(struct snd_soc_dai * dai,int mute,int direction)78903c0f1b5SKuninori Morimoto static int cs42l52_mute(struct snd_soc_dai *dai, int mute, int direction)
790dfe0f98bSBrian Austin {
7919665a749SKuninori Morimoto struct snd_soc_component *component = dai->component;
792dfe0f98bSBrian Austin
793dfe0f98bSBrian Austin if (mute)
7949665a749SKuninori Morimoto snd_soc_component_update_bits(component, CS42L52_PB_CTL1,
795dfe0f98bSBrian Austin CS42L52_PB_CTL1_MUTE_MASK,
796dfe0f98bSBrian Austin CS42L52_PB_CTL1_MUTE);
797dfe0f98bSBrian Austin else
7989665a749SKuninori Morimoto snd_soc_component_update_bits(component, CS42L52_PB_CTL1,
799dfe0f98bSBrian Austin CS42L52_PB_CTL1_MUTE_MASK,
800dfe0f98bSBrian Austin CS42L52_PB_CTL1_UNMUTE);
801dfe0f98bSBrian Austin
802dfe0f98bSBrian Austin return 0;
803dfe0f98bSBrian Austin }
804dfe0f98bSBrian Austin
cs42l52_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)805dfe0f98bSBrian Austin static int cs42l52_pcm_hw_params(struct snd_pcm_substream *substream,
806dfe0f98bSBrian Austin struct snd_pcm_hw_params *params,
807dfe0f98bSBrian Austin struct snd_soc_dai *dai)
808dfe0f98bSBrian Austin {
8099665a749SKuninori Morimoto struct snd_soc_component *component = dai->component;
8109665a749SKuninori Morimoto struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
811dfe0f98bSBrian Austin u32 clk = 0;
812dfe0f98bSBrian Austin int index;
813dfe0f98bSBrian Austin
814dfe0f98bSBrian Austin index = cs42l52_get_clk(cs42l52->sysclk, params_rate(params));
815dfe0f98bSBrian Austin if (index >= 0) {
816dfe0f98bSBrian Austin cs42l52->sysclk = clk_map_table[index].mclk;
817dfe0f98bSBrian Austin
818dfe0f98bSBrian Austin clk |= (clk_map_table[index].speed << CLK_SPEED_SHIFT) |
819dfe0f98bSBrian Austin (clk_map_table[index].group << CLK_32K_SR_SHIFT) |
820dfe0f98bSBrian Austin (clk_map_table[index].videoclk << CLK_27M_MCLK_SHIFT) |
821dfe0f98bSBrian Austin (clk_map_table[index].ratio << CLK_RATIO_SHIFT) |
822dfe0f98bSBrian Austin clk_map_table[index].mclkdiv2;
823dfe0f98bSBrian Austin
8249665a749SKuninori Morimoto snd_soc_component_write(component, CS42L52_CLK_CTL, clk);
825dfe0f98bSBrian Austin } else {
8269665a749SKuninori Morimoto dev_err(component->dev, "can't get correct mclk\n");
827dfe0f98bSBrian Austin return -EINVAL;
828dfe0f98bSBrian Austin }
829dfe0f98bSBrian Austin
830dfe0f98bSBrian Austin return 0;
831dfe0f98bSBrian Austin }
832dfe0f98bSBrian Austin
cs42l52_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)8339665a749SKuninori Morimoto static int cs42l52_set_bias_level(struct snd_soc_component *component,
834dfe0f98bSBrian Austin enum snd_soc_bias_level level)
835dfe0f98bSBrian Austin {
8369665a749SKuninori Morimoto struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
837dfe0f98bSBrian Austin
838dfe0f98bSBrian Austin switch (level) {
839dfe0f98bSBrian Austin case SND_SOC_BIAS_ON:
840dfe0f98bSBrian Austin break;
841dfe0f98bSBrian Austin case SND_SOC_BIAS_PREPARE:
8429665a749SKuninori Morimoto snd_soc_component_update_bits(component, CS42L52_PWRCTL1,
843dfe0f98bSBrian Austin CS42L52_PWRCTL1_PDN_CODEC, 0);
844dfe0f98bSBrian Austin break;
845dfe0f98bSBrian Austin case SND_SOC_BIAS_STANDBY:
8469665a749SKuninori Morimoto if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
847dfe0f98bSBrian Austin regcache_cache_only(cs42l52->regmap, false);
848dfe0f98bSBrian Austin regcache_sync(cs42l52->regmap);
849dfe0f98bSBrian Austin }
8509665a749SKuninori Morimoto snd_soc_component_write(component, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
851dfe0f98bSBrian Austin break;
852dfe0f98bSBrian Austin case SND_SOC_BIAS_OFF:
8539665a749SKuninori Morimoto snd_soc_component_write(component, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
854dfe0f98bSBrian Austin regcache_cache_only(cs42l52->regmap, true);
855dfe0f98bSBrian Austin break;
856dfe0f98bSBrian Austin }
857dfe0f98bSBrian Austin
858dfe0f98bSBrian Austin return 0;
859dfe0f98bSBrian Austin }
860dfe0f98bSBrian Austin
861dfe0f98bSBrian Austin #define CS42L52_RATES (SNDRV_PCM_RATE_8000_96000)
862dfe0f98bSBrian Austin
863dfe0f98bSBrian Austin #define CS42L52_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
864dfe0f98bSBrian Austin SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
865dfe0f98bSBrian Austin SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
866dfe0f98bSBrian Austin SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
867dfe0f98bSBrian Austin
86864793047SAxel Lin static const struct snd_soc_dai_ops cs42l52_ops = {
869dfe0f98bSBrian Austin .hw_params = cs42l52_pcm_hw_params,
87003c0f1b5SKuninori Morimoto .mute_stream = cs42l52_mute,
871dfe0f98bSBrian Austin .set_fmt = cs42l52_set_fmt,
872dfe0f98bSBrian Austin .set_sysclk = cs42l52_set_sysclk,
87303c0f1b5SKuninori Morimoto .no_capture_mute = 1,
874dfe0f98bSBrian Austin };
875dfe0f98bSBrian Austin
876a7f44885SMark Brown static struct snd_soc_dai_driver cs42l52_dai = {
877dfe0f98bSBrian Austin .name = "cs42l52",
878dfe0f98bSBrian Austin .playback = {
879dfe0f98bSBrian Austin .stream_name = "Playback",
880dfe0f98bSBrian Austin .channels_min = 1,
881dfe0f98bSBrian Austin .channels_max = 2,
882dfe0f98bSBrian Austin .rates = CS42L52_RATES,
883dfe0f98bSBrian Austin .formats = CS42L52_FORMATS,
884dfe0f98bSBrian Austin },
885dfe0f98bSBrian Austin .capture = {
886dfe0f98bSBrian Austin .stream_name = "Capture",
887dfe0f98bSBrian Austin .channels_min = 1,
888dfe0f98bSBrian Austin .channels_max = 2,
889dfe0f98bSBrian Austin .rates = CS42L52_RATES,
890dfe0f98bSBrian Austin .formats = CS42L52_FORMATS,
891dfe0f98bSBrian Austin },
892dfe0f98bSBrian Austin .ops = &cs42l52_ops,
893dfe0f98bSBrian Austin };
894dfe0f98bSBrian Austin
895dfe0f98bSBrian Austin static int beep_rates[] = {
896dfe0f98bSBrian Austin 261, 522, 585, 667, 706, 774, 889, 1000,
897dfe0f98bSBrian Austin 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
898dfe0f98bSBrian Austin };
899dfe0f98bSBrian Austin
cs42l52_beep_work(struct work_struct * work)900dfe0f98bSBrian Austin static void cs42l52_beep_work(struct work_struct *work)
901dfe0f98bSBrian Austin {
902dfe0f98bSBrian Austin struct cs42l52_private *cs42l52 =
903dfe0f98bSBrian Austin container_of(work, struct cs42l52_private, beep_work);
9049665a749SKuninori Morimoto struct snd_soc_component *component = cs42l52->component;
9059665a749SKuninori Morimoto struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
906dfe0f98bSBrian Austin int i;
907dfe0f98bSBrian Austin int val = 0;
908dfe0f98bSBrian Austin int best = 0;
909dfe0f98bSBrian Austin
910dfe0f98bSBrian Austin if (cs42l52->beep_rate) {
911dfe0f98bSBrian Austin for (i = 0; i < ARRAY_SIZE(beep_rates); i++) {
912dfe0f98bSBrian Austin if (abs(cs42l52->beep_rate - beep_rates[i]) <
913dfe0f98bSBrian Austin abs(cs42l52->beep_rate - beep_rates[best]))
914dfe0f98bSBrian Austin best = i;
915dfe0f98bSBrian Austin }
916dfe0f98bSBrian Austin
9179665a749SKuninori Morimoto dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n",
918dfe0f98bSBrian Austin beep_rates[best], cs42l52->beep_rate);
919dfe0f98bSBrian Austin
920dfe0f98bSBrian Austin val = (best << CS42L52_BEEP_RATE_SHIFT);
921dfe0f98bSBrian Austin
922dfe0f98bSBrian Austin snd_soc_dapm_enable_pin(dapm, "Beep");
923dfe0f98bSBrian Austin } else {
9249665a749SKuninori Morimoto dev_dbg(component->dev, "Disabling beep\n");
925dfe0f98bSBrian Austin snd_soc_dapm_disable_pin(dapm, "Beep");
926dfe0f98bSBrian Austin }
927dfe0f98bSBrian Austin
9289665a749SKuninori Morimoto snd_soc_component_update_bits(component, CS42L52_BEEP_FREQ,
929dfe0f98bSBrian Austin CS42L52_BEEP_RATE_MASK, val);
930dfe0f98bSBrian Austin
931dfe0f98bSBrian Austin snd_soc_dapm_sync(dapm);
932dfe0f98bSBrian Austin }
933dfe0f98bSBrian Austin
934dfe0f98bSBrian Austin /* For usability define a way of injecting beep events for the device -
935dfe0f98bSBrian Austin * many systems will not have a keyboard.
936dfe0f98bSBrian Austin */
cs42l52_beep_event(struct input_dev * dev,unsigned int type,unsigned int code,int hz)937dfe0f98bSBrian Austin static int cs42l52_beep_event(struct input_dev *dev, unsigned int type,
938dfe0f98bSBrian Austin unsigned int code, int hz)
939dfe0f98bSBrian Austin {
9409665a749SKuninori Morimoto struct snd_soc_component *component = input_get_drvdata(dev);
9419665a749SKuninori Morimoto struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
942dfe0f98bSBrian Austin
9439665a749SKuninori Morimoto dev_dbg(component->dev, "Beep event %x %x\n", code, hz);
944dfe0f98bSBrian Austin
945dfe0f98bSBrian Austin switch (code) {
946dfe0f98bSBrian Austin case SND_BELL:
947dfe0f98bSBrian Austin if (hz)
948dfe0f98bSBrian Austin hz = 261;
9493371c6f9SGustavo A. R. Silva break;
950dfe0f98bSBrian Austin case SND_TONE:
951dfe0f98bSBrian Austin break;
952dfe0f98bSBrian Austin default:
953dfe0f98bSBrian Austin return -1;
954dfe0f98bSBrian Austin }
955dfe0f98bSBrian Austin
956dfe0f98bSBrian Austin /* Kick the beep from a workqueue */
957dfe0f98bSBrian Austin cs42l52->beep_rate = hz;
958dfe0f98bSBrian Austin schedule_work(&cs42l52->beep_work);
959dfe0f98bSBrian Austin return 0;
960dfe0f98bSBrian Austin }
961dfe0f98bSBrian Austin
beep_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)962058efb40SYueHaibing static ssize_t beep_store(struct device *dev, struct device_attribute *attr,
963dfe0f98bSBrian Austin const char *buf, size_t count)
964dfe0f98bSBrian Austin {
965dfe0f98bSBrian Austin struct cs42l52_private *cs42l52 = dev_get_drvdata(dev);
966dfe0f98bSBrian Austin long int time;
967dfe0f98bSBrian Austin int ret;
968dfe0f98bSBrian Austin
969dfe0f98bSBrian Austin ret = kstrtol(buf, 10, &time);
970dfe0f98bSBrian Austin if (ret != 0)
971dfe0f98bSBrian Austin return ret;
972dfe0f98bSBrian Austin
973dfe0f98bSBrian Austin input_event(cs42l52->beep, EV_SND, SND_TONE, time);
974dfe0f98bSBrian Austin
975dfe0f98bSBrian Austin return count;
976dfe0f98bSBrian Austin }
977dfe0f98bSBrian Austin
978058efb40SYueHaibing static DEVICE_ATTR_WO(beep);
979dfe0f98bSBrian Austin
cs42l52_init_beep(struct snd_soc_component * component)9809665a749SKuninori Morimoto static void cs42l52_init_beep(struct snd_soc_component *component)
981dfe0f98bSBrian Austin {
9829665a749SKuninori Morimoto struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
983dfe0f98bSBrian Austin int ret;
984dfe0f98bSBrian Austin
9859665a749SKuninori Morimoto cs42l52->beep = devm_input_allocate_device(component->dev);
986dfe0f98bSBrian Austin if (!cs42l52->beep) {
9879665a749SKuninori Morimoto dev_err(component->dev, "Failed to allocate beep device\n");
988dfe0f98bSBrian Austin return;
989dfe0f98bSBrian Austin }
990dfe0f98bSBrian Austin
991dfe0f98bSBrian Austin INIT_WORK(&cs42l52->beep_work, cs42l52_beep_work);
992dfe0f98bSBrian Austin cs42l52->beep_rate = 0;
993dfe0f98bSBrian Austin
994dfe0f98bSBrian Austin cs42l52->beep->name = "CS42L52 Beep Generator";
9959665a749SKuninori Morimoto cs42l52->beep->phys = dev_name(component->dev);
996dfe0f98bSBrian Austin cs42l52->beep->id.bustype = BUS_I2C;
997dfe0f98bSBrian Austin
998dfe0f98bSBrian Austin cs42l52->beep->evbit[0] = BIT_MASK(EV_SND);
999dfe0f98bSBrian Austin cs42l52->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
1000dfe0f98bSBrian Austin cs42l52->beep->event = cs42l52_beep_event;
10019665a749SKuninori Morimoto cs42l52->beep->dev.parent = component->dev;
10029665a749SKuninori Morimoto input_set_drvdata(cs42l52->beep, component);
1003dfe0f98bSBrian Austin
1004dfe0f98bSBrian Austin ret = input_register_device(cs42l52->beep);
1005dfe0f98bSBrian Austin if (ret != 0) {
1006dfe0f98bSBrian Austin cs42l52->beep = NULL;
10079665a749SKuninori Morimoto dev_err(component->dev, "Failed to register beep device\n");
1008dfe0f98bSBrian Austin }
1009dfe0f98bSBrian Austin
10109665a749SKuninori Morimoto ret = device_create_file(component->dev, &dev_attr_beep);
1011dfe0f98bSBrian Austin if (ret != 0) {
10129665a749SKuninori Morimoto dev_err(component->dev, "Failed to create keyclick file: %d\n",
1013dfe0f98bSBrian Austin ret);
1014dfe0f98bSBrian Austin }
1015dfe0f98bSBrian Austin }
1016dfe0f98bSBrian Austin
cs42l52_free_beep(struct snd_soc_component * component)10179665a749SKuninori Morimoto static void cs42l52_free_beep(struct snd_soc_component *component)
1018dfe0f98bSBrian Austin {
10199665a749SKuninori Morimoto struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
1020dfe0f98bSBrian Austin
10219665a749SKuninori Morimoto device_remove_file(component->dev, &dev_attr_beep);
1022dfe0f98bSBrian Austin cancel_work_sync(&cs42l52->beep_work);
1023dfe0f98bSBrian Austin cs42l52->beep = NULL;
1024dfe0f98bSBrian Austin
10259665a749SKuninori Morimoto snd_soc_component_update_bits(component, CS42L52_BEEP_TONE_CTL,
1026dfe0f98bSBrian Austin CS42L52_BEEP_EN_MASK, 0);
1027dfe0f98bSBrian Austin }
1028dfe0f98bSBrian Austin
cs42l52_probe(struct snd_soc_component * component)10299665a749SKuninori Morimoto static int cs42l52_probe(struct snd_soc_component *component)
1030dfe0f98bSBrian Austin {
10319665a749SKuninori Morimoto struct cs42l52_private *cs42l52 = snd_soc_component_get_drvdata(component);
1032dfe0f98bSBrian Austin
1033dfe0f98bSBrian Austin regcache_cache_only(cs42l52->regmap, true);
1034dfe0f98bSBrian Austin
10359665a749SKuninori Morimoto cs42l52_add_mic_controls(component);
103644b2ed54SBrian Austin
10379665a749SKuninori Morimoto cs42l52_init_beep(component);
1038dfe0f98bSBrian Austin
1039dfe0f98bSBrian Austin cs42l52->sysclk = CS42L52_DEFAULT_CLK;
1040dfe0f98bSBrian Austin cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
1041dfe0f98bSBrian Austin
10425d6be5aaSXiubo Li return 0;
1043dfe0f98bSBrian Austin }
1044dfe0f98bSBrian Austin
cs42l52_remove(struct snd_soc_component * component)10459665a749SKuninori Morimoto static void cs42l52_remove(struct snd_soc_component *component)
1046dfe0f98bSBrian Austin {
10479665a749SKuninori Morimoto cs42l52_free_beep(component);
1048dfe0f98bSBrian Austin }
1049dfe0f98bSBrian Austin
10509665a749SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_cs42l52 = {
1051dfe0f98bSBrian Austin .probe = cs42l52_probe,
1052dfe0f98bSBrian Austin .remove = cs42l52_remove,
1053dfe0f98bSBrian Austin .set_bias_level = cs42l52_set_bias_level,
105459aad18cSKuninori Morimoto .controls = cs42l52_snd_controls,
105559aad18cSKuninori Morimoto .num_controls = ARRAY_SIZE(cs42l52_snd_controls),
1056dfe0f98bSBrian Austin .dapm_widgets = cs42l52_dapm_widgets,
1057dfe0f98bSBrian Austin .num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets),
1058dfe0f98bSBrian Austin .dapm_routes = cs42l52_audio_map,
1059dfe0f98bSBrian Austin .num_dapm_routes = ARRAY_SIZE(cs42l52_audio_map),
10609665a749SKuninori Morimoto .suspend_bias_off = 1,
10619665a749SKuninori Morimoto .idle_bias_on = 1,
10629665a749SKuninori Morimoto .use_pmdown_time = 1,
10639665a749SKuninori Morimoto .endianness = 1,
1064dfe0f98bSBrian Austin };
1065dfe0f98bSBrian Austin
1066dfe0f98bSBrian Austin /* Current and threshold powerup sequence Pg37 */
10678019ff6cSNariman Poushin static const struct reg_sequence cs42l52_threshold_patch[] = {
1068dfe0f98bSBrian Austin
1069dfe0f98bSBrian Austin { 0x00, 0x99 },
1070dfe0f98bSBrian Austin { 0x3E, 0xBA },
1071dfe0f98bSBrian Austin { 0x47, 0x80 },
1072dfe0f98bSBrian Austin { 0x32, 0xBB },
1073dfe0f98bSBrian Austin { 0x32, 0x3B },
1074dfe0f98bSBrian Austin { 0x00, 0x00 },
1075dfe0f98bSBrian Austin
1076dfe0f98bSBrian Austin };
1077dfe0f98bSBrian Austin
1078b5fbcbabSKrzysztof Kozlowski static const struct regmap_config cs42l52_regmap = {
1079dfe0f98bSBrian Austin .reg_bits = 8,
1080dfe0f98bSBrian Austin .val_bits = 8,
1081dfe0f98bSBrian Austin
1082dfe0f98bSBrian Austin .max_register = CS42L52_MAX_REGISTER,
1083dfe0f98bSBrian Austin .reg_defaults = cs42l52_reg_defaults,
1084dfe0f98bSBrian Austin .num_reg_defaults = ARRAY_SIZE(cs42l52_reg_defaults),
1085dfe0f98bSBrian Austin .readable_reg = cs42l52_readable_register,
1086dfe0f98bSBrian Austin .volatile_reg = cs42l52_volatile_register,
1087*99d2c7b8SMark Brown .cache_type = REGCACHE_MAPLE,
1088dfe0f98bSBrian Austin };
1089dfe0f98bSBrian Austin
cs42l52_i2c_probe(struct i2c_client * i2c_client)10904a404345SStephen Kitt static int cs42l52_i2c_probe(struct i2c_client *i2c_client)
1091dfe0f98bSBrian Austin {
1092dfe0f98bSBrian Austin struct cs42l52_private *cs42l52;
10936dd17757SBrian Austin struct cs42l52_platform_data *pdata = dev_get_platdata(&i2c_client->dev);
1094dfe0f98bSBrian Austin int ret;
10954ac9b48aSCharles Keepax unsigned int devid;
1096dfe0f98bSBrian Austin unsigned int reg;
1097391fc59dSBrian Austin u32 val32;
1098dfe0f98bSBrian Austin
1099cd9e0b82SMarkus Elfring cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l52), GFP_KERNEL);
1100dfe0f98bSBrian Austin if (cs42l52 == NULL)
1101dfe0f98bSBrian Austin return -ENOMEM;
1102dfe0f98bSBrian Austin cs42l52->dev = &i2c_client->dev;
1103dfe0f98bSBrian Austin
1104134b2f57SBrian Austin cs42l52->regmap = devm_regmap_init_i2c(i2c_client, &cs42l52_regmap);
1105dfe0f98bSBrian Austin if (IS_ERR(cs42l52->regmap)) {
1106dfe0f98bSBrian Austin ret = PTR_ERR(cs42l52->regmap);
1107dfe0f98bSBrian Austin dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
1108134b2f57SBrian Austin return ret;
1109dfe0f98bSBrian Austin }
1110391fc59dSBrian Austin if (pdata) {
11116dd17757SBrian Austin cs42l52->pdata = *pdata;
1112391fc59dSBrian Austin } else {
1113cd9e0b82SMarkus Elfring pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
1114391fc59dSBrian Austin GFP_KERNEL);
1115e04db58cSMarkus Elfring if (!pdata)
1116391fc59dSBrian Austin return -ENOMEM;
1117e04db58cSMarkus Elfring
1118391fc59dSBrian Austin if (i2c_client->dev.of_node) {
1119391fc59dSBrian Austin if (of_property_read_bool(i2c_client->dev.of_node,
1120391fc59dSBrian Austin "cirrus,mica-differential-cfg"))
1121391fc59dSBrian Austin pdata->mica_diff_cfg = true;
1122391fc59dSBrian Austin
1123391fc59dSBrian Austin if (of_property_read_bool(i2c_client->dev.of_node,
1124391fc59dSBrian Austin "cirrus,micb-differential-cfg"))
1125391fc59dSBrian Austin pdata->micb_diff_cfg = true;
1126391fc59dSBrian Austin
1127391fc59dSBrian Austin if (of_property_read_u32(i2c_client->dev.of_node,
1128391fc59dSBrian Austin "cirrus,micbias-lvl", &val32) >= 0)
1129391fc59dSBrian Austin pdata->micbias_lvl = val32;
1130391fc59dSBrian Austin
1131391fc59dSBrian Austin if (of_property_read_u32(i2c_client->dev.of_node,
1132391fc59dSBrian Austin "cirrus,chgfreq-divisor", &val32) >= 0)
113369ae8489SMark Brown pdata->chgfreq = val32;
1134391fc59dSBrian Austin
1135391fc59dSBrian Austin pdata->reset_gpio =
1136391fc59dSBrian Austin of_get_named_gpio(i2c_client->dev.of_node,
1137391fc59dSBrian Austin "cirrus,reset-gpio", 0);
1138391fc59dSBrian Austin }
1139391fc59dSBrian Austin cs42l52->pdata = *pdata;
1140391fc59dSBrian Austin }
1141dfe0f98bSBrian Austin
11426dd17757SBrian Austin if (cs42l52->pdata.reset_gpio) {
11434e17d2d3SAxel Lin ret = devm_gpio_request_one(&i2c_client->dev,
11444e17d2d3SAxel Lin cs42l52->pdata.reset_gpio,
11454e17d2d3SAxel Lin GPIOF_OUT_INIT_HIGH,
11464e17d2d3SAxel Lin "CS42L52 /RST");
11476dd17757SBrian Austin if (ret < 0) {
11486dd17757SBrian Austin dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
11496dd17757SBrian Austin cs42l52->pdata.reset_gpio, ret);
11506dd17757SBrian Austin return ret;
11516dd17757SBrian Austin }
11526dd17757SBrian Austin gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 0);
11536dd17757SBrian Austin gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 1);
11546dd17757SBrian Austin }
11556dd17757SBrian Austin
11566dd17757SBrian Austin i2c_set_clientdata(i2c_client, cs42l52);
1157dfe0f98bSBrian Austin
1158dfe0f98bSBrian Austin ret = regmap_register_patch(cs42l52->regmap, cs42l52_threshold_patch,
1159dfe0f98bSBrian Austin ARRAY_SIZE(cs42l52_threshold_patch));
1160dfe0f98bSBrian Austin if (ret != 0)
1161dfe0f98bSBrian Austin dev_warn(cs42l52->dev, "Failed to apply regmap patch: %d\n",
1162dfe0f98bSBrian Austin ret);
1163dfe0f98bSBrian Austin
1164dfe0f98bSBrian Austin ret = regmap_read(cs42l52->regmap, CS42L52_CHIP, ®);
11654ac9b48aSCharles Keepax if (ret) {
11664ac9b48aSCharles Keepax dev_err(&i2c_client->dev, "Failed to read chip ID: %d\n", ret);
11674ac9b48aSCharles Keepax return ret;
11684ac9b48aSCharles Keepax }
11694ac9b48aSCharles Keepax
1170dfe0f98bSBrian Austin devid = reg & CS42L52_CHIP_ID_MASK;
1171dfe0f98bSBrian Austin if (devid != CS42L52_CHIP_ID) {
1172dfe0f98bSBrian Austin ret = -ENODEV;
1173dfe0f98bSBrian Austin dev_err(&i2c_client->dev,
1174dfe0f98bSBrian Austin "CS42L52 Device ID (%X). Expected %X\n",
1175dfe0f98bSBrian Austin devid, CS42L52_CHIP_ID);
1176134b2f57SBrian Austin return ret;
1177dfe0f98bSBrian Austin }
1178dfe0f98bSBrian Austin
1179e5f03af6SBrian Austin dev_info(&i2c_client->dev, "Cirrus Logic CS42L52, Revision: %02X\n",
1180a14bf887SAxel Lin reg & CS42L52_CHIP_REV_MASK);
1181e5f03af6SBrian Austin
1182153723f6SBrian Austin /* Set Platform Data */
118344b2ed54SBrian Austin if (cs42l52->pdata.mica_diff_cfg)
1184153723f6SBrian Austin regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL,
1185153723f6SBrian Austin CS42L52_MIC_CTL_TYPE_MASK,
118644b2ed54SBrian Austin cs42l52->pdata.mica_diff_cfg <<
1187153723f6SBrian Austin CS42L52_MIC_CTL_TYPE_SHIFT);
1188153723f6SBrian Austin
118944b2ed54SBrian Austin if (cs42l52->pdata.micb_diff_cfg)
1190153723f6SBrian Austin regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL,
1191153723f6SBrian Austin CS42L52_MIC_CTL_TYPE_MASK,
119244b2ed54SBrian Austin cs42l52->pdata.micb_diff_cfg <<
1193153723f6SBrian Austin CS42L52_MIC_CTL_TYPE_SHIFT);
1194153723f6SBrian Austin
1195153723f6SBrian Austin if (cs42l52->pdata.chgfreq)
1196153723f6SBrian Austin regmap_update_bits(cs42l52->regmap, CS42L52_CHARGE_PUMP,
1197153723f6SBrian Austin CS42L52_CHARGE_PUMP_MASK,
1198153723f6SBrian Austin cs42l52->pdata.chgfreq <<
1199153723f6SBrian Austin CS42L52_CHARGE_PUMP_SHIFT);
1200153723f6SBrian Austin
1201153723f6SBrian Austin if (cs42l52->pdata.micbias_lvl)
1202153723f6SBrian Austin regmap_update_bits(cs42l52->regmap, CS42L52_IFACE_CTL2,
1203153723f6SBrian Austin CS42L52_IFACE_CTL2_BIAS_LVL,
1204153723f6SBrian Austin cs42l52->pdata.micbias_lvl);
1205dfe0f98bSBrian Austin
12064ac9b48aSCharles Keepax return devm_snd_soc_register_component(&i2c_client->dev,
12079665a749SKuninori Morimoto &soc_component_dev_cs42l52, &cs42l52_dai, 1);
1208dfe0f98bSBrian Austin }
1209dfe0f98bSBrian Austin
1210391fc59dSBrian Austin static const struct of_device_id cs42l52_of_match[] = {
1211391fc59dSBrian Austin { .compatible = "cirrus,cs42l52", },
1212391fc59dSBrian Austin {},
1213391fc59dSBrian Austin };
1214391fc59dSBrian Austin MODULE_DEVICE_TABLE(of, cs42l52_of_match);
1215391fc59dSBrian Austin
1216391fc59dSBrian Austin
1217dfe0f98bSBrian Austin static const struct i2c_device_id cs42l52_id[] = {
1218dfe0f98bSBrian Austin { "cs42l52", 0 },
1219dfe0f98bSBrian Austin { }
1220dfe0f98bSBrian Austin };
1221dfe0f98bSBrian Austin MODULE_DEVICE_TABLE(i2c, cs42l52_id);
1222dfe0f98bSBrian Austin
1223dfe0f98bSBrian Austin static struct i2c_driver cs42l52_i2c_driver = {
1224dfe0f98bSBrian Austin .driver = {
1225dfe0f98bSBrian Austin .name = "cs42l52",
1226391fc59dSBrian Austin .of_match_table = cs42l52_of_match,
1227dfe0f98bSBrian Austin },
1228dfe0f98bSBrian Austin .id_table = cs42l52_id,
12299abcd240SUwe Kleine-König .probe = cs42l52_i2c_probe,
1230dfe0f98bSBrian Austin };
1231dfe0f98bSBrian Austin
1232dfe0f98bSBrian Austin module_i2c_driver(cs42l52_i2c_driver);
1233dfe0f98bSBrian Austin
1234dfe0f98bSBrian Austin MODULE_DESCRIPTION("ASoC CS42L52 driver");
1235dfe0f98bSBrian Austin MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
1236dfe0f98bSBrian Austin MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
1237dfe0f98bSBrian Austin MODULE_LICENSE("GPL");
1238