diff options
Diffstat (limited to 'firmware/drivers/audio/aic3x.c')
-rw-r--r-- | firmware/drivers/audio/aic3x.c | 197 |
1 files changed, 143 insertions, 54 deletions
diff --git a/firmware/drivers/audio/aic3x.c b/firmware/drivers/audio/aic3x.c index 5c6d5fa9ad..97eb17ebef 100644 --- a/firmware/drivers/audio/aic3x.c +++ b/firmware/drivers/audio/aic3x.c | |||
@@ -23,11 +23,6 @@ | |||
23 | #include "system.h" | 23 | #include "system.h" |
24 | #include "string.h" | 24 | #include "string.h" |
25 | #include "audio.h" | 25 | #include "audio.h" |
26 | |||
27 | #ifdef SANSA_CONNECT | ||
28 | #include "avr-sansaconnect.h" | ||
29 | #endif | ||
30 | |||
31 | #if CONFIG_I2C == I2C_DM320 | 26 | #if CONFIG_I2C == I2C_DM320 |
32 | #include "i2c-dm320.h" | 27 | #include "i2c-dm320.h" |
33 | #endif | 28 | #endif |
@@ -84,11 +79,41 @@ static void aic3x_write_reg(unsigned reg, unsigned value) | |||
84 | } | 79 | } |
85 | } | 80 | } |
86 | 81 | ||
82 | static unsigned char aic3x_read_reg(unsigned reg) | ||
83 | { | ||
84 | unsigned char data; | ||
85 | |||
86 | #if CONFIG_I2C == I2C_DM320 | ||
87 | if (i2c_read_bytes(AIC3X_ADDR, reg, &data, 1)) | ||
88 | #else | ||
89 | #warning Implement aic3x_read_reg() | ||
90 | #endif | ||
91 | { | ||
92 | logf("AIC3X read error reg=0x%0x", reg); | ||
93 | data = 0; | ||
94 | } | ||
95 | |||
96 | return data; | ||
97 | } | ||
98 | |||
99 | static void aic3x_change_reg(unsigned reg, unsigned char or_mask, | ||
100 | unsigned char and_mask) | ||
101 | { | ||
102 | unsigned char data; | ||
103 | |||
104 | data = aic3x_read_reg(reg); | ||
105 | |||
106 | data &= and_mask; | ||
107 | data |= or_mask; | ||
108 | |||
109 | aic3x_write_reg(reg, data); | ||
110 | } | ||
111 | |||
87 | static void aic3x_apply_volume(void) | 112 | static void aic3x_apply_volume(void) |
88 | { | 113 | { |
89 | unsigned char data[3]; | 114 | unsigned char data[3]; |
90 | 115 | ||
91 | #if 0 /* handle page switching onve we use first page at all */ | 116 | #if 0 /* handle page switching once we use first page at all */ |
92 | aic3x_write_reg(0, 0); /* switch to page 0 */ | 117 | aic3x_write_reg(0, 0); /* switch to page 0 */ |
93 | #endif | 118 | #endif |
94 | 119 | ||
@@ -113,11 +138,29 @@ static void audiohw_mute(bool mute) | |||
113 | { | 138 | { |
114 | if (mute) | 139 | if (mute) |
115 | { | 140 | { |
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); | ||
149 | |||
116 | volume_left |= 0x80; | 150 | volume_left |= 0x80; |
117 | volume_right |= 0x80; | 151 | volume_right |= 0x80; |
118 | } | 152 | } |
119 | else | 153 | else |
120 | { | 154 | { |
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); | ||
163 | |||
121 | volume_left &= 0x7F; | 164 | volume_left &= 0x7F; |
122 | volume_right &= 0x7F; | 165 | volume_right &= 0x7F; |
123 | } | 166 | } |
@@ -137,78 +180,88 @@ void audiohw_init(void) | |||
137 | /* Do software reset (self-clearing) */ | 180 | /* Do software reset (self-clearing) */ |
138 | aic3x_write_reg(AIC3X_SOFT_RESET, 0x80); | 181 | aic3x_write_reg(AIC3X_SOFT_RESET, 0x80); |
139 | 182 | ||
140 | /* ADC fs = fs(ref)/5.5; DAC fs = fs(ref) */ | 183 | /* driver power-on time 200 ms, ramp-up step time 4 ms */ |
141 | aic3x_write_reg(AIC3X_SMPL_RATE, 0x90); | 184 | aic3x_write_reg(AIC3X_POP_REDUCT, 0x7C); |
142 | |||
143 | /* Enable PLL. Set Q=16, P=1 */ | ||
144 | aic3x_write_reg(AIC3X_PLL_REG_A, 0x81); | ||
145 | /* PLL J = 53 */ | ||
146 | aic3x_write_reg(AIC3X_PLL_REG_B, 0xD4); | ||
147 | /* PLL D = 5211 */ | ||
148 | aic3x_write_reg(AIC3X_PLL_REG_C, 0x51); | ||
149 | aic3x_write_reg(AIC3X_PLL_REG_D, 0x6C); /* PLL D = 5211 */ | ||
150 | 185 | ||
151 | /* Left DAC plays left channel, Right DAC plays right channel */ | 186 | /* Output common-move voltage 1.35V, disable LINE2[LR] bypass */ |
152 | aic3x_write_reg(AIC3X_DATAPATH, 0xA); | 187 | /* Output soft-stepping = one step per fs */ |
188 | aic3x_write_reg(AIC3X_POWER_OUT, 0x00); | ||
153 | 189 | ||
154 | /* Audio data interface */ | 190 | /* Audio data interface */ |
191 | /* GPIO1 used for audio serial data bus ADC word clock */ | ||
192 | aic3x_write_reg(AIC3X_GPIO1_CTRL, 0x10); | ||
155 | /* BCLK and WCLK are outputs (master mode) */ | 193 | /* BCLK and WCLK are outputs (master mode) */ |
156 | aic3x_write_reg(AIC3X_DATA_REG_A, 0xC0); | 194 | aic3x_write_reg(AIC3X_DATA_REG_A, 0xC0); |
157 | /* right-justified mode */ | 195 | /* right-justified mode */ |
158 | aic3x_write_reg(AIC3X_DATA_REG_B, 0x80); | 196 | aic3x_write_reg(AIC3X_DATA_REG_B, 0x80); |
159 | /* data offset = 0 clocks */ | 197 | /* data offset = 0 clocks */ |
160 | aic3x_write_reg(AIC3X_DATA_REG_C, 0); | 198 | aic3x_write_reg(AIC3X_DATA_REG_C, 0); |
161 | 199 | ||
162 | /* GPIO1 used for audio serial data bus ADC word clock */ | 200 | /* Left DAC plays left channel, Right DAC plays right channel */ |
163 | aic3x_write_reg(AIC3X_GPIO1_CTRL, 0x10); | 201 | aic3x_write_reg(AIC3X_DATAPATH, 0xA); |
164 | 202 | ||
165 | /* power left and right DAC, HPLCOM constant VCM output */ | 203 | /* power left and right DAC, HPLCOM constant VCM output */ |
166 | aic3x_write_reg(AIC3X_DAC_POWER, 0xD0); | 204 | aic3x_write_reg(AIC3X_DAC_POWER, 0xD0); |
167 | /* HPRCOM as constant VCM output. Enable short-circuit protection | 205 | /* HPRCOM as constant VCM output. Enable short-circuit protection |
168 | (limit current) */ | 206 | (limit current) */ |
169 | aic3x_write_reg(AIC3X_HIGH_POWER, 0xC); | 207 | aic3x_write_reg(AIC3X_HIGH_POWER, 0xC); |
170 | |||
171 | /* driver power-on time 200 ms, ramp-up step time 4 ms */ | ||
172 | aic3x_write_reg(AIC3X_POP_REDUCT, 0x7C); | ||
173 | |||
174 | /* DAC_L1 routed to HPLOUT, volume analog gain 0xC (-6.0dB) */ | ||
175 | aic3x_write_reg(AIC3X_DAC_L1_VOL, 0x8C); | ||
176 | /* HPLOUT output level 0dB, not muted, fully powered up */ | ||
177 | aic3x_write_reg(AIC3X_HPLOUT_LVL, 0xB); | ||
178 | 208 | ||
179 | /* HPLCOM is muted */ | 209 | /* DAC_L1 routed to HPLOUT */ |
180 | aic3x_write_reg(AIC3X_HPLCOM_LVL, 0x7); | 210 | aic3x_write_reg(AIC3X_DAC_L1_VOL, 0x80); |
211 | /* DAC_R1 routed to HPROUT */ | ||
212 | aic3x_write_reg(AIC3X_DAC_R1_VOL, 0x80); | ||
181 | 213 | ||
182 | /* DAC_R1 routed to HPROUT, volume analog gain 0xC (-6.0 dB) */ | 214 | /* DAC_L1 routed to MONO_LOP/M */ |
183 | aic3x_write_reg(AIC3X_DAC_R1_VOL, 0x8C); | 215 | aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL, 0x80); |
184 | /* HPROUT output level 0dB, not muted, fully powered up */ | 216 | /* DAC_R1 routed to MONO_LOP/M */ |
185 | aic3x_write_reg(AIC3X_HPROUT_LVL, 0xB); | 217 | aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL, 0x80); |
186 | |||
187 | /* DAC_L1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */ | ||
188 | aic3x_write_reg(AIC3X_DAC_L1_MONO_LOP_M_VOL, 0x92); | ||
189 | /* DAC_R1 routed to MONO_LOP/M, gain 0x2 (-1.0dB) */ | ||
190 | aic3x_write_reg(AIC3X_DAC_R1_MONO_LOP_M_VOL, 0x92); | ||
191 | |||
192 | /* MONO_LOP output level 6dB, not muted, fully powered up */ | ||
193 | aic3x_write_reg(AIC3X_MONO_LOP_M_LVL, 0x6b); | ||
194 | 218 | ||
195 | /* DAC_L1 routed to LEFT_LOP/M */ | 219 | /* DAC_L1 routed to LEFT_LOP/M */ |
196 | aic3x_write_reg(AIC3X_DAC_L1_LEFT_LOP_M_VOL, 0x80); | 220 | aic3x_write_reg(AIC3X_DAC_L1_LEFT_LOP_M_VOL, 0x80); |
197 | /* LEFT_LOP/M output level 0dB, not muted */ | ||
198 | aic3x_write_reg(AIC3X_LEFT_LOP_M_LVL, 0xB); | ||
199 | |||
200 | /* DAC_R1 routed to RIGHT_LOP/M */ | 221 | /* DAC_R1 routed to RIGHT_LOP/M */ |
201 | aic3x_write_reg(AIC3X_DAC_R1_RIGHT_LOP_M_VOL, 0x80); | 222 | aic3x_write_reg(AIC3X_DAC_R1_RIGHT_LOP_M_VOL, 0x80); |
223 | |||
224 | /* LEFT_LOP/M output level 0dB, not muted */ | ||
225 | aic3x_write_reg(AIC3X_LEFT_LOP_M_LVL, 0x8); | ||
202 | /* RIGHT_LOP/M output level 0dB, not muted */ | 226 | /* RIGHT_LOP/M output level 0dB, not muted */ |
203 | aic3x_write_reg(AIC3X_RIGHT_LOP_M_LVL, 0xB); | 227 | aic3x_write_reg(AIC3X_RIGHT_LOP_M_LVL, 0x8); |
228 | |||
229 | /* Enable PLL. Set Q=16, P=1 */ | ||
230 | aic3x_write_reg(AIC3X_PLL_REG_A, 0x81); | ||
231 | /* PLL J = 53 */ | ||
232 | aic3x_write_reg(AIC3X_PLL_REG_B, 0xD4); | ||
233 | /* PLL D = 5211 */ | ||
234 | aic3x_write_reg(AIC3X_PLL_REG_C, 0x51); | ||
235 | aic3x_write_reg(AIC3X_PLL_REG_D, 0x6C); | ||
236 | /* PLL R = 1 */ | ||
237 | aic3x_write_reg(AIC3X_OVERFLOW, 0x01); | ||
238 | |||
239 | /* ADC fs = fs(ref)/5.5; DAC fs = fs(ref) */ | ||
240 | aic3x_write_reg(AIC3X_SMPL_RATE, 0x90); | ||
241 | |||
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); | ||
246 | |||
247 | /* HPLCOM is high impedance when powered down, not fully powered up */ | ||
248 | aic3x_write_reg(AIC3X_HPLCOM_LVL, 0x04); | ||
204 | } | 249 | } |
205 | 250 | ||
206 | void audiohw_postinit(void) | 251 | void audiohw_postinit(void) |
207 | { | 252 | { |
208 | audiohw_mute(false); | 253 | audiohw_mute(false); |
254 | |||
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); | ||
259 | |||
260 | /* MONO_LOP output level 6dB, not muted */ | ||
261 | aic3x_write_reg(AIC3X_MONO_LOP_M_LVL, 0x69); | ||
209 | 262 | ||
210 | /* Power up Left, Right DAC/LOP, HPLOUT and HPROUT */ | 263 | /* PGA_R is not routed to MONO_LOP/M, analog gain -52.7dB */ |
211 | aic3x_write_reg(AIC3X_MOD_POWER, 0xFE); | 264 | aic3x_write_reg(AIC3X_PGA_R_MONO_LOP_M_VOL, 0x69); |
212 | } | 265 | } |
213 | 266 | ||
214 | void audiohw_set_frequency(int fsel) | 267 | void audiohw_set_frequency(int fsel) |
@@ -238,10 +291,46 @@ void audiohw_set_headphone_vol(int vol_l, int vol_r) | |||
238 | /* Nice shutdown of AIC3X codec */ | 291 | /* Nice shutdown of AIC3X codec */ |
239 | void audiohw_close(void) | 292 | void audiohw_close(void) |
240 | { | 293 | { |
241 | audiohw_mute(true); | 294 | /* HPLOUT, HPROUT, HPLCOM not fully powered up */ |
242 | #ifdef SANSA_CONNECT | 295 | aic3x_change_reg(AIC3X_HPLOUT_LVL, 0x00, 0xFE); |
243 | avr_hid_reset_codec(); | 296 | aic3x_change_reg(AIC3X_HPROUT_LVL, 0x00, 0xFE); |
244 | #endif | 297 | aic3x_change_reg(AIC3X_HPLCOM_LVL, 0x00, 0xFC); |
298 | |||
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); | ||
303 | |||
304 | /* Power down left and right DAC */ | ||
305 | aic3x_change_reg(AIC3X_DAC_POWER, 0x00, 0x30); | ||
306 | |||
307 | /* Disable PLL */ | ||
308 | aic3x_change_reg(AIC3X_PLL_REG_A, 0x00, 0x7F); | ||
245 | } | 309 | } |
246 | 310 | ||
311 | void aic3x_switch_output(bool stereo) | ||
312 | { | ||
313 | if (stereo) | ||
314 | { | ||
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); | ||
323 | } | ||
324 | else | ||
325 | { | ||
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); | ||
334 | } | ||
335 | } | ||
247 | 336 | ||