Mercurial > hg > beaglert
comparison core/I2c_Codec.cpp @ 0:8a575ba3ab52
Initial commit.
author | andrewm |
---|---|
date | Fri, 31 Oct 2014 19:10:17 +0100 |
parents | |
children | c44fa102d02b |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:8a575ba3ab52 |
---|---|
1 /* | |
2 * I2c_Codec.cpp | |
3 * | |
4 * Handle writing the registers to the TLV320AIC310x | |
5 * series audio codecs, used on the BeagleBone Audio Cape. | |
6 * This code is designed to bypass the ALSA driver and | |
7 * configure the codec directly in a sensible way. It | |
8 * is complemented by code running on the PRU which uses | |
9 * the McASP serial port to transfer audio data. | |
10 * | |
11 * Created on: May 25, 2014 | |
12 * Author: Andrew McPherson | |
13 */ | |
14 | |
15 #include "../include/I2c_Codec.h" | |
16 | |
17 I2c_Codec::I2c_Codec() | |
18 : running(false), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0) | |
19 {} | |
20 | |
21 // This method initialises the audio codec to its default state | |
22 int I2c_Codec::initCodec() | |
23 { | |
24 // Write the reset register of the codec | |
25 if(writeRegister(0x01, 0x80)) // Software reset register | |
26 { | |
27 cout << "Failed to reset codec\n"; | |
28 return 1; | |
29 } | |
30 | |
31 // Wait for codec to process the reset (for safety) | |
32 usleep(5000); | |
33 | |
34 return 0; | |
35 } | |
36 | |
37 // Tell the codec to start generating audio | |
38 // See the TLV320AIC3106 datasheet for full details of the registers | |
39 // The dual_rate flag, when true, runs the codec at 88.2kHz; otherwise | |
40 // it runs at 44.1kHz | |
41 int I2c_Codec::startAudio(int dual_rate) | |
42 { | |
43 if(writeRegister(0x02, 0x00)) // Codec sample rate register: fs_ref / 1 | |
44 return 1; | |
45 if(writeRegister(0x03, 0x91)) // PLL register A: enable | |
46 return 1; | |
47 if(writeRegister(0x04, 0x1C)) // PLL register B | |
48 return 1; | |
49 if(writeRegister(0x05, 0x52)) // PLL register C | |
50 return 1; | |
51 if(writeRegister(0x06, 0x40)) // PLL register D | |
52 return 1; | |
53 if(dual_rate) { | |
54 if(writeRegister(0x07, 0xEA)) // Codec datapath register: 44.1kHz; dual rate; standard datapath | |
55 return 1; | |
56 } | |
57 else { | |
58 if(writeRegister(0x07, 0x8A)) // Codec datapath register: 44.1kHz; std rate; standard datapath | |
59 return 1; | |
60 } | |
61 if(writeRegister(0x08, 0xC0)) // Audio serial control register A: BLCK, WCLK outputs | |
62 return 1; | |
63 if(writeRegister(0x09, 0x40)) // Audio serial control register B: DSP mode, word len 16 bits | |
64 return 1; | |
65 if(writeRegister(0x0A, 0x00)) // Audio serial control register C: 0 bit offset | |
66 return 1; | |
67 if(writeRegister(0x0B, 0x01)) // Audio codec overflow flag register: PLL R = 1 | |
68 return 1; | |
69 if(writeRegister(0x0C, 0x00)) // Digital filter register: disabled | |
70 return 1; | |
71 if(writeRegister(0x0D, 0x00)) // Headset / button press register A: disabled | |
72 return 1; | |
73 if(writeRegister(0x0E, 0x00)) // Headset / button press register B: disabled | |
74 return 1; | |
75 if(writeRegister(0x0F, 0x20)) // Left ADC PGA gain control: not muted; 0x20 = 16dB | |
76 return 1; | |
77 if(writeRegister(0x10, 0x20)) // Right ADC PGA gain control: not muted; 0x20 = 16dB | |
78 return 1; | |
79 | |
80 if(writeRegister(0x25, 0xC0)) // DAC power/driver register: DAC power on (left and right) | |
81 return 1; | |
82 if(writeRegister(0x26, 0x04)) // High power output driver register: Enable short circuit protection | |
83 return 1; | |
84 if(writeRegister(0x28, 0x02)) // High power output stage register: disable soft stepping | |
85 return 1; | |
86 | |
87 if(writeRegister(0x52, 0x80)) // DAC_L1 to LEFT_LOP volume control: routed, volume 0dB | |
88 return 1; | |
89 if(writeRegister(0x5C, 0x80)) // DAC_R1 to RIGHT_LOP volume control: routed, volume 0dB | |
90 return 1; | |
91 | |
92 if(writeHPVolumeRegisters()) // Send DAC to high-power outputs | |
93 return 1; | |
94 | |
95 if(writeRegister(0x66, 0x02)) // Clock generation control register: use MCLK, PLL N = 2 | |
96 return 1; | |
97 | |
98 if(writeRegister(0x33, 0x0D)) // HPLOUT output level control: output level = 0dB, not muted, powered up | |
99 return 1; | |
100 if(writeRegister(0x41, 0x0D)) // HPROUT output level control: output level = 0dB, not muted, powered up | |
101 return 1; | |
102 if(writeRegister(0x56, 0x09)) // LEFT_LOP output level control: 0dB, not muted, powered up | |
103 return 1; | |
104 if(writeRegister(0x5D, 0x09)) // RIGHT_LOP output level control: 0dB, not muted, powered up | |
105 return 1; | |
106 | |
107 if(writeDACVolumeRegisters(false)) // Unmute and set volume | |
108 return 1; | |
109 | |
110 if(writeRegister(0x65, 0x00)) // GPIO control register B: disabled; codec uses PLLDIV_OUT | |
111 return 1; | |
112 | |
113 if(writeADCVolumeRegisters(false)) // Unmute and set ADC volume | |
114 return 1; | |
115 | |
116 running = true; | |
117 return 0; | |
118 } | |
119 | |
120 // Set the volume of the DAC output | |
121 int I2c_Codec::setDACVolume(int halfDbSteps) | |
122 { | |
123 dacVolumeHalfDbs = halfDbSteps; | |
124 if(running) | |
125 return writeDACVolumeRegisters(false); | |
126 | |
127 return 0; | |
128 } | |
129 | |
130 // Set the volume of the DAC output | |
131 int I2c_Codec::setADCVolume(int halfDbSteps) | |
132 { | |
133 adcVolumeHalfDbs = halfDbSteps; | |
134 if(running) | |
135 return writeADCVolumeRegisters(false); | |
136 | |
137 return 0; | |
138 } | |
139 | |
140 // Update the DAC volume control registers | |
141 int I2c_Codec::writeDACVolumeRegisters(bool mute) | |
142 { | |
143 int volumeBits = 0; | |
144 | |
145 if(dacVolumeHalfDbs < 0) { // Volume is specified in half-dBs with 0 as full scale | |
146 volumeBits = -dacVolumeHalfDbs; | |
147 if(volumeBits > 127) | |
148 volumeBits = 127; | |
149 } | |
150 | |
151 if(mute) { | |
152 if(writeRegister(0x2B, volumeBits | 0x80)) // Left DAC volume control: muted | |
153 return 1; | |
154 if(writeRegister(0x2C, volumeBits | 0x80)) // Right DAC volume control: muted | |
155 return 1; | |
156 } | |
157 else { | |
158 if(writeRegister(0x2B, volumeBits)) // Left DAC volume control: not muted | |
159 return 1; | |
160 if(writeRegister(0x2C, volumeBits)) // Right DAC volume control: not muted | |
161 return 1; | |
162 } | |
163 | |
164 return 0; | |
165 } | |
166 | |
167 // Update the ADC volume control registers | |
168 int I2c_Codec::writeADCVolumeRegisters(bool mute) | |
169 { | |
170 int volumeBits = 0; | |
171 | |
172 // Volume is specified in half-dBs with 0 as full scale | |
173 // The codec uses 1.5dB steps so we divide this number by 3 | |
174 if(adcVolumeHalfDbs < 0) { | |
175 volumeBits = -adcVolumeHalfDbs / 3; | |
176 if(volumeBits > 8) | |
177 volumeBits = 8; | |
178 } | |
179 | |
180 if(mute) { | |
181 if(writeRegister(0x13, 0x00)) // Line1L to Left ADC control register: power down | |
182 return 1; | |
183 if(writeRegister(0x16, 0x00)) // Line1R to Right ADC control register: power down | |
184 return 1; | |
185 } | |
186 else { | |
187 if(writeRegister(0x13, 0x7C)) // Line1L disabled; left ADC powered up with soft step | |
188 return 1; | |
189 if(writeRegister(0x16, 0x7C)) // Line1R disabled; right ADC powered up with soft step | |
190 return 1; | |
191 if(writeRegister(0x11, (volumeBits << 4) | 0x0F)) // Line2L connected to left ADC | |
192 return 1; | |
193 if(writeRegister(0x12, volumeBits | 0xF0)) // Line2R connected to right ADC | |
194 return 1; | |
195 } | |
196 | |
197 return 0; | |
198 } | |
199 | |
200 // Set the volume of the headphone output | |
201 int I2c_Codec::setHPVolume(int halfDbSteps) | |
202 { | |
203 hpVolumeHalfDbs = halfDbSteps; | |
204 if(running) | |
205 return writeHPVolumeRegisters(); | |
206 | |
207 return 0; | |
208 } | |
209 | |
210 | |
211 // Update the headphone volume control registers | |
212 int I2c_Codec::writeHPVolumeRegisters() | |
213 { | |
214 int volumeBits = 0; | |
215 | |
216 if(hpVolumeHalfDbs < 0) { // Volume is specified in half-dBs with 0 as full scale | |
217 volumeBits = -hpVolumeHalfDbs; | |
218 if(volumeBits > 127) | |
219 volumeBits = 127; | |
220 } | |
221 | |
222 if(writeRegister(0x2F, volumeBits | 0x80)) // DAC_L1 to HPLOUT register: route to HPLOUT, volume 0dB | |
223 return 1; | |
224 if(writeRegister(0x40, volumeBits | 0x80)) // DAC_R1 to HPROUT register: route to HPROUT, volume 0dB | |
225 return 1; | |
226 | |
227 return 0; | |
228 } | |
229 | |
230 // This tells the codec to stop generating audio and mute the outputs | |
231 int I2c_Codec::stopAudio() | |
232 { | |
233 if(writeDACVolumeRegisters(true)) // Mute the DACs | |
234 return 1; | |
235 if(writeADCVolumeRegisters(true)) // Mute the ADCs | |
236 return 1; | |
237 | |
238 usleep(10000); | |
239 | |
240 if(writeRegister(0x33, 0x0C)) // HPLOUT output level register: muted | |
241 return 1; | |
242 if(writeRegister(0x41, 0x0C)) // HPROUT output level register: muted | |
243 return 1; | |
244 if(writeRegister(0x56, 0x08)) // LEFT_LOP output level control: muted | |
245 return 1; | |
246 if(writeRegister(0x5D, 0x08)) // RIGHT_LOP output level control: muted | |
247 return 1; | |
248 if(writeRegister(0x25, 0x00)) // DAC power/driver register: power off | |
249 return 1; | |
250 if(writeRegister(0x03, 0x11)) // PLL register A: disable | |
251 return 1; | |
252 if(writeRegister(0x01, 0x80)) // Reset codec to defaults | |
253 return 1; | |
254 | |
255 running = false; | |
256 return 0; | |
257 } | |
258 | |
259 // Write a specific register on the codec | |
260 int I2c_Codec::writeRegister(unsigned int reg, unsigned int value) | |
261 { | |
262 char buf[2] = { reg & 0xFF, value & 0xFF }; | |
263 | |
264 if(write(i2C_file, buf, 2) != 2) | |
265 { | |
266 cout << "Failed to write register " << reg << " on codec\n"; | |
267 return 1; | |
268 } | |
269 | |
270 return 0; | |
271 } | |
272 | |
273 | |
274 int I2c_Codec::readI2C() | |
275 { | |
276 // Nothing to do here, we only write the registers | |
277 return 0; | |
278 } | |
279 | |
280 | |
281 I2c_Codec::~I2c_Codec() | |
282 { | |
283 if(running) | |
284 stopAudio(); | |
285 } | |
286 |