diff options
Diffstat (limited to 'sound/soc/codecs/sta32x.c')
-rw-r--r-- | sound/soc/codecs/sta32x.c | 979 |
1 files changed, 979 insertions, 0 deletions
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c new file mode 100644 index 00000000000..d5630aff6a0 --- /dev/null +++ b/sound/soc/codecs/sta32x.c | |||
@@ -0,0 +1,979 @@ | |||
1 | /* | ||
2 | * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system | ||
3 | * | ||
4 | * Copyright: 2011 Raumfeld GmbH | ||
5 | * Author: Johannes Stezenbach <js@sig21.net> | ||
6 | * | ||
7 | * based on code from: | ||
8 | * Wolfson Microelectronics PLC. | ||
9 | * Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
10 | * Freescale Semiconductor, Inc. | ||
11 | * Timur Tabi <timur@freescale.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/moduleparam.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/pm.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/regulator/consumer.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include <sound/soc-dapm.h> | ||
35 | #include <sound/initval.h> | ||
36 | #include <sound/tlv.h> | ||
37 | |||
38 | #include "sta32x.h" | ||
39 | |||
40 | #define STA32X_RATES (SNDRV_PCM_RATE_32000 | \ | ||
41 | SNDRV_PCM_RATE_44100 | \ | ||
42 | SNDRV_PCM_RATE_48000 | \ | ||
43 | SNDRV_PCM_RATE_88200 | \ | ||
44 | SNDRV_PCM_RATE_96000 | \ | ||
45 | SNDRV_PCM_RATE_176400 | \ | ||
46 | SNDRV_PCM_RATE_192000) | ||
47 | |||
48 | #define STA32X_FORMATS \ | ||
49 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
50 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ | ||
51 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ | ||
52 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ | ||
53 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ | ||
54 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) | ||
55 | |||
56 | /* Power-up register defaults */ | ||
57 | static const u8 sta32x_regs[STA32X_REGISTER_COUNT] = { | ||
58 | 0x63, 0x80, 0xc2, 0x40, 0xc2, 0x5c, 0x10, 0xff, 0x60, 0x60, | ||
59 | 0x60, 0x80, 0x00, 0x00, 0x00, 0x40, 0x80, 0x77, 0x6a, 0x69, | ||
60 | 0x6a, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, | ||
62 | 0xc0, 0xf3, 0x33, 0x00, 0x0c, | ||
63 | }; | ||
64 | |||
65 | /* regulator power supply names */ | ||
66 | static const char *sta32x_supply_names[] = { | ||
67 | "Vdda", /* analog supply, 3.3VV */ | ||
68 | "Vdd3", /* digital supply, 3.3V */ | ||
69 | "Vcc" /* power amp spply, 10V - 36V */ | ||
70 | }; | ||
71 | |||
72 | /* codec private data */ | ||
73 | struct sta32x_priv { | ||
74 | struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)]; | ||
75 | struct snd_soc_codec *codec; | ||
76 | |||
77 | unsigned int mclk; | ||
78 | unsigned int format; | ||
79 | |||
80 | u32 coef_shadow[STA32X_COEF_COUNT]; | ||
81 | }; | ||
82 | |||
83 | static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1); | ||
84 | static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1); | ||
85 | static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0); | ||
86 | |||
87 | static const char *sta32x_drc_ac[] = { | ||
88 | "Anti-Clipping", "Dynamic Range Compression" }; | ||
89 | static const char *sta32x_auto_eq_mode[] = { | ||
90 | "User", "Preset", "Loudness" }; | ||
91 | static const char *sta32x_auto_gc_mode[] = { | ||
92 | "User", "AC no clipping", "AC limited clipping (10%)", | ||
93 | "DRC nighttime listening mode" }; | ||
94 | static const char *sta32x_auto_xo_mode[] = { | ||
95 | "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz", | ||
96 | "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" }; | ||
97 | static const char *sta32x_preset_eq_mode[] = { | ||
98 | "Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft", | ||
99 | "Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1", | ||
100 | "Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2", | ||
101 | "Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7", | ||
102 | "Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12", | ||
103 | "Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" }; | ||
104 | static const char *sta32x_limiter_select[] = { | ||
105 | "Limiter Disabled", "Limiter #1", "Limiter #2" }; | ||
106 | static const char *sta32x_limiter_attack_rate[] = { | ||
107 | "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024", | ||
108 | "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752", | ||
109 | "0.0645", "0.0564", "0.0501", "0.0451" }; | ||
110 | static const char *sta32x_limiter_release_rate[] = { | ||
111 | "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299", | ||
112 | "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137", | ||
113 | "0.0134", "0.0117", "0.0110", "0.0104" }; | ||
114 | |||
115 | static const unsigned int sta32x_limiter_ac_attack_tlv[] = { | ||
116 | TLV_DB_RANGE_HEAD(2), | ||
117 | 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), | ||
118 | 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), | ||
119 | }; | ||
120 | |||
121 | static const unsigned int sta32x_limiter_ac_release_tlv[] = { | ||
122 | TLV_DB_RANGE_HEAD(5), | ||
123 | 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), | ||
124 | 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), | ||
125 | 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), | ||
126 | 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), | ||
127 | 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), | ||
128 | }; | ||
129 | |||
130 | static const unsigned int sta32x_limiter_drc_attack_tlv[] = { | ||
131 | TLV_DB_RANGE_HEAD(3), | ||
132 | 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), | ||
133 | 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), | ||
134 | 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), | ||
135 | }; | ||
136 | |||
137 | static const unsigned int sta32x_limiter_drc_release_tlv[] = { | ||
138 | TLV_DB_RANGE_HEAD(5), | ||
139 | 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), | ||
140 | 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), | ||
141 | 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), | ||
142 | 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), | ||
143 | 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), | ||
144 | }; | ||
145 | |||
146 | static const struct soc_enum sta32x_drc_ac_enum = | ||
147 | SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, | ||
148 | 2, sta32x_drc_ac); | ||
149 | static const struct soc_enum sta32x_auto_eq_enum = | ||
150 | SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, | ||
151 | 3, sta32x_auto_eq_mode); | ||
152 | static const struct soc_enum sta32x_auto_gc_enum = | ||
153 | SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, | ||
154 | 4, sta32x_auto_gc_mode); | ||
155 | static const struct soc_enum sta32x_auto_xo_enum = | ||
156 | SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, | ||
157 | 16, sta32x_auto_xo_mode); | ||
158 | static const struct soc_enum sta32x_preset_eq_enum = | ||
159 | SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, | ||
160 | 32, sta32x_preset_eq_mode); | ||
161 | static const struct soc_enum sta32x_limiter_ch1_enum = | ||
162 | SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, | ||
163 | 3, sta32x_limiter_select); | ||
164 | static const struct soc_enum sta32x_limiter_ch2_enum = | ||
165 | SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, | ||
166 | 3, sta32x_limiter_select); | ||
167 | static const struct soc_enum sta32x_limiter_ch3_enum = | ||
168 | SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, | ||
169 | 3, sta32x_limiter_select); | ||
170 | static const struct soc_enum sta32x_limiter1_attack_rate_enum = | ||
171 | SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT, | ||
172 | 16, sta32x_limiter_attack_rate); | ||
173 | static const struct soc_enum sta32x_limiter2_attack_rate_enum = | ||
174 | SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT, | ||
175 | 16, sta32x_limiter_attack_rate); | ||
176 | static const struct soc_enum sta32x_limiter1_release_rate_enum = | ||
177 | SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT, | ||
178 | 16, sta32x_limiter_release_rate); | ||
179 | static const struct soc_enum sta32x_limiter2_release_rate_enum = | ||
180 | SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, | ||
181 | 16, sta32x_limiter_release_rate); | ||
182 | |||
183 | /* byte array controls for setting biquad, mixer, scaling coefficients; | ||
184 | * for biquads all five coefficients need to be set in one go, | ||
185 | * mixer and pre/postscale coefs can be set individually; | ||
186 | * each coef is 24bit, the bytes are ordered in the same way | ||
187 | * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0) | ||
188 | */ | ||
189 | |||
190 | static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol, | ||
191 | struct snd_ctl_elem_info *uinfo) | ||
192 | { | ||
193 | int numcoef = kcontrol->private_value >> 16; | ||
194 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
195 | uinfo->count = 3 * numcoef; | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, | ||
200 | struct snd_ctl_elem_value *ucontrol) | ||
201 | { | ||
202 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
203 | int numcoef = kcontrol->private_value >> 16; | ||
204 | int index = kcontrol->private_value & 0xffff; | ||
205 | unsigned int cfud; | ||
206 | int i; | ||
207 | |||
208 | /* preserve reserved bits in STA32X_CFUD */ | ||
209 | cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; | ||
210 | /* chip documentation does not say if the bits are self clearing, | ||
211 | * so do it explicitly */ | ||
212 | snd_soc_write(codec, STA32X_CFUD, cfud); | ||
213 | |||
214 | snd_soc_write(codec, STA32X_CFADDR2, index); | ||
215 | if (numcoef == 1) | ||
216 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x04); | ||
217 | else if (numcoef == 5) | ||
218 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x08); | ||
219 | else | ||
220 | return -EINVAL; | ||
221 | for (i = 0; i < 3 * numcoef; i++) | ||
222 | ucontrol->value.bytes.data[i] = | ||
223 | snd_soc_read(codec, STA32X_B1CF1 + i); | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, | ||
229 | struct snd_ctl_elem_value *ucontrol) | ||
230 | { | ||
231 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
232 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
233 | int numcoef = kcontrol->private_value >> 16; | ||
234 | int index = kcontrol->private_value & 0xffff; | ||
235 | unsigned int cfud; | ||
236 | int i; | ||
237 | |||
238 | /* preserve reserved bits in STA32X_CFUD */ | ||
239 | cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; | ||
240 | /* chip documentation does not say if the bits are self clearing, | ||
241 | * so do it explicitly */ | ||
242 | snd_soc_write(codec, STA32X_CFUD, cfud); | ||
243 | |||
244 | snd_soc_write(codec, STA32X_CFADDR2, index); | ||
245 | for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++) | ||
246 | sta32x->coef_shadow[index + i] = | ||
247 | (ucontrol->value.bytes.data[3 * i] << 16) | ||
248 | | (ucontrol->value.bytes.data[3 * i + 1] << 8) | ||
249 | | (ucontrol->value.bytes.data[3 * i + 2]); | ||
250 | for (i = 0; i < 3 * numcoef; i++) | ||
251 | snd_soc_write(codec, STA32X_B1CF1 + i, | ||
252 | ucontrol->value.bytes.data[i]); | ||
253 | if (numcoef == 1) | ||
254 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); | ||
255 | else if (numcoef == 5) | ||
256 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x02); | ||
257 | else | ||
258 | return -EINVAL; | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | int sta32x_sync_coef_shadow(struct snd_soc_codec *codec) | ||
264 | { | ||
265 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
266 | unsigned int cfud; | ||
267 | int i; | ||
268 | |||
269 | /* preserve reserved bits in STA32X_CFUD */ | ||
270 | cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; | ||
271 | |||
272 | for (i = 0; i < STA32X_COEF_COUNT; i++) { | ||
273 | snd_soc_write(codec, STA32X_CFADDR2, i); | ||
274 | snd_soc_write(codec, STA32X_B1CF1, | ||
275 | (sta32x->coef_shadow[i] >> 16) & 0xff); | ||
276 | snd_soc_write(codec, STA32X_B1CF2, | ||
277 | (sta32x->coef_shadow[i] >> 8) & 0xff); | ||
278 | snd_soc_write(codec, STA32X_B1CF3, | ||
279 | (sta32x->coef_shadow[i]) & 0xff); | ||
280 | /* chip documentation does not say if the bits are | ||
281 | * self-clearing, so do it explicitly */ | ||
282 | snd_soc_write(codec, STA32X_CFUD, cfud); | ||
283 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); | ||
284 | } | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | int sta32x_cache_sync(struct snd_soc_codec *codec) | ||
289 | { | ||
290 | unsigned int mute; | ||
291 | int rc; | ||
292 | |||
293 | if (!codec->cache_sync) | ||
294 | return 0; | ||
295 | |||
296 | /* mute during register sync */ | ||
297 | mute = snd_soc_read(codec, STA32X_MMUTE); | ||
298 | snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE); | ||
299 | sta32x_sync_coef_shadow(codec); | ||
300 | rc = snd_soc_cache_sync(codec); | ||
301 | snd_soc_write(codec, STA32X_MMUTE, mute); | ||
302 | return rc; | ||
303 | } | ||
304 | |||
305 | #define SINGLE_COEF(xname, index) \ | ||
306 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
307 | .info = sta32x_coefficient_info, \ | ||
308 | .get = sta32x_coefficient_get,\ | ||
309 | .put = sta32x_coefficient_put, \ | ||
310 | .private_value = index | (1 << 16) } | ||
311 | |||
312 | #define BIQUAD_COEFS(xname, index) \ | ||
313 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
314 | .info = sta32x_coefficient_info, \ | ||
315 | .get = sta32x_coefficient_get,\ | ||
316 | .put = sta32x_coefficient_put, \ | ||
317 | .private_value = index | (5 << 16) } | ||
318 | |||
319 | static const struct snd_kcontrol_new sta32x_snd_controls[] = { | ||
320 | SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv), | ||
321 | SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1), | ||
322 | SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1), | ||
323 | SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1), | ||
324 | SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1), | ||
325 | SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv), | ||
326 | SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv), | ||
327 | SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv), | ||
328 | SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0), | ||
329 | SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum), | ||
330 | SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0), | ||
331 | SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0), | ||
332 | SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0), | ||
333 | SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0), | ||
334 | SOC_ENUM("Automode EQ", sta32x_auto_eq_enum), | ||
335 | SOC_ENUM("Automode GC", sta32x_auto_gc_enum), | ||
336 | SOC_ENUM("Automode XO", sta32x_auto_xo_enum), | ||
337 | SOC_ENUM("Preset EQ", sta32x_preset_eq_enum), | ||
338 | SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0), | ||
339 | SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0), | ||
340 | SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0), | ||
341 | SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0), | ||
342 | SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), | ||
343 | SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), | ||
344 | SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), | ||
345 | SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum), | ||
346 | SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum), | ||
347 | SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum), | ||
348 | SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv), | ||
349 | SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv), | ||
350 | SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum), | ||
351 | SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum), | ||
352 | SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), | ||
353 | SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), | ||
354 | |||
355 | /* depending on mode, the attack/release thresholds have | ||
356 | * two different enum definitions; provide both | ||
357 | */ | ||
358 | SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT, | ||
359 | 16, 0, sta32x_limiter_ac_attack_tlv), | ||
360 | SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT, | ||
361 | 16, 0, sta32x_limiter_ac_attack_tlv), | ||
362 | SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT, | ||
363 | 16, 0, sta32x_limiter_ac_release_tlv), | ||
364 | SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, | ||
365 | 16, 0, sta32x_limiter_ac_release_tlv), | ||
366 | SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT, | ||
367 | 16, 0, sta32x_limiter_drc_attack_tlv), | ||
368 | SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT, | ||
369 | 16, 0, sta32x_limiter_drc_attack_tlv), | ||
370 | SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT, | ||
371 | 16, 0, sta32x_limiter_drc_release_tlv), | ||
372 | SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, | ||
373 | 16, 0, sta32x_limiter_drc_release_tlv), | ||
374 | |||
375 | BIQUAD_COEFS("Ch1 - Biquad 1", 0), | ||
376 | BIQUAD_COEFS("Ch1 - Biquad 2", 5), | ||
377 | BIQUAD_COEFS("Ch1 - Biquad 3", 10), | ||
378 | BIQUAD_COEFS("Ch1 - Biquad 4", 15), | ||
379 | BIQUAD_COEFS("Ch2 - Biquad 1", 20), | ||
380 | BIQUAD_COEFS("Ch2 - Biquad 2", 25), | ||
381 | BIQUAD_COEFS("Ch2 - Biquad 3", 30), | ||
382 | BIQUAD_COEFS("Ch2 - Biquad 4", 35), | ||
383 | BIQUAD_COEFS("High-pass", 40), | ||
384 | BIQUAD_COEFS("Low-pass", 45), | ||
385 | SINGLE_COEF("Ch1 - Prescale", 50), | ||
386 | SINGLE_COEF("Ch2 - Prescale", 51), | ||
387 | SINGLE_COEF("Ch1 - Postscale", 52), | ||
388 | SINGLE_COEF("Ch2 - Postscale", 53), | ||
389 | SINGLE_COEF("Ch3 - Postscale", 54), | ||
390 | SINGLE_COEF("Thermal warning - Postscale", 55), | ||
391 | SINGLE_COEF("Ch1 - Mix 1", 56), | ||
392 | SINGLE_COEF("Ch1 - Mix 2", 57), | ||
393 | SINGLE_COEF("Ch2 - Mix 1", 58), | ||
394 | SINGLE_COEF("Ch2 - Mix 2", 59), | ||
395 | SINGLE_COEF("Ch3 - Mix 1", 60), | ||
396 | SINGLE_COEF("Ch3 - Mix 2", 61), | ||
397 | }; | ||
398 | |||
399 | static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = { | ||
400 | SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), | ||
401 | SND_SOC_DAPM_OUTPUT("LEFT"), | ||
402 | SND_SOC_DAPM_OUTPUT("RIGHT"), | ||
403 | SND_SOC_DAPM_OUTPUT("SUB"), | ||
404 | }; | ||
405 | |||
406 | static const struct snd_soc_dapm_route sta32x_dapm_routes[] = { | ||
407 | { "LEFT", NULL, "DAC" }, | ||
408 | { "RIGHT", NULL, "DAC" }, | ||
409 | { "SUB", NULL, "DAC" }, | ||
410 | }; | ||
411 | |||
412 | /* MCLK interpolation ratio per fs */ | ||
413 | static struct { | ||
414 | int fs; | ||
415 | int ir; | ||
416 | } interpolation_ratios[] = { | ||
417 | { 32000, 0 }, | ||
418 | { 44100, 0 }, | ||
419 | { 48000, 0 }, | ||
420 | { 88200, 1 }, | ||
421 | { 96000, 1 }, | ||
422 | { 176400, 2 }, | ||
423 | { 192000, 2 }, | ||
424 | }; | ||
425 | |||
426 | /* MCLK to fs clock ratios */ | ||
427 | static struct { | ||
428 | int ratio; | ||
429 | int mcs; | ||
430 | } mclk_ratios[3][7] = { | ||
431 | { { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 }, | ||
432 | { 128, 4 }, { 576, 5 }, { 0, 0 } }, | ||
433 | { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, | ||
434 | { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, | ||
435 | }; | ||
436 | |||
437 | |||
438 | /** | ||
439 | * sta32x_set_dai_sysclk - configure MCLK | ||
440 | * @codec_dai: the codec DAI | ||
441 | * @clk_id: the clock ID (ignored) | ||
442 | * @freq: the MCLK input frequency | ||
443 | * @dir: the clock direction (ignored) | ||
444 | * | ||
445 | * The value of MCLK is used to determine which sample rates are supported | ||
446 | * by the STA32X, based on the mclk_ratios table. | ||
447 | * | ||
448 | * This function must be called by the machine driver's 'startup' function, | ||
449 | * otherwise the list of supported sample rates will not be available in | ||
450 | * time for ALSA. | ||
451 | * | ||
452 | * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause | ||
453 | * theoretically possible sample rates to be enabled. Call it again with a | ||
454 | * proper value set one the external clock is set (most probably you would do | ||
455 | * that from a machine's driver 'hw_param' hook. | ||
456 | */ | ||
457 | static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
458 | int clk_id, unsigned int freq, int dir) | ||
459 | { | ||
460 | struct snd_soc_codec *codec = codec_dai->codec; | ||
461 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
462 | int i, j, ir, fs; | ||
463 | unsigned int rates = 0; | ||
464 | unsigned int rate_min = -1; | ||
465 | unsigned int rate_max = 0; | ||
466 | |||
467 | pr_debug("mclk=%u\n", freq); | ||
468 | sta32x->mclk = freq; | ||
469 | |||
470 | if (sta32x->mclk) { | ||
471 | for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { | ||
472 | ir = interpolation_ratios[i].ir; | ||
473 | fs = interpolation_ratios[i].fs; | ||
474 | for (j = 0; mclk_ratios[ir][j].ratio; j++) { | ||
475 | if (mclk_ratios[ir][j].ratio * fs == freq) { | ||
476 | rates |= snd_pcm_rate_to_rate_bit(fs); | ||
477 | if (fs < rate_min) | ||
478 | rate_min = fs; | ||
479 | if (fs > rate_max) | ||
480 | rate_max = fs; | ||
481 | } | ||
482 | } | ||
483 | } | ||
484 | /* FIXME: soc should support a rate list */ | ||
485 | rates &= ~SNDRV_PCM_RATE_KNOT; | ||
486 | |||
487 | if (!rates) { | ||
488 | dev_err(codec->dev, "could not find a valid sample rate\n"); | ||
489 | return -EINVAL; | ||
490 | } | ||
491 | } else { | ||
492 | /* enable all possible rates */ | ||
493 | rates = STA32X_RATES; | ||
494 | rate_min = 32000; | ||
495 | rate_max = 192000; | ||
496 | } | ||
497 | |||
498 | codec_dai->driver->playback.rates = rates; | ||
499 | codec_dai->driver->playback.rate_min = rate_min; | ||
500 | codec_dai->driver->playback.rate_max = rate_max; | ||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | /** | ||
505 | * sta32x_set_dai_fmt - configure the codec for the selected audio format | ||
506 | * @codec_dai: the codec DAI | ||
507 | * @fmt: a SND_SOC_DAIFMT_x value indicating the data format | ||
508 | * | ||
509 | * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the | ||
510 | * codec accordingly. | ||
511 | */ | ||
512 | static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
513 | unsigned int fmt) | ||
514 | { | ||
515 | struct snd_soc_codec *codec = codec_dai->codec; | ||
516 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
517 | u8 confb = snd_soc_read(codec, STA32X_CONFB); | ||
518 | |||
519 | pr_debug("\n"); | ||
520 | confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM); | ||
521 | |||
522 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
523 | case SND_SOC_DAIFMT_CBS_CFS: | ||
524 | break; | ||
525 | default: | ||
526 | return -EINVAL; | ||
527 | } | ||
528 | |||
529 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
530 | case SND_SOC_DAIFMT_I2S: | ||
531 | case SND_SOC_DAIFMT_RIGHT_J: | ||
532 | case SND_SOC_DAIFMT_LEFT_J: | ||
533 | sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
534 | break; | ||
535 | default: | ||
536 | return -EINVAL; | ||
537 | } | ||
538 | |||
539 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
540 | case SND_SOC_DAIFMT_NB_NF: | ||
541 | confb |= STA32X_CONFB_C2IM; | ||
542 | break; | ||
543 | case SND_SOC_DAIFMT_NB_IF: | ||
544 | confb |= STA32X_CONFB_C1IM; | ||
545 | break; | ||
546 | default: | ||
547 | return -EINVAL; | ||
548 | } | ||
549 | |||
550 | snd_soc_write(codec, STA32X_CONFB, confb); | ||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | /** | ||
555 | * sta32x_hw_params - program the STA32X with the given hardware parameters. | ||
556 | * @substream: the audio stream | ||
557 | * @params: the hardware parameters to set | ||
558 | * @dai: the SOC DAI (ignored) | ||
559 | * | ||
560 | * This function programs the hardware with the values provided. | ||
561 | * Specifically, the sample rate and the data format. | ||
562 | */ | ||
563 | static int sta32x_hw_params(struct snd_pcm_substream *substream, | ||
564 | struct snd_pcm_hw_params *params, | ||
565 | struct snd_soc_dai *dai) | ||
566 | { | ||
567 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
568 | struct snd_soc_codec *codec = rtd->codec; | ||
569 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
570 | unsigned int rate; | ||
571 | int i, mcs = -1, ir = -1; | ||
572 | u8 confa, confb; | ||
573 | |||
574 | rate = params_rate(params); | ||
575 | pr_debug("rate: %u\n", rate); | ||
576 | for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) | ||
577 | if (interpolation_ratios[i].fs == rate) | ||
578 | ir = interpolation_ratios[i].ir; | ||
579 | if (ir < 0) | ||
580 | return -EINVAL; | ||
581 | for (i = 0; mclk_ratios[ir][i].ratio; i++) | ||
582 | if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) | ||
583 | mcs = mclk_ratios[ir][i].mcs; | ||
584 | if (mcs < 0) | ||
585 | return -EINVAL; | ||
586 | |||
587 | confa = snd_soc_read(codec, STA32X_CONFA); | ||
588 | confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK); | ||
589 | confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT); | ||
590 | |||
591 | confb = snd_soc_read(codec, STA32X_CONFB); | ||
592 | confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB); | ||
593 | switch (params_format(params)) { | ||
594 | case SNDRV_PCM_FORMAT_S24_LE: | ||
595 | case SNDRV_PCM_FORMAT_S24_BE: | ||
596 | case SNDRV_PCM_FORMAT_S24_3LE: | ||
597 | case SNDRV_PCM_FORMAT_S24_3BE: | ||
598 | pr_debug("24bit\n"); | ||
599 | /* fall through */ | ||
600 | case SNDRV_PCM_FORMAT_S32_LE: | ||
601 | case SNDRV_PCM_FORMAT_S32_BE: | ||
602 | pr_debug("24bit or 32bit\n"); | ||
603 | switch (sta32x->format) { | ||
604 | case SND_SOC_DAIFMT_I2S: | ||
605 | confb |= 0x0; | ||
606 | break; | ||
607 | case SND_SOC_DAIFMT_LEFT_J: | ||
608 | confb |= 0x1; | ||
609 | break; | ||
610 | case SND_SOC_DAIFMT_RIGHT_J: | ||
611 | confb |= 0x2; | ||
612 | break; | ||
613 | } | ||
614 | |||
615 | break; | ||
616 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
617 | case SNDRV_PCM_FORMAT_S20_3BE: | ||
618 | pr_debug("20bit\n"); | ||
619 | switch (sta32x->format) { | ||
620 | case SND_SOC_DAIFMT_I2S: | ||
621 | confb |= 0x4; | ||
622 | break; | ||
623 | case SND_SOC_DAIFMT_LEFT_J: | ||
624 | confb |= 0x5; | ||
625 | break; | ||
626 | case SND_SOC_DAIFMT_RIGHT_J: | ||
627 | confb |= 0x6; | ||
628 | break; | ||
629 | } | ||
630 | |||
631 | break; | ||
632 | case SNDRV_PCM_FORMAT_S18_3LE: | ||
633 | case SNDRV_PCM_FORMAT_S18_3BE: | ||
634 | pr_debug("18bit\n"); | ||
635 | switch (sta32x->format) { | ||
636 | case SND_SOC_DAIFMT_I2S: | ||
637 | confb |= 0x8; | ||
638 | break; | ||
639 | case SND_SOC_DAIFMT_LEFT_J: | ||
640 | confb |= 0x9; | ||
641 | break; | ||
642 | case SND_SOC_DAIFMT_RIGHT_J: | ||
643 | confb |= 0xa; | ||
644 | break; | ||
645 | } | ||
646 | |||
647 | break; | ||
648 | case SNDRV_PCM_FORMAT_S16_LE: | ||
649 | case SNDRV_PCM_FORMAT_S16_BE: | ||
650 | pr_debug("16bit\n"); | ||
651 | switch (sta32x->format) { | ||
652 | case SND_SOC_DAIFMT_I2S: | ||
653 | confb |= 0x0; | ||
654 | break; | ||
655 | case SND_SOC_DAIFMT_LEFT_J: | ||
656 | confb |= 0xd; | ||
657 | break; | ||
658 | case SND_SOC_DAIFMT_RIGHT_J: | ||
659 | confb |= 0xe; | ||
660 | break; | ||
661 | } | ||
662 | |||
663 | break; | ||
664 | default: | ||
665 | return -EINVAL; | ||
666 | } | ||
667 | |||
668 | snd_soc_write(codec, STA32X_CONFA, confa); | ||
669 | snd_soc_write(codec, STA32X_CONFB, confb); | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | /** | ||
674 | * sta32x_set_bias_level - DAPM callback | ||
675 | * @codec: the codec device | ||
676 | * @level: DAPM power level | ||
677 | * | ||
678 | * This is called by ALSA to put the codec into low power mode | ||
679 | * or to wake it up. If the codec is powered off completely | ||
680 | * all registers must be restored after power on. | ||
681 | */ | ||
682 | static int sta32x_set_bias_level(struct snd_soc_codec *codec, | ||
683 | enum snd_soc_bias_level level) | ||
684 | { | ||
685 | int ret; | ||
686 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
687 | |||
688 | pr_debug("level = %d\n", level); | ||
689 | switch (level) { | ||
690 | case SND_SOC_BIAS_ON: | ||
691 | break; | ||
692 | |||
693 | case SND_SOC_BIAS_PREPARE: | ||
694 | /* Full power on */ | ||
695 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
696 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, | ||
697 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); | ||
698 | break; | ||
699 | |||
700 | case SND_SOC_BIAS_STANDBY: | ||
701 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
702 | ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), | ||
703 | sta32x->supplies); | ||
704 | if (ret != 0) { | ||
705 | dev_err(codec->dev, | ||
706 | "Failed to enable supplies: %d\n", ret); | ||
707 | return ret; | ||
708 | } | ||
709 | |||
710 | sta32x_cache_sync(codec); | ||
711 | } | ||
712 | |||
713 | /* Power up to mute */ | ||
714 | /* FIXME */ | ||
715 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
716 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, | ||
717 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); | ||
718 | |||
719 | break; | ||
720 | |||
721 | case SND_SOC_BIAS_OFF: | ||
722 | /* The chip runs through the power down sequence for us. */ | ||
723 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
724 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, | ||
725 | STA32X_CONFF_PWDN); | ||
726 | msleep(300); | ||
727 | |||
728 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), | ||
729 | sta32x->supplies); | ||
730 | break; | ||
731 | } | ||
732 | codec->dapm.bias_level = level; | ||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | static struct snd_soc_dai_ops sta32x_dai_ops = { | ||
737 | .hw_params = sta32x_hw_params, | ||
738 | .set_sysclk = sta32x_set_dai_sysclk, | ||
739 | .set_fmt = sta32x_set_dai_fmt, | ||
740 | }; | ||
741 | |||
742 | static struct snd_soc_dai_driver sta32x_dai = { | ||
743 | .name = "STA32X", | ||
744 | .playback = { | ||
745 | .stream_name = "Playback", | ||
746 | .channels_min = 2, | ||
747 | .channels_max = 2, | ||
748 | .rates = STA32X_RATES, | ||
749 | .formats = STA32X_FORMATS, | ||
750 | }, | ||
751 | .ops = &sta32x_dai_ops, | ||
752 | }; | ||
753 | |||
754 | #ifdef CONFIG_PM | ||
755 | static int sta32x_suspend(struct snd_soc_codec *codec, pm_message_t state) | ||
756 | { | ||
757 | sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | static int sta32x_resume(struct snd_soc_codec *codec) | ||
762 | { | ||
763 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
764 | return 0; | ||
765 | } | ||
766 | #else | ||
767 | #define sta32x_suspend NULL | ||
768 | #define sta32x_resume NULL | ||
769 | #endif | ||
770 | |||
771 | static int sta32x_probe(struct snd_soc_codec *codec) | ||
772 | { | ||
773 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
774 | int i, ret = 0; | ||
775 | |||
776 | sta32x->codec = codec; | ||
777 | |||
778 | /* regulators */ | ||
779 | for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) | ||
780 | sta32x->supplies[i].supply = sta32x_supply_names[i]; | ||
781 | |||
782 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sta32x->supplies), | ||
783 | sta32x->supplies); | ||
784 | if (ret != 0) { | ||
785 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
786 | goto err; | ||
787 | } | ||
788 | |||
789 | ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), | ||
790 | sta32x->supplies); | ||
791 | if (ret != 0) { | ||
792 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
793 | goto err_get; | ||
794 | } | ||
795 | |||
796 | /* Tell ASoC what kind of I/O to use to read the registers. ASoC will | ||
797 | * then do the I2C transactions itself. | ||
798 | */ | ||
799 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); | ||
800 | if (ret < 0) { | ||
801 | dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret); | ||
802 | return ret; | ||
803 | } | ||
804 | |||
805 | /* read reg reset values into cache */ | ||
806 | for (i = 0; i < STA32X_REGISTER_COUNT; i++) | ||
807 | snd_soc_cache_write(codec, i, sta32x_regs[i]); | ||
808 | |||
809 | /* preserve reset values of reserved register bits */ | ||
810 | snd_soc_cache_write(codec, STA32X_CONFC, | ||
811 | codec->hw_read(codec, STA32X_CONFC)); | ||
812 | snd_soc_cache_write(codec, STA32X_CONFE, | ||
813 | codec->hw_read(codec, STA32X_CONFE)); | ||
814 | snd_soc_cache_write(codec, STA32X_CONFF, | ||
815 | codec->hw_read(codec, STA32X_CONFF)); | ||
816 | snd_soc_cache_write(codec, STA32X_MMUTE, | ||
817 | codec->hw_read(codec, STA32X_MMUTE)); | ||
818 | snd_soc_cache_write(codec, STA32X_AUTO1, | ||
819 | codec->hw_read(codec, STA32X_AUTO1)); | ||
820 | snd_soc_cache_write(codec, STA32X_AUTO3, | ||
821 | codec->hw_read(codec, STA32X_AUTO3)); | ||
822 | snd_soc_cache_write(codec, STA32X_C3CFG, | ||
823 | codec->hw_read(codec, STA32X_C3CFG)); | ||
824 | |||
825 | /* FIXME enable thermal warning adjustment and recovery */ | ||
826 | snd_soc_update_bits(codec, STA32X_CONFA, | ||
827 | STA32X_CONFA_TWAB | STA32X_CONFA_TWRB, 0); | ||
828 | |||
829 | /* FIXME select 2.1 mode */ | ||
830 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
831 | STA32X_CONFF_OCFG_MASK, | ||
832 | 1 << STA32X_CONFF_OCFG_SHIFT); | ||
833 | |||
834 | /* FIXME channel to output mapping */ | ||
835 | snd_soc_update_bits(codec, STA32X_C1CFG, | ||
836 | STA32X_CxCFG_OM_MASK, | ||
837 | 0 << STA32X_CxCFG_OM_SHIFT); | ||
838 | snd_soc_update_bits(codec, STA32X_C2CFG, | ||
839 | STA32X_CxCFG_OM_MASK, | ||
840 | 1 << STA32X_CxCFG_OM_SHIFT); | ||
841 | snd_soc_update_bits(codec, STA32X_C3CFG, | ||
842 | STA32X_CxCFG_OM_MASK, | ||
843 | 2 << STA32X_CxCFG_OM_SHIFT); | ||
844 | |||
845 | /* initialize coefficient shadow RAM with reset values */ | ||
846 | for (i = 4; i <= 49; i += 5) | ||
847 | sta32x->coef_shadow[i] = 0x400000; | ||
848 | for (i = 50; i <= 54; i++) | ||
849 | sta32x->coef_shadow[i] = 0x7fffff; | ||
850 | sta32x->coef_shadow[55] = 0x5a9df7; | ||
851 | sta32x->coef_shadow[56] = 0x7fffff; | ||
852 | sta32x->coef_shadow[59] = 0x7fffff; | ||
853 | sta32x->coef_shadow[60] = 0x400000; | ||
854 | sta32x->coef_shadow[61] = 0x400000; | ||
855 | |||
856 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
857 | /* Bias level configuration will have done an extra enable */ | ||
858 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
859 | |||
860 | return 0; | ||
861 | |||
862 | err_get: | ||
863 | regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
864 | err: | ||
865 | return ret; | ||
866 | } | ||
867 | |||
868 | static int sta32x_remove(struct snd_soc_codec *codec) | ||
869 | { | ||
870 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
871 | |||
872 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
873 | regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
874 | |||
875 | return 0; | ||
876 | } | ||
877 | |||
878 | static int sta32x_reg_is_volatile(struct snd_soc_codec *codec, | ||
879 | unsigned int reg) | ||
880 | { | ||
881 | switch (reg) { | ||
882 | case STA32X_CONFA ... STA32X_L2ATRT: | ||
883 | case STA32X_MPCC1 ... STA32X_FDRC2: | ||
884 | return 0; | ||
885 | } | ||
886 | return 1; | ||
887 | } | ||
888 | |||
889 | static const struct snd_soc_codec_driver sta32x_codec = { | ||
890 | .probe = sta32x_probe, | ||
891 | .remove = sta32x_remove, | ||
892 | .suspend = sta32x_suspend, | ||
893 | .resume = sta32x_resume, | ||
894 | .reg_cache_size = STA32X_REGISTER_COUNT, | ||
895 | .reg_word_size = sizeof(u8), | ||
896 | .volatile_register = sta32x_reg_is_volatile, | ||
897 | .set_bias_level = sta32x_set_bias_level, | ||
898 | .controls = sta32x_snd_controls, | ||
899 | .num_controls = ARRAY_SIZE(sta32x_snd_controls), | ||
900 | .dapm_widgets = sta32x_dapm_widgets, | ||
901 | .num_dapm_widgets = ARRAY_SIZE(sta32x_dapm_widgets), | ||
902 | .dapm_routes = sta32x_dapm_routes, | ||
903 | .num_dapm_routes = ARRAY_SIZE(sta32x_dapm_routes), | ||
904 | }; | ||
905 | |||
906 | static __devinit int sta32x_i2c_probe(struct i2c_client *i2c, | ||
907 | const struct i2c_device_id *id) | ||
908 | { | ||
909 | struct sta32x_priv *sta32x; | ||
910 | int ret; | ||
911 | |||
912 | sta32x = kzalloc(sizeof(struct sta32x_priv), GFP_KERNEL); | ||
913 | if (!sta32x) | ||
914 | return -ENOMEM; | ||
915 | |||
916 | i2c_set_clientdata(i2c, sta32x); | ||
917 | |||
918 | ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1); | ||
919 | if (ret != 0) { | ||
920 | dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret); | ||
921 | kfree(sta32x); | ||
922 | return ret; | ||
923 | } | ||
924 | |||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | static __devexit int sta32x_i2c_remove(struct i2c_client *client) | ||
929 | { | ||
930 | struct sta32x_priv *sta32x = i2c_get_clientdata(client); | ||
931 | struct snd_soc_codec *codec = sta32x->codec; | ||
932 | |||
933 | if (codec) | ||
934 | sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
935 | |||
936 | regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
937 | |||
938 | if (codec) { | ||
939 | snd_soc_unregister_codec(&client->dev); | ||
940 | snd_soc_codec_set_drvdata(codec, NULL); | ||
941 | } | ||
942 | |||
943 | kfree(sta32x); | ||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | static const struct i2c_device_id sta32x_i2c_id[] = { | ||
948 | { "sta326", 0 }, | ||
949 | { "sta328", 0 }, | ||
950 | { "sta329", 0 }, | ||
951 | { } | ||
952 | }; | ||
953 | MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id); | ||
954 | |||
955 | static struct i2c_driver sta32x_i2c_driver = { | ||
956 | .driver = { | ||
957 | .name = "sta32x", | ||
958 | .owner = THIS_MODULE, | ||
959 | }, | ||
960 | .probe = sta32x_i2c_probe, | ||
961 | .remove = __devexit_p(sta32x_i2c_remove), | ||
962 | .id_table = sta32x_i2c_id, | ||
963 | }; | ||
964 | |||
965 | static int __init sta32x_init(void) | ||
966 | { | ||
967 | return i2c_add_driver(&sta32x_i2c_driver); | ||
968 | } | ||
969 | module_init(sta32x_init); | ||
970 | |||
971 | static void __exit sta32x_exit(void) | ||
972 | { | ||
973 | i2c_del_driver(&sta32x_i2c_driver); | ||
974 | } | ||
975 | module_exit(sta32x_exit); | ||
976 | |||
977 | MODULE_DESCRIPTION("ASoC STA32X driver"); | ||
978 | MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>"); | ||
979 | MODULE_LICENSE("GPL"); | ||