1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * TDA7419 audio processor driver |
4 | * |
5 | * Copyright 2018 Konsulko Group |
6 | * |
7 | * Author: Matt Porter <mporter@konsulko.com> |
8 | */ |
9 | |
10 | #include <linux/i2c.h> |
11 | #include <linux/init.h> |
12 | #include <linux/module.h> |
13 | #include <linux/regmap.h> |
14 | #include <sound/core.h> |
15 | #include <sound/control.h> |
16 | #include <sound/soc.h> |
17 | #include <sound/tlv.h> |
18 | |
19 | #define TDA7419_MAIN_SRC_REG 0x00 |
20 | #define TDA7419_LOUDNESS_REG 0x01 |
21 | #define TDA7419_MUTE_CLK_REG 0x02 |
22 | #define TDA7419_VOLUME_REG 0x03 |
23 | #define TDA7419_TREBLE_REG 0x04 |
24 | #define TDA7419_MIDDLE_REG 0x05 |
25 | #define TDA7419_BASS_REG 0x06 |
26 | #define TDA7419_SECOND_SRC_REG 0x07 |
27 | #define TDA7419_SUB_MID_BASS_REG 0x08 |
28 | #define TDA7419_MIXING_GAIN_REG 0x09 |
29 | #define TDA7419_ATTENUATOR_LF_REG 0x0a |
30 | #define TDA7419_ATTENUATOR_RF_REG 0x0b |
31 | #define TDA7419_ATTENUATOR_LR_REG 0x0c |
32 | #define TDA7419_ATTENUATOR_RR_REG 0x0d |
33 | #define TDA7419_MIXING_LEVEL_REG 0x0e |
34 | #define TDA7419_ATTENUATOR_SUB_REG 0x0f |
35 | #define TDA7419_SA_CLK_AC_REG 0x10 |
36 | #define TDA7419_TESTING_REG 0x11 |
37 | |
38 | #define TDA7419_MAIN_SRC_SEL 0 |
39 | #define TDA7419_MAIN_SRC_GAIN 3 |
40 | #define TDA7419_MAIN_SRC_AUTOZERO 7 |
41 | |
42 | #define TDA7419_LOUDNESS_ATTEN 0 |
43 | #define TDA7419_LOUDNESS_CENTER_FREQ 4 |
44 | #define TDA7419_LOUDNESS_BOOST 6 |
45 | #define TDA7419_LOUDNESS_SOFT_STEP 7 |
46 | |
47 | #define TDA7419_VOLUME_SOFT_STEP 7 |
48 | |
49 | #define TDA7419_SOFT_MUTE 0 |
50 | #define TDA7419_MUTE_INFLUENCE 1 |
51 | #define TDA7419_SOFT_MUTE_TIME 2 |
52 | #define TDA7419_SOFT_STEP_TIME 4 |
53 | #define TDA7419_CLK_FAST_MODE 7 |
54 | |
55 | #define TDA7419_TREBLE_CENTER_FREQ 5 |
56 | #define TDA7419_REF_OUT_SELECT 7 |
57 | |
58 | #define TDA7419_MIDDLE_Q_FACTOR 5 |
59 | #define TDA7419_MIDDLE_SOFT_STEP 7 |
60 | |
61 | #define TDA7419_BASS_Q_FACTOR 5 |
62 | #define TDA7419_BASS_SOFT_STEP 7 |
63 | |
64 | #define TDA7419_SECOND_SRC_SEL 0 |
65 | #define TDA7419_SECOND_SRC_GAIN 3 |
66 | #define TDA7419_REAR_SPKR_SRC 7 |
67 | |
68 | #define TDA7419_SUB_CUT_OFF_FREQ 0 |
69 | #define TDA7419_MIDDLE_CENTER_FREQ 2 |
70 | #define TDA7419_BASS_CENTER_FREQ 4 |
71 | #define TDA7419_BASS_DC_MODE 6 |
72 | #define TDA7419_SMOOTHING_FILTER 7 |
73 | |
74 | #define TDA7419_MIX_LF 0 |
75 | #define TDA7419_MIX_RF 1 |
76 | #define TDA7419_MIX_ENABLE 2 |
77 | #define TDA7419_SUB_ENABLE 3 |
78 | #define TDA7419_HPF_GAIN 4 |
79 | |
80 | #define TDA7419_SA_Q_FACTOR 0 |
81 | #define TDA7419_RESET_MODE 1 |
82 | #define TDA7419_SA_SOURCE 2 |
83 | #define TDA7419_SA_RUN 3 |
84 | #define TDA7419_RESET 4 |
85 | #define TDA7419_CLK_SOURCE 5 |
86 | #define TDA7419_COUPLING_MODE 6 |
87 | |
88 | struct tda7419_data { |
89 | struct regmap *regmap; |
90 | }; |
91 | |
92 | static bool tda7419_readable_reg(struct device *dev, unsigned int reg) |
93 | { |
94 | return false; |
95 | } |
96 | |
97 | static const struct reg_default tda7419_regmap_defaults[] = { |
98 | { TDA7419_MAIN_SRC_REG, 0xfe }, |
99 | { TDA7419_LOUDNESS_REG, 0xfe }, |
100 | { TDA7419_MUTE_CLK_REG, 0xfe }, |
101 | { TDA7419_VOLUME_REG, 0xfe }, |
102 | { TDA7419_TREBLE_REG, 0xfe }, |
103 | { TDA7419_MIDDLE_REG, 0xfe }, |
104 | { TDA7419_BASS_REG, 0xfe }, |
105 | { TDA7419_SECOND_SRC_REG, 0xfe }, |
106 | { TDA7419_SUB_MID_BASS_REG, 0xfe }, |
107 | { TDA7419_MIXING_GAIN_REG, 0xfe }, |
108 | { TDA7419_ATTENUATOR_LF_REG, 0xfe }, |
109 | { TDA7419_ATTENUATOR_RF_REG, 0xfe }, |
110 | { TDA7419_ATTENUATOR_LR_REG, 0xfe }, |
111 | { TDA7419_ATTENUATOR_RR_REG, 0xfe }, |
112 | { TDA7419_MIXING_LEVEL_REG, 0xfe }, |
113 | { TDA7419_ATTENUATOR_SUB_REG, 0xfe }, |
114 | { TDA7419_SA_CLK_AC_REG, 0xfe }, |
115 | { TDA7419_TESTING_REG, 0xfe }, |
116 | }; |
117 | |
118 | static const struct regmap_config tda7419_regmap_config = { |
119 | .reg_bits = 8, |
120 | .val_bits = 8, |
121 | .max_register = TDA7419_TESTING_REG, |
122 | .cache_type = REGCACHE_RBTREE, |
123 | .readable_reg = tda7419_readable_reg, |
124 | .reg_defaults = tda7419_regmap_defaults, |
125 | .num_reg_defaults = ARRAY_SIZE(tda7419_regmap_defaults), |
126 | }; |
127 | |
128 | struct tda7419_vol_control { |
129 | int min, max; |
130 | unsigned int reg, rreg, mask, thresh; |
131 | unsigned int invert:1; |
132 | }; |
133 | |
134 | static inline bool tda7419_vol_is_stereo(struct tda7419_vol_control *tvc) |
135 | { |
136 | if (tvc->reg == tvc->rreg) |
137 | return false; |
138 | |
139 | return true; |
140 | } |
141 | |
142 | static int tda7419_vol_info(struct snd_kcontrol *kcontrol, |
143 | struct snd_ctl_elem_info *uinfo) |
144 | { |
145 | struct tda7419_vol_control *tvc = |
146 | (struct tda7419_vol_control *)kcontrol->private_value; |
147 | |
148 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
149 | uinfo->count = tda7419_vol_is_stereo(tvc) ? 2 : 1; |
150 | uinfo->value.integer.min = tvc->min; |
151 | uinfo->value.integer.max = tvc->max; |
152 | |
153 | return 0; |
154 | } |
155 | |
156 | static inline int tda7419_vol_get_value(int val, unsigned int mask, |
157 | int min, int thresh, |
158 | unsigned int invert) |
159 | { |
160 | val &= mask; |
161 | if (val < thresh) { |
162 | if (invert) |
163 | val = 0 - val; |
164 | } else if (val > thresh) { |
165 | if (invert) |
166 | val = val - thresh; |
167 | else |
168 | val = thresh - val; |
169 | } |
170 | |
171 | if (val < min) |
172 | val = min; |
173 | |
174 | return val; |
175 | } |
176 | |
177 | static int tda7419_vol_get(struct snd_kcontrol *kcontrol, |
178 | struct snd_ctl_elem_value *ucontrol) |
179 | { |
180 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
181 | struct tda7419_vol_control *tvc = |
182 | (struct tda7419_vol_control *)kcontrol->private_value; |
183 | unsigned int reg = tvc->reg; |
184 | unsigned int rreg = tvc->rreg; |
185 | unsigned int mask = tvc->mask; |
186 | int min = tvc->min; |
187 | int thresh = tvc->thresh; |
188 | unsigned int invert = tvc->invert; |
189 | int val; |
190 | |
191 | val = snd_soc_component_read(component, reg); |
192 | ucontrol->value.integer.value[0] = |
193 | tda7419_vol_get_value(val, mask, min, thresh, invert); |
194 | |
195 | if (tda7419_vol_is_stereo(tvc)) { |
196 | val = snd_soc_component_read(component, reg: rreg); |
197 | ucontrol->value.integer.value[1] = |
198 | tda7419_vol_get_value(val, mask, min, thresh, invert); |
199 | } |
200 | |
201 | return 0; |
202 | } |
203 | |
204 | static inline int tda7419_vol_put_value(int val, int thresh, |
205 | unsigned int invert) |
206 | { |
207 | if (val < 0) { |
208 | if (invert) |
209 | val = abs(val); |
210 | else |
211 | val = thresh - val; |
212 | } else if ((val > 0) && invert) { |
213 | val += thresh; |
214 | } |
215 | |
216 | return val; |
217 | } |
218 | |
219 | static int tda7419_vol_put(struct snd_kcontrol *kcontrol, |
220 | struct snd_ctl_elem_value *ucontrol) |
221 | { |
222 | struct snd_soc_component *component = |
223 | snd_kcontrol_chip(kcontrol); |
224 | struct tda7419_vol_control *tvc = |
225 | (struct tda7419_vol_control *)kcontrol->private_value; |
226 | unsigned int reg = tvc->reg; |
227 | unsigned int rreg = tvc->rreg; |
228 | unsigned int mask = tvc->mask; |
229 | int thresh = tvc->thresh; |
230 | unsigned int invert = tvc->invert; |
231 | int val; |
232 | int ret; |
233 | |
234 | val = tda7419_vol_put_value(val: ucontrol->value.integer.value[0], |
235 | thresh, invert); |
236 | ret = snd_soc_component_update_bits(component, reg, |
237 | mask, val); |
238 | if (ret < 0) |
239 | return ret; |
240 | |
241 | if (tda7419_vol_is_stereo(tvc)) { |
242 | val = tda7419_vol_put_value(val: ucontrol->value.integer.value[1], |
243 | thresh, invert); |
244 | ret = snd_soc_component_update_bits(component, reg: rreg, |
245 | mask, val); |
246 | } |
247 | |
248 | return ret; |
249 | } |
250 | |
251 | #define TDA7419_SINGLE_VALUE(xreg, xmask, xmin, xmax, xthresh, xinvert) \ |
252 | ((unsigned long)&(struct tda7419_vol_control) \ |
253 | {.reg = xreg, .rreg = xreg, .mask = xmask, .min = xmin, \ |
254 | .max = xmax, .thresh = xthresh, .invert = xinvert}) |
255 | |
256 | #define TDA7419_DOUBLE_R_VALUE(xregl, xregr, xmask, xmin, xmax, xthresh, \ |
257 | xinvert) \ |
258 | ((unsigned long)&(struct tda7419_vol_control) \ |
259 | {.reg = xregl, .rreg = xregr, .mask = xmask, .min = xmin, \ |
260 | .max = xmax, .thresh = xthresh, .invert = xinvert}) |
261 | |
262 | #define TDA7419_SINGLE_TLV(xname, xreg, xmask, xmin, xmax, xthresh, \ |
263 | xinvert, xtlv_array) \ |
264 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
265 | .name = xname, \ |
266 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
267 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
268 | .tlv.p = (xtlv_array), \ |
269 | .info = tda7419_vol_info, \ |
270 | .get = tda7419_vol_get, \ |
271 | .put = tda7419_vol_put, \ |
272 | .private_value = TDA7419_SINGLE_VALUE(xreg, xmask, xmin, \ |
273 | xmax, xthresh, xinvert), \ |
274 | } |
275 | |
276 | #define TDA7419_DOUBLE_R_TLV(xname, xregl, xregr, xmask, xmin, xmax, \ |
277 | xthresh, xinvert, xtlv_array) \ |
278 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
279 | .name = xname, \ |
280 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
281 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
282 | .tlv.p = (xtlv_array), \ |
283 | .info = tda7419_vol_info, \ |
284 | .get = tda7419_vol_get, \ |
285 | .put = tda7419_vol_put, \ |
286 | .private_value = TDA7419_DOUBLE_R_VALUE(xregl, xregr, xmask, \ |
287 | xmin, xmax, xthresh, \ |
288 | xinvert), \ |
289 | } |
290 | |
291 | static const char * const enum_src_sel[] = { |
292 | "QD" , "SE1" , "SE2" , "SE3" , "SE" , "Mute" , "Mute" , "Mute" }; |
293 | static SOC_ENUM_SINGLE_DECL(soc_enum_main_src_sel, |
294 | TDA7419_MAIN_SRC_REG, TDA7419_MAIN_SRC_SEL, enum_src_sel); |
295 | static const struct snd_kcontrol_new soc_mux_main_src_sel = |
296 | SOC_DAPM_ENUM("Main Source Select" , soc_enum_main_src_sel); |
297 | static DECLARE_TLV_DB_SCALE(tlv_src_gain, 0, 100, 0); |
298 | static DECLARE_TLV_DB_SCALE(tlv_loudness_atten, -1500, 100, 0); |
299 | static const char * const enum_loudness_center_freq[] = { |
300 | "Flat" , "400 Hz" , "800 Hz" , "2400 Hz" }; |
301 | static SOC_ENUM_SINGLE_DECL(soc_enum_loudness_center_freq, |
302 | TDA7419_LOUDNESS_REG, TDA7419_LOUDNESS_CENTER_FREQ, |
303 | enum_loudness_center_freq); |
304 | static const char * const enum_mute_influence[] = { |
305 | "Pin and IIC" , "IIC" }; |
306 | static SOC_ENUM_SINGLE_DECL(soc_enum_mute_influence, |
307 | TDA7419_MUTE_CLK_REG, TDA7419_MUTE_INFLUENCE, enum_mute_influence); |
308 | static const char * const enum_soft_mute_time[] = { |
309 | "0.48 ms" , "0.96 ms" , "123 ms" , "123 ms" }; |
310 | static SOC_ENUM_SINGLE_DECL(soc_enum_soft_mute_time, |
311 | TDA7419_MUTE_CLK_REG, TDA7419_SOFT_MUTE_TIME, enum_soft_mute_time); |
312 | static const char * const enum_soft_step_time[] = { |
313 | "0.160 ms" , "0.321 ms" , "0.642 ms" , "1.28 ms" , |
314 | "2.56 ms" , "5.12 ms" , "10.24 ms" , "20.48 ms" }; |
315 | static SOC_ENUM_SINGLE_DECL(soc_enum_soft_step_time, |
316 | TDA7419_MUTE_CLK_REG, TDA7419_SOFT_STEP_TIME, enum_soft_step_time); |
317 | static DECLARE_TLV_DB_SCALE(tlv_volume, -8000, 100, 1); |
318 | static const char * const enum_treble_center_freq[] = { |
319 | "10.0 kHz" , "12.5 kHz" , "15.0 kHz" , "17.5 kHz" }; |
320 | static DECLARE_TLV_DB_SCALE(tlv_filter, -1500, 100, 0); |
321 | static SOC_ENUM_SINGLE_DECL(soc_enum_treble_center_freq, |
322 | TDA7419_TREBLE_REG, TDA7419_TREBLE_CENTER_FREQ, |
323 | enum_treble_center_freq); |
324 | static const char * const enum_ref_out_select[] = { |
325 | "External Vref (4 V)" , "Internal Vref (3.3 V)" }; |
326 | static SOC_ENUM_SINGLE_DECL(soc_enum_ref_out_select, |
327 | TDA7419_TREBLE_REG, TDA7419_REF_OUT_SELECT, enum_ref_out_select); |
328 | static const char * const enum_middle_q_factor[] = { |
329 | "0.5" , "0.75" , "1.0" , "1.25" }; |
330 | static SOC_ENUM_SINGLE_DECL(soc_enum_middle_q_factor, |
331 | TDA7419_MIDDLE_REG, TDA7419_MIDDLE_Q_FACTOR, enum_middle_q_factor); |
332 | static const char * const enum_bass_q_factor[] = { |
333 | "1.0" , "1.25" , "1.5" , "2.0" }; |
334 | static SOC_ENUM_SINGLE_DECL(soc_enum_bass_q_factor, |
335 | TDA7419_BASS_REG, TDA7419_BASS_Q_FACTOR, enum_bass_q_factor); |
336 | static SOC_ENUM_SINGLE_DECL(soc_enum_second_src_sel, |
337 | TDA7419_SECOND_SRC_REG, TDA7419_SECOND_SRC_SEL, enum_src_sel); |
338 | static const struct snd_kcontrol_new soc_mux_second_src_sel = |
339 | SOC_DAPM_ENUM("Second Source Select" , soc_enum_second_src_sel); |
340 | static const char * const enum_rear_spkr_src[] = { |
341 | "Main" , "Second" }; |
342 | static SOC_ENUM_SINGLE_DECL(soc_enum_rear_spkr_src, |
343 | TDA7419_SECOND_SRC_REG, TDA7419_REAR_SPKR_SRC, enum_rear_spkr_src); |
344 | static const struct snd_kcontrol_new soc_mux_rear_spkr_src = |
345 | SOC_DAPM_ENUM("Rear Speaker Source" , soc_enum_rear_spkr_src); |
346 | static const char * const enum_sub_cut_off_freq[] = { |
347 | "Flat" , "80 Hz" , "120 Hz" , "160 Hz" }; |
348 | static SOC_ENUM_SINGLE_DECL(soc_enum_sub_cut_off_freq, |
349 | TDA7419_SUB_MID_BASS_REG, TDA7419_SUB_CUT_OFF_FREQ, |
350 | enum_sub_cut_off_freq); |
351 | static const char * const enum_middle_center_freq[] = { |
352 | "500 Hz" , "1000 Hz" , "1500 Hz" , "2500 Hz" }; |
353 | static SOC_ENUM_SINGLE_DECL(soc_enum_middle_center_freq, |
354 | TDA7419_SUB_MID_BASS_REG, TDA7419_MIDDLE_CENTER_FREQ, |
355 | enum_middle_center_freq); |
356 | static const char * const enum_bass_center_freq[] = { |
357 | "60 Hz" , "80 Hz" , "100 Hz" , "200 Hz" }; |
358 | static SOC_ENUM_SINGLE_DECL(soc_enum_bass_center_freq, |
359 | TDA7419_SUB_MID_BASS_REG, TDA7419_BASS_CENTER_FREQ, |
360 | enum_bass_center_freq); |
361 | static const char * const enum_sa_q_factor[] = { |
362 | "3.5" , "1.75" }; |
363 | static SOC_ENUM_SINGLE_DECL(soc_enum_sa_q_factor, |
364 | TDA7419_SA_CLK_AC_REG, TDA7419_SA_Q_FACTOR, enum_sa_q_factor); |
365 | static const char * const enum_reset_mode[] = { |
366 | "IIC" , "Auto" }; |
367 | static SOC_ENUM_SINGLE_DECL(soc_enum_reset_mode, |
368 | TDA7419_SA_CLK_AC_REG, TDA7419_RESET_MODE, enum_reset_mode); |
369 | static const char * const enum_sa_src[] = { |
370 | "Bass" , "In Gain" }; |
371 | static SOC_ENUM_SINGLE_DECL(soc_enum_sa_src, |
372 | TDA7419_SA_CLK_AC_REG, TDA7419_SA_SOURCE, enum_sa_src); |
373 | static const char * const enum_clk_src[] = { |
374 | "Internal" , "External" }; |
375 | static SOC_ENUM_SINGLE_DECL(soc_enum_clk_src, |
376 | TDA7419_SA_CLK_AC_REG, TDA7419_CLK_SOURCE, enum_clk_src); |
377 | static const char * const enum_coupling_mode[] = { |
378 | "DC Coupling (without HPF)" , "AC Coupling after In Gain" , |
379 | "DC Coupling (with HPF)" , "AC Coupling after Bass" }; |
380 | static SOC_ENUM_SINGLE_DECL(soc_enum_coupling_mode, |
381 | TDA7419_SA_CLK_AC_REG, TDA7419_COUPLING_MODE, enum_coupling_mode); |
382 | |
383 | /* ASoC Controls */ |
384 | static struct snd_kcontrol_new tda7419_controls[] = { |
385 | SOC_SINGLE_TLV("Main Source Capture Volume" , TDA7419_MAIN_SRC_REG, |
386 | TDA7419_MAIN_SRC_GAIN, 15, 0, tlv_src_gain), |
387 | SOC_SINGLE("Main Source AutoZero Switch" , TDA7419_MAIN_SRC_REG, |
388 | TDA7419_MAIN_SRC_AUTOZERO, 1, 1), |
389 | SOC_SINGLE_TLV("Loudness Playback Volume" , TDA7419_LOUDNESS_REG, |
390 | TDA7419_LOUDNESS_ATTEN, 15, 1, tlv_loudness_atten), |
391 | SOC_ENUM("Loudness Center Frequency" , soc_enum_loudness_center_freq), |
392 | SOC_SINGLE("Loudness High Boost Switch" , TDA7419_LOUDNESS_REG, |
393 | TDA7419_LOUDNESS_BOOST, 1, 1), |
394 | SOC_SINGLE("Loudness Soft Step Switch" , TDA7419_LOUDNESS_REG, |
395 | TDA7419_LOUDNESS_SOFT_STEP, 1, 1), |
396 | SOC_SINGLE("Soft Mute Switch" , TDA7419_MUTE_CLK_REG, TDA7419_SOFT_MUTE, 1, 1), |
397 | SOC_ENUM("Mute Influence" , soc_enum_mute_influence), |
398 | SOC_ENUM("Soft Mute Time" , soc_enum_soft_mute_time), |
399 | SOC_ENUM("Soft Step Time" , soc_enum_soft_step_time), |
400 | SOC_SINGLE("Clock Fast Mode Switch" , TDA7419_MUTE_CLK_REG, |
401 | TDA7419_CLK_FAST_MODE, 1, 1), |
402 | TDA7419_SINGLE_TLV("Master Playback Volume" , TDA7419_VOLUME_REG, |
403 | 0x7f, -80, 15, 0x10, 0, tlv_volume), |
404 | SOC_SINGLE("Volume Soft Step Switch" , TDA7419_VOLUME_REG, |
405 | TDA7419_VOLUME_SOFT_STEP, 1, 1), |
406 | TDA7419_SINGLE_TLV("Treble Playback Volume" , TDA7419_TREBLE_REG, |
407 | 0x1f, -15, 15, 0x10, 1, tlv_filter), |
408 | SOC_ENUM("Treble Center Frequency" , soc_enum_treble_center_freq), |
409 | SOC_ENUM("Reference Output Select" , soc_enum_ref_out_select), |
410 | TDA7419_SINGLE_TLV("Middle Playback Volume" , TDA7419_MIDDLE_REG, |
411 | 0x1f, -15, 15, 0x10, 1, tlv_filter), |
412 | SOC_ENUM("Middle Q Factor" , soc_enum_middle_q_factor), |
413 | SOC_SINGLE("Middle Soft Step Switch" , TDA7419_MIDDLE_REG, |
414 | TDA7419_MIDDLE_SOFT_STEP, 1, 1), |
415 | TDA7419_SINGLE_TLV("Bass Playback Volume" , TDA7419_BASS_REG, |
416 | 0x1f, -15, 15, 0x10, 1, tlv_filter), |
417 | SOC_ENUM("Bass Q Factor" , soc_enum_bass_q_factor), |
418 | SOC_SINGLE("Bass Soft Step Switch" , TDA7419_BASS_REG, |
419 | TDA7419_BASS_SOFT_STEP, 1, 1), |
420 | SOC_SINGLE_TLV("Second Source Capture Volume" , TDA7419_SECOND_SRC_REG, |
421 | TDA7419_SECOND_SRC_GAIN, 15, 0, tlv_src_gain), |
422 | SOC_ENUM("Subwoofer Cut-off Frequency" , soc_enum_sub_cut_off_freq), |
423 | SOC_ENUM("Middle Center Frequency" , soc_enum_middle_center_freq), |
424 | SOC_ENUM("Bass Center Frequency" , soc_enum_bass_center_freq), |
425 | SOC_SINGLE("Bass DC Mode Switch" , TDA7419_SUB_MID_BASS_REG, |
426 | TDA7419_BASS_DC_MODE, 1, 1), |
427 | SOC_SINGLE("Smoothing Filter Switch" , TDA7419_SUB_MID_BASS_REG, |
428 | TDA7419_SMOOTHING_FILTER, 1, 1), |
429 | TDA7419_DOUBLE_R_TLV("Front Speaker Playback Volume" , TDA7419_ATTENUATOR_LF_REG, |
430 | TDA7419_ATTENUATOR_RF_REG, 0x7f, -80, 15, 0x10, 0, |
431 | tlv_volume), |
432 | SOC_SINGLE("Left Front Soft Step Switch" , TDA7419_ATTENUATOR_LF_REG, |
433 | TDA7419_VOLUME_SOFT_STEP, 1, 1), |
434 | SOC_SINGLE("Right Front Soft Step Switch" , TDA7419_ATTENUATOR_RF_REG, |
435 | TDA7419_VOLUME_SOFT_STEP, 1, 1), |
436 | TDA7419_DOUBLE_R_TLV("Rear Speaker Playback Volume" , TDA7419_ATTENUATOR_LR_REG, |
437 | TDA7419_ATTENUATOR_RR_REG, 0x7f, -80, 15, 0x10, 0, |
438 | tlv_volume), |
439 | SOC_SINGLE("Left Rear Soft Step Switch" , TDA7419_ATTENUATOR_LR_REG, |
440 | TDA7419_VOLUME_SOFT_STEP, 1, 1), |
441 | SOC_SINGLE("Right Rear Soft Step Switch" , TDA7419_ATTENUATOR_RR_REG, |
442 | TDA7419_VOLUME_SOFT_STEP, 1, 1), |
443 | TDA7419_SINGLE_TLV("Mixing Capture Volume" , TDA7419_MIXING_LEVEL_REG, |
444 | 0x7f, -80, 15, 0x10, 0, tlv_volume), |
445 | SOC_SINGLE("Mixing Level Soft Step Switch" , TDA7419_MIXING_LEVEL_REG, |
446 | TDA7419_VOLUME_SOFT_STEP, 1, 1), |
447 | TDA7419_SINGLE_TLV("Subwoofer Playback Volume" , TDA7419_ATTENUATOR_SUB_REG, |
448 | 0x7f, -80, 15, 0x10, 0, tlv_volume), |
449 | SOC_SINGLE("Subwoofer Soft Step Switch" , TDA7419_ATTENUATOR_SUB_REG, |
450 | TDA7419_VOLUME_SOFT_STEP, 1, 1), |
451 | SOC_ENUM("Spectrum Analyzer Q Factor" , soc_enum_sa_q_factor), |
452 | SOC_ENUM("Spectrum Analyzer Reset Mode" , soc_enum_reset_mode), |
453 | SOC_ENUM("Spectrum Analyzer Source" , soc_enum_sa_src), |
454 | SOC_SINGLE("Spectrum Analyzer Run Switch" , TDA7419_SA_CLK_AC_REG, |
455 | TDA7419_SA_RUN, 1, 1), |
456 | SOC_SINGLE("Spectrum Analyzer Reset Switch" , TDA7419_SA_CLK_AC_REG, |
457 | TDA7419_RESET, 1, 1), |
458 | SOC_ENUM("Clock Source" , soc_enum_clk_src), |
459 | SOC_ENUM("Coupling Mode" , soc_enum_coupling_mode), |
460 | }; |
461 | |
462 | static const struct snd_kcontrol_new soc_mixer_lf_output_controls[] = { |
463 | SOC_DAPM_SINGLE("Mix to LF Speaker Switch" , |
464 | TDA7419_MIXING_GAIN_REG, |
465 | TDA7419_MIX_LF, 1, 1), |
466 | }; |
467 | |
468 | static const struct snd_kcontrol_new soc_mixer_rf_output_controls[] = { |
469 | SOC_DAPM_SINGLE("Mix to RF Speaker Switch" , |
470 | TDA7419_MIXING_GAIN_REG, |
471 | TDA7419_MIX_RF, 1, 1), |
472 | }; |
473 | |
474 | static const struct snd_kcontrol_new soc_mix_enable_switch_controls[] = { |
475 | SOC_DAPM_SINGLE("Switch" , TDA7419_MIXING_GAIN_REG, |
476 | TDA7419_MIX_ENABLE, 1, 1), |
477 | }; |
478 | |
479 | static const struct snd_kcontrol_new soc_sub_enable_switch_controls[] = { |
480 | SOC_DAPM_SINGLE("Switch" , TDA7419_MIXING_GAIN_REG, |
481 | TDA7419_MIX_ENABLE, 1, 1), |
482 | }; |
483 | |
484 | static const struct snd_soc_dapm_widget tda7419_dapm_widgets[] = { |
485 | SND_SOC_DAPM_INPUT("SE3L" ), |
486 | SND_SOC_DAPM_INPUT("SE3R" ), |
487 | SND_SOC_DAPM_INPUT("SE2L" ), |
488 | SND_SOC_DAPM_INPUT("SE2R" ), |
489 | SND_SOC_DAPM_INPUT("SE1L" ), |
490 | SND_SOC_DAPM_INPUT("SE1R" ), |
491 | SND_SOC_DAPM_INPUT("DIFFL" ), |
492 | SND_SOC_DAPM_INPUT("DIFFR" ), |
493 | SND_SOC_DAPM_INPUT("MIX" ), |
494 | |
495 | SND_SOC_DAPM_MUX("Main Source Select" , SND_SOC_NOPM, |
496 | 0, 0, &soc_mux_main_src_sel), |
497 | SND_SOC_DAPM_MUX("Second Source Select" , SND_SOC_NOPM, |
498 | 0, 0, &soc_mux_second_src_sel), |
499 | SND_SOC_DAPM_MUX("Rear Speaker Source" , SND_SOC_NOPM, |
500 | 0, 0, &soc_mux_rear_spkr_src), |
501 | |
502 | SND_SOC_DAPM_SWITCH("Mix Enable" , SND_SOC_NOPM, |
503 | 0, 0, &soc_mix_enable_switch_controls[0]), |
504 | SND_SOC_DAPM_MIXER_NAMED_CTL("LF Output Mixer" , SND_SOC_NOPM, |
505 | 0, 0, &soc_mixer_lf_output_controls[0], |
506 | ARRAY_SIZE(soc_mixer_lf_output_controls)), |
507 | SND_SOC_DAPM_MIXER_NAMED_CTL("RF Output Mixer" , SND_SOC_NOPM, |
508 | 0, 0, &soc_mixer_rf_output_controls[0], |
509 | ARRAY_SIZE(soc_mixer_rf_output_controls)), |
510 | |
511 | SND_SOC_DAPM_SWITCH("Subwoofer Enable" , |
512 | SND_SOC_NOPM, 0, 0, |
513 | &soc_sub_enable_switch_controls[0]), |
514 | |
515 | SND_SOC_DAPM_OUTPUT("OUTLF" ), |
516 | SND_SOC_DAPM_OUTPUT("OUTRF" ), |
517 | SND_SOC_DAPM_OUTPUT("OUTLR" ), |
518 | SND_SOC_DAPM_OUTPUT("OUTRR" ), |
519 | SND_SOC_DAPM_OUTPUT("OUTSW" ), |
520 | }; |
521 | |
522 | static const struct snd_soc_dapm_route tda7419_dapm_routes[] = { |
523 | {"Main Source Select" , "SE3" , "SE3L" }, |
524 | {"Main Source Select" , "SE3" , "SE3R" }, |
525 | {"Main Source Select" , "SE2" , "SE2L" }, |
526 | {"Main Source Select" , "SE2" , "SE2R" }, |
527 | {"Main Source Select" , "SE1" , "SE1L" }, |
528 | {"Main Source Select" , "SE1" , "SE1R" }, |
529 | {"Main Source Select" , "SE" , "DIFFL" }, |
530 | {"Main Source Select" , "SE" , "DIFFR" }, |
531 | {"Main Source Select" , "QD" , "DIFFL" }, |
532 | {"Main Source Select" , "QD" , "DIFFR" }, |
533 | |
534 | {"Second Source Select" , "SE3" , "SE3L" }, |
535 | {"Second Source Select" , "SE3" , "SE3R" }, |
536 | {"Second Source Select" , "SE2" , "SE2L" }, |
537 | {"Second Source Select" , "SE2" , "SE2R" }, |
538 | {"Second Source Select" , "SE1" , "SE1L" }, |
539 | {"Second Source Select" , "SE1" , "SE1R" }, |
540 | {"Second Source Select" , "SE" , "DIFFL" }, |
541 | {"Second Source Select" , "SE" , "DIFFR" }, |
542 | {"Second Source Select" , "QD" , "DIFFL" }, |
543 | {"Second Source Select" , "QD" , "DIFFR" }, |
544 | |
545 | {"Rear Speaker Source" , "Main" , "Main Source Select" }, |
546 | {"Rear Speaker Source" , "Second" , "Second Source Select" }, |
547 | |
548 | {"Subwoofer Enable" , "Switch" , "Main Source Select" }, |
549 | |
550 | {"Mix Enable" , "Switch" , "MIX" }, |
551 | |
552 | {"LF Output Mixer" , NULL, "Main Source Select" }, |
553 | {"LF Output Mixer" , "Mix to LF Speaker Switch" , "Mix Enable" }, |
554 | {"RF Output Mixer" , NULL, "Main Source Select" }, |
555 | {"RF Output Mixer" , "Mix to RF Speaker Switch" , "Mix Enable" }, |
556 | |
557 | {"OUTLF" , NULL, "LF Output Mixer" }, |
558 | {"OUTRF" , NULL, "RF Output Mixer" }, |
559 | {"OUTLR" , NULL, "Rear Speaker Source" }, |
560 | {"OUTRR" , NULL, "Rear Speaker Source" }, |
561 | {"OUTSW" , NULL, "Subwoofer Enable" }, |
562 | }; |
563 | |
564 | static const struct snd_soc_component_driver tda7419_component_driver = { |
565 | .name = "tda7419" , |
566 | .controls = tda7419_controls, |
567 | .num_controls = ARRAY_SIZE(tda7419_controls), |
568 | .dapm_widgets = tda7419_dapm_widgets, |
569 | .num_dapm_widgets = ARRAY_SIZE(tda7419_dapm_widgets), |
570 | .dapm_routes = tda7419_dapm_routes, |
571 | .num_dapm_routes = ARRAY_SIZE(tda7419_dapm_routes), |
572 | }; |
573 | |
574 | static int tda7419_probe(struct i2c_client *i2c) |
575 | { |
576 | struct tda7419_data *tda7419; |
577 | int i, ret; |
578 | |
579 | tda7419 = devm_kzalloc(dev: &i2c->dev, |
580 | size: sizeof(struct tda7419_data), |
581 | GFP_KERNEL); |
582 | if (tda7419 == NULL) |
583 | return -ENOMEM; |
584 | |
585 | i2c_set_clientdata(client: i2c, data: tda7419); |
586 | |
587 | tda7419->regmap = devm_regmap_init_i2c(i2c, &tda7419_regmap_config); |
588 | if (IS_ERR(ptr: tda7419->regmap)) { |
589 | ret = PTR_ERR(ptr: tda7419->regmap); |
590 | dev_err(&i2c->dev, "error initializing regmap: %d\n" , |
591 | ret); |
592 | return ret; |
593 | } |
594 | |
595 | /* |
596 | * Reset registers to power-on defaults. The part does not provide a |
597 | * soft-reset function and the registers are not readable. This ensures |
598 | * that the cache matches register contents even if the registers have |
599 | * been previously initialized and not power cycled before probe. |
600 | */ |
601 | for (i = 0; i < ARRAY_SIZE(tda7419_regmap_defaults); i++) |
602 | regmap_write(map: tda7419->regmap, |
603 | reg: tda7419_regmap_defaults[i].reg, |
604 | val: tda7419_regmap_defaults[i].def); |
605 | |
606 | ret = devm_snd_soc_register_component(dev: &i2c->dev, |
607 | component_driver: &tda7419_component_driver, NULL, num_dai: 0); |
608 | if (ret < 0) { |
609 | dev_err(&i2c->dev, "error registering component: %d\n" , |
610 | ret); |
611 | } |
612 | |
613 | return ret; |
614 | } |
615 | |
616 | static const struct i2c_device_id tda7419_i2c_id[] = { |
617 | { "tda7419" , 0 }, |
618 | { } |
619 | }; |
620 | MODULE_DEVICE_TABLE(i2c, tda7419_i2c_id); |
621 | |
622 | static const struct of_device_id tda7419_of_match[] = { |
623 | { .compatible = "st,tda7419" }, |
624 | { }, |
625 | }; |
626 | |
627 | static struct i2c_driver tda7419_driver = { |
628 | .driver = { |
629 | .name = "tda7419" , |
630 | .of_match_table = tda7419_of_match, |
631 | }, |
632 | .probe = tda7419_probe, |
633 | .id_table = tda7419_i2c_id, |
634 | }; |
635 | |
636 | module_i2c_driver(tda7419_driver); |
637 | |
638 | MODULE_AUTHOR("Matt Porter <mporter@konsulko.com>" ); |
639 | MODULE_DESCRIPTION("TDA7419 audio processor driver" ); |
640 | MODULE_LICENSE("GPL" ); |
641 | |