1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Codec driver for ST STA350 2.1-channel high-efficiency digital audio system |
4 | * |
5 | * Copyright: 2014 Raumfeld GmbH |
6 | * Author: Sven Brandau <info@brandau.biz> |
7 | * |
8 | * based on code from: |
9 | * Raumfeld GmbH |
10 | * Johannes Stezenbach <js@sig21.net> |
11 | * Wolfson Microelectronics PLC. |
12 | * Mark Brown <broonie@opensource.wolfsonmicro.com> |
13 | * Freescale Semiconductor, Inc. |
14 | * Timur Tabi <timur@freescale.com> |
15 | */ |
16 | |
17 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ |
18 | |
19 | #include <linux/module.h> |
20 | #include <linux/moduleparam.h> |
21 | #include <linux/init.h> |
22 | #include <linux/delay.h> |
23 | #include <linux/pm.h> |
24 | #include <linux/i2c.h> |
25 | #include <linux/of.h> |
26 | #include <linux/regmap.h> |
27 | #include <linux/regulator/consumer.h> |
28 | #include <linux/gpio/consumer.h> |
29 | #include <linux/slab.h> |
30 | #include <sound/core.h> |
31 | #include <sound/pcm.h> |
32 | #include <sound/pcm_params.h> |
33 | #include <sound/soc.h> |
34 | #include <sound/soc-dapm.h> |
35 | #include <sound/initval.h> |
36 | #include <sound/tlv.h> |
37 | |
38 | #include <sound/sta350.h> |
39 | #include "sta350.h" |
40 | |
41 | #define STA350_RATES (SNDRV_PCM_RATE_32000 | \ |
42 | SNDRV_PCM_RATE_44100 | \ |
43 | SNDRV_PCM_RATE_48000 | \ |
44 | SNDRV_PCM_RATE_88200 | \ |
45 | SNDRV_PCM_RATE_96000 | \ |
46 | SNDRV_PCM_RATE_176400 | \ |
47 | SNDRV_PCM_RATE_192000) |
48 | |
49 | #define STA350_FORMATS \ |
50 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ |
51 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE | \ |
52 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
53 | |
54 | /* Power-up register defaults */ |
55 | static const struct reg_default sta350_regs[] = { |
56 | { 0x0, 0x63 }, |
57 | { 0x1, 0x80 }, |
58 | { 0x2, 0xdf }, |
59 | { 0x3, 0x40 }, |
60 | { 0x4, 0xc2 }, |
61 | { 0x5, 0x5c }, |
62 | { 0x6, 0x00 }, |
63 | { 0x7, 0xff }, |
64 | { 0x8, 0x60 }, |
65 | { 0x9, 0x60 }, |
66 | { 0xa, 0x60 }, |
67 | { 0xb, 0x00 }, |
68 | { 0xc, 0x00 }, |
69 | { 0xd, 0x00 }, |
70 | { 0xe, 0x00 }, |
71 | { 0xf, 0x40 }, |
72 | { 0x10, 0x80 }, |
73 | { 0x11, 0x77 }, |
74 | { 0x12, 0x6a }, |
75 | { 0x13, 0x69 }, |
76 | { 0x14, 0x6a }, |
77 | { 0x15, 0x69 }, |
78 | { 0x16, 0x00 }, |
79 | { 0x17, 0x00 }, |
80 | { 0x18, 0x00 }, |
81 | { 0x19, 0x00 }, |
82 | { 0x1a, 0x00 }, |
83 | { 0x1b, 0x00 }, |
84 | { 0x1c, 0x00 }, |
85 | { 0x1d, 0x00 }, |
86 | { 0x1e, 0x00 }, |
87 | { 0x1f, 0x00 }, |
88 | { 0x20, 0x00 }, |
89 | { 0x21, 0x00 }, |
90 | { 0x22, 0x00 }, |
91 | { 0x23, 0x00 }, |
92 | { 0x24, 0x00 }, |
93 | { 0x25, 0x00 }, |
94 | { 0x26, 0x00 }, |
95 | { 0x27, 0x2a }, |
96 | { 0x28, 0xc0 }, |
97 | { 0x29, 0xf3 }, |
98 | { 0x2a, 0x33 }, |
99 | { 0x2b, 0x00 }, |
100 | { 0x2c, 0x0c }, |
101 | { 0x31, 0x00 }, |
102 | { 0x36, 0x00 }, |
103 | { 0x37, 0x00 }, |
104 | { 0x38, 0x00 }, |
105 | { 0x39, 0x01 }, |
106 | { 0x3a, 0xee }, |
107 | { 0x3b, 0xff }, |
108 | { 0x3c, 0x7e }, |
109 | { 0x3d, 0xc0 }, |
110 | { 0x3e, 0x26 }, |
111 | { 0x3f, 0x00 }, |
112 | { 0x48, 0x00 }, |
113 | { 0x49, 0x00 }, |
114 | { 0x4a, 0x00 }, |
115 | { 0x4b, 0x04 }, |
116 | { 0x4c, 0x00 }, |
117 | }; |
118 | |
119 | static const struct regmap_range sta350_write_regs_range[] = { |
120 | regmap_reg_range(STA350_CONFA, STA350_AUTO2), |
121 | regmap_reg_range(STA350_C1CFG, STA350_FDRC2), |
122 | regmap_reg_range(STA350_EQCFG, STA350_EVOLRES), |
123 | regmap_reg_range(STA350_NSHAPE, STA350_MISC2), |
124 | }; |
125 | |
126 | static const struct regmap_range sta350_read_regs_range[] = { |
127 | regmap_reg_range(STA350_CONFA, STA350_AUTO2), |
128 | regmap_reg_range(STA350_C1CFG, STA350_STATUS), |
129 | regmap_reg_range(STA350_EQCFG, STA350_EVOLRES), |
130 | regmap_reg_range(STA350_NSHAPE, STA350_MISC2), |
131 | }; |
132 | |
133 | static const struct regmap_range sta350_volatile_regs_range[] = { |
134 | regmap_reg_range(STA350_CFADDR2, STA350_CFUD), |
135 | regmap_reg_range(STA350_STATUS, STA350_STATUS), |
136 | }; |
137 | |
138 | static const struct regmap_access_table sta350_write_regs = { |
139 | .yes_ranges = sta350_write_regs_range, |
140 | .n_yes_ranges = ARRAY_SIZE(sta350_write_regs_range), |
141 | }; |
142 | |
143 | static const struct regmap_access_table sta350_read_regs = { |
144 | .yes_ranges = sta350_read_regs_range, |
145 | .n_yes_ranges = ARRAY_SIZE(sta350_read_regs_range), |
146 | }; |
147 | |
148 | static const struct regmap_access_table sta350_volatile_regs = { |
149 | .yes_ranges = sta350_volatile_regs_range, |
150 | .n_yes_ranges = ARRAY_SIZE(sta350_volatile_regs_range), |
151 | }; |
152 | |
153 | /* regulator power supply names */ |
154 | static const char * const sta350_supply_names[] = { |
155 | "vdd-dig" , /* digital supply, 3.3V */ |
156 | "vdd-pll" , /* pll supply, 3.3V */ |
157 | "vcc" /* power amp supply, 5V - 26V */ |
158 | }; |
159 | |
160 | /* codec private data */ |
161 | struct sta350_priv { |
162 | struct regmap *regmap; |
163 | struct regulator_bulk_data supplies[ARRAY_SIZE(sta350_supply_names)]; |
164 | struct sta350_platform_data *pdata; |
165 | |
166 | unsigned int mclk; |
167 | unsigned int format; |
168 | |
169 | u32 coef_shadow[STA350_COEF_COUNT]; |
170 | int shutdown; |
171 | |
172 | struct gpio_desc *gpiod_nreset; |
173 | struct gpio_desc *gpiod_power_down; |
174 | |
175 | struct mutex coeff_lock; |
176 | }; |
177 | |
178 | static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12750, 50, 1); |
179 | static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1); |
180 | static const DECLARE_TLV_DB_SCALE(tone_tlv, -1200, 200, 0); |
181 | |
182 | static const char * const sta350_drc_ac[] = { |
183 | "Anti-Clipping" , "Dynamic Range Compression" |
184 | }; |
185 | static const char * const sta350_auto_gc_mode[] = { |
186 | "User" , "AC no clipping" , "AC limited clipping (10%)" , |
187 | "DRC nighttime listening mode" |
188 | }; |
189 | static const char * const sta350_auto_xo_mode[] = { |
190 | "User" , "80Hz" , "100Hz" , "120Hz" , "140Hz" , "160Hz" , "180Hz" , |
191 | "200Hz" , "220Hz" , "240Hz" , "260Hz" , "280Hz" , "300Hz" , "320Hz" , |
192 | "340Hz" , "360Hz" |
193 | }; |
194 | static const char * const sta350_binary_output[] = { |
195 | "FFX 3-state output - normal operation" , "Binary output" |
196 | }; |
197 | static const char * const sta350_limiter_select[] = { |
198 | "Limiter Disabled" , "Limiter #1" , "Limiter #2" |
199 | }; |
200 | static const char * const sta350_limiter_attack_rate[] = { |
201 | "3.1584" , "2.7072" , "2.2560" , "1.8048" , "1.3536" , "0.9024" , |
202 | "0.4512" , "0.2256" , "0.1504" , "0.1123" , "0.0902" , "0.0752" , |
203 | "0.0645" , "0.0564" , "0.0501" , "0.0451" |
204 | }; |
205 | static const char * const sta350_limiter_release_rate[] = { |
206 | "0.5116" , "0.1370" , "0.0744" , "0.0499" , "0.0360" , "0.0299" , |
207 | "0.0264" , "0.0208" , "0.0198" , "0.0172" , "0.0147" , "0.0137" , |
208 | "0.0134" , "0.0117" , "0.0110" , "0.0104" |
209 | }; |
210 | static const char * const sta350_noise_shaper_type[] = { |
211 | "Third order" , "Fourth order" |
212 | }; |
213 | |
214 | static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_attack_tlv, |
215 | 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), |
216 | 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), |
217 | ); |
218 | |
219 | static DECLARE_TLV_DB_RANGE(sta350_limiter_ac_release_tlv, |
220 | 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), |
221 | 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), |
222 | 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), |
223 | 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), |
224 | 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), |
225 | ); |
226 | |
227 | static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_attack_tlv, |
228 | 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), |
229 | 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), |
230 | 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), |
231 | ); |
232 | |
233 | static DECLARE_TLV_DB_RANGE(sta350_limiter_drc_release_tlv, |
234 | 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), |
235 | 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), |
236 | 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), |
237 | 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), |
238 | 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), |
239 | ); |
240 | |
241 | static SOC_ENUM_SINGLE_DECL(sta350_drc_ac_enum, |
242 | STA350_CONFD, STA350_CONFD_DRC_SHIFT, |
243 | sta350_drc_ac); |
244 | static SOC_ENUM_SINGLE_DECL(sta350_noise_shaper_enum, |
245 | STA350_CONFE, STA350_CONFE_NSBW_SHIFT, |
246 | sta350_noise_shaper_type); |
247 | static SOC_ENUM_SINGLE_DECL(sta350_auto_gc_enum, |
248 | STA350_AUTO1, STA350_AUTO1_AMGC_SHIFT, |
249 | sta350_auto_gc_mode); |
250 | static SOC_ENUM_SINGLE_DECL(sta350_auto_xo_enum, |
251 | STA350_AUTO2, STA350_AUTO2_XO_SHIFT, |
252 | sta350_auto_xo_mode); |
253 | static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch1_enum, |
254 | STA350_C1CFG, STA350_CxCFG_BO_SHIFT, |
255 | sta350_binary_output); |
256 | static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch2_enum, |
257 | STA350_C2CFG, STA350_CxCFG_BO_SHIFT, |
258 | sta350_binary_output); |
259 | static SOC_ENUM_SINGLE_DECL(sta350_binary_output_ch3_enum, |
260 | STA350_C3CFG, STA350_CxCFG_BO_SHIFT, |
261 | sta350_binary_output); |
262 | static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch1_enum, |
263 | STA350_C1CFG, STA350_CxCFG_LS_SHIFT, |
264 | sta350_limiter_select); |
265 | static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch2_enum, |
266 | STA350_C2CFG, STA350_CxCFG_LS_SHIFT, |
267 | sta350_limiter_select); |
268 | static SOC_ENUM_SINGLE_DECL(sta350_limiter_ch3_enum, |
269 | STA350_C3CFG, STA350_CxCFG_LS_SHIFT, |
270 | sta350_limiter_select); |
271 | static SOC_ENUM_SINGLE_DECL(sta350_limiter1_attack_rate_enum, |
272 | STA350_L1AR, STA350_LxA_SHIFT, |
273 | sta350_limiter_attack_rate); |
274 | static SOC_ENUM_SINGLE_DECL(sta350_limiter2_attack_rate_enum, |
275 | STA350_L2AR, STA350_LxA_SHIFT, |
276 | sta350_limiter_attack_rate); |
277 | static SOC_ENUM_SINGLE_DECL(sta350_limiter1_release_rate_enum, |
278 | STA350_L1AR, STA350_LxR_SHIFT, |
279 | sta350_limiter_release_rate); |
280 | static SOC_ENUM_SINGLE_DECL(sta350_limiter2_release_rate_enum, |
281 | STA350_L2AR, STA350_LxR_SHIFT, |
282 | sta350_limiter_release_rate); |
283 | |
284 | /* |
285 | * byte array controls for setting biquad, mixer, scaling coefficients; |
286 | * for biquads all five coefficients need to be set in one go, |
287 | * mixer and pre/postscale coefs can be set individually; |
288 | * each coef is 24bit, the bytes are ordered in the same way |
289 | * as given in the STA350 data sheet (big endian; b1, b2, a1, a2, b0) |
290 | */ |
291 | |
292 | static int sta350_coefficient_info(struct snd_kcontrol *kcontrol, |
293 | struct snd_ctl_elem_info *uinfo) |
294 | { |
295 | int numcoef = kcontrol->private_value >> 16; |
296 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; |
297 | uinfo->count = 3 * numcoef; |
298 | return 0; |
299 | } |
300 | |
301 | static int sta350_coefficient_get(struct snd_kcontrol *kcontrol, |
302 | struct snd_ctl_elem_value *ucontrol) |
303 | { |
304 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
305 | struct sta350_priv *sta350 = snd_soc_component_get_drvdata(c: component); |
306 | int numcoef = kcontrol->private_value >> 16; |
307 | int index = kcontrol->private_value & 0xffff; |
308 | unsigned int cfud, val; |
309 | int i, ret = 0; |
310 | |
311 | mutex_lock(&sta350->coeff_lock); |
312 | |
313 | /* preserve reserved bits in STA350_CFUD */ |
314 | regmap_read(map: sta350->regmap, STA350_CFUD, val: &cfud); |
315 | cfud &= 0xf0; |
316 | /* |
317 | * chip documentation does not say if the bits are self clearing, |
318 | * so do it explicitly |
319 | */ |
320 | regmap_write(map: sta350->regmap, STA350_CFUD, val: cfud); |
321 | |
322 | regmap_write(map: sta350->regmap, STA350_CFADDR2, val: index); |
323 | if (numcoef == 1) { |
324 | regmap_write(map: sta350->regmap, STA350_CFUD, val: cfud | 0x04); |
325 | } else if (numcoef == 5) { |
326 | regmap_write(map: sta350->regmap, STA350_CFUD, val: cfud | 0x08); |
327 | } else { |
328 | ret = -EINVAL; |
329 | goto exit_unlock; |
330 | } |
331 | |
332 | for (i = 0; i < 3 * numcoef; i++) { |
333 | regmap_read(map: sta350->regmap, STA350_B1CF1 + i, val: &val); |
334 | ucontrol->value.bytes.data[i] = val; |
335 | } |
336 | |
337 | exit_unlock: |
338 | mutex_unlock(lock: &sta350->coeff_lock); |
339 | |
340 | return ret; |
341 | } |
342 | |
343 | static int sta350_coefficient_put(struct snd_kcontrol *kcontrol, |
344 | struct snd_ctl_elem_value *ucontrol) |
345 | { |
346 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
347 | struct sta350_priv *sta350 = snd_soc_component_get_drvdata(c: component); |
348 | int numcoef = kcontrol->private_value >> 16; |
349 | int index = kcontrol->private_value & 0xffff; |
350 | unsigned int cfud; |
351 | int i; |
352 | |
353 | /* preserve reserved bits in STA350_CFUD */ |
354 | regmap_read(map: sta350->regmap, STA350_CFUD, val: &cfud); |
355 | cfud &= 0xf0; |
356 | /* |
357 | * chip documentation does not say if the bits are self clearing, |
358 | * so do it explicitly |
359 | */ |
360 | regmap_write(map: sta350->regmap, STA350_CFUD, val: cfud); |
361 | |
362 | regmap_write(map: sta350->regmap, STA350_CFADDR2, val: index); |
363 | for (i = 0; i < numcoef && (index + i < STA350_COEF_COUNT); i++) |
364 | sta350->coef_shadow[index + i] = |
365 | (ucontrol->value.bytes.data[3 * i] << 16) |
366 | | (ucontrol->value.bytes.data[3 * i + 1] << 8) |
367 | | (ucontrol->value.bytes.data[3 * i + 2]); |
368 | for (i = 0; i < 3 * numcoef; i++) |
369 | regmap_write(map: sta350->regmap, STA350_B1CF1 + i, |
370 | val: ucontrol->value.bytes.data[i]); |
371 | if (numcoef == 1) |
372 | regmap_write(map: sta350->regmap, STA350_CFUD, val: cfud | 0x01); |
373 | else if (numcoef == 5) |
374 | regmap_write(map: sta350->regmap, STA350_CFUD, val: cfud | 0x02); |
375 | else |
376 | return -EINVAL; |
377 | |
378 | return 0; |
379 | } |
380 | |
381 | static int sta350_sync_coef_shadow(struct snd_soc_component *component) |
382 | { |
383 | struct sta350_priv *sta350 = snd_soc_component_get_drvdata(c: component); |
384 | unsigned int cfud; |
385 | int i; |
386 | |
387 | /* preserve reserved bits in STA350_CFUD */ |
388 | regmap_read(map: sta350->regmap, STA350_CFUD, val: &cfud); |
389 | cfud &= 0xf0; |
390 | |
391 | for (i = 0; i < STA350_COEF_COUNT; i++) { |
392 | regmap_write(map: sta350->regmap, STA350_CFADDR2, val: i); |
393 | regmap_write(map: sta350->regmap, STA350_B1CF1, |
394 | val: (sta350->coef_shadow[i] >> 16) & 0xff); |
395 | regmap_write(map: sta350->regmap, STA350_B1CF2, |
396 | val: (sta350->coef_shadow[i] >> 8) & 0xff); |
397 | regmap_write(map: sta350->regmap, STA350_B1CF3, |
398 | val: (sta350->coef_shadow[i]) & 0xff); |
399 | /* |
400 | * chip documentation does not say if the bits are |
401 | * self-clearing, so do it explicitly |
402 | */ |
403 | regmap_write(map: sta350->regmap, STA350_CFUD, val: cfud); |
404 | regmap_write(map: sta350->regmap, STA350_CFUD, val: cfud | 0x01); |
405 | } |
406 | return 0; |
407 | } |
408 | |
409 | static int sta350_cache_sync(struct snd_soc_component *component) |
410 | { |
411 | struct sta350_priv *sta350 = snd_soc_component_get_drvdata(c: component); |
412 | unsigned int mute; |
413 | int rc; |
414 | |
415 | /* mute during register sync */ |
416 | regmap_read(map: sta350->regmap, STA350_CFUD, val: &mute); |
417 | regmap_write(map: sta350->regmap, STA350_MMUTE, val: mute | STA350_MMUTE_MMUTE); |
418 | sta350_sync_coef_shadow(component); |
419 | rc = regcache_sync(map: sta350->regmap); |
420 | regmap_write(map: sta350->regmap, STA350_MMUTE, val: mute); |
421 | return rc; |
422 | } |
423 | |
424 | #define SINGLE_COEF(xname, index) \ |
425 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
426 | .info = sta350_coefficient_info, \ |
427 | .get = sta350_coefficient_get,\ |
428 | .put = sta350_coefficient_put, \ |
429 | .private_value = index | (1 << 16) } |
430 | |
431 | #define BIQUAD_COEFS(xname, index) \ |
432 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
433 | .info = sta350_coefficient_info, \ |
434 | .get = sta350_coefficient_get,\ |
435 | .put = sta350_coefficient_put, \ |
436 | .private_value = index | (5 << 16) } |
437 | |
438 | static const struct snd_kcontrol_new sta350_snd_controls[] = { |
439 | SOC_SINGLE_TLV("Master Volume" , STA350_MVOL, 0, 0xff, 1, mvol_tlv), |
440 | /* VOL */ |
441 | SOC_SINGLE_TLV("Ch1 Volume" , STA350_C1VOL, 0, 0xff, 1, chvol_tlv), |
442 | SOC_SINGLE_TLV("Ch2 Volume" , STA350_C2VOL, 0, 0xff, 1, chvol_tlv), |
443 | SOC_SINGLE_TLV("Ch3 Volume" , STA350_C3VOL, 0, 0xff, 1, chvol_tlv), |
444 | /* CONFD */ |
445 | SOC_SINGLE("High Pass Filter Bypass Switch" , |
446 | STA350_CONFD, STA350_CONFD_HPB_SHIFT, 1, 1), |
447 | SOC_SINGLE("De-emphasis Filter Switch" , |
448 | STA350_CONFD, STA350_CONFD_DEMP_SHIFT, 1, 0), |
449 | SOC_SINGLE("DSP Bypass Switch" , |
450 | STA350_CONFD, STA350_CONFD_DSPB_SHIFT, 1, 0), |
451 | SOC_SINGLE("Post-scale Link Switch" , |
452 | STA350_CONFD, STA350_CONFD_PSL_SHIFT, 1, 0), |
453 | SOC_SINGLE("Biquad Coefficient Link Switch" , |
454 | STA350_CONFD, STA350_CONFD_BQL_SHIFT, 1, 0), |
455 | SOC_ENUM("Compressor/Limiter Switch" , sta350_drc_ac_enum), |
456 | SOC_ENUM("Noise Shaper Bandwidth" , sta350_noise_shaper_enum), |
457 | SOC_SINGLE("Zero-detect Mute Enable Switch" , |
458 | STA350_CONFD, STA350_CONFD_ZDE_SHIFT, 1, 0), |
459 | SOC_SINGLE("Submix Mode Switch" , |
460 | STA350_CONFD, STA350_CONFD_SME_SHIFT, 1, 0), |
461 | /* CONFE */ |
462 | SOC_SINGLE("Zero Cross Switch" , STA350_CONFE, STA350_CONFE_ZCE_SHIFT, 1, 0), |
463 | SOC_SINGLE("Soft Ramp Switch" , STA350_CONFE, STA350_CONFE_SVE_SHIFT, 1, 0), |
464 | /* MUTE */ |
465 | SOC_SINGLE("Master Switch" , STA350_MMUTE, STA350_MMUTE_MMUTE_SHIFT, 1, 1), |
466 | SOC_SINGLE("Ch1 Switch" , STA350_MMUTE, STA350_MMUTE_C1M_SHIFT, 1, 1), |
467 | SOC_SINGLE("Ch2 Switch" , STA350_MMUTE, STA350_MMUTE_C2M_SHIFT, 1, 1), |
468 | SOC_SINGLE("Ch3 Switch" , STA350_MMUTE, STA350_MMUTE_C3M_SHIFT, 1, 1), |
469 | /* AUTOx */ |
470 | SOC_ENUM("Automode GC" , sta350_auto_gc_enum), |
471 | SOC_ENUM("Automode XO" , sta350_auto_xo_enum), |
472 | /* CxCFG */ |
473 | SOC_SINGLE("Ch1 Tone Control Bypass Switch" , |
474 | STA350_C1CFG, STA350_CxCFG_TCB_SHIFT, 1, 0), |
475 | SOC_SINGLE("Ch2 Tone Control Bypass Switch" , |
476 | STA350_C2CFG, STA350_CxCFG_TCB_SHIFT, 1, 0), |
477 | SOC_SINGLE("Ch1 EQ Bypass Switch" , |
478 | STA350_C1CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0), |
479 | SOC_SINGLE("Ch2 EQ Bypass Switch" , |
480 | STA350_C2CFG, STA350_CxCFG_EQBP_SHIFT, 1, 0), |
481 | SOC_SINGLE("Ch1 Master Volume Bypass Switch" , |
482 | STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), |
483 | SOC_SINGLE("Ch2 Master Volume Bypass Switch" , |
484 | STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), |
485 | SOC_SINGLE("Ch3 Master Volume Bypass Switch" , |
486 | STA350_C1CFG, STA350_CxCFG_VBP_SHIFT, 1, 0), |
487 | SOC_ENUM("Ch1 Binary Output Select" , sta350_binary_output_ch1_enum), |
488 | SOC_ENUM("Ch2 Binary Output Select" , sta350_binary_output_ch2_enum), |
489 | SOC_ENUM("Ch3 Binary Output Select" , sta350_binary_output_ch3_enum), |
490 | SOC_ENUM("Ch1 Limiter Select" , sta350_limiter_ch1_enum), |
491 | SOC_ENUM("Ch2 Limiter Select" , sta350_limiter_ch2_enum), |
492 | SOC_ENUM("Ch3 Limiter Select" , sta350_limiter_ch3_enum), |
493 | /* TONE */ |
494 | SOC_SINGLE_RANGE_TLV("Bass Tone Control Volume" , |
495 | STA350_TONE, STA350_TONE_BTC_SHIFT, 1, 13, 0, tone_tlv), |
496 | SOC_SINGLE_RANGE_TLV("Treble Tone Control Volume" , |
497 | STA350_TONE, STA350_TONE_TTC_SHIFT, 1, 13, 0, tone_tlv), |
498 | SOC_ENUM("Limiter1 Attack Rate (dB/ms)" , sta350_limiter1_attack_rate_enum), |
499 | SOC_ENUM("Limiter2 Attack Rate (dB/ms)" , sta350_limiter2_attack_rate_enum), |
500 | SOC_ENUM("Limiter1 Release Rate (dB/ms)" , sta350_limiter1_release_rate_enum), |
501 | SOC_ENUM("Limiter2 Release Rate (dB/ms)" , sta350_limiter2_release_rate_enum), |
502 | |
503 | /* |
504 | * depending on mode, the attack/release thresholds have |
505 | * two different enum definitions; provide both |
506 | */ |
507 | SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)" , |
508 | STA350_L1ATRT, STA350_LxA_SHIFT, |
509 | 16, 0, sta350_limiter_ac_attack_tlv), |
510 | SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)" , |
511 | STA350_L2ATRT, STA350_LxA_SHIFT, |
512 | 16, 0, sta350_limiter_ac_attack_tlv), |
513 | SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)" , |
514 | STA350_L1ATRT, STA350_LxR_SHIFT, |
515 | 16, 0, sta350_limiter_ac_release_tlv), |
516 | SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)" , |
517 | STA350_L2ATRT, STA350_LxR_SHIFT, |
518 | 16, 0, sta350_limiter_ac_release_tlv), |
519 | SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)" , |
520 | STA350_L1ATRT, STA350_LxA_SHIFT, |
521 | 16, 0, sta350_limiter_drc_attack_tlv), |
522 | SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)" , |
523 | STA350_L2ATRT, STA350_LxA_SHIFT, |
524 | 16, 0, sta350_limiter_drc_attack_tlv), |
525 | SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)" , |
526 | STA350_L1ATRT, STA350_LxR_SHIFT, |
527 | 16, 0, sta350_limiter_drc_release_tlv), |
528 | SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)" , |
529 | STA350_L2ATRT, STA350_LxR_SHIFT, |
530 | 16, 0, sta350_limiter_drc_release_tlv), |
531 | |
532 | BIQUAD_COEFS("Ch1 - Biquad 1" , 0), |
533 | BIQUAD_COEFS("Ch1 - Biquad 2" , 5), |
534 | BIQUAD_COEFS("Ch1 - Biquad 3" , 10), |
535 | BIQUAD_COEFS("Ch1 - Biquad 4" , 15), |
536 | BIQUAD_COEFS("Ch2 - Biquad 1" , 20), |
537 | BIQUAD_COEFS("Ch2 - Biquad 2" , 25), |
538 | BIQUAD_COEFS("Ch2 - Biquad 3" , 30), |
539 | BIQUAD_COEFS("Ch2 - Biquad 4" , 35), |
540 | BIQUAD_COEFS("High-pass" , 40), |
541 | BIQUAD_COEFS("Low-pass" , 45), |
542 | SINGLE_COEF("Ch1 - Prescale" , 50), |
543 | SINGLE_COEF("Ch2 - Prescale" , 51), |
544 | SINGLE_COEF("Ch1 - Postscale" , 52), |
545 | SINGLE_COEF("Ch2 - Postscale" , 53), |
546 | SINGLE_COEF("Ch3 - Postscale" , 54), |
547 | SINGLE_COEF("Thermal warning - Postscale" , 55), |
548 | SINGLE_COEF("Ch1 - Mix 1" , 56), |
549 | SINGLE_COEF("Ch1 - Mix 2" , 57), |
550 | SINGLE_COEF("Ch2 - Mix 1" , 58), |
551 | SINGLE_COEF("Ch2 - Mix 2" , 59), |
552 | SINGLE_COEF("Ch3 - Mix 1" , 60), |
553 | SINGLE_COEF("Ch3 - Mix 2" , 61), |
554 | }; |
555 | |
556 | static const struct snd_soc_dapm_widget sta350_dapm_widgets[] = { |
557 | SND_SOC_DAPM_DAC("DAC" , NULL, SND_SOC_NOPM, 0, 0), |
558 | SND_SOC_DAPM_OUTPUT("LEFT" ), |
559 | SND_SOC_DAPM_OUTPUT("RIGHT" ), |
560 | SND_SOC_DAPM_OUTPUT("SUB" ), |
561 | }; |
562 | |
563 | static const struct snd_soc_dapm_route sta350_dapm_routes[] = { |
564 | { "LEFT" , NULL, "DAC" }, |
565 | { "RIGHT" , NULL, "DAC" }, |
566 | { "SUB" , NULL, "DAC" }, |
567 | { "DAC" , NULL, "Playback" }, |
568 | }; |
569 | |
570 | /* MCLK interpolation ratio per fs */ |
571 | static struct { |
572 | int fs; |
573 | int ir; |
574 | } interpolation_ratios[] = { |
575 | { 32000, 0 }, |
576 | { 44100, 0 }, |
577 | { 48000, 0 }, |
578 | { 88200, 1 }, |
579 | { 96000, 1 }, |
580 | { 176400, 2 }, |
581 | { 192000, 2 }, |
582 | }; |
583 | |
584 | /* MCLK to fs clock ratios */ |
585 | static int mcs_ratio_table[3][6] = { |
586 | { 768, 512, 384, 256, 128, 576 }, |
587 | { 384, 256, 192, 128, 64, 0 }, |
588 | { 192, 128, 96, 64, 32, 0 }, |
589 | }; |
590 | |
591 | /** |
592 | * sta350_set_dai_sysclk - configure MCLK |
593 | * @codec_dai: the codec DAI |
594 | * @clk_id: the clock ID (ignored) |
595 | * @freq: the MCLK input frequency |
596 | * @dir: the clock direction (ignored) |
597 | * |
598 | * The value of MCLK is used to determine which sample rates are supported |
599 | * by the STA350, based on the mcs_ratio_table. |
600 | * |
601 | * This function must be called by the machine driver's 'startup' function, |
602 | * otherwise the list of supported sample rates will not be available in |
603 | * time for ALSA. |
604 | */ |
605 | static int sta350_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
606 | int clk_id, unsigned int freq, int dir) |
607 | { |
608 | struct snd_soc_component *component = codec_dai->component; |
609 | struct sta350_priv *sta350 = snd_soc_component_get_drvdata(c: component); |
610 | |
611 | dev_dbg(component->dev, "mclk=%u\n" , freq); |
612 | sta350->mclk = freq; |
613 | |
614 | return 0; |
615 | } |
616 | |
617 | /** |
618 | * sta350_set_dai_fmt - configure the codec for the selected audio format |
619 | * @codec_dai: the codec DAI |
620 | * @fmt: a SND_SOC_DAIFMT_x value indicating the data format |
621 | * |
622 | * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the |
623 | * codec accordingly. |
624 | */ |
625 | static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai, |
626 | unsigned int fmt) |
627 | { |
628 | struct snd_soc_component *component = codec_dai->component; |
629 | struct sta350_priv *sta350 = snd_soc_component_get_drvdata(c: component); |
630 | unsigned int confb = 0; |
631 | |
632 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
633 | case SND_SOC_DAIFMT_CBC_CFC: |
634 | break; |
635 | default: |
636 | return -EINVAL; |
637 | } |
638 | |
639 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
640 | case SND_SOC_DAIFMT_I2S: |
641 | case SND_SOC_DAIFMT_RIGHT_J: |
642 | case SND_SOC_DAIFMT_LEFT_J: |
643 | sta350->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; |
644 | break; |
645 | default: |
646 | return -EINVAL; |
647 | } |
648 | |
649 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
650 | case SND_SOC_DAIFMT_NB_NF: |
651 | confb |= STA350_CONFB_C2IM; |
652 | break; |
653 | case SND_SOC_DAIFMT_NB_IF: |
654 | confb |= STA350_CONFB_C1IM; |
655 | break; |
656 | default: |
657 | return -EINVAL; |
658 | } |
659 | |
660 | return regmap_update_bits(map: sta350->regmap, STA350_CONFB, |
661 | STA350_CONFB_C1IM | STA350_CONFB_C2IM, val: confb); |
662 | } |
663 | |
664 | /** |
665 | * sta350_hw_params - program the STA350 with the given hardware parameters. |
666 | * @substream: the audio stream |
667 | * @params: the hardware parameters to set |
668 | * @dai: the SOC DAI (ignored) |
669 | * |
670 | * This function programs the hardware with the values provided. |
671 | * Specifically, the sample rate and the data format. |
672 | */ |
673 | static int sta350_hw_params(struct snd_pcm_substream *substream, |
674 | struct snd_pcm_hw_params *params, |
675 | struct snd_soc_dai *dai) |
676 | { |
677 | struct snd_soc_component *component = dai->component; |
678 | struct sta350_priv *sta350 = snd_soc_component_get_drvdata(c: component); |
679 | int i, mcs = -EINVAL, ir = -EINVAL; |
680 | unsigned int confa, confb; |
681 | unsigned int rate, ratio; |
682 | int ret; |
683 | |
684 | if (!sta350->mclk) { |
685 | dev_err(component->dev, |
686 | "sta350->mclk is unset. Unable to determine ratio\n" ); |
687 | return -EIO; |
688 | } |
689 | |
690 | rate = params_rate(p: params); |
691 | ratio = sta350->mclk / rate; |
692 | dev_dbg(component->dev, "rate: %u, ratio: %u\n" , rate, ratio); |
693 | |
694 | for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { |
695 | if (interpolation_ratios[i].fs == rate) { |
696 | ir = interpolation_ratios[i].ir; |
697 | break; |
698 | } |
699 | } |
700 | |
701 | if (ir < 0) { |
702 | dev_err(component->dev, "Unsupported samplerate: %u\n" , rate); |
703 | return -EINVAL; |
704 | } |
705 | |
706 | for (i = 0; i < 6; i++) { |
707 | if (mcs_ratio_table[ir][i] == ratio) { |
708 | mcs = i; |
709 | break; |
710 | } |
711 | } |
712 | |
713 | if (mcs < 0) { |
714 | dev_err(component->dev, "Unresolvable ratio: %u\n" , ratio); |
715 | return -EINVAL; |
716 | } |
717 | |
718 | confa = (ir << STA350_CONFA_IR_SHIFT) | |
719 | (mcs << STA350_CONFA_MCS_SHIFT); |
720 | confb = 0; |
721 | |
722 | switch (params_width(p: params)) { |
723 | case 24: |
724 | dev_dbg(component->dev, "24bit\n" ); |
725 | fallthrough; |
726 | case 32: |
727 | dev_dbg(component->dev, "24bit or 32bit\n" ); |
728 | switch (sta350->format) { |
729 | case SND_SOC_DAIFMT_I2S: |
730 | confb |= 0x0; |
731 | break; |
732 | case SND_SOC_DAIFMT_LEFT_J: |
733 | confb |= 0x1; |
734 | break; |
735 | case SND_SOC_DAIFMT_RIGHT_J: |
736 | confb |= 0x2; |
737 | break; |
738 | } |
739 | |
740 | break; |
741 | case 20: |
742 | dev_dbg(component->dev, "20bit\n" ); |
743 | switch (sta350->format) { |
744 | case SND_SOC_DAIFMT_I2S: |
745 | confb |= 0x4; |
746 | break; |
747 | case SND_SOC_DAIFMT_LEFT_J: |
748 | confb |= 0x5; |
749 | break; |
750 | case SND_SOC_DAIFMT_RIGHT_J: |
751 | confb |= 0x6; |
752 | break; |
753 | } |
754 | |
755 | break; |
756 | case 18: |
757 | dev_dbg(component->dev, "18bit\n" ); |
758 | switch (sta350->format) { |
759 | case SND_SOC_DAIFMT_I2S: |
760 | confb |= 0x8; |
761 | break; |
762 | case SND_SOC_DAIFMT_LEFT_J: |
763 | confb |= 0x9; |
764 | break; |
765 | case SND_SOC_DAIFMT_RIGHT_J: |
766 | confb |= 0xa; |
767 | break; |
768 | } |
769 | |
770 | break; |
771 | case 16: |
772 | dev_dbg(component->dev, "16bit\n" ); |
773 | switch (sta350->format) { |
774 | case SND_SOC_DAIFMT_I2S: |
775 | confb |= 0x0; |
776 | break; |
777 | case SND_SOC_DAIFMT_LEFT_J: |
778 | confb |= 0xd; |
779 | break; |
780 | case SND_SOC_DAIFMT_RIGHT_J: |
781 | confb |= 0xe; |
782 | break; |
783 | } |
784 | |
785 | break; |
786 | default: |
787 | return -EINVAL; |
788 | } |
789 | |
790 | ret = regmap_update_bits(map: sta350->regmap, STA350_CONFA, |
791 | STA350_CONFA_MCS_MASK | STA350_CONFA_IR_MASK, |
792 | val: confa); |
793 | if (ret < 0) |
794 | return ret; |
795 | |
796 | ret = regmap_update_bits(map: sta350->regmap, STA350_CONFB, |
797 | STA350_CONFB_SAI_MASK | STA350_CONFB_SAIFB, |
798 | val: confb); |
799 | if (ret < 0) |
800 | return ret; |
801 | |
802 | return 0; |
803 | } |
804 | |
805 | static int sta350_startup_sequence(struct sta350_priv *sta350) |
806 | { |
807 | if (sta350->gpiod_power_down) |
808 | gpiod_set_value(desc: sta350->gpiod_power_down, value: 1); |
809 | |
810 | if (sta350->gpiod_nreset) { |
811 | gpiod_set_value(desc: sta350->gpiod_nreset, value: 0); |
812 | mdelay(1); |
813 | gpiod_set_value(desc: sta350->gpiod_nreset, value: 1); |
814 | mdelay(1); |
815 | } |
816 | |
817 | return 0; |
818 | } |
819 | |
820 | /** |
821 | * sta350_set_bias_level - DAPM callback |
822 | * @component: the component device |
823 | * @level: DAPM power level |
824 | * |
825 | * This is called by ALSA to put the component into low power mode |
826 | * or to wake it up. If the component is powered off completely |
827 | * all registers must be restored after power on. |
828 | */ |
829 | static int sta350_set_bias_level(struct snd_soc_component *component, |
830 | enum snd_soc_bias_level level) |
831 | { |
832 | struct sta350_priv *sta350 = snd_soc_component_get_drvdata(c: component); |
833 | int ret; |
834 | |
835 | dev_dbg(component->dev, "level = %d\n" , level); |
836 | switch (level) { |
837 | case SND_SOC_BIAS_ON: |
838 | break; |
839 | |
840 | case SND_SOC_BIAS_PREPARE: |
841 | /* Full power on */ |
842 | regmap_update_bits(map: sta350->regmap, STA350_CONFF, |
843 | STA350_CONFF_PWDN | STA350_CONFF_EAPD, |
844 | STA350_CONFF_PWDN | STA350_CONFF_EAPD); |
845 | break; |
846 | |
847 | case SND_SOC_BIAS_STANDBY: |
848 | if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { |
849 | ret = regulator_bulk_enable( |
850 | ARRAY_SIZE(sta350->supplies), |
851 | consumers: sta350->supplies); |
852 | if (ret < 0) { |
853 | dev_err(component->dev, |
854 | "Failed to enable supplies: %d\n" , |
855 | ret); |
856 | return ret; |
857 | } |
858 | sta350_startup_sequence(sta350); |
859 | sta350_cache_sync(component); |
860 | } |
861 | |
862 | /* Power down */ |
863 | regmap_update_bits(map: sta350->regmap, STA350_CONFF, |
864 | STA350_CONFF_PWDN | STA350_CONFF_EAPD, |
865 | val: 0); |
866 | |
867 | break; |
868 | |
869 | case SND_SOC_BIAS_OFF: |
870 | /* The chip runs through the power down sequence for us */ |
871 | regmap_update_bits(map: sta350->regmap, STA350_CONFF, |
872 | STA350_CONFF_PWDN | STA350_CONFF_EAPD, val: 0); |
873 | |
874 | /* power down: low */ |
875 | if (sta350->gpiod_power_down) |
876 | gpiod_set_value(desc: sta350->gpiod_power_down, value: 0); |
877 | |
878 | if (sta350->gpiod_nreset) |
879 | gpiod_set_value(desc: sta350->gpiod_nreset, value: 0); |
880 | |
881 | regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), |
882 | consumers: sta350->supplies); |
883 | break; |
884 | } |
885 | return 0; |
886 | } |
887 | |
888 | static const struct snd_soc_dai_ops sta350_dai_ops = { |
889 | .hw_params = sta350_hw_params, |
890 | .set_sysclk = sta350_set_dai_sysclk, |
891 | .set_fmt = sta350_set_dai_fmt, |
892 | }; |
893 | |
894 | static struct snd_soc_dai_driver sta350_dai = { |
895 | .name = "sta350-hifi" , |
896 | .playback = { |
897 | .stream_name = "Playback" , |
898 | .channels_min = 2, |
899 | .channels_max = 2, |
900 | .rates = STA350_RATES, |
901 | .formats = STA350_FORMATS, |
902 | }, |
903 | .ops = &sta350_dai_ops, |
904 | }; |
905 | |
906 | static int sta350_probe(struct snd_soc_component *component) |
907 | { |
908 | struct sta350_priv *sta350 = snd_soc_component_get_drvdata(c: component); |
909 | struct sta350_platform_data *pdata = sta350->pdata; |
910 | int i, ret = 0, thermal = 0; |
911 | |
912 | ret = regulator_bulk_enable(ARRAY_SIZE(sta350->supplies), |
913 | consumers: sta350->supplies); |
914 | if (ret < 0) { |
915 | dev_err(component->dev, "Failed to enable supplies: %d\n" , ret); |
916 | return ret; |
917 | } |
918 | |
919 | ret = sta350_startup_sequence(sta350); |
920 | if (ret < 0) { |
921 | dev_err(component->dev, "Failed to startup device\n" ); |
922 | return ret; |
923 | } |
924 | |
925 | /* CONFA */ |
926 | if (!pdata->thermal_warning_recovery) |
927 | thermal |= STA350_CONFA_TWAB; |
928 | if (!pdata->thermal_warning_adjustment) |
929 | thermal |= STA350_CONFA_TWRB; |
930 | if (!pdata->fault_detect_recovery) |
931 | thermal |= STA350_CONFA_FDRB; |
932 | regmap_update_bits(map: sta350->regmap, STA350_CONFA, |
933 | STA350_CONFA_TWAB | STA350_CONFA_TWRB | |
934 | STA350_CONFA_FDRB, |
935 | val: thermal); |
936 | |
937 | /* CONFC */ |
938 | regmap_update_bits(map: sta350->regmap, STA350_CONFC, |
939 | STA350_CONFC_OM_MASK, |
940 | val: pdata->ffx_power_output_mode |
941 | << STA350_CONFC_OM_SHIFT); |
942 | regmap_update_bits(map: sta350->regmap, STA350_CONFC, |
943 | STA350_CONFC_CSZ_MASK, |
944 | val: pdata->drop_compensation_ns |
945 | << STA350_CONFC_CSZ_SHIFT); |
946 | regmap_update_bits(map: sta350->regmap, |
947 | STA350_CONFC, |
948 | STA350_CONFC_OCRB, |
949 | val: pdata->oc_warning_adjustment ? |
950 | STA350_CONFC_OCRB : 0); |
951 | |
952 | /* CONFE */ |
953 | regmap_update_bits(map: sta350->regmap, STA350_CONFE, |
954 | STA350_CONFE_MPCV, |
955 | val: pdata->max_power_use_mpcc ? |
956 | STA350_CONFE_MPCV : 0); |
957 | regmap_update_bits(map: sta350->regmap, STA350_CONFE, |
958 | STA350_CONFE_MPC, |
959 | val: pdata->max_power_correction ? |
960 | STA350_CONFE_MPC : 0); |
961 | regmap_update_bits(map: sta350->regmap, STA350_CONFE, |
962 | STA350_CONFE_AME, |
963 | val: pdata->am_reduction_mode ? |
964 | STA350_CONFE_AME : 0); |
965 | regmap_update_bits(map: sta350->regmap, STA350_CONFE, |
966 | STA350_CONFE_PWMS, |
967 | val: pdata->odd_pwm_speed_mode ? |
968 | STA350_CONFE_PWMS : 0); |
969 | regmap_update_bits(map: sta350->regmap, STA350_CONFE, |
970 | STA350_CONFE_DCCV, |
971 | val: pdata->distortion_compensation ? |
972 | STA350_CONFE_DCCV : 0); |
973 | /* CONFF */ |
974 | regmap_update_bits(map: sta350->regmap, STA350_CONFF, |
975 | STA350_CONFF_IDE, |
976 | val: pdata->invalid_input_detect_mute ? |
977 | STA350_CONFF_IDE : 0); |
978 | regmap_update_bits(map: sta350->regmap, STA350_CONFF, |
979 | STA350_CONFF_OCFG_MASK, |
980 | val: pdata->output_conf |
981 | << STA350_CONFF_OCFG_SHIFT); |
982 | |
983 | /* channel to output mapping */ |
984 | regmap_update_bits(map: sta350->regmap, STA350_C1CFG, |
985 | STA350_CxCFG_OM_MASK, |
986 | val: pdata->ch1_output_mapping |
987 | << STA350_CxCFG_OM_SHIFT); |
988 | regmap_update_bits(map: sta350->regmap, STA350_C2CFG, |
989 | STA350_CxCFG_OM_MASK, |
990 | val: pdata->ch2_output_mapping |
991 | << STA350_CxCFG_OM_SHIFT); |
992 | regmap_update_bits(map: sta350->regmap, STA350_C3CFG, |
993 | STA350_CxCFG_OM_MASK, |
994 | val: pdata->ch3_output_mapping |
995 | << STA350_CxCFG_OM_SHIFT); |
996 | |
997 | /* miscellaneous registers */ |
998 | regmap_update_bits(map: sta350->regmap, STA350_MISC1, |
999 | STA350_MISC1_CPWMEN, |
1000 | val: pdata->activate_mute_output ? |
1001 | STA350_MISC1_CPWMEN : 0); |
1002 | regmap_update_bits(map: sta350->regmap, STA350_MISC1, |
1003 | STA350_MISC1_BRIDGOFF, |
1004 | val: pdata->bridge_immediate_off ? |
1005 | STA350_MISC1_BRIDGOFF : 0); |
1006 | regmap_update_bits(map: sta350->regmap, STA350_MISC1, |
1007 | STA350_MISC1_NSHHPEN, |
1008 | val: pdata->noise_shape_dc_cut ? |
1009 | STA350_MISC1_NSHHPEN : 0); |
1010 | regmap_update_bits(map: sta350->regmap, STA350_MISC1, |
1011 | STA350_MISC1_RPDNEN, |
1012 | val: pdata->powerdown_master_vol ? |
1013 | STA350_MISC1_RPDNEN: 0); |
1014 | |
1015 | regmap_update_bits(map: sta350->regmap, STA350_MISC2, |
1016 | STA350_MISC2_PNDLSL_MASK, |
1017 | val: pdata->powerdown_delay_divider |
1018 | << STA350_MISC2_PNDLSL_SHIFT); |
1019 | |
1020 | /* initialize coefficient shadow RAM with reset values */ |
1021 | for (i = 4; i <= 49; i += 5) |
1022 | sta350->coef_shadow[i] = 0x400000; |
1023 | for (i = 50; i <= 54; i++) |
1024 | sta350->coef_shadow[i] = 0x7fffff; |
1025 | sta350->coef_shadow[55] = 0x5a9df7; |
1026 | sta350->coef_shadow[56] = 0x7fffff; |
1027 | sta350->coef_shadow[59] = 0x7fffff; |
1028 | sta350->coef_shadow[60] = 0x400000; |
1029 | sta350->coef_shadow[61] = 0x400000; |
1030 | |
1031 | snd_soc_component_force_bias_level(component, level: SND_SOC_BIAS_STANDBY); |
1032 | /* Bias level configuration will have done an extra enable */ |
1033 | regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), consumers: sta350->supplies); |
1034 | |
1035 | return 0; |
1036 | } |
1037 | |
1038 | static void sta350_remove(struct snd_soc_component *component) |
1039 | { |
1040 | struct sta350_priv *sta350 = snd_soc_component_get_drvdata(c: component); |
1041 | |
1042 | regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), consumers: sta350->supplies); |
1043 | } |
1044 | |
1045 | static const struct snd_soc_component_driver sta350_component = { |
1046 | .probe = sta350_probe, |
1047 | .remove = sta350_remove, |
1048 | .set_bias_level = sta350_set_bias_level, |
1049 | .controls = sta350_snd_controls, |
1050 | .num_controls = ARRAY_SIZE(sta350_snd_controls), |
1051 | .dapm_widgets = sta350_dapm_widgets, |
1052 | .num_dapm_widgets = ARRAY_SIZE(sta350_dapm_widgets), |
1053 | .dapm_routes = sta350_dapm_routes, |
1054 | .num_dapm_routes = ARRAY_SIZE(sta350_dapm_routes), |
1055 | .suspend_bias_off = 1, |
1056 | .idle_bias_on = 1, |
1057 | .use_pmdown_time = 1, |
1058 | .endianness = 1, |
1059 | }; |
1060 | |
1061 | static const struct regmap_config sta350_regmap = { |
1062 | .reg_bits = 8, |
1063 | .val_bits = 8, |
1064 | .max_register = STA350_MISC2, |
1065 | .reg_defaults = sta350_regs, |
1066 | .num_reg_defaults = ARRAY_SIZE(sta350_regs), |
1067 | .cache_type = REGCACHE_MAPLE, |
1068 | .wr_table = &sta350_write_regs, |
1069 | .rd_table = &sta350_read_regs, |
1070 | .volatile_table = &sta350_volatile_regs, |
1071 | }; |
1072 | |
1073 | #ifdef CONFIG_OF |
1074 | static const struct of_device_id st350_dt_ids[] = { |
1075 | { .compatible = "st,sta350" , }, |
1076 | { } |
1077 | }; |
1078 | MODULE_DEVICE_TABLE(of, st350_dt_ids); |
1079 | |
1080 | static const char * const sta350_ffx_modes[] = { |
1081 | [STA350_FFX_PM_DROP_COMP] = "drop-compensation" , |
1082 | [STA350_FFX_PM_TAPERED_COMP] = "tapered-compensation" , |
1083 | [STA350_FFX_PM_FULL_POWER] = "full-power-mode" , |
1084 | [STA350_FFX_PM_VARIABLE_DROP_COMP] = "variable-drop-compensation" , |
1085 | }; |
1086 | |
1087 | static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350) |
1088 | { |
1089 | struct device_node *np = dev->of_node; |
1090 | struct sta350_platform_data *pdata; |
1091 | const char *ffx_power_mode; |
1092 | u16 tmp; |
1093 | u8 tmp8; |
1094 | |
1095 | pdata = devm_kzalloc(dev, size: sizeof(*pdata), GFP_KERNEL); |
1096 | if (!pdata) |
1097 | return -ENOMEM; |
1098 | |
1099 | of_property_read_u8(np, propname: "st,output-conf" , |
1100 | out_value: &pdata->output_conf); |
1101 | of_property_read_u8(np, propname: "st,ch1-output-mapping" , |
1102 | out_value: &pdata->ch1_output_mapping); |
1103 | of_property_read_u8(np, propname: "st,ch2-output-mapping" , |
1104 | out_value: &pdata->ch2_output_mapping); |
1105 | of_property_read_u8(np, propname: "st,ch3-output-mapping" , |
1106 | out_value: &pdata->ch3_output_mapping); |
1107 | |
1108 | pdata->thermal_warning_recovery = |
1109 | of_property_read_bool(np, propname: "st,thermal-warning-recovery" ); |
1110 | pdata->thermal_warning_adjustment = |
1111 | of_property_read_bool(np, propname: "st,thermal-warning-adjustment" ); |
1112 | pdata->fault_detect_recovery = |
1113 | of_property_read_bool(np, propname: "st,fault-detect-recovery" ); |
1114 | |
1115 | pdata->ffx_power_output_mode = STA350_FFX_PM_VARIABLE_DROP_COMP; |
1116 | if (!of_property_read_string(np, propname: "st,ffx-power-output-mode" , |
1117 | out_string: &ffx_power_mode)) { |
1118 | int i, mode = -EINVAL; |
1119 | |
1120 | for (i = 0; i < ARRAY_SIZE(sta350_ffx_modes); i++) |
1121 | if (!strcasecmp(s1: ffx_power_mode, s2: sta350_ffx_modes[i])) |
1122 | mode = i; |
1123 | |
1124 | if (mode < 0) |
1125 | dev_warn(dev, "Unsupported ffx output mode: %s\n" , |
1126 | ffx_power_mode); |
1127 | else |
1128 | pdata->ffx_power_output_mode = mode; |
1129 | } |
1130 | |
1131 | tmp = 140; |
1132 | of_property_read_u16(np, propname: "st,drop-compensation-ns" , out_value: &tmp); |
1133 | pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20; |
1134 | |
1135 | pdata->oc_warning_adjustment = |
1136 | of_property_read_bool(np, propname: "st,overcurrent-warning-adjustment" ); |
1137 | |
1138 | /* CONFE */ |
1139 | pdata->max_power_use_mpcc = |
1140 | of_property_read_bool(np, propname: "st,max-power-use-mpcc" ); |
1141 | pdata->max_power_correction = |
1142 | of_property_read_bool(np, propname: "st,max-power-correction" ); |
1143 | pdata->am_reduction_mode = |
1144 | of_property_read_bool(np, propname: "st,am-reduction-mode" ); |
1145 | pdata->odd_pwm_speed_mode = |
1146 | of_property_read_bool(np, propname: "st,odd-pwm-speed-mode" ); |
1147 | pdata->distortion_compensation = |
1148 | of_property_read_bool(np, propname: "st,distortion-compensation" ); |
1149 | |
1150 | /* CONFF */ |
1151 | pdata->invalid_input_detect_mute = |
1152 | of_property_read_bool(np, propname: "st,invalid-input-detect-mute" ); |
1153 | |
1154 | /* MISC */ |
1155 | pdata->activate_mute_output = |
1156 | of_property_read_bool(np, propname: "st,activate-mute-output" ); |
1157 | pdata->bridge_immediate_off = |
1158 | of_property_read_bool(np, propname: "st,bridge-immediate-off" ); |
1159 | pdata->noise_shape_dc_cut = |
1160 | of_property_read_bool(np, propname: "st,noise-shape-dc-cut" ); |
1161 | pdata->powerdown_master_vol = |
1162 | of_property_read_bool(np, propname: "st,powerdown-master-volume" ); |
1163 | |
1164 | if (!of_property_read_u8(np, propname: "st,powerdown-delay-divider" , out_value: &tmp8)) { |
1165 | if (is_power_of_2(n: tmp8) && tmp8 >= 1 && tmp8 <= 128) |
1166 | pdata->powerdown_delay_divider = ilog2(tmp8); |
1167 | else |
1168 | dev_warn(dev, "Unsupported powerdown delay divider %d\n" , |
1169 | tmp8); |
1170 | } |
1171 | |
1172 | sta350->pdata = pdata; |
1173 | |
1174 | return 0; |
1175 | } |
1176 | #endif |
1177 | |
1178 | static int sta350_i2c_probe(struct i2c_client *i2c) |
1179 | { |
1180 | struct device *dev = &i2c->dev; |
1181 | struct sta350_priv *sta350; |
1182 | int ret, i; |
1183 | |
1184 | sta350 = devm_kzalloc(dev, size: sizeof(struct sta350_priv), GFP_KERNEL); |
1185 | if (!sta350) |
1186 | return -ENOMEM; |
1187 | |
1188 | mutex_init(&sta350->coeff_lock); |
1189 | sta350->pdata = dev_get_platdata(dev); |
1190 | |
1191 | #ifdef CONFIG_OF |
1192 | if (dev->of_node) { |
1193 | ret = sta350_probe_dt(dev, sta350); |
1194 | if (ret < 0) |
1195 | return ret; |
1196 | } |
1197 | #endif |
1198 | |
1199 | /* GPIOs */ |
1200 | sta350->gpiod_nreset = devm_gpiod_get_optional(dev, con_id: "reset" , |
1201 | flags: GPIOD_OUT_LOW); |
1202 | if (IS_ERR(ptr: sta350->gpiod_nreset)) |
1203 | return PTR_ERR(ptr: sta350->gpiod_nreset); |
1204 | |
1205 | sta350->gpiod_power_down = devm_gpiod_get_optional(dev, con_id: "power-down" , |
1206 | flags: GPIOD_OUT_LOW); |
1207 | if (IS_ERR(ptr: sta350->gpiod_power_down)) |
1208 | return PTR_ERR(ptr: sta350->gpiod_power_down); |
1209 | |
1210 | /* regulators */ |
1211 | for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++) |
1212 | sta350->supplies[i].supply = sta350_supply_names[i]; |
1213 | |
1214 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sta350->supplies), |
1215 | consumers: sta350->supplies); |
1216 | if (ret < 0) { |
1217 | dev_err(dev, "Failed to request supplies: %d\n" , ret); |
1218 | return ret; |
1219 | } |
1220 | |
1221 | sta350->regmap = devm_regmap_init_i2c(i2c, &sta350_regmap); |
1222 | if (IS_ERR(ptr: sta350->regmap)) { |
1223 | ret = PTR_ERR(ptr: sta350->regmap); |
1224 | dev_err(dev, "Failed to init regmap: %d\n" , ret); |
1225 | return ret; |
1226 | } |
1227 | |
1228 | i2c_set_clientdata(client: i2c, data: sta350); |
1229 | |
1230 | ret = devm_snd_soc_register_component(dev, component_driver: &sta350_component, dai_drv: &sta350_dai, num_dai: 1); |
1231 | if (ret < 0) |
1232 | dev_err(dev, "Failed to register component (%d)\n" , ret); |
1233 | |
1234 | return ret; |
1235 | } |
1236 | |
1237 | static void sta350_i2c_remove(struct i2c_client *client) |
1238 | {} |
1239 | |
1240 | static const struct i2c_device_id sta350_i2c_id[] = { |
1241 | { "sta350" , 0 }, |
1242 | { } |
1243 | }; |
1244 | MODULE_DEVICE_TABLE(i2c, sta350_i2c_id); |
1245 | |
1246 | static struct i2c_driver sta350_i2c_driver = { |
1247 | .driver = { |
1248 | .name = "sta350" , |
1249 | .of_match_table = of_match_ptr(st350_dt_ids), |
1250 | }, |
1251 | .probe = sta350_i2c_probe, |
1252 | .remove = sta350_i2c_remove, |
1253 | .id_table = sta350_i2c_id, |
1254 | }; |
1255 | |
1256 | module_i2c_driver(sta350_i2c_driver); |
1257 | |
1258 | MODULE_DESCRIPTION("ASoC STA350 driver" ); |
1259 | MODULE_AUTHOR("Sven Brandau <info@brandau.biz>" ); |
1260 | MODULE_LICENSE("GPL" ); |
1261 | |