summaryrefslogtreecommitdiff
path: root/firmware/drivers/audio/aic3x.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/audio/aic3x.c')
-rw-r--r--firmware/drivers/audio/aic3x.c197
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
82static 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
99static 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
87static void aic3x_apply_volume(void) 112static 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
206void audiohw_postinit(void) 251void 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
214void audiohw_set_frequency(int fsel) 267void 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 */
239void audiohw_close(void) 292void 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
311void 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