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