blob: 12aa46821ab555e388307eb1e757bbcc6ba5619a [file] [log] [blame]
Dave Chapmana472ed52005-12-16 11:00:44 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Dave Chapmanc3f9d002005-12-19 14:30:52 +000010 * Driver for WM8975 audio codec
Dave Chapmana472ed52005-12-16 11:00:44 +000011 *
Dave Chapmanc3f9d002005-12-19 14:30:52 +000012 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in December 2005
14 *
15 * Original file: linux/arch/armnommu/mach-ipod/audio.c
16 *
17 * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org)
Dave Chapmana472ed52005-12-16 11:00:44 +000018 *
19 * All files in this archive are subject to the GNU General Public License.
20 * See the file COPYING in the source tree root for full license agreement.
21 *
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
24 *
25 ****************************************************************************/
26#include "lcd.h"
27#include "cpu.h"
28#include "kernel.h"
29#include "thread.h"
30#include "power.h"
31#include "debug.h"
32#include "system.h"
33#include "sprintf.h"
34#include "button.h"
35#include "string.h"
36#include "file.h"
37#include "buffer.h"
38#include "audio.h"
39
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +000040#include "wmcodec.h"
Dave Chapmana472ed52005-12-16 11:00:44 +000041#include "wm8975.h"
Daniel Ankersacbbe822006-12-09 19:18:18 +000042#include "i2s.h"
Dave Chapmana472ed52005-12-16 11:00:44 +000043
Marcoen Hirschberg1b967f42006-12-06 13:34:15 +000044/* convert tenth of dB volume (-730..60) to master volume register value */
45int tenthdb2master(int db)
46{
47 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
48 /* 1111111 == +6dB (0x7f) */
49 /* 1111001 == 0dB (0x79) */
50 /* 0110000 == -73dB (0x30 */
51 /* 0101111 == mute (0x2f) */
52
53 if (db < VOLUME_MIN) {
54 return 0x0;
55 } else {
56 return((db/10)+73+0x30);
57 }
58}
59
60/* convert tenth of dB volume (-780..0) to mixer volume register value */
61int tenthdb2mixer(int db)
62{
63 if (db < -660) /* 1.5 dB steps */
64 return (2640 - db) / 15;
65 else if (db < -600) /* 0.75 dB steps */
66 return (990 - db) * 2 / 15;
67 else if (db < -460) /* 0.5 dB steps */
68 return (460 - db) / 5;
69 else /* 0.25 dB steps */
70 return -db * 2 / 5;
71}
72
73
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +000074void audiohw_reset(void);
Dave Chapmana472ed52005-12-16 11:00:44 +000075
76#define IPOD_PCM_LEVEL 0x65 /* -6dB */
77
Dave Chapmana472ed52005-12-16 11:00:44 +000078
79/* Silently enable / disable audio output */
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +000080void audiohw_enable_output(bool enable)
Dave Chapmana472ed52005-12-16 11:00:44 +000081{
82 if (enable)
83 {
84 /* reset the I2S controller into known state */
85 i2s_reset();
86
87 /*
88 * 1. Switch on power supplies.
89 * By default the WM8750L is in Standby Mode, the DAC is
90 * digitally muted and the Audio Interface, Line outputs
91 * and Headphone outputs are all OFF (DACMU = 1 Power
92 * Management registers 1 and 2 are all zeros).
93 */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +000094 wmcodec_write(RESET, 0x1ff); /*Reset*/
95 wmcodec_write(RESET, 0x0);
Dave Chapmana472ed52005-12-16 11:00:44 +000096
97 /* 2. Enable Vmid and VREF. */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +000098 wmcodec_write(PWRMGMT1, 0xc0); /*Pwr Mgmt(1)*/
Dave Chapmana472ed52005-12-16 11:00:44 +000099
100 /* 3. Enable DACs as required. */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000101 wmcodec_write(PWRMGMT2, 0x180); /*Pwr Mgmt(2)*/
Dave Chapmana472ed52005-12-16 11:00:44 +0000102
103 /* 4. Enable line and / or headphone output buffers as required. */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000104 wmcodec_write(PWRMGMT2, 0x1f8); /*Pwr Mgmt(2)*/
Dave Chapmana472ed52005-12-16 11:00:44 +0000105
106 /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */
107 /* IWL=00(16 bit) FORMAT=10(I2S format) */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000108 wmcodec_write(AINTFCE, 0x42);
Dave Chapmana472ed52005-12-16 11:00:44 +0000109
110 /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000111 audiohw_set_sample_rate(WM8975_44100HZ);
Dave Chapmana472ed52005-12-16 11:00:44 +0000112
113 /* set the volume to -6dB */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000114 wmcodec_write(LOUT1VOL, IPOD_PCM_LEVEL);
115 wmcodec_write(ROUT1VOL,0x100 | IPOD_PCM_LEVEL);
116 wmcodec_write(LOUT1VOL, IPOD_PCM_LEVEL);
117 wmcodec_write(ROUT1VOL,0x100 | IPOD_PCM_LEVEL);
Dave Chapman6ffd3cf2006-02-12 17:18:47 +0000118
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000119 wmcodec_write(LOUTMIX1, 0x150); /* Left out Mix(def) */
120 wmcodec_write(LOUTMIX2, 0x50);
Dave Chapmana472ed52005-12-16 11:00:44 +0000121
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000122 wmcodec_write(ROUTMIX1, 0x50); /* Right out Mix(def) */
123 wmcodec_write(ROUTMIX2, 0x150);
Dave Chapmana472ed52005-12-16 11:00:44 +0000124
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000125 wmcodec_write(MOUTMIX1, 0x0); /* Mono out Mix */
126 wmcodec_write(MOUTMIX2, 0x0);
Dave Chapmana472ed52005-12-16 11:00:44 +0000127
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000128 audiohw_mute(0);
Dave Chapmana472ed52005-12-16 11:00:44 +0000129 } else {
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000130 audiohw_mute(1);
Dave Chapmana472ed52005-12-16 11:00:44 +0000131 }
132}
133
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000134int audiohw_set_master_vol(int vol_l, int vol_r)
Dave Chapmana472ed52005-12-16 11:00:44 +0000135{
136 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
137 /* 1111111 == +6dB */
138 /* 1111001 == 0dB */
139 /* 0110000 == -73dB */
140 /* 0101111 == mute (0x2f) */
141
142 /* OUT1 */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000143 wmcodec_write(LOUT1VOL, vol_l);
144 wmcodec_write(ROUT1VOL, 0x100 | vol_r);
Dave Chapmana472ed52005-12-16 11:00:44 +0000145
Thom Johansen473fc2b2006-03-22 13:04:49 +0000146 return 0;
147}
148
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000149int audiohw_set_lineout_vol(int vol_l, int vol_r)
Thom Johansen473fc2b2006-03-22 13:04:49 +0000150{
Dave Chapmana472ed52005-12-16 11:00:44 +0000151 /* OUT2 */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000152 wmcodec_write(LOUT2VOL, vol_l);
153 wmcodec_write(ROUT2VOL, 0x100 | vol_r);
Dave Chapman149f5bb2005-12-16 11:18:04 +0000154
155 return 0;
Dave Chapmana472ed52005-12-16 11:00:44 +0000156}
157
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000158int audiohw_set_mixer_vol(int channel1, int channel2)
Dave Chapmana472ed52005-12-16 11:00:44 +0000159{
Dave Chapman149f5bb2005-12-16 11:18:04 +0000160 (void)channel1;
161 (void)channel2;
Dave Chapmana472ed52005-12-16 11:00:44 +0000162
Dave Chapman149f5bb2005-12-16 11:18:04 +0000163 return 0;
Dave Chapmana472ed52005-12-16 11:00:44 +0000164}
165
Dave Chapman5ffa8c52006-01-30 21:12:31 +0000166/* We are using Linear bass control */
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000167void audiohw_set_bass(int value)
Dave Chapmana472ed52005-12-16 11:00:44 +0000168{
Dave Chapman5ffa8c52006-01-30 21:12:31 +0000169 int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0};
170
171 if ((value >= -6) && (value <= 9)) {
172 /* We use linear bass control with 130Hz cutoff */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000173 wmcodec_write(BASSCTRL, regvalues[value+6]);
Dave Chapman5ffa8c52006-01-30 21:12:31 +0000174 }
Dave Chapmana472ed52005-12-16 11:00:44 +0000175}
176
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000177void audiohw_set_treble(int value)
Dave Chapmana472ed52005-12-16 11:00:44 +0000178{
Dave Chapman5ffa8c52006-01-30 21:12:31 +0000179 int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0};
180
181 if ((value >= -6) && (value <= 9)) {
182 /* We use a 8Khz cutoff */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000183 wmcodec_write(TREBCTRL, regvalues[value+6]);
Dave Chapman5ffa8c52006-01-30 21:12:31 +0000184 }
Dave Chapmana472ed52005-12-16 11:00:44 +0000185}
186
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000187int audiohw_mute(int mute)
Dave Chapmana472ed52005-12-16 11:00:44 +0000188{
189 if (mute)
190 {
191 /* Set DACMU = 1 to soft-mute the audio DACs. */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000192 wmcodec_write(DACCTRL, 0x8);
Dave Chapmana472ed52005-12-16 11:00:44 +0000193 } else {
194 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000195 wmcodec_write(DACCTRL, 0x0);
Dave Chapmana472ed52005-12-16 11:00:44 +0000196 }
Dave Chapman149f5bb2005-12-16 11:18:04 +0000197
198 return 0;
Dave Chapmana472ed52005-12-16 11:00:44 +0000199}
200
201/* Nice shutdown of WM8975 codec */
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000202void audiohw_close(void)
Dave Chapmana472ed52005-12-16 11:00:44 +0000203{
204 /* 1. Set DACMU = 1 to soft-mute the audio DACs. */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000205 wmcodec_write(DACCTRL, 0x8);
Dave Chapmana472ed52005-12-16 11:00:44 +0000206
207 /* 2. Disable all output buffers. */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000208 wmcodec_write(PWRMGMT2, 0x0); /*Pwr Mgmt(2)*/
Dave Chapmana472ed52005-12-16 11:00:44 +0000209
210 /* 3. Switch off the power supplies. */
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000211 wmcodec_write(PWRMGMT1, 0x0); /*Pwr Mgmt(1)*/
Dave Chapmana472ed52005-12-16 11:00:44 +0000212}
213
214/* Change the order of the noise shaper, 5th order is recommended above 32kHz */
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000215void audiohw_set_nsorder(int order)
Dave Chapmana472ed52005-12-16 11:00:44 +0000216{
Dave Chapman149f5bb2005-12-16 11:18:04 +0000217 (void)order;
Dave Chapmana472ed52005-12-16 11:00:44 +0000218}
219
220/* Note: Disable output before calling this function */
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000221void audiohw_set_sample_rate(int sampling_control) {
Dave Chapmana472ed52005-12-16 11:00:44 +0000222
Marcoen Hirschberg1d7ebdf2006-10-20 17:12:42 +0000223 wmcodec_write(0x08, sampling_control);
Dave Chapmana472ed52005-12-16 11:00:44 +0000224
225}
226
Barry Wardelldf0dc222006-12-18 01:52:21 +0000227void audiohw_enable_recording(bool source_mic)
228{
229 (void)source_mic;
Dave Chapmana472ed52005-12-16 11:00:44 +0000230
Barry Wardelldf0dc222006-12-18 01:52:21 +0000231 /* reset the I2S controller into known state */
232 i2s_reset();
233
234 /*
235 * 1. Switch on power supplies.
236 * By default the WM8750L is in Standby Mode, the DAC is
237 * digitally muted and the Audio Interface, Line outputs
238 * and Headphone outputs are all OFF (DACMU = 1 Power
239 * Management registers 1 and 2 are all zeros).
240 */
241 wmcodec_write(0x0f, 0x1ff);
242 wmcodec_write(0x0f, 0x000);
243
244 /* 2. Enable Vmid and VREF. */
245 wmcodec_write(0x19, 0xc0); /*Pwr Mgmt(1)*/
246
247 /* 3. Enable ADCs as required. */
248 wmcodec_write(0x19, 0xcc); /*Pwr Mgmt(1)*/
249 wmcodec_write(0x1a, 0x180); /*Pwr Mgmt(2)*/
250
251 /* 4. Enable line and / or headphone output buffers as required. */
252 wmcodec_write(0x19, 0xfc); /*Pwr Mgmt(1)*/
253
254 /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */
255 /* IWL=00(16 bit) FORMAT=10(I2S format) */
256 wmcodec_write(0x07, 0x42);
257
258 /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */
Barry Wardellca7a2642006-12-18 02:18:56 +0000259 audiohw_set_sample_rate(WM8975_44100HZ);
Barry Wardelldf0dc222006-12-18 01:52:21 +0000260
261 /* unmute inputs */
262 wmcodec_write(0x00, 0x17); /* LINVOL (def 0dB) */
263 wmcodec_write(0x01, 0x117); /* RINVOL (def 0dB) */
264
265 wmcodec_write(0x15, 0x1d7); /* LADCVOL max vol x was ff */
266 wmcodec_write(0x16, 0x1d7); /* RADCVOL max vol x was ff */
267
268 if (source_mic) {
269 /* VSEL=10(def) DATSEL=10 (use right ADC only) */
270 wmcodec_write(0x17, 0xc8); /* Additional control(1) */
271
272 /* VROI=1 (sets output resistance to 40kohms) */
273 wmcodec_write(0x1b, 0x40); /* Additional control(3) */
274
275 /* LINSEL=1 (LINPUT2) LMICBOOST=10 (20dB boost) */
276 wmcodec_write(0x20, 0x60); /* ADCL signal path */
277 wmcodec_write(0x21, 0x60); /* ADCR signal path */
278 } else {
279 /* VSEL=10(def) DATSEL=00 (left->left, right->right) */
280 wmcodec_write(0x17, 0xc0); /* Additional control(1) */
281
282 /* VROI=1 (sets output resistance to 40kohms) */
283 wmcodec_write(0x1b, 0x40); /* Additional control(3) */
284
285 /* LINSEL=0 (LINPUT1) LMICBOOST=00 (bypass boost) */
286 wmcodec_write(0x20, 0x00); /* ADCL signal path */
287 /* RINSEL=0 (RINPUT1) RMICBOOST=00 (bypass boost) */
288 wmcodec_write(0x21, 0x00); /* ADCR signal path */
289 }
Dave Chapmana472ed52005-12-16 11:00:44 +0000290}
Barry Wardelldf0dc222006-12-18 01:52:21 +0000291
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000292void audiohw_disable_recording(void) {
Barry Wardelldf0dc222006-12-18 01:52:21 +0000293 /* 1. Set DACMU = 1 to soft-mute the audio DACs. */
294 wmcodec_write(0x05, 0x8);
Dave Chapmana472ed52005-12-16 11:00:44 +0000295
Barry Wardelldf0dc222006-12-18 01:52:21 +0000296 /* 2. Disable all output buffers. */
297 wmcodec_write(0x1a, 0x0); /*Pwr Mgmt(2)*/
298
299 /* 3. Switch off the power supplies. */
300 wmcodec_write(0x19, 0x0); /*Pwr Mgmt(1)*/
Dave Chapmana472ed52005-12-16 11:00:44 +0000301}
302
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000303void audiohw_set_recvol(int left, int right, int type) {
Dave Chapmana472ed52005-12-16 11:00:44 +0000304
Dave Chapman149f5bb2005-12-16 11:18:04 +0000305 (void)left;
306 (void)right;
307 (void)type;
Dave Chapmana472ed52005-12-16 11:00:44 +0000308}
309
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000310void audiohw_set_monitor(int enable) {
Dave Chapmana472ed52005-12-16 11:00:44 +0000311
Dave Chapman149f5bb2005-12-16 11:18:04 +0000312 (void)enable;
Dave Chapmana472ed52005-12-16 11:00:44 +0000313}