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