1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Driver for AS3514 audio codec
12 * Copyright (c) 2007 Daniel Ankers
13 * Copyright (c) 2007 Christian Gmeiner
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
34 /* AMS Sansas based on the AS3525 use the LINE2 input for the analog radio
35 signal instead of LINE1 */
36 #if CONFIG_CPU == AS3525
42 const struct sound_settings_info audiohw_settings
[] = {
43 [SOUND_VOLUME
] = {"dB", 0, 1, -74, 6, -25},
44 /* HAVE_SW_TONE_CONTROLS */
45 [SOUND_BASS
] = {"dB", 0, 1, -24, 24, 0},
46 [SOUND_TREBLE
] = {"dB", 0, 1, -24, 24, 0},
47 [SOUND_BALANCE
] = {"%", 0, 1,-100, 100, 0},
48 [SOUND_CHANNELS
] = {"", 0, 1, 0, 5, 0},
49 [SOUND_STEREO_WIDTH
] = {"%", 0, 5, 0, 250, 100},
51 [SOUND_MIC_GAIN
] = {"dB", 1, 1, 0, 39, 23},
52 [SOUND_LEFT_GAIN
] = {"dB", 1, 1, 0, 31, 23},
53 [SOUND_RIGHT_GAIN
] = {"dB", 1, 1, 0, 31, 23},
57 /* Shadow registers */
58 static struct as3514_info
60 int vol_r
; /* Cached volume level (R) */
61 int vol_l
; /* Cached volume level (L) */
62 uint8_t regs
[AS3514_NUM_AUDIO_REGS
]; /* 8-bit registers */
66 * little helper method to set register values.
67 * With the help of as3514.regs, we minimize i2c
70 static void as3514_write(unsigned int reg
, unsigned int value
)
72 if (ascodec_write(reg
, value
) != 2)
74 DEBUGF("as3514 error reg=0x%02x", reg
);
77 if (reg
< ARRAYLEN(as3514
.regs
))
79 as3514
.regs
[reg
] = value
;
83 DEBUGF("as3514 error reg=0x%02x", reg
);
87 /* Helpers to set/clear bits */
88 static void as3514_set(unsigned int reg
, unsigned int bits
)
90 as3514_write(reg
, as3514
.regs
[reg
] | bits
);
93 static void as3514_clear(unsigned int reg
, unsigned int bits
)
95 as3514_write(reg
, as3514
.regs
[reg
] & ~bits
);
98 static void as3514_write_masked(unsigned int reg
, unsigned int bits
,
101 as3514_write(reg
, (as3514
.regs
[reg
] & ~mask
) | (bits
& mask
));
104 /* convert tenth of dB volume to master volume register value */
105 int tenthdb2master(int db
)
107 /* +6 to -73.5dB in 1.5dB steps == 53 levels */
108 if (db
< VOLUME_MIN
) {
110 } else if (db
>= VOLUME_MAX
) {
113 return((db
-VOLUME_MIN
)/15); /* VOLUME_MIN is negative */
117 int sound_val2phys(int setting
, int value
)
123 #if defined(HAVE_RECORDING)
124 case SOUND_LEFT_GAIN
:
125 case SOUND_RIGHT_GAIN
:
127 result
= (value
- 23) * 15;
140 * Initialise the PP I2C and I2S.
142 void audiohw_preinit(void)
146 /* read all reg values */
147 for (i
= 0; i
< ARRAYLEN(as3514
.regs
); i
++)
149 as3514
.regs
[i
] = ascodec_read(i
);
152 /* Set ADC off, mixer on, DAC on, line out off, line in off, mic off */
154 /* Turn on SUM, DAC */
155 as3514_write(AS3514_AUDIOSET1
, AUDIOSET1_DAC_on
| AUDIOSET1_SUM_on
);
157 /* Set BIAS on, DITH on, AGC on, IBR_DAC max, LSP_LP on, IBR_LSP min */
158 as3514_write(AS3514_AUDIOSET2
,
159 AUDIOSET2_IBR_DAC_0
| AUDIOSET2_LSP_LP
|
160 AUDIOSET2_IBR_LSP_50
);
162 /* AMS Sansas based on the AS3525 need HPCM enabled, otherwise they output the
163 L-R signal on both L and R headphone outputs instead of normal stereo.
164 Turning it off saves a little power on targets that don't need it. */
165 #if (CONFIG_CPU == AS3525)
166 /* Set HPCM on, ZCU on */
167 as3514_write(AS3514_AUDIOSET3
, 0);
169 /* Set HPCM off, ZCU on */
170 as3514_write(AS3514_AUDIOSET3
, AUDIOSET3_HPCM_off
);
173 /* Mute and disable speaker */
174 as3514_write(AS3514_LSP_OUT_R
, LSP_OUT_R_SP_OVC_TO_256MS
| 0x00);
175 as3514_write(AS3514_LSP_OUT_L
, LSP_OUT_L_SP_MUTE
| 0x00);
177 /* Set headphone over-current to 0, Min volume */
178 as3514_write(AS3514_HPH_OUT_R
,
179 HPH_OUT_R_HP_OVC_TO_0MS
| 0x00);
181 /* Headphone ON, MUTE, Min volume */
182 as3514_write(AS3514_HPH_OUT_L
,
183 HPH_OUT_L_HP_ON
| HPH_OUT_L_HP_MUTE
| 0x00);
185 #ifdef PHILIPS_SA9200
186 /* LRCK 8-23kHz (there are audible clicks while reading the ADC otherwise) */
187 as3514_write(AS3514_PLLMODE
, PLLMODE_LRCK_8_23
);
190 as3514_write(AS3514_PLLMODE
, PLLMODE_LRCK_24_48
);
194 as3514_set(AS3514_DAC_L
, DAC_L_DAC_MUTE_off
);
197 as3514_set(AS3514_MIC1_L
, MIC1_L_M1_SUP_off
);
199 as3514_set(AS3514_MIC2_L
, MIC2_L_M2_SUP_off
);
202 void audiohw_postinit(void)
204 /* wait until outputs have stabilized */
208 ascodec_suppressor_on(false);
214 void audiohw_set_master_vol(int vol_l
, int vol_r
)
216 unsigned int hph_r
, hph_l
;
217 unsigned int mix_l
, mix_r
;
219 /* keep track of current setting */
220 as3514
.vol_l
= vol_l
;
221 as3514
.vol_r
= vol_r
;
223 /* We combine the mixer channel volume range with the headphone volume
224 range - keep first stage as loud as possible */
230 hph_r
= vol_r
- 0x16;
238 hph_l
= vol_l
- 0x16;
241 as3514_write_masked(AS3514_DAC_R
, mix_r
, AS3514_VOL_MASK
);
242 as3514_write_masked(AS3514_DAC_L
, mix_l
, AS3514_VOL_MASK
);
243 #if defined(HAVE_RECORDING) || defined(HAVE_FMRADIO_IN)
244 as3514_write_masked((LINE_INPUT
== 1) ? AS3514_LINE_IN1_R
:
246 mix_r
, AS3514_VOL_MASK
);
247 as3514_write_masked((LINE_INPUT
== 1) ? AS3514_LINE_IN1_L
:
249 mix_l
, AS3514_VOL_MASK
);
251 as3514_write_masked(AS3514_HPH_OUT_R
, hph_r
, AS3514_VOL_MASK
);
252 as3514_write_masked(AS3514_HPH_OUT_L
, hph_l
, AS3514_VOL_MASK
);
255 void audiohw_set_lineout_vol(int vol_l
, int vol_r
)
257 as3514_write_masked(AS3514_LINE_OUT_R
, vol_r
, AS3514_VOL_MASK
);
258 as3514_write_masked(AS3514_LINE_OUT_L
, vol_l
, AS3514_VOL_MASK
);
261 void audiohw_mute(bool mute
)
264 as3514_set(AS3514_HPH_OUT_L
, HPH_OUT_L_HP_MUTE
);
266 as3514_clear(AS3514_HPH_OUT_L
, HPH_OUT_L_HP_MUTE
);
270 /* Nice shutdown of AS3514 audio codec */
271 void audiohw_close(void)
273 /* mute headphones */
277 ascodec_suppressor_on(true);
281 as3514_clear(AS3514_AUDIOSET3
, AUDIOSET3_HPCM_off
);
283 /* turn off everything */
284 as3514_clear(AS3514_HPH_OUT_L
, HPH_OUT_L_HP_ON
);
285 as3514_write(AS3514_AUDIOSET1
, 0x0);
287 /* Allow caps to discharge */
291 void audiohw_set_frequency(int fsel
)
296 #if defined(HAVE_RECORDING)
297 void audiohw_enable_recording(bool source_mic
)
300 /* ADCmux = Stereo Microphone */
301 as3514_write_masked(AS3514_ADC_R
, ADC_R_ADCMUX_ST_MIC
,
304 /* MIC1_on, others off */
305 as3514_write_masked(AS3514_AUDIOSET1
, AUDIOSET1_MIC1_on
,
306 AUDIOSET1_INPUT_MASK
);
309 as3514_clear(AS3514_MIC1_R
, MIC1_R_M1_AGC_off
);
311 /* ADCmux = Line_IN1 or Line_IN2 */
312 as3514_write_masked(AS3514_ADC_R
,
313 (LINE_INPUT
== 1) ? ADC_R_ADCMUX_LINE_IN1
:
314 ADC_R_ADCMUX_LINE_IN2
,
317 /* LIN1_or LIN2 on, rest off */
318 as3514_write_masked(AS3514_AUDIOSET1
,
319 (LINE_INPUT
== 1) ? AUDIOSET1_LIN1_on
:
321 AUDIOSET1_INPUT_MASK
);
325 as3514_set(AS3514_ADC_L
, ADC_L_ADC_MUTE_off
);
327 as3514_set(AS3514_AUDIOSET1
, AUDIOSET1_ADC_on
);
330 void audiohw_disable_recording(void)
333 as3514_clear(AS3514_ADC_L
, ADC_L_ADC_MUTE_off
);
335 /* ADC_off, all input sources off */
336 as3514_clear(AS3514_AUDIOSET1
, AUDIOSET1_ADC_on
| AUDIOSET1_INPUT_MASK
);
340 * Set recording volume
342 * Line in : 0 .. 23 .. 31 =>
343 Volume -34.5 .. +00.0 .. +12.0 dB
344 * Mic (left): 0 .. 23 .. 39 =>
345 * Volume -34.5 .. +00.0 .. +24.0 dB
348 void audiohw_set_recvol(int left
, int right
, int type
)
354 /* Combine MIC gains seamlessly with ADC levels */
358 /* M1_Gain = +40db, ADR_Vol = +7.5dB .. +12.0 dB =>
359 +19.5 dB .. +24.0 dB */
361 mic1_r
= MIC1_R_M1_GAIN_40DB
;
362 } else if (left
>= 32) {
363 /* M1_Gain = +34db, ADR_Vol = +7.5dB .. +12.0 dB =>
364 +13.5 dB .. +18.0 dB */
366 mic1_r
= MIC1_R_M1_GAIN_34DB
;
368 /* M1_Gain = +28db, ADR_Vol = -34.5dB .. +12.0 dB =>
369 -34.5 dB .. +12.0 dB */
370 mic1_r
= MIC1_R_M1_GAIN_28DB
;
375 as3514_write_masked(AS3514_MIC1_R
, mic1_r
, MIC1_R_M1_GAIN
);
378 case AUDIO_GAIN_LINEIN
:
384 as3514_write_masked(AS3514_ADC_R
, right
, AS3514_VOL_MASK
);
385 as3514_write_masked(AS3514_ADC_L
, left
, AS3514_VOL_MASK
);
387 #endif /* HAVE_RECORDING */
389 #if defined(HAVE_RECORDING) || defined(HAVE_FMRADIO_IN)
391 * Enable line in analog monitoring
394 void audiohw_set_monitor(bool enable
)
397 /* select either LIN1 or LIN2 */
398 as3514_write_masked(AS3514_AUDIOSET1
,
400 AUDIOSET1_LIN1_on
: AUDIOSET1_LIN2_on
,
401 AUDIOSET1_LIN1_on
| AUDIOSET1_LIN2_on
);
402 as3514_set((LINE_INPUT
== 1) ? AS3514_LINE_IN1_R
: AS3514_LINE_IN2_R
,
403 LINE_IN1_R_LI1R_MUTE_off
);
404 as3514_set((LINE_INPUT
== 1) ? AS3514_LINE_IN1_L
: AS3514_LINE_IN2_L
,
405 LINE_IN1_L_LI1L_MUTE_off
);
408 /* turn off both LIN1 and LIN2 */
409 as3514_clear(AS3514_LINE_IN1_R
, LINE_IN1_R_LI1R_MUTE_off
);
410 as3514_clear(AS3514_LINE_IN1_L
, LINE_IN1_L_LI1L_MUTE_off
);
411 as3514_clear(AS3514_LINE_IN2_R
, LINE_IN2_R_LI2R_MUTE_off
);
412 as3514_clear(AS3514_LINE_IN2_L
, LINE_IN2_L_LI2L_MUTE_off
);
413 as3514_clear(AS3514_AUDIOSET1
, AUDIOSET1_LIN1_on
| AUDIOSET1_LIN2_on
);
416 #endif /* HAVE_RECORDING || HAVE_FMRADIO_IN */