diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic3x.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 1230 |
1 files changed, 648 insertions, 582 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 71a69908ccf6..fc687790188b 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -12,11 +12,11 @@ | |||
12 | * | 12 | * |
13 | * Notes: | 13 | * Notes: |
14 | * The AIC3X is a driver for a low power stereo audio | 14 | * The AIC3X is a driver for a low power stereo audio |
15 | * codecs aic31, aic32, aic33. | 15 | * codecs aic31, aic32, aic33, aic3007. |
16 | * | 16 | * |
17 | * It supports full aic33 codec functionality. | 17 | * It supports full aic33 codec functionality. |
18 | * The compatibility with aic32, aic31 is as follows: | 18 | * The compatibility with aic32, aic31 and aic3007 is as follows: |
19 | * aic32 | aic31 | 19 | * aic32/aic3007 | aic31 |
20 | * --------------------------------------- | 20 | * --------------------------------------- |
21 | * MONO_LOUT -> N/A | MONO_LOUT -> N/A | 21 | * MONO_LOUT -> N/A | MONO_LOUT -> N/A |
22 | * | IN1L -> LINE1L | 22 | * | IN1L -> LINE1L |
@@ -61,13 +61,29 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = { | |||
61 | "DRVDD", /* ADC Analog and Output Driver Voltage */ | 61 | "DRVDD", /* ADC Analog and Output Driver Voltage */ |
62 | }; | 62 | }; |
63 | 63 | ||
64 | struct aic3x_priv; | ||
65 | |||
66 | struct aic3x_disable_nb { | ||
67 | struct notifier_block nb; | ||
68 | struct aic3x_priv *aic3x; | ||
69 | }; | ||
70 | |||
64 | /* codec private data */ | 71 | /* codec private data */ |
65 | struct aic3x_priv { | 72 | struct aic3x_priv { |
66 | struct snd_soc_codec codec; | 73 | struct snd_soc_codec *codec; |
67 | struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; | 74 | struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES]; |
75 | struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; | ||
76 | enum snd_soc_control_type control_type; | ||
77 | struct aic3x_setup_data *setup; | ||
78 | void *control_data; | ||
68 | unsigned int sysclk; | 79 | unsigned int sysclk; |
69 | int master; | 80 | int master; |
70 | int gpio_reset; | 81 | int gpio_reset; |
82 | int power; | ||
83 | #define AIC3X_MODEL_3X 0 | ||
84 | #define AIC3X_MODEL_33 1 | ||
85 | #define AIC3X_MODEL_3007 2 | ||
86 | u16 model; | ||
71 | }; | 87 | }; |
72 | 88 | ||
73 | /* | 89 | /* |
@@ -106,62 +122,23 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { | |||
106 | }; | 122 | }; |
107 | 123 | ||
108 | /* | 124 | /* |
109 | * read aic3x register cache | 125 | * read from the aic3x register space. Only use for this function is if |
126 | * wanting to read volatile bits from those registers that has both read-only | ||
127 | * and read/write bits. All other cases should use snd_soc_read. | ||
110 | */ | 128 | */ |
111 | static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec, | 129 | static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, |
112 | unsigned int reg) | 130 | u8 *value) |
113 | { | 131 | { |
114 | u8 *cache = codec->reg_cache; | 132 | u8 *cache = codec->reg_cache; |
115 | if (reg >= AIC3X_CACHEREGNUM) | ||
116 | return -1; | ||
117 | return cache[reg]; | ||
118 | } | ||
119 | 133 | ||
120 | /* | 134 | if (codec->cache_only) |
121 | * write aic3x register cache | 135 | return -EINVAL; |
122 | */ | ||
123 | static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec, | ||
124 | u8 reg, u8 value) | ||
125 | { | ||
126 | u8 *cache = codec->reg_cache; | ||
127 | if (reg >= AIC3X_CACHEREGNUM) | 136 | if (reg >= AIC3X_CACHEREGNUM) |
128 | return; | 137 | return -1; |
129 | cache[reg] = value; | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * write to the aic3x register space | ||
134 | */ | ||
135 | static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, | ||
136 | unsigned int value) | ||
137 | { | ||
138 | u8 data[2]; | ||
139 | |||
140 | /* data is | ||
141 | * D15..D8 aic3x register offset | ||
142 | * D7...D0 register data | ||
143 | */ | ||
144 | data[0] = reg & 0xff; | ||
145 | data[1] = value & 0xff; | ||
146 | |||
147 | aic3x_write_reg_cache(codec, data[0], data[1]); | ||
148 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
149 | return 0; | ||
150 | else | ||
151 | return -EIO; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * read from the aic3x register space | ||
156 | */ | ||
157 | static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, | ||
158 | u8 *value) | ||
159 | { | ||
160 | *value = reg & 0xff; | ||
161 | 138 | ||
162 | value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]); | 139 | *value = codec->hw_read(codec, reg); |
140 | cache[reg] = *value; | ||
163 | 141 | ||
164 | aic3x_write_reg_cache(codec, reg, *value); | ||
165 | return 0; | 142 | return 0; |
166 | } | 143 | } |
167 | 144 | ||
@@ -286,64 +263,102 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
286 | SOC_DOUBLE_R_TLV("PCM Playback Volume", | 263 | SOC_DOUBLE_R_TLV("PCM Playback Volume", |
287 | LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv), | 264 | LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv), |
288 | 265 | ||
266 | /* | ||
267 | * Output controls that map to output mixer switches. Note these are | ||
268 | * only for swapped L-to-R and R-to-L routes. See below stereo controls | ||
269 | * for direct L-to-L and R-to-R routes. | ||
270 | */ | ||
271 | SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume", | ||
272 | LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), | ||
273 | SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume", | ||
274 | PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), | ||
275 | SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume", | ||
276 | DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), | ||
277 | |||
278 | SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume", | ||
279 | LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), | ||
280 | SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume", | ||
281 | PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), | ||
282 | SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume", | ||
283 | DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), | ||
284 | |||
285 | SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume", | ||
286 | LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), | ||
287 | SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume", | ||
288 | PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), | ||
289 | SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume", | ||
290 | DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), | ||
291 | |||
292 | SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume", | ||
293 | LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), | ||
294 | SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume", | ||
295 | PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), | ||
296 | SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume", | ||
297 | DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), | ||
298 | |||
299 | SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume", | ||
300 | LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), | ||
301 | SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume", | ||
302 | PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), | ||
303 | SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume", | ||
304 | DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), | ||
305 | |||
306 | SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume", | ||
307 | LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), | ||
308 | SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume", | ||
309 | PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), | ||
310 | SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume", | ||
311 | DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), | ||
312 | |||
313 | /* Stereo output controls for direct L-to-L and R-to-R routes */ | ||
314 | SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume", | ||
315 | LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL, | ||
316 | 0, 118, 1, output_stage_tlv), | ||
317 | SOC_DOUBLE_R_TLV("Line PGA Bypass Volume", | ||
318 | PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL, | ||
319 | 0, 118, 1, output_stage_tlv), | ||
289 | SOC_DOUBLE_R_TLV("Line DAC Playback Volume", | 320 | SOC_DOUBLE_R_TLV("Line DAC Playback Volume", |
290 | DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, | 321 | DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, |
291 | 0, 118, 1, output_stage_tlv), | 322 | 0, 118, 1, output_stage_tlv), |
292 | SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0), | 323 | |
293 | SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0), | 324 | SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume", |
294 | SOC_DOUBLE_R_TLV("LineL DAC Playback Volume", | 325 | LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL, |
295 | DACL1_2_LLOPM_VOL, DACR1_2_LLOPM_VOL, | ||
296 | 0, 118, 1, output_stage_tlv), | ||
297 | SOC_SINGLE_TLV("LineL Left PGA Bypass Playback Volume", | ||
298 | PGAL_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv), | ||
299 | SOC_SINGLE_TLV("LineR Right PGA Bypass Playback Volume", | ||
300 | PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv), | ||
301 | SOC_DOUBLE_R_TLV("LineL Line2 Bypass Playback Volume", | ||
302 | LINE2L_2_LLOPM_VOL, LINE2R_2_LLOPM_VOL, | ||
303 | 0, 118, 1, output_stage_tlv), | 326 | 0, 118, 1, output_stage_tlv), |
304 | SOC_DOUBLE_R_TLV("LineR Line2 Bypass Playback Volume", | 327 | SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume", |
305 | LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL, | 328 | PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL, |
306 | 0, 118, 1, output_stage_tlv), | 329 | 0, 118, 1, output_stage_tlv), |
307 | |||
308 | SOC_DOUBLE_R_TLV("Mono DAC Playback Volume", | 330 | SOC_DOUBLE_R_TLV("Mono DAC Playback Volume", |
309 | DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL, | 331 | DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL, |
310 | 0, 118, 1, output_stage_tlv), | 332 | 0, 118, 1, output_stage_tlv), |
311 | SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), | 333 | |
312 | SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume", | 334 | SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume", |
313 | PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL, | 335 | LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, |
314 | 0, 118, 1, output_stage_tlv), | 336 | 0, 118, 1, output_stage_tlv), |
315 | SOC_DOUBLE_R_TLV("Mono Line2 Bypass Playback Volume", | 337 | SOC_DOUBLE_R_TLV("HP PGA Bypass Volume", |
316 | LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL, | 338 | PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL, |
317 | 0, 118, 1, output_stage_tlv), | 339 | 0, 118, 1, output_stage_tlv), |
318 | |||
319 | SOC_DOUBLE_R_TLV("HP DAC Playback Volume", | 340 | SOC_DOUBLE_R_TLV("HP DAC Playback Volume", |
320 | DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL, | 341 | DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL, |
321 | 0, 118, 1, output_stage_tlv), | 342 | 0, 118, 1, output_stage_tlv), |
322 | SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, | 343 | |
323 | 0x01, 0), | 344 | SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume", |
324 | SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume", | 345 | LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, |
325 | PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL, | ||
326 | 0, 118, 1, output_stage_tlv), | 346 | 0, 118, 1, output_stage_tlv), |
327 | SOC_SINGLE_TLV("HPL PGA Bypass Playback Volume", | 347 | SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume", |
328 | PGAL_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv), | 348 | PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL, |
329 | SOC_SINGLE_TLV("HPR PGA Bypass Playback Volume", | ||
330 | PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv), | ||
331 | SOC_DOUBLE_R_TLV("HP Line2 Bypass Playback Volume", | ||
332 | LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, | ||
333 | 0, 118, 1, output_stage_tlv), | 349 | 0, 118, 1, output_stage_tlv), |
334 | |||
335 | SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume", | 350 | SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume", |
336 | DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL, | 351 | DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL, |
337 | 0, 118, 1, output_stage_tlv), | 352 | 0, 118, 1, output_stage_tlv), |
338 | SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, | 353 | |
354 | /* Output pin mute controls */ | ||
355 | SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, | ||
356 | 0x01, 0), | ||
357 | SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), | ||
358 | SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, | ||
359 | 0x01, 0), | ||
360 | SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, | ||
339 | 0x01, 0), | 361 | 0x01, 0), |
340 | SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume", | ||
341 | PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv), | ||
342 | SOC_SINGLE_TLV("HPRCOM PGA Bypass Playback Volume", | ||
343 | PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv), | ||
344 | SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Playback Volume", | ||
345 | LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, | ||
346 | 0, 118, 1, output_stage_tlv), | ||
347 | 362 | ||
348 | /* | 363 | /* |
349 | * Note: enable Automatic input Gain Controller with care. It can | 364 | * Note: enable Automatic input Gain Controller with care. It can |
@@ -359,6 +374,14 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
359 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), | 374 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), |
360 | }; | 375 | }; |
361 | 376 | ||
377 | /* | ||
378 | * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps | ||
379 | */ | ||
380 | static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0); | ||
381 | |||
382 | static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl = | ||
383 | SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv); | ||
384 | |||
362 | /* Left DAC Mux */ | 385 | /* Left DAC Mux */ |
363 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = | 386 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = |
364 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); | 387 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); |
@@ -375,22 +398,74 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]); | |||
375 | static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = | 398 | static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = |
376 | SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); | 399 | SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); |
377 | 400 | ||
378 | /* Left DAC_L1 Mixer */ | 401 | /* Left Line Mixer */ |
379 | static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { | 402 | static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = { |
380 | SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), | 403 | SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), |
381 | SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0), | 404 | SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), |
382 | SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), | 405 | SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), |
383 | SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), | 406 | SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), |
384 | SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), | 407 | SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0), |
408 | SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0), | ||
409 | }; | ||
410 | |||
411 | /* Right Line Mixer */ | ||
412 | static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = { | ||
413 | SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), | ||
414 | SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0), | ||
415 | SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0), | ||
416 | SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), | ||
417 | SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), | ||
418 | SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), | ||
419 | }; | ||
420 | |||
421 | /* Mono Mixer */ | ||
422 | static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = { | ||
423 | SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), | ||
424 | SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), | ||
425 | SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), | ||
426 | SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), | ||
427 | SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), | ||
428 | SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), | ||
429 | }; | ||
430 | |||
431 | /* Left HP Mixer */ | ||
432 | static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = { | ||
433 | SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), | ||
434 | SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), | ||
435 | SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), | ||
436 | SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0), | ||
437 | SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0), | ||
438 | SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0), | ||
439 | }; | ||
440 | |||
441 | /* Right HP Mixer */ | ||
442 | static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = { | ||
443 | SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0), | ||
444 | SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0), | ||
445 | SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0), | ||
446 | SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), | ||
447 | SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), | ||
448 | SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), | ||
449 | }; | ||
450 | |||
451 | /* Left HPCOM Mixer */ | ||
452 | static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = { | ||
453 | SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), | ||
454 | SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), | ||
455 | SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), | ||
456 | SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0), | ||
457 | SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0), | ||
458 | SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0), | ||
385 | }; | 459 | }; |
386 | 460 | ||
387 | /* Right DAC_R1 Mixer */ | 461 | /* Right HPCOM Mixer */ |
388 | static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { | 462 | static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = { |
389 | SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0), | 463 | SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0), |
390 | SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), | 464 | SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0), |
391 | SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), | 465 | SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0), |
392 | SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), | 466 | SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), |
393 | SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), | 467 | SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), |
468 | SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), | ||
394 | }; | 469 | }; |
395 | 470 | ||
396 | /* Left PGA Mixer */ | 471 | /* Left PGA Mixer */ |
@@ -427,54 +502,11 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]); | |||
427 | static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = | 502 | static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = |
428 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); | 503 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); |
429 | 504 | ||
430 | /* Left PGA Bypass Mixer */ | ||
431 | static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = { | ||
432 | SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), | ||
433 | SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0), | ||
434 | SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), | ||
435 | SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), | ||
436 | SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0), | ||
437 | SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), | ||
438 | SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0), | ||
439 | }; | ||
440 | |||
441 | /* Right PGA Bypass Mixer */ | ||
442 | static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = { | ||
443 | SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0), | ||
444 | SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), | ||
445 | SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), | ||
446 | SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0), | ||
447 | SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), | ||
448 | SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0), | ||
449 | SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), | ||
450 | }; | ||
451 | |||
452 | /* Left Line2 Bypass Mixer */ | ||
453 | static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = { | ||
454 | SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), | ||
455 | SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), | ||
456 | SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), | ||
457 | SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), | ||
458 | SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), | ||
459 | }; | ||
460 | |||
461 | /* Right Line2 Bypass Mixer */ | ||
462 | static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = { | ||
463 | SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), | ||
464 | SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), | ||
465 | SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), | ||
466 | SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), | ||
467 | SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), | ||
468 | }; | ||
469 | |||
470 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | 505 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { |
471 | /* Left DAC to Left Outputs */ | 506 | /* Left DAC to Left Outputs */ |
472 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0), | 507 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0), |
473 | SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0, | 508 | SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0, |
474 | &aic3x_left_dac_mux_controls), | 509 | &aic3x_left_dac_mux_controls), |
475 | SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0, | ||
476 | &aic3x_left_dac_mixer_controls[0], | ||
477 | ARRAY_SIZE(aic3x_left_dac_mixer_controls)), | ||
478 | SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0, | 510 | SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0, |
479 | &aic3x_left_hpcom_mux_controls), | 511 | &aic3x_left_hpcom_mux_controls), |
480 | SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0), | 512 | SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0), |
@@ -485,9 +517,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
485 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0), | 517 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0), |
486 | SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0, | 518 | SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0, |
487 | &aic3x_right_dac_mux_controls), | 519 | &aic3x_right_dac_mux_controls), |
488 | SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0, | ||
489 | &aic3x_right_dac_mixer_controls[0], | ||
490 | ARRAY_SIZE(aic3x_right_dac_mixer_controls)), | ||
491 | SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0, | 520 | SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0, |
492 | &aic3x_right_hpcom_mux_controls), | 521 | &aic3x_right_hpcom_mux_controls), |
493 | SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0), | 522 | SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0), |
@@ -551,25 +580,28 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
551 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", | 580 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", |
552 | MICBIAS_CTRL, 6, 3, 3, 0), | 581 | MICBIAS_CTRL, 6, 3, 3, 0), |
553 | 582 | ||
554 | /* Left PGA to Left Output bypass */ | 583 | /* Output mixers */ |
555 | SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, | 584 | SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0, |
556 | &aic3x_left_pga_bp_mixer_controls[0], | 585 | &aic3x_left_line_mixer_controls[0], |
557 | ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)), | 586 | ARRAY_SIZE(aic3x_left_line_mixer_controls)), |
558 | 587 | SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0, | |
559 | /* Right PGA to Right Output bypass */ | 588 | &aic3x_right_line_mixer_controls[0], |
560 | SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, | 589 | ARRAY_SIZE(aic3x_right_line_mixer_controls)), |
561 | &aic3x_right_pga_bp_mixer_controls[0], | 590 | SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, |
562 | ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)), | 591 | &aic3x_mono_mixer_controls[0], |
563 | 592 | ARRAY_SIZE(aic3x_mono_mixer_controls)), | |
564 | /* Left Line2 to Left Output bypass */ | 593 | SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0, |
565 | SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0, | 594 | &aic3x_left_hp_mixer_controls[0], |
566 | &aic3x_left_line2_bp_mixer_controls[0], | 595 | ARRAY_SIZE(aic3x_left_hp_mixer_controls)), |
567 | ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)), | 596 | SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0, |
568 | 597 | &aic3x_right_hp_mixer_controls[0], | |
569 | /* Right Line2 to Right Output bypass */ | 598 | ARRAY_SIZE(aic3x_right_hp_mixer_controls)), |
570 | SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0, | 599 | SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0, |
571 | &aic3x_right_line2_bp_mixer_controls[0], | 600 | &aic3x_left_hpcom_mixer_controls[0], |
572 | ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)), | 601 | ARRAY_SIZE(aic3x_left_hpcom_mixer_controls)), |
602 | SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0, | ||
603 | &aic3x_right_hpcom_mixer_controls[0], | ||
604 | ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)), | ||
573 | 605 | ||
574 | SND_SOC_DAPM_OUTPUT("LLOUT"), | 606 | SND_SOC_DAPM_OUTPUT("LLOUT"), |
575 | SND_SOC_DAPM_OUTPUT("RLOUT"), | 607 | SND_SOC_DAPM_OUTPUT("RLOUT"), |
@@ -585,69 +617,26 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
585 | SND_SOC_DAPM_INPUT("LINE1R"), | 617 | SND_SOC_DAPM_INPUT("LINE1R"), |
586 | SND_SOC_DAPM_INPUT("LINE2L"), | 618 | SND_SOC_DAPM_INPUT("LINE2L"), |
587 | SND_SOC_DAPM_INPUT("LINE2R"), | 619 | SND_SOC_DAPM_INPUT("LINE2R"), |
588 | }; | ||
589 | |||
590 | static const struct snd_soc_dapm_route intercon[] = { | ||
591 | /* Left Output */ | ||
592 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, | ||
593 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, | ||
594 | {"Left DAC Mux", "DAC_L3", "Left DAC"}, | ||
595 | |||
596 | {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"}, | ||
597 | {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"}, | ||
598 | {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"}, | ||
599 | {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"}, | ||
600 | {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"}, | ||
601 | {"Left Line Out", NULL, "Left DAC Mux"}, | ||
602 | {"Left HP Out", NULL, "Left DAC Mux"}, | ||
603 | |||
604 | {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"}, | ||
605 | {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"}, | ||
606 | {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"}, | ||
607 | |||
608 | {"Left Line Out", NULL, "Left DAC_L1 Mixer"}, | ||
609 | {"Mono Out", NULL, "Left DAC_L1 Mixer"}, | ||
610 | {"Left HP Out", NULL, "Left DAC_L1 Mixer"}, | ||
611 | {"Left HP Com", NULL, "Left HPCOM Mux"}, | ||
612 | |||
613 | {"LLOUT", NULL, "Left Line Out"}, | ||
614 | {"LLOUT", NULL, "Left Line Out"}, | ||
615 | {"HPLOUT", NULL, "Left HP Out"}, | ||
616 | {"HPLCOM", NULL, "Left HP Com"}, | ||
617 | |||
618 | /* Right Output */ | ||
619 | {"Right DAC Mux", "DAC_R1", "Right DAC"}, | ||
620 | {"Right DAC Mux", "DAC_R2", "Right DAC"}, | ||
621 | {"Right DAC Mux", "DAC_R3", "Right DAC"}, | ||
622 | 620 | ||
623 | {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"}, | 621 | /* |
624 | {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"}, | 622 | * Virtual output pin to detection block inside codec. This can be |
625 | {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"}, | 623 | * used to keep codec bias on if gpio or detection features are needed. |
626 | {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"}, | 624 | * Force pin on or construct a path with an input jack and mic bias |
627 | {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"}, | 625 | * widgets. |
628 | {"Right Line Out", NULL, "Right DAC Mux"}, | 626 | */ |
629 | {"Right HP Out", NULL, "Right DAC Mux"}, | 627 | SND_SOC_DAPM_OUTPUT("Detection"), |
628 | }; | ||
630 | 629 | ||
631 | {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"}, | 630 | static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = { |
632 | {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"}, | 631 | /* Class-D outputs */ |
633 | {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"}, | 632 | SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0), |
634 | {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"}, | 633 | SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0), |
635 | {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"}, | ||
636 | 634 | ||
637 | {"Right Line Out", NULL, "Right DAC_R1 Mixer"}, | 635 | SND_SOC_DAPM_OUTPUT("SPOP"), |
638 | {"Mono Out", NULL, "Right DAC_R1 Mixer"}, | 636 | SND_SOC_DAPM_OUTPUT("SPOM"), |
639 | {"Right HP Out", NULL, "Right DAC_R1 Mixer"}, | 637 | }; |
640 | {"Right HP Com", NULL, "Right HPCOM Mux"}, | ||
641 | |||
642 | {"RLOUT", NULL, "Right Line Out"}, | ||
643 | {"RLOUT", NULL, "Right Line Out"}, | ||
644 | {"HPROUT", NULL, "Right HP Out"}, | ||
645 | {"HPRCOM", NULL, "Right HP Com"}, | ||
646 | |||
647 | /* Mono Output */ | ||
648 | {"MONO_LOUT", NULL, "Mono Out"}, | ||
649 | {"MONO_LOUT", NULL, "Mono Out"}, | ||
650 | 638 | ||
639 | static const struct snd_soc_dapm_route intercon[] = { | ||
651 | /* Left Input */ | 640 | /* Left Input */ |
652 | {"Left Line1L Mux", "single-ended", "LINE1L"}, | 641 | {"Left Line1L Mux", "single-ended", "LINE1L"}, |
653 | {"Left Line1L Mux", "differential", "LINE1L"}, | 642 | {"Left Line1L Mux", "differential", "LINE1L"}, |
@@ -680,74 +669,6 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
680 | {"Right ADC", NULL, "Right PGA Mixer"}, | 669 | {"Right ADC", NULL, "Right PGA Mixer"}, |
681 | {"Right ADC", NULL, "GPIO1 dmic modclk"}, | 670 | {"Right ADC", NULL, "GPIO1 dmic modclk"}, |
682 | 671 | ||
683 | /* Left PGA Bypass */ | ||
684 | {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"}, | ||
685 | {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"}, | ||
686 | {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"}, | ||
687 | {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"}, | ||
688 | {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"}, | ||
689 | {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"}, | ||
690 | {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"}, | ||
691 | |||
692 | {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"}, | ||
693 | {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"}, | ||
694 | {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"}, | ||
695 | |||
696 | {"Left Line Out", NULL, "Left PGA Bypass Mixer"}, | ||
697 | {"Mono Out", NULL, "Left PGA Bypass Mixer"}, | ||
698 | {"Left HP Out", NULL, "Left PGA Bypass Mixer"}, | ||
699 | |||
700 | /* Right PGA Bypass */ | ||
701 | {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"}, | ||
702 | {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"}, | ||
703 | {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"}, | ||
704 | {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"}, | ||
705 | {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"}, | ||
706 | {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"}, | ||
707 | {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"}, | ||
708 | |||
709 | {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"}, | ||
710 | {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"}, | ||
711 | {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"}, | ||
712 | {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"}, | ||
713 | {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"}, | ||
714 | |||
715 | {"Right Line Out", NULL, "Right PGA Bypass Mixer"}, | ||
716 | {"Mono Out", NULL, "Right PGA Bypass Mixer"}, | ||
717 | {"Right HP Out", NULL, "Right PGA Bypass Mixer"}, | ||
718 | |||
719 | /* Left Line2 Bypass */ | ||
720 | {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"}, | ||
721 | {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"}, | ||
722 | {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"}, | ||
723 | {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"}, | ||
724 | {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"}, | ||
725 | |||
726 | {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"}, | ||
727 | {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"}, | ||
728 | {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"}, | ||
729 | |||
730 | {"Left Line Out", NULL, "Left Line2 Bypass Mixer"}, | ||
731 | {"Mono Out", NULL, "Left Line2 Bypass Mixer"}, | ||
732 | {"Left HP Out", NULL, "Left Line2 Bypass Mixer"}, | ||
733 | |||
734 | /* Right Line2 Bypass */ | ||
735 | {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"}, | ||
736 | {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"}, | ||
737 | {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"}, | ||
738 | {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"}, | ||
739 | {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"}, | ||
740 | |||
741 | {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"}, | ||
742 | {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"}, | ||
743 | {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"}, | ||
744 | {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"}, | ||
745 | {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"}, | ||
746 | |||
747 | {"Right Line Out", NULL, "Right Line2 Bypass Mixer"}, | ||
748 | {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, | ||
749 | {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, | ||
750 | |||
751 | /* | 672 | /* |
752 | * Logical path between digital mic enable and GPIO1 modulator clock | 673 | * Logical path between digital mic enable and GPIO1 modulator clock |
753 | * output function | 674 | * output function |
@@ -755,16 +676,131 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
755 | {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, | 676 | {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, |
756 | {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, | 677 | {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, |
757 | {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, | 678 | {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, |
679 | |||
680 | /* Left DAC Output */ | ||
681 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, | ||
682 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, | ||
683 | {"Left DAC Mux", "DAC_L3", "Left DAC"}, | ||
684 | |||
685 | /* Right DAC Output */ | ||
686 | {"Right DAC Mux", "DAC_R1", "Right DAC"}, | ||
687 | {"Right DAC Mux", "DAC_R2", "Right DAC"}, | ||
688 | {"Right DAC Mux", "DAC_R3", "Right DAC"}, | ||
689 | |||
690 | /* Left Line Output */ | ||
691 | {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, | ||
692 | {"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, | ||
693 | {"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"}, | ||
694 | {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, | ||
695 | {"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, | ||
696 | {"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"}, | ||
697 | |||
698 | {"Left Line Out", NULL, "Left Line Mixer"}, | ||
699 | {"Left Line Out", NULL, "Left DAC Mux"}, | ||
700 | {"LLOUT", NULL, "Left Line Out"}, | ||
701 | |||
702 | /* Right Line Output */ | ||
703 | {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, | ||
704 | {"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, | ||
705 | {"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"}, | ||
706 | {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, | ||
707 | {"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, | ||
708 | {"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"}, | ||
709 | |||
710 | {"Right Line Out", NULL, "Right Line Mixer"}, | ||
711 | {"Right Line Out", NULL, "Right DAC Mux"}, | ||
712 | {"RLOUT", NULL, "Right Line Out"}, | ||
713 | |||
714 | /* Mono Output */ | ||
715 | {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, | ||
716 | {"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, | ||
717 | {"Mono Mixer", "DACL1 Switch", "Left DAC Mux"}, | ||
718 | {"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, | ||
719 | {"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, | ||
720 | {"Mono Mixer", "DACR1 Switch", "Right DAC Mux"}, | ||
721 | |||
722 | {"Mono Out", NULL, "Mono Mixer"}, | ||
723 | {"MONO_LOUT", NULL, "Mono Out"}, | ||
724 | |||
725 | /* Left HP Output */ | ||
726 | {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, | ||
727 | {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, | ||
728 | {"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"}, | ||
729 | {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, | ||
730 | {"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, | ||
731 | {"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"}, | ||
732 | |||
733 | {"Left HP Out", NULL, "Left HP Mixer"}, | ||
734 | {"Left HP Out", NULL, "Left DAC Mux"}, | ||
735 | {"HPLOUT", NULL, "Left HP Out"}, | ||
736 | |||
737 | /* Right HP Output */ | ||
738 | {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, | ||
739 | {"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, | ||
740 | {"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"}, | ||
741 | {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, | ||
742 | {"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, | ||
743 | {"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"}, | ||
744 | |||
745 | {"Right HP Out", NULL, "Right HP Mixer"}, | ||
746 | {"Right HP Out", NULL, "Right DAC Mux"}, | ||
747 | {"HPROUT", NULL, "Right HP Out"}, | ||
748 | |||
749 | /* Left HPCOM Output */ | ||
750 | {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, | ||
751 | {"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, | ||
752 | {"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"}, | ||
753 | {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, | ||
754 | {"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, | ||
755 | {"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"}, | ||
756 | |||
757 | {"Left HPCOM Mux", "differential of HPLOUT", "Left HP Mixer"}, | ||
758 | {"Left HPCOM Mux", "constant VCM", "Left HPCOM Mixer"}, | ||
759 | {"Left HPCOM Mux", "single-ended", "Left HPCOM Mixer"}, | ||
760 | {"Left HP Com", NULL, "Left HPCOM Mux"}, | ||
761 | {"HPLCOM", NULL, "Left HP Com"}, | ||
762 | |||
763 | /* Right HPCOM Output */ | ||
764 | {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"}, | ||
765 | {"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"}, | ||
766 | {"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"}, | ||
767 | {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"}, | ||
768 | {"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"}, | ||
769 | {"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"}, | ||
770 | |||
771 | {"Right HPCOM Mux", "differential of HPROUT", "Right HP Mixer"}, | ||
772 | {"Right HPCOM Mux", "constant VCM", "Right HPCOM Mixer"}, | ||
773 | {"Right HPCOM Mux", "single-ended", "Right HPCOM Mixer"}, | ||
774 | {"Right HPCOM Mux", "differential of HPLCOM", "Left HPCOM Mixer"}, | ||
775 | {"Right HPCOM Mux", "external feedback", "Right HPCOM Mixer"}, | ||
776 | {"Right HP Com", NULL, "Right HPCOM Mux"}, | ||
777 | {"HPRCOM", NULL, "Right HP Com"}, | ||
778 | }; | ||
779 | |||
780 | static const struct snd_soc_dapm_route intercon_3007[] = { | ||
781 | /* Class-D outputs */ | ||
782 | {"Left Class-D Out", NULL, "Left Line Out"}, | ||
783 | {"Right Class-D Out", NULL, "Left Line Out"}, | ||
784 | {"SPOP", NULL, "Left Class-D Out"}, | ||
785 | {"SPOM", NULL, "Right Class-D Out"}, | ||
758 | }; | 786 | }; |
759 | 787 | ||
760 | static int aic3x_add_widgets(struct snd_soc_codec *codec) | 788 | static int aic3x_add_widgets(struct snd_soc_codec *codec) |
761 | { | 789 | { |
790 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | ||
791 | |||
762 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, | 792 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, |
763 | ARRAY_SIZE(aic3x_dapm_widgets)); | 793 | ARRAY_SIZE(aic3x_dapm_widgets)); |
764 | 794 | ||
765 | /* set up audio path interconnects */ | 795 | /* set up audio path interconnects */ |
766 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | 796 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
767 | 797 | ||
798 | if (aic3x->model == AIC3X_MODEL_3007) { | ||
799 | snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets, | ||
800 | ARRAY_SIZE(aic3007_dapm_widgets)); | ||
801 | snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007)); | ||
802 | } | ||
803 | |||
768 | return 0; | 804 | return 0; |
769 | } | 805 | } |
770 | 806 | ||
@@ -773,8 +809,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
773 | struct snd_soc_dai *dai) | 809 | struct snd_soc_dai *dai) |
774 | { | 810 | { |
775 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 811 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
776 | struct snd_soc_device *socdev = rtd->socdev; | 812 | struct snd_soc_codec *codec =rtd->codec; |
777 | struct snd_soc_codec *codec = socdev->card->codec; | ||
778 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 813 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
779 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; | 814 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; |
780 | u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; | 815 | u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; |
@@ -783,8 +818,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
783 | int clk; | 818 | int clk; |
784 | 819 | ||
785 | /* select data word length */ | 820 | /* select data word length */ |
786 | data = | 821 | data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); |
787 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); | ||
788 | switch (params_format(params)) { | 822 | switch (params_format(params)) { |
789 | case SNDRV_PCM_FORMAT_S16_LE: | 823 | case SNDRV_PCM_FORMAT_S16_LE: |
790 | break; | 824 | break; |
@@ -798,7 +832,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
798 | data |= (0x03 << 4); | 832 | data |= (0x03 << 4); |
799 | break; | 833 | break; |
800 | } | 834 | } |
801 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | 835 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, data); |
802 | 836 | ||
803 | /* Fsref can be 44100 or 48000 */ | 837 | /* Fsref can be 44100 or 48000 */ |
804 | fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; | 838 | fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; |
@@ -813,17 +847,17 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
813 | 847 | ||
814 | if (bypass_pll) { | 848 | if (bypass_pll) { |
815 | pll_q &= 0xf; | 849 | pll_q &= 0xf; |
816 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); | 850 | snd_soc_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); |
817 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); | 851 | snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); |
818 | /* disable PLL if it is bypassed */ | 852 | /* disable PLL if it is bypassed */ |
819 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 853 | reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); |
820 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); | 854 | snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE); |
821 | 855 | ||
822 | } else { | 856 | } else { |
823 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); | 857 | snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); |
824 | /* enable PLL when it is used */ | 858 | /* enable PLL when it is used */ |
825 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 859 | reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); |
826 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE); | 860 | snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE); |
827 | } | 861 | } |
828 | 862 | ||
829 | /* Route Left DAC to left channel input and | 863 | /* Route Left DAC to left channel input and |
@@ -832,7 +866,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
832 | data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; | 866 | data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; |
833 | if (params_rate(params) >= 64000) | 867 | if (params_rate(params) >= 64000) |
834 | data |= DUAL_RATE_MODE; | 868 | data |= DUAL_RATE_MODE; |
835 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); | 869 | snd_soc_write(codec, AIC3X_CODEC_DATAPATH_REG, data); |
836 | 870 | ||
837 | /* codec sample rate select */ | 871 | /* codec sample rate select */ |
838 | data = (fsref * 20) / params_rate(params); | 872 | data = (fsref * 20) / params_rate(params); |
@@ -841,7 +875,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
841 | data /= 5; | 875 | data /= 5; |
842 | data -= 2; | 876 | data -= 2; |
843 | data |= (data << 4); | 877 | data |= (data << 4); |
844 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); | 878 | snd_soc_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); |
845 | 879 | ||
846 | if (bypass_pll) | 880 | if (bypass_pll) |
847 | return 0; | 881 | return 0; |
@@ -910,13 +944,16 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
910 | } | 944 | } |
911 | 945 | ||
912 | found: | 946 | found: |
913 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 947 | data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); |
914 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); | 948 | snd_soc_write(codec, AIC3X_PLL_PROGA_REG, |
915 | aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); | 949 | data | (pll_p << PLLP_SHIFT)); |
916 | aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); | 950 | snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, |
917 | aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT); | 951 | pll_r << PLLR_SHIFT); |
918 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, | 952 | snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); |
919 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); | 953 | snd_soc_write(codec, AIC3X_PLL_PROGC_REG, |
954 | (pll_d >> 6) << PLLD_MSB_SHIFT); | ||
955 | snd_soc_write(codec, AIC3X_PLL_PROGD_REG, | ||
956 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); | ||
920 | 957 | ||
921 | return 0; | 958 | return 0; |
922 | } | 959 | } |
@@ -924,15 +961,15 @@ found: | |||
924 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) | 961 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) |
925 | { | 962 | { |
926 | struct snd_soc_codec *codec = dai->codec; | 963 | struct snd_soc_codec *codec = dai->codec; |
927 | u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; | 964 | u8 ldac_reg = snd_soc_read(codec, LDAC_VOL) & ~MUTE_ON; |
928 | u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON; | 965 | u8 rdac_reg = snd_soc_read(codec, RDAC_VOL) & ~MUTE_ON; |
929 | 966 | ||
930 | if (mute) { | 967 | if (mute) { |
931 | aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); | 968 | snd_soc_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); |
932 | aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); | 969 | snd_soc_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); |
933 | } else { | 970 | } else { |
934 | aic3x_write(codec, LDAC_VOL, ldac_reg); | 971 | snd_soc_write(codec, LDAC_VOL, ldac_reg); |
935 | aic3x_write(codec, RDAC_VOL, rdac_reg); | 972 | snd_soc_write(codec, RDAC_VOL, rdac_reg); |
936 | } | 973 | } |
937 | 974 | ||
938 | return 0; | 975 | return 0; |
@@ -956,8 +993,8 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
956 | u8 iface_areg, iface_breg; | 993 | u8 iface_areg, iface_breg; |
957 | int delay = 0; | 994 | int delay = 0; |
958 | 995 | ||
959 | iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; | 996 | iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; |
960 | iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; | 997 | iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; |
961 | 998 | ||
962 | /* set master/slave audio interface */ | 999 | /* set master/slave audio interface */ |
963 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 1000 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
@@ -996,13 +1033,98 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
996 | } | 1033 | } |
997 | 1034 | ||
998 | /* set iface */ | 1035 | /* set iface */ |
999 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); | 1036 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); |
1000 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); | 1037 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); |
1001 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay); | 1038 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay); |
1039 | |||
1040 | return 0; | ||
1041 | } | ||
1042 | |||
1043 | static int aic3x_init_3007(struct snd_soc_codec *codec) | ||
1044 | { | ||
1045 | u8 tmp1, tmp2, *cache = codec->reg_cache; | ||
1046 | |||
1047 | /* | ||
1048 | * There is no need to cache writes to undocumented page 0xD but | ||
1049 | * respective page 0 register cache entries must be preserved | ||
1050 | */ | ||
1051 | tmp1 = cache[0xD]; | ||
1052 | tmp2 = cache[0x8]; | ||
1053 | /* Class-D speaker driver init; datasheet p. 46 */ | ||
1054 | snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D); | ||
1055 | snd_soc_write(codec, 0xD, 0x0D); | ||
1056 | snd_soc_write(codec, 0x8, 0x5C); | ||
1057 | snd_soc_write(codec, 0x8, 0x5D); | ||
1058 | snd_soc_write(codec, 0x8, 0x5C); | ||
1059 | snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00); | ||
1060 | cache[0xD] = tmp1; | ||
1061 | cache[0x8] = tmp2; | ||
1002 | 1062 | ||
1003 | return 0; | 1063 | return 0; |
1004 | } | 1064 | } |
1005 | 1065 | ||
1066 | static int aic3x_regulator_event(struct notifier_block *nb, | ||
1067 | unsigned long event, void *data) | ||
1068 | { | ||
1069 | struct aic3x_disable_nb *disable_nb = | ||
1070 | container_of(nb, struct aic3x_disable_nb, nb); | ||
1071 | struct aic3x_priv *aic3x = disable_nb->aic3x; | ||
1072 | |||
1073 | if (event & REGULATOR_EVENT_DISABLE) { | ||
1074 | /* | ||
1075 | * Put codec to reset and require cache sync as at least one | ||
1076 | * of the supplies was disabled | ||
1077 | */ | ||
1078 | if (aic3x->gpio_reset >= 0) | ||
1079 | gpio_set_value(aic3x->gpio_reset, 0); | ||
1080 | aic3x->codec->cache_sync = 1; | ||
1081 | } | ||
1082 | |||
1083 | return 0; | ||
1084 | } | ||
1085 | |||
1086 | static int aic3x_set_power(struct snd_soc_codec *codec, int power) | ||
1087 | { | ||
1088 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | ||
1089 | int i, ret; | ||
1090 | u8 *cache = codec->reg_cache; | ||
1091 | |||
1092 | if (power) { | ||
1093 | ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), | ||
1094 | aic3x->supplies); | ||
1095 | if (ret) | ||
1096 | goto out; | ||
1097 | aic3x->power = 1; | ||
1098 | /* | ||
1099 | * Reset release and cache sync is necessary only if some | ||
1100 | * supply was off or if there were cached writes | ||
1101 | */ | ||
1102 | if (!codec->cache_sync) | ||
1103 | goto out; | ||
1104 | |||
1105 | if (aic3x->gpio_reset >= 0) { | ||
1106 | udelay(1); | ||
1107 | gpio_set_value(aic3x->gpio_reset, 1); | ||
1108 | } | ||
1109 | |||
1110 | /* Sync reg_cache with the hardware */ | ||
1111 | codec->cache_only = 0; | ||
1112 | for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) | ||
1113 | snd_soc_write(codec, i, cache[i]); | ||
1114 | if (aic3x->model == AIC3X_MODEL_3007) | ||
1115 | aic3x_init_3007(codec); | ||
1116 | codec->cache_sync = 0; | ||
1117 | } else { | ||
1118 | aic3x->power = 0; | ||
1119 | /* HW writes are needless when bias is off */ | ||
1120 | codec->cache_only = 1; | ||
1121 | ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), | ||
1122 | aic3x->supplies); | ||
1123 | } | ||
1124 | out: | ||
1125 | return ret; | ||
1126 | } | ||
1127 | |||
1006 | static int aic3x_set_bias_level(struct snd_soc_codec *codec, | 1128 | static int aic3x_set_bias_level(struct snd_soc_codec *codec, |
1007 | enum snd_soc_bias_level level) | 1129 | enum snd_soc_bias_level level) |
1008 | { | 1130 | { |
@@ -1013,23 +1135,29 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1013 | case SND_SOC_BIAS_ON: | 1135 | case SND_SOC_BIAS_ON: |
1014 | break; | 1136 | break; |
1015 | case SND_SOC_BIAS_PREPARE: | 1137 | case SND_SOC_BIAS_PREPARE: |
1016 | if (aic3x->master) { | 1138 | if (codec->bias_level == SND_SOC_BIAS_STANDBY && |
1139 | aic3x->master) { | ||
1017 | /* enable pll */ | 1140 | /* enable pll */ |
1018 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 1141 | reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); |
1019 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, | 1142 | snd_soc_write(codec, AIC3X_PLL_PROGA_REG, |
1020 | reg | PLL_ENABLE); | 1143 | reg | PLL_ENABLE); |
1021 | } | 1144 | } |
1022 | break; | 1145 | break; |
1023 | case SND_SOC_BIAS_STANDBY: | 1146 | case SND_SOC_BIAS_STANDBY: |
1024 | /* fall through and disable pll */ | 1147 | if (!aic3x->power) |
1025 | case SND_SOC_BIAS_OFF: | 1148 | aic3x_set_power(codec, 1); |
1026 | if (aic3x->master) { | 1149 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && |
1150 | aic3x->master) { | ||
1027 | /* disable pll */ | 1151 | /* disable pll */ |
1028 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 1152 | reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG); |
1029 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, | 1153 | snd_soc_write(codec, AIC3X_PLL_PROGA_REG, |
1030 | reg & ~PLL_ENABLE); | 1154 | reg & ~PLL_ENABLE); |
1031 | } | 1155 | } |
1032 | break; | 1156 | break; |
1157 | case SND_SOC_BIAS_OFF: | ||
1158 | if (aic3x->power) | ||
1159 | aic3x_set_power(codec, 0); | ||
1160 | break; | ||
1033 | } | 1161 | } |
1034 | codec->bias_level = level; | 1162 | codec->bias_level = level; |
1035 | 1163 | ||
@@ -1040,8 +1168,8 @@ void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) | |||
1040 | { | 1168 | { |
1041 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; | 1169 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; |
1042 | u8 bit = gpio ? 3: 0; | 1170 | u8 bit = gpio ? 3: 0; |
1043 | u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit); | 1171 | u8 val = snd_soc_read(codec, reg) & ~(1 << bit); |
1044 | aic3x_write(codec, reg, val | (!!state << bit)); | 1172 | snd_soc_write(codec, reg, val | (!!state << bit)); |
1045 | } | 1173 | } |
1046 | EXPORT_SYMBOL_GPL(aic3x_set_gpio); | 1174 | EXPORT_SYMBOL_GPL(aic3x_set_gpio); |
1047 | 1175 | ||
@@ -1070,7 +1198,7 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, | |||
1070 | if (detect & AIC3X_HEADSET_DETECT_MASK) | 1198 | if (detect & AIC3X_HEADSET_DETECT_MASK) |
1071 | val |= AIC3X_HEADSET_DETECT_ENABLED; | 1199 | val |= AIC3X_HEADSET_DETECT_ENABLED; |
1072 | 1200 | ||
1073 | aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); | 1201 | snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); |
1074 | } | 1202 | } |
1075 | EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); | 1203 | EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); |
1076 | 1204 | ||
@@ -1101,8 +1229,8 @@ static struct snd_soc_dai_ops aic3x_dai_ops = { | |||
1101 | .set_fmt = aic3x_set_dai_fmt, | 1229 | .set_fmt = aic3x_set_dai_fmt, |
1102 | }; | 1230 | }; |
1103 | 1231 | ||
1104 | struct snd_soc_dai aic3x_dai = { | 1232 | static struct snd_soc_dai_driver aic3x_dai = { |
1105 | .name = "tlv320aic3x", | 1233 | .name = "tlv320aic3x-hifi", |
1106 | .playback = { | 1234 | .playback = { |
1107 | .stream_name = "Playback", | 1235 | .stream_name = "Playback", |
1108 | .channels_min = 1, | 1236 | .channels_min = 1, |
@@ -1116,34 +1244,18 @@ struct snd_soc_dai aic3x_dai = { | |||
1116 | .rates = AIC3X_RATES, | 1244 | .rates = AIC3X_RATES, |
1117 | .formats = AIC3X_FORMATS,}, | 1245 | .formats = AIC3X_FORMATS,}, |
1118 | .ops = &aic3x_dai_ops, | 1246 | .ops = &aic3x_dai_ops, |
1247 | .symmetric_rates = 1, | ||
1119 | }; | 1248 | }; |
1120 | EXPORT_SYMBOL_GPL(aic3x_dai); | ||
1121 | 1249 | ||
1122 | static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) | 1250 | static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state) |
1123 | { | 1251 | { |
1124 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1125 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1126 | |||
1127 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1252 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1128 | 1253 | ||
1129 | return 0; | 1254 | return 0; |
1130 | } | 1255 | } |
1131 | 1256 | ||
1132 | static int aic3x_resume(struct platform_device *pdev) | 1257 | static int aic3x_resume(struct snd_soc_codec *codec) |
1133 | { | 1258 | { |
1134 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1135 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1136 | int i; | ||
1137 | u8 data[2]; | ||
1138 | u8 *cache = codec->reg_cache; | ||
1139 | |||
1140 | /* Sync reg_cache with the hardware */ | ||
1141 | for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) { | ||
1142 | data[0] = i; | ||
1143 | data[1] = cache[i]; | ||
1144 | codec->hw_write(codec->control_data, data, 2); | ||
1145 | } | ||
1146 | |||
1147 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1259 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1148 | 1260 | ||
1149 | return 0; | 1261 | return 0; |
@@ -1155,152 +1267,203 @@ static int aic3x_resume(struct platform_device *pdev) | |||
1155 | */ | 1267 | */ |
1156 | static int aic3x_init(struct snd_soc_codec *codec) | 1268 | static int aic3x_init(struct snd_soc_codec *codec) |
1157 | { | 1269 | { |
1270 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | ||
1158 | int reg; | 1271 | int reg; |
1159 | 1272 | ||
1160 | mutex_init(&codec->mutex); | 1273 | snd_soc_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); |
1161 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1274 | snd_soc_write(codec, AIC3X_RESET, SOFT_RESET); |
1162 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1163 | |||
1164 | codec->name = "tlv320aic3x"; | ||
1165 | codec->owner = THIS_MODULE; | ||
1166 | codec->read = aic3x_read_reg_cache; | ||
1167 | codec->write = aic3x_write; | ||
1168 | codec->set_bias_level = aic3x_set_bias_level; | ||
1169 | codec->dai = &aic3x_dai; | ||
1170 | codec->num_dai = 1; | ||
1171 | codec->reg_cache_size = ARRAY_SIZE(aic3x_reg); | ||
1172 | codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); | ||
1173 | if (codec->reg_cache == NULL) | ||
1174 | return -ENOMEM; | ||
1175 | |||
1176 | aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); | ||
1177 | aic3x_write(codec, AIC3X_RESET, SOFT_RESET); | ||
1178 | 1275 | ||
1179 | /* DAC default volume and mute */ | 1276 | /* DAC default volume and mute */ |
1180 | aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); | 1277 | snd_soc_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); |
1181 | aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); | 1278 | snd_soc_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); |
1182 | 1279 | ||
1183 | /* DAC to HP default volume and route to Output mixer */ | 1280 | /* DAC to HP default volume and route to Output mixer */ |
1184 | aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); | 1281 | snd_soc_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); |
1185 | aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); | 1282 | snd_soc_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); |
1186 | aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); | 1283 | snd_soc_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); |
1187 | aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); | 1284 | snd_soc_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); |
1188 | /* DAC to Line Out default volume and route to Output mixer */ | 1285 | /* DAC to Line Out default volume and route to Output mixer */ |
1189 | aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | 1286 | snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); |
1190 | aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | 1287 | snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); |
1191 | /* DAC to Mono Line Out default volume and route to Output mixer */ | 1288 | /* DAC to Mono Line Out default volume and route to Output mixer */ |
1192 | aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | 1289 | snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); |
1193 | aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | 1290 | snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); |
1194 | 1291 | ||
1195 | /* unmute all outputs */ | 1292 | /* unmute all outputs */ |
1196 | reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); | 1293 | reg = snd_soc_read(codec, LLOPM_CTRL); |
1197 | aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE); | 1294 | snd_soc_write(codec, LLOPM_CTRL, reg | UNMUTE); |
1198 | reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); | 1295 | reg = snd_soc_read(codec, RLOPM_CTRL); |
1199 | aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE); | 1296 | snd_soc_write(codec, RLOPM_CTRL, reg | UNMUTE); |
1200 | reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); | 1297 | reg = snd_soc_read(codec, MONOLOPM_CTRL); |
1201 | aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE); | 1298 | snd_soc_write(codec, MONOLOPM_CTRL, reg | UNMUTE); |
1202 | reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); | 1299 | reg = snd_soc_read(codec, HPLOUT_CTRL); |
1203 | aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE); | 1300 | snd_soc_write(codec, HPLOUT_CTRL, reg | UNMUTE); |
1204 | reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); | 1301 | reg = snd_soc_read(codec, HPROUT_CTRL); |
1205 | aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE); | 1302 | snd_soc_write(codec, HPROUT_CTRL, reg | UNMUTE); |
1206 | reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); | 1303 | reg = snd_soc_read(codec, HPLCOM_CTRL); |
1207 | aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE); | 1304 | snd_soc_write(codec, HPLCOM_CTRL, reg | UNMUTE); |
1208 | reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); | 1305 | reg = snd_soc_read(codec, HPRCOM_CTRL); |
1209 | aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE); | 1306 | snd_soc_write(codec, HPRCOM_CTRL, reg | UNMUTE); |
1210 | 1307 | ||
1211 | /* ADC default volume and unmute */ | 1308 | /* ADC default volume and unmute */ |
1212 | aic3x_write(codec, LADC_VOL, DEFAULT_GAIN); | 1309 | snd_soc_write(codec, LADC_VOL, DEFAULT_GAIN); |
1213 | aic3x_write(codec, RADC_VOL, DEFAULT_GAIN); | 1310 | snd_soc_write(codec, RADC_VOL, DEFAULT_GAIN); |
1214 | /* By default route Line1 to ADC PGA mixer */ | 1311 | /* By default route Line1 to ADC PGA mixer */ |
1215 | aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0); | 1312 | snd_soc_write(codec, LINE1L_2_LADC_CTRL, 0x0); |
1216 | aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0); | 1313 | snd_soc_write(codec, LINE1R_2_RADC_CTRL, 0x0); |
1217 | 1314 | ||
1218 | /* PGA to HP Bypass default volume, disconnect from Output Mixer */ | 1315 | /* PGA to HP Bypass default volume, disconnect from Output Mixer */ |
1219 | aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); | 1316 | snd_soc_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); |
1220 | aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); | 1317 | snd_soc_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); |
1221 | aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); | 1318 | snd_soc_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); |
1222 | aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); | 1319 | snd_soc_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); |
1223 | /* PGA to Line Out default volume, disconnect from Output Mixer */ | 1320 | /* PGA to Line Out default volume, disconnect from Output Mixer */ |
1224 | aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); | 1321 | snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); |
1225 | aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); | 1322 | snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); |
1226 | /* PGA to Mono Line Out default volume, disconnect from Output Mixer */ | 1323 | /* PGA to Mono Line Out default volume, disconnect from Output Mixer */ |
1227 | aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); | 1324 | snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); |
1228 | aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); | 1325 | snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); |
1229 | 1326 | ||
1230 | /* Line2 to HP Bypass default volume, disconnect from Output Mixer */ | 1327 | /* Line2 to HP Bypass default volume, disconnect from Output Mixer */ |
1231 | aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); | 1328 | snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); |
1232 | aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); | 1329 | snd_soc_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); |
1233 | aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); | 1330 | snd_soc_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); |
1234 | aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); | 1331 | snd_soc_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); |
1235 | /* Line2 Line Out default volume, disconnect from Output Mixer */ | 1332 | /* Line2 Line Out default volume, disconnect from Output Mixer */ |
1236 | aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); | 1333 | snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); |
1237 | aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); | 1334 | snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); |
1238 | /* Line2 to Mono Out default volume, disconnect from Output Mixer */ | 1335 | /* Line2 to Mono Out default volume, disconnect from Output Mixer */ |
1239 | aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); | 1336 | snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); |
1240 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); | 1337 | snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); |
1241 | 1338 | ||
1242 | /* off, with power on */ | 1339 | if (aic3x->model == AIC3X_MODEL_3007) { |
1243 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1340 | aic3x_init_3007(codec); |
1341 | snd_soc_write(codec, CLASSD_CTRL, 0); | ||
1342 | } | ||
1244 | 1343 | ||
1245 | return 0; | 1344 | return 0; |
1246 | } | 1345 | } |
1247 | 1346 | ||
1248 | static struct snd_soc_codec *aic3x_codec; | 1347 | static int aic3x_probe(struct snd_soc_codec *codec) |
1249 | |||
1250 | static int aic3x_register(struct snd_soc_codec *codec) | ||
1251 | { | 1348 | { |
1252 | int ret; | 1349 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
1350 | int ret, i; | ||
1253 | 1351 | ||
1254 | ret = aic3x_init(codec); | 1352 | codec->control_data = aic3x->control_data; |
1255 | if (ret < 0) { | 1353 | aic3x->codec = codec; |
1256 | dev_err(codec->dev, "Failed to initialise device\n"); | 1354 | codec->idle_bias_off = 1; |
1355 | |||
1356 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type); | ||
1357 | if (ret != 0) { | ||
1358 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
1257 | return ret; | 1359 | return ret; |
1258 | } | 1360 | } |
1259 | 1361 | ||
1260 | aic3x_codec = codec; | 1362 | if (aic3x->gpio_reset >= 0) { |
1363 | ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset"); | ||
1364 | if (ret != 0) | ||
1365 | goto err_gpio; | ||
1366 | gpio_direction_output(aic3x->gpio_reset, 0); | ||
1367 | } | ||
1368 | |||
1369 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) | ||
1370 | aic3x->supplies[i].supply = aic3x_supply_names[i]; | ||
1261 | 1371 | ||
1262 | ret = snd_soc_register_codec(codec); | 1372 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), |
1263 | if (ret) { | 1373 | aic3x->supplies); |
1264 | dev_err(codec->dev, "Failed to register codec\n"); | 1374 | if (ret != 0) { |
1265 | return ret; | 1375 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); |
1376 | goto err_get; | ||
1377 | } | ||
1378 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) { | ||
1379 | aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event; | ||
1380 | aic3x->disable_nb[i].aic3x = aic3x; | ||
1381 | ret = regulator_register_notifier(aic3x->supplies[i].consumer, | ||
1382 | &aic3x->disable_nb[i].nb); | ||
1383 | if (ret) { | ||
1384 | dev_err(codec->dev, | ||
1385 | "Failed to request regulator notifier: %d\n", | ||
1386 | ret); | ||
1387 | goto err_notif; | ||
1388 | } | ||
1266 | } | 1389 | } |
1267 | 1390 | ||
1268 | ret = snd_soc_register_dai(&aic3x_dai); | 1391 | codec->cache_only = 1; |
1269 | if (ret) { | 1392 | aic3x_init(codec); |
1270 | dev_err(codec->dev, "Failed to register dai\n"); | 1393 | |
1271 | snd_soc_unregister_codec(codec); | 1394 | if (aic3x->setup) { |
1272 | return ret; | 1395 | /* setup GPIO functions */ |
1396 | snd_soc_write(codec, AIC3X_GPIO1_REG, | ||
1397 | (aic3x->setup->gpio_func[0] & 0xf) << 4); | ||
1398 | snd_soc_write(codec, AIC3X_GPIO2_REG, | ||
1399 | (aic3x->setup->gpio_func[1] & 0xf) << 4); | ||
1273 | } | 1400 | } |
1274 | 1401 | ||
1402 | snd_soc_add_controls(codec, aic3x_snd_controls, | ||
1403 | ARRAY_SIZE(aic3x_snd_controls)); | ||
1404 | if (aic3x->model == AIC3X_MODEL_3007) | ||
1405 | snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1); | ||
1406 | |||
1407 | aic3x_add_widgets(codec); | ||
1408 | |||
1275 | return 0; | 1409 | return 0; |
1410 | |||
1411 | err_notif: | ||
1412 | while (i--) | ||
1413 | regulator_unregister_notifier(aic3x->supplies[i].consumer, | ||
1414 | &aic3x->disable_nb[i].nb); | ||
1415 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | ||
1416 | err_get: | ||
1417 | if (aic3x->gpio_reset >= 0) | ||
1418 | gpio_free(aic3x->gpio_reset); | ||
1419 | err_gpio: | ||
1420 | kfree(aic3x); | ||
1421 | return ret; | ||
1276 | } | 1422 | } |
1277 | 1423 | ||
1278 | static int aic3x_unregister(struct aic3x_priv *aic3x) | 1424 | static int aic3x_remove(struct snd_soc_codec *codec) |
1279 | { | 1425 | { |
1280 | aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF); | 1426 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
1281 | 1427 | int i; | |
1282 | snd_soc_unregister_dai(&aic3x_dai); | ||
1283 | snd_soc_unregister_codec(&aic3x->codec); | ||
1284 | 1428 | ||
1429 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1285 | if (aic3x->gpio_reset >= 0) { | 1430 | if (aic3x->gpio_reset >= 0) { |
1286 | gpio_set_value(aic3x->gpio_reset, 0); | 1431 | gpio_set_value(aic3x->gpio_reset, 0); |
1287 | gpio_free(aic3x->gpio_reset); | 1432 | gpio_free(aic3x->gpio_reset); |
1288 | } | 1433 | } |
1289 | regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | 1434 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) |
1435 | regulator_unregister_notifier(aic3x->supplies[i].consumer, | ||
1436 | &aic3x->disable_nb[i].nb); | ||
1290 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | 1437 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); |
1291 | 1438 | ||
1292 | kfree(aic3x); | ||
1293 | aic3x_codec = NULL; | ||
1294 | |||
1295 | return 0; | 1439 | return 0; |
1296 | } | 1440 | } |
1297 | 1441 | ||
1442 | static struct snd_soc_codec_driver soc_codec_dev_aic3x = { | ||
1443 | .set_bias_level = aic3x_set_bias_level, | ||
1444 | .reg_cache_size = ARRAY_SIZE(aic3x_reg), | ||
1445 | .reg_word_size = sizeof(u8), | ||
1446 | .reg_cache_default = aic3x_reg, | ||
1447 | .probe = aic3x_probe, | ||
1448 | .remove = aic3x_remove, | ||
1449 | .suspend = aic3x_suspend, | ||
1450 | .resume = aic3x_resume, | ||
1451 | }; | ||
1452 | |||
1298 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1453 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1299 | /* | 1454 | /* |
1300 | * AIC3X 2 wire address can be up to 4 devices with device addresses | 1455 | * AIC3X 2 wire address can be up to 4 devices with device addresses |
1301 | * 0x18, 0x19, 0x1A, 0x1B | 1456 | * 0x18, 0x19, 0x1A, 0x1B |
1302 | */ | 1457 | */ |
1303 | 1458 | ||
1459 | static const struct i2c_device_id aic3x_i2c_id[] = { | ||
1460 | [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 }, | ||
1461 | [AIC3X_MODEL_33] = { "tlv320aic33", 0 }, | ||
1462 | [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 }, | ||
1463 | { } | ||
1464 | }; | ||
1465 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); | ||
1466 | |||
1304 | /* | 1467 | /* |
1305 | * If the i2c layer weren't so broken, we could pass this kind of data | 1468 | * If the i2c layer weren't so broken, we could pass this kind of data |
1306 | * around | 1469 | * around |
@@ -1308,10 +1471,10 @@ static int aic3x_unregister(struct aic3x_priv *aic3x) | |||
1308 | static int aic3x_i2c_probe(struct i2c_client *i2c, | 1471 | static int aic3x_i2c_probe(struct i2c_client *i2c, |
1309 | const struct i2c_device_id *id) | 1472 | const struct i2c_device_id *id) |
1310 | { | 1473 | { |
1311 | struct snd_soc_codec *codec; | ||
1312 | struct aic3x_priv *aic3x; | ||
1313 | struct aic3x_pdata *pdata = i2c->dev.platform_data; | 1474 | struct aic3x_pdata *pdata = i2c->dev.platform_data; |
1314 | int ret, i; | 1475 | struct aic3x_priv *aic3x; |
1476 | int ret; | ||
1477 | const struct i2c_device_id *tbl; | ||
1315 | 1478 | ||
1316 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); | 1479 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); |
1317 | if (aic3x == NULL) { | 1480 | if (aic3x == NULL) { |
@@ -1319,75 +1482,41 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, | |||
1319 | return -ENOMEM; | 1482 | return -ENOMEM; |
1320 | } | 1483 | } |
1321 | 1484 | ||
1322 | codec = &aic3x->codec; | 1485 | aic3x->control_data = i2c; |
1323 | codec->dev = &i2c->dev; | 1486 | aic3x->control_type = SND_SOC_I2C; |
1324 | snd_soc_codec_set_drvdata(codec, aic3x); | ||
1325 | codec->control_data = i2c; | ||
1326 | codec->hw_write = (hw_write_t) i2c_master_send; | ||
1327 | 1487 | ||
1328 | i2c_set_clientdata(i2c, aic3x); | 1488 | i2c_set_clientdata(i2c, aic3x); |
1329 | 1489 | if (pdata) { | |
1330 | aic3x->gpio_reset = -1; | ||
1331 | if (pdata && pdata->gpio_reset >= 0) { | ||
1332 | ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset"); | ||
1333 | if (ret != 0) | ||
1334 | goto err_gpio; | ||
1335 | aic3x->gpio_reset = pdata->gpio_reset; | 1490 | aic3x->gpio_reset = pdata->gpio_reset; |
1336 | gpio_direction_output(aic3x->gpio_reset, 0); | 1491 | aic3x->setup = pdata->setup; |
1337 | } | 1492 | } else { |
1338 | 1493 | aic3x->gpio_reset = -1; | |
1339 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) | ||
1340 | aic3x->supplies[i].supply = aic3x_supply_names[i]; | ||
1341 | |||
1342 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies), | ||
1343 | aic3x->supplies); | ||
1344 | if (ret != 0) { | ||
1345 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
1346 | goto err_get; | ||
1347 | } | ||
1348 | |||
1349 | ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies), | ||
1350 | aic3x->supplies); | ||
1351 | if (ret != 0) { | ||
1352 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
1353 | goto err_enable; | ||
1354 | } | 1494 | } |
1355 | 1495 | ||
1356 | if (aic3x->gpio_reset >= 0) { | 1496 | for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) { |
1357 | udelay(1); | 1497 | if (!strcmp(tbl->name, id->name)) |
1358 | gpio_set_value(aic3x->gpio_reset, 1); | 1498 | break; |
1359 | } | 1499 | } |
1500 | aic3x->model = tbl - aic3x_i2c_id; | ||
1360 | 1501 | ||
1361 | return aic3x_register(codec); | 1502 | ret = snd_soc_register_codec(&i2c->dev, |
1362 | 1503 | &soc_codec_dev_aic3x, &aic3x_dai, 1); | |
1363 | err_enable: | 1504 | if (ret < 0) |
1364 | regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies); | 1505 | kfree(aic3x); |
1365 | err_get: | ||
1366 | if (aic3x->gpio_reset >= 0) | ||
1367 | gpio_free(aic3x->gpio_reset); | ||
1368 | err_gpio: | ||
1369 | kfree(aic3x); | ||
1370 | return ret; | 1506 | return ret; |
1371 | } | 1507 | } |
1372 | 1508 | ||
1373 | static int aic3x_i2c_remove(struct i2c_client *client) | 1509 | static int aic3x_i2c_remove(struct i2c_client *client) |
1374 | { | 1510 | { |
1375 | struct aic3x_priv *aic3x = i2c_get_clientdata(client); | 1511 | snd_soc_unregister_codec(&client->dev); |
1376 | 1512 | kfree(i2c_get_clientdata(client)); | |
1377 | return aic3x_unregister(aic3x); | 1513 | return 0; |
1378 | } | 1514 | } |
1379 | 1515 | ||
1380 | static const struct i2c_device_id aic3x_i2c_id[] = { | ||
1381 | { "tlv320aic3x", 0 }, | ||
1382 | { "tlv320aic33", 0 }, | ||
1383 | { } | ||
1384 | }; | ||
1385 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); | ||
1386 | |||
1387 | /* machine i2c codec control layer */ | 1516 | /* machine i2c codec control layer */ |
1388 | static struct i2c_driver aic3x_i2c_driver = { | 1517 | static struct i2c_driver aic3x_i2c_driver = { |
1389 | .driver = { | 1518 | .driver = { |
1390 | .name = "aic3x I2C Codec", | 1519 | .name = "tlv320aic3x-codec", |
1391 | .owner = THIS_MODULE, | 1520 | .owner = THIS_MODULE, |
1392 | }, | 1521 | }, |
1393 | .probe = aic3x_i2c_probe, | 1522 | .probe = aic3x_i2c_probe, |
@@ -1409,90 +1538,27 @@ static inline void aic3x_i2c_exit(void) | |||
1409 | { | 1538 | { |
1410 | i2c_del_driver(&aic3x_i2c_driver); | 1539 | i2c_del_driver(&aic3x_i2c_driver); |
1411 | } | 1540 | } |
1412 | #else | ||
1413 | static inline void aic3x_i2c_init(void) { } | ||
1414 | static inline void aic3x_i2c_exit(void) { } | ||
1415 | #endif | 1541 | #endif |
1416 | 1542 | ||
1417 | static int aic3x_probe(struct platform_device *pdev) | 1543 | static int __init aic3x_modinit(void) |
1418 | { | 1544 | { |
1419 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1420 | struct aic3x_setup_data *setup; | ||
1421 | struct snd_soc_codec *codec; | ||
1422 | int ret = 0; | 1545 | int ret = 0; |
1423 | 1546 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | |
1424 | codec = aic3x_codec; | 1547 | ret = i2c_add_driver(&aic3x_i2c_driver); |
1425 | if (!codec) { | 1548 | if (ret != 0) { |
1426 | dev_err(&pdev->dev, "Codec not registered\n"); | 1549 | printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n", |
1427 | return -ENODEV; | 1550 | ret); |
1428 | } | ||
1429 | |||
1430 | socdev->card->codec = codec; | ||
1431 | setup = socdev->codec_data; | ||
1432 | |||
1433 | if (setup) { | ||
1434 | /* setup GPIO functions */ | ||
1435 | aic3x_write(codec, AIC3X_GPIO1_REG, | ||
1436 | (setup->gpio_func[0] & 0xf) << 4); | ||
1437 | aic3x_write(codec, AIC3X_GPIO2_REG, | ||
1438 | (setup->gpio_func[1] & 0xf) << 4); | ||
1439 | } | ||
1440 | |||
1441 | /* register pcms */ | ||
1442 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1443 | if (ret < 0) { | ||
1444 | printk(KERN_ERR "aic3x: failed to create pcms\n"); | ||
1445 | goto pcm_err; | ||
1446 | } | 1551 | } |
1447 | 1552 | #endif | |
1448 | snd_soc_add_controls(codec, aic3x_snd_controls, | ||
1449 | ARRAY_SIZE(aic3x_snd_controls)); | ||
1450 | |||
1451 | aic3x_add_widgets(codec); | ||
1452 | |||
1453 | return ret; | ||
1454 | |||
1455 | pcm_err: | ||
1456 | kfree(codec->reg_cache); | ||
1457 | return ret; | 1553 | return ret; |
1458 | } | 1554 | } |
1459 | |||
1460 | static int aic3x_remove(struct platform_device *pdev) | ||
1461 | { | ||
1462 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1463 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1464 | |||
1465 | /* power down chip */ | ||
1466 | if (codec->control_data) | ||
1467 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1468 | |||
1469 | snd_soc_free_pcms(socdev); | ||
1470 | snd_soc_dapm_free(socdev); | ||
1471 | |||
1472 | kfree(codec->reg_cache); | ||
1473 | |||
1474 | return 0; | ||
1475 | } | ||
1476 | |||
1477 | struct snd_soc_codec_device soc_codec_dev_aic3x = { | ||
1478 | .probe = aic3x_probe, | ||
1479 | .remove = aic3x_remove, | ||
1480 | .suspend = aic3x_suspend, | ||
1481 | .resume = aic3x_resume, | ||
1482 | }; | ||
1483 | EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); | ||
1484 | |||
1485 | static int __init aic3x_modinit(void) | ||
1486 | { | ||
1487 | aic3x_i2c_init(); | ||
1488 | |||
1489 | return 0; | ||
1490 | } | ||
1491 | module_init(aic3x_modinit); | 1555 | module_init(aic3x_modinit); |
1492 | 1556 | ||
1493 | static void __exit aic3x_exit(void) | 1557 | static void __exit aic3x_exit(void) |
1494 | { | 1558 | { |
1495 | aic3x_i2c_exit(); | 1559 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1560 | i2c_del_driver(&aic3x_i2c_driver); | ||
1561 | #endif | ||
1496 | } | 1562 | } |
1497 | module_exit(aic3x_exit); | 1563 | module_exit(aic3x_exit); |
1498 | 1564 | ||