1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2011 by Tomasz Moń
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
26 #if CONFIG_I2C == I2C_DM320
27 #include "i2c-dm320.h"
31 /* (7-bit) address is 0x18, the LSB is read/write flag */
32 #define AIC3X_ADDR (0x18 << 1)
34 static char volume_left
= 0, volume_right
= 0;
36 const struct sound_settings_info audiohw_settings
[] = {
37 [SOUND_VOLUME
] = {"dB", 0, 1, VOLUME_MIN
/10, VOLUME_MAX
/10, -25},
38 /* HAVE_SW_TONE_CONTROLS */
39 [SOUND_BASS
] = {"dB", 0, 1, -24, 24, 0},
40 [SOUND_TREBLE
] = {"dB", 0, 1, -24, 24, 0},
41 [SOUND_BALANCE
] = {"%", 0, 1,-100, 100, 0},
42 [SOUND_CHANNELS
] = {"", 0, 1, 0, 5, 0},
43 [SOUND_STEREO_WIDTH
] = {"%", 0, 5, 0, 250, 100},
46 /* convert tenth of dB volume to master volume register value */
47 int tenthdb2master(int db
)
49 /* 0 to -63.0dB in 1dB steps, aic3x can goto -63.5 in 0.5dB steps */
54 else if (db
>= VOLUME_MAX
)
60 return (-((db
)/5)); /* VOLUME_MIN is negative */
64 static void aic3x_write_reg(unsigned reg
, unsigned value
)
66 unsigned char data
[2];
71 #if CONFIG_I2C == I2C_DM320
72 if (i2c_write(AIC3X_ADDR
, data
, 2) != 0)
74 #warning Implement aic3x_write_reg()
77 logf("AIC3X error reg=0x%x", reg
);
82 static unsigned char aic3x_read_reg(unsigned reg
)
86 #if CONFIG_I2C == I2C_DM320
87 if (i2c_read_bytes(AIC3X_ADDR
, reg
, &data
, 1))
89 #warning Implement aic3x_read_reg()
92 logf("AIC3X read error reg=0x%0x", reg
);
99 static void aic3x_change_reg(unsigned reg
, unsigned char or_mask
,
100 unsigned char and_mask
)
104 data
= aic3x_read_reg(reg
);
109 aic3x_write_reg(reg
, data
);
112 static void aic3x_apply_volume(void)
114 unsigned char data
[3];
116 #if 0 /* handle page switching once we use first page at all */
117 aic3x_write_reg(0, 0); /* switch to page 0 */
120 data
[0] = AIC3X_LEFT_VOL
;
121 data
[1] = volume_left
;
122 data
[2] = volume_right
;
124 /* use autoincrement write */
125 #if CONFIG_I2C == I2C_DM320
126 if (i2c_write(AIC3X_ADDR
, data
, 3) != 0)
128 #warning Implement aic3x_apply_volume()
131 logf("AIC3X error in apply volume");
137 static void audiohw_mute(bool mute
)
141 /* DAC_L1 routed to HPLOUT, mute */
142 aic3x_write_reg(AIC3X_DAC_L1_VOL
, 0xF6);
143 /* DAC_R1 routed to HPROUT, mute */
144 aic3x_write_reg(AIC3X_DAC_R1_VOL
, 0xF6);
145 /* DAC_L1 routed to MONO_LOP/M, mute */
146 aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL
, 0xF6);
147 /* DAC_R1 routed to MONO_LOP/M, mute */
148 aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL
, 0xF6);
151 volume_right
|= 0x80;
155 /* DAC_L1 routed to HPLOUT, volume analog gain 0xC (-6.0dB) */
156 aic3x_write_reg(AIC3X_DAC_L1_VOL
, 0x8C);
157 /* DAC_R1 routed to HPROUT, volume analog gain 0xC (-6.0 dB) */
158 aic3x_write_reg(AIC3X_DAC_R1_VOL
, 0x8C);
159 /* DAC_L1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */
160 aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL
, 0x92);
161 /* DAC_R1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */
162 aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL
, 0x92);
165 volume_right
&= 0x7F;
168 aic3x_apply_volume();
171 /* public functions */
174 * Init our tlv with default values
176 void audiohw_init(void)
180 /* Do software reset (self-clearing) */
181 aic3x_write_reg(AIC3X_SOFT_RESET
, 0x80);
183 /* driver power-on time 200 ms, ramp-up step time 4 ms */
184 aic3x_write_reg(AIC3X_POP_REDUCT
, 0x7C);
186 /* Output common-move voltage 1.35V, disable LINE2[LR] bypass */
187 /* Output soft-stepping = one step per fs */
188 aic3x_write_reg(AIC3X_POWER_OUT
, 0x00);
190 /* Audio data interface */
191 /* GPIO1 used for audio serial data bus ADC word clock */
192 aic3x_write_reg(AIC3X_GPIO1_CTRL
, 0x10);
193 /* BCLK and WCLK are outputs (master mode) */
194 aic3x_write_reg(AIC3X_DATA_REG_A
, 0xC0);
195 /* right-justified mode */
196 aic3x_write_reg(AIC3X_DATA_REG_B
, 0x80);
197 /* data offset = 0 clocks */
198 aic3x_write_reg(AIC3X_DATA_REG_C
, 0);
200 /* Left DAC plays left channel, Right DAC plays right channel */
201 aic3x_write_reg(AIC3X_DATAPATH
, 0xA);
203 /* power left and right DAC, HPLCOM constant VCM output */
204 aic3x_write_reg(AIC3X_DAC_POWER
, 0xD0);
205 /* HPRCOM as constant VCM output. Enable short-circuit protection
207 aic3x_write_reg(AIC3X_HIGH_POWER
, 0xC);
209 /* DAC_L1 routed to HPLOUT */
210 aic3x_write_reg(AIC3X_DAC_L1_VOL
, 0x80);
211 /* DAC_R1 routed to HPROUT */
212 aic3x_write_reg(AIC3X_DAC_R1_VOL
, 0x80);
214 /* DAC_L1 routed to MONO_LOP/M */
215 aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL
, 0x80);
216 /* DAC_R1 routed to MONO_LOP/M */
217 aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL
, 0x80);
219 /* DAC_L1 routed to LEFT_LOP/M */
220 aic3x_write_reg(AIC3X_DAC_L1_LEFT_LOP_M_VOL
, 0x80);
221 /* DAC_R1 routed to RIGHT_LOP/M */
222 aic3x_write_reg(AIC3X_DAC_R1_RIGHT_LOP_M_VOL
, 0x80);
224 /* LEFT_LOP/M output level 0dB, not muted */
225 aic3x_write_reg(AIC3X_LEFT_LOP_M_LVL
, 0x8);
226 /* RIGHT_LOP/M output level 0dB, not muted */
227 aic3x_write_reg(AIC3X_RIGHT_LOP_M_LVL
, 0x8);
229 /* Enable PLL. Set Q=16, P=1 */
230 aic3x_write_reg(AIC3X_PLL_REG_A
, 0x81);
232 aic3x_write_reg(AIC3X_PLL_REG_B
, 0xD4);
234 aic3x_write_reg(AIC3X_PLL_REG_C
, 0x51);
235 aic3x_write_reg(AIC3X_PLL_REG_D
, 0x6C);
237 aic3x_write_reg(AIC3X_OVERFLOW
, 0x01);
239 /* ADC fs = fs(ref)/5.5; DAC fs = fs(ref) */
240 aic3x_write_reg(AIC3X_SMPL_RATE
, 0x90);
242 /* HPLOUT output level 0dB, muted, high impedance */
243 aic3x_write_reg(AIC3X_HPLOUT_LVL
, 0x04);
244 /* HPROUT output level 0dB, muted, high impedance */
245 aic3x_write_reg(AIC3X_HPROUT_LVL
, 0x04);
247 /* HPLCOM is high impedance when powered down, not fully powered up */
248 aic3x_write_reg(AIC3X_HPLCOM_LVL
, 0x04);
251 void audiohw_postinit(void)
255 /* HPLOUT output level 0dB, not muted, fully powered up */
256 aic3x_write_reg(AIC3X_HPLOUT_LVL
, 0x09);
257 /* HPROUT output level 0dB, not muted, fully powered up */
258 aic3x_write_reg(AIC3X_HPROUT_LVL
, 0x09);
260 /* MONO_LOP output level 6dB, not muted */
261 aic3x_write_reg(AIC3X_MONO_LOP_M_LVL
, 0x69);
263 /* PGA_R is not routed to MONO_LOP/M, analog gain -52.7dB */
264 aic3x_write_reg(AIC3X_PGA_R_MONO_LOP_M_VOL
, 0x69);
267 void audiohw_set_frequency(int fsel
)
273 void audiohw_set_headphone_vol(int vol_l
, int vol_r
)
275 if ((volume_left
& 0x7F) == (vol_l
& 0x7F) &&
276 (volume_right
& 0x7F) == (vol_r
& 0x7F))
278 /* Volume already set to this value */
282 volume_left
&= 0x80; /* preserve mute bit */
283 volume_left
|= (vol_l
& 0x7F); /* set gain */
285 volume_right
&= 0x80; /* preserve mute bit */
286 volume_right
|= (vol_r
& 0x7F); /* set gain */
288 aic3x_apply_volume();
291 /* Nice shutdown of AIC3X codec */
292 void audiohw_close(void)
294 /* HPLOUT, HPROUT, HPLCOM not fully powered up */
295 aic3x_change_reg(AIC3X_HPLOUT_LVL
, 0x00, 0xFE);
296 aic3x_change_reg(AIC3X_HPROUT_LVL
, 0x00, 0xFE);
297 aic3x_change_reg(AIC3X_HPLCOM_LVL
, 0x00, 0xFC);
299 /* MONO_LOP/M, LEFT_LOP/M, RIGHT_LOP/M muted, not fully powered up */
300 aic3x_change_reg(AIC3X_MONO_LOP_M_LVL
, 0x00, 0xF6);
301 aic3x_change_reg(AIC3X_LEFT_LOP_M_LVL
, 0x00, 0xF6);
302 aic3x_change_reg(AIC3X_RIGHT_LOP_M_LVL
, 0x00, 0xF6);
304 /* Power down left and right DAC */
305 aic3x_change_reg(AIC3X_DAC_POWER
, 0x00, 0x30);
308 aic3x_change_reg(AIC3X_PLL_REG_A
, 0x00, 0x7F);
311 void aic3x_switch_output(bool stereo
)
315 /* mute MONO_LOP/M */
316 aic3x_change_reg(AIC3X_MONO_LOP_M_LVL
, 0x00, 0xF6);
317 /* HPLOUT fully powered up */
318 aic3x_change_reg(AIC3X_HPLOUT_LVL
, 0x01, 0xFF);
319 /* HPROUT fully powered up */
320 aic3x_change_reg(AIC3X_HPROUT_LVL
, 0x01, 0xFF);
321 /* HPLCOM fully powered up */
322 aic3x_change_reg(AIC3X_HPLCOM_LVL
, 0x01, 0xFF);
326 /* MONO_LOP/M not muted */
327 aic3x_change_reg(AIC3X_MONO_LOP_M_LVL
, 0x09, 0xFF);
328 /* HPLOUT not fully powered up */
329 aic3x_change_reg(AIC3X_HPLOUT_LVL
, 0x00, 0xFE);
330 /* HPROUT not fully powered up */
331 aic3x_change_reg(AIC3X_HPROUT_LVL
, 0x00, 0xFE);
332 /* HPLCOM not fully powered up */
333 aic3x_change_reg(AIC3X_HPLCOM_LVL
, 0x00, 0xFE);