diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/wm8758.c | 276 | ||||
-rw-r--r-- | firmware/drivers/wm8975.c | 36 |
2 files changed, 294 insertions, 18 deletions
diff --git a/firmware/drivers/wm8758.c b/firmware/drivers/wm8758.c new file mode 100644 index 0000000000..3069b3cba7 --- /dev/null +++ b/firmware/drivers/wm8758.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Driver for WM8758 audio codec | ||
11 | * | ||
12 | * 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) | ||
18 | * | ||
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 | |||
40 | #include "i2c-pp5020.h" | ||
41 | #include "wm8758.h" | ||
42 | #include "pcf50605.h" | ||
43 | |||
44 | void wmcodec_reset(void); | ||
45 | |||
46 | #define IPOD_PCM_LEVEL 0x65 /* -6dB */ | ||
47 | |||
48 | //#define BASSCTRL 0x | ||
49 | //#define TREBCTRL 0x0b | ||
50 | |||
51 | /* | ||
52 | * Reset the I2S BIT.FORMAT I2S, 16bit, FIFO.FORMAT 32bit | ||
53 | */ | ||
54 | static void i2s_reset(void) | ||
55 | { | ||
56 | /* PP502x */ | ||
57 | |||
58 | /* I2S soft reset */ | ||
59 | outl(inl(0x70002800) | 0x80000000, 0x70002800); | ||
60 | outl(inl(0x70002800) & ~0x80000000, 0x70002800); | ||
61 | |||
62 | /* BIT.FORMAT [11:10] = I2S (default) */ | ||
63 | outl(inl(0x70002800) & ~0xc00, 0x70002800); | ||
64 | /* BIT.SIZE [9:8] = 16bit (default) */ | ||
65 | outl(inl(0x70002800) & ~0x300, 0x70002800); | ||
66 | |||
67 | /* FIFO.FORMAT [6:4] = 32 bit LSB */ | ||
68 | /* since BIT.SIZ < FIFO.FORMAT low 16 bits will be 0 */ | ||
69 | outl(inl(0x70002800) | 0x30, 0x70002800); | ||
70 | |||
71 | /* RX_ATN_LVL=1 == when 12 slots full */ | ||
72 | /* TX_ATN_LVL=1 == when 12 slots empty */ | ||
73 | outl(inl(0x7000280c) | 0x33, 0x7000280c); | ||
74 | |||
75 | /* Rx.CLR = 1, TX.CLR = 1 */ | ||
76 | outl(inl(0x7000280c) | 0x1100, 0x7000280c); | ||
77 | } | ||
78 | |||
79 | void wm8758_write(int reg, int data) | ||
80 | { | ||
81 | ipod_i2c_send(0x1a, (reg<<1) | ((data&0x100)>>8),data&0xff); | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * Initialise the WM8758 for playback via headphone and line out. | ||
86 | * Note, I'm using the WM8750 datasheet as its apparently close. | ||
87 | */ | ||
88 | int wmcodec_init(void) { | ||
89 | /* reset I2C */ | ||
90 | i2c_init(); | ||
91 | |||
92 | /* normal outputs for CDI and I2S pin groups */ | ||
93 | outl(inl(0x70000020) & ~0x300, 0x70000020); | ||
94 | |||
95 | /*mini2?*/ | ||
96 | outl(inl(0x70000010) & ~0x3000000, 0x70000010); | ||
97 | /*mini2?*/ | ||
98 | |||
99 | /* device reset */ | ||
100 | outl(inl(0x60006004) | 0x800, 0x60006004); | ||
101 | outl(inl(0x60006004) & ~0x800, 0x60006004); | ||
102 | |||
103 | /* device enable */ | ||
104 | outl(inl(0x6000600C) | 0x807, 0x6000600C); | ||
105 | |||
106 | /* enable external dev clock clocks */ | ||
107 | outl(inl(0x6000600c) | 0x2, 0x6000600c); | ||
108 | |||
109 | /* external dev clock to 24MHz */ | ||
110 | outl(inl(0x70000018) & ~0xc, 0x70000018); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | /* Silently enable / disable audio output */ | ||
116 | void wmcodec_enable_output(bool enable) | ||
117 | { | ||
118 | if (enable) | ||
119 | { | ||
120 | /* reset the I2S controller into known state */ | ||
121 | i2s_reset(); | ||
122 | |||
123 | wm8758_write(RESET, 0x1ff); /*Reset*/ | ||
124 | |||
125 | wm8758_write(PWRMGMT1, 0x2b); | ||
126 | wm8758_write(PWRMGMT2, 0x180); | ||
127 | wm8758_write(PWRMGMT3, 0x6f); | ||
128 | |||
129 | wm8758_write(AINTFCE, 0x10); | ||
130 | wm8758_write(CLKCTRL, 0x49); | ||
131 | |||
132 | wm8758_write(OUTCTRL, 1 | (0x3 << 5)); | ||
133 | |||
134 | /* The iPod can handle multiple frequencies, but fix at 44.1KHz | ||
135 | for now */ | ||
136 | wmcodec_set_sample_rate(WM8758_44100HZ); | ||
137 | |||
138 | wm8758_write(LOUTMIX,0x1); /* Enable mixer */ | ||
139 | wm8758_write(ROUTMIX,0x1); /* Enable mixer */ | ||
140 | wmcodec_mute(0); | ||
141 | } else { | ||
142 | wmcodec_mute(1); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | int wmcodec_set_master_vol(int vol_l, int vol_r) | ||
147 | { | ||
148 | /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ | ||
149 | /* 1111111 == +6dB */ | ||
150 | /* 1111001 == 0dB */ | ||
151 | /* 0110000 == -73dB */ | ||
152 | /* 0101111 == mute (0x2f) */ | ||
153 | |||
154 | /* OUT1 */ | ||
155 | wm8758_write(LOUT1VOL, vol_l); | ||
156 | wm8758_write(ROUT1VOL, 0x100 | vol_r); | ||
157 | |||
158 | /* OUT2 */ | ||
159 | wm8758_write(LOUT2VOL, vol_l); | ||
160 | wm8758_write(ROUT2VOL, 0x100 | vol_r); | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | int wmcodec_set_mixer_vol(int channel1, int channel2) | ||
166 | { | ||
167 | (void)channel1; | ||
168 | (void)channel2; | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | /* We are using Linear bass control */ | ||
174 | void wmcodec_set_bass(int value) | ||
175 | { | ||
176 | (void)value; | ||
177 | #if 0 | ||
178 | /* Not yet implemented - this is the wm8975 code*/ | ||
179 | 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 linear bass control with 130Hz cutoff */ | ||
183 | wm8758_write(BASSCTRL, regvalues[value+6]); | ||
184 | } | ||
185 | #endif | ||
186 | } | ||
187 | |||
188 | void wmcodec_set_treble(int value) | ||
189 | { | ||
190 | (void)value; | ||
191 | #if 0 | ||
192 | /* Not yet implemented - this is the wm8975 code*/ | ||
193 | int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0}; | ||
194 | |||
195 | if ((value >= -6) && (value <= 9)) { | ||
196 | /* We use a 8Khz cutoff */ | ||
197 | wm8758_write(TREBCTRL, regvalues[value+6]); | ||
198 | } | ||
199 | #endif | ||
200 | |||
201 | } | ||
202 | |||
203 | int wmcodec_mute(int mute) | ||
204 | { | ||
205 | if (mute) | ||
206 | { | ||
207 | /* Set DACMU = 1 to soft-mute the audio DACs. */ | ||
208 | wm8758_write(DACCTRL, 0x40); | ||
209 | } else { | ||
210 | /* Set DACMU = 0 to soft-un-mute the audio DACs. */ | ||
211 | wm8758_write(DACCTRL, 0x0); | ||
212 | } | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | /* Nice shutdown of WM8758 codec */ | ||
218 | void wmcodec_close(void) | ||
219 | { | ||
220 | wmcodec_mute(1); | ||
221 | |||
222 | wm8758_write(PWRMGMT3, 0x0); | ||
223 | |||
224 | wm8758_write(PWRMGMT1, 0x0); | ||
225 | |||
226 | wm8758_write(PWRMGMT2, 0x40); | ||
227 | } | ||
228 | |||
229 | /* Change the order of the noise shaper, 5th order is recommended above 32kHz */ | ||
230 | void wmcodec_set_nsorder(int order) | ||
231 | { | ||
232 | (void)order; | ||
233 | } | ||
234 | |||
235 | /* Note: Disable output before calling this function */ | ||
236 | void wmcodec_set_sample_rate(int sampling_control) | ||
237 | { | ||
238 | /**** We force 44.1KHz for now. ****/ | ||
239 | (void)sampling_control; | ||
240 | |||
241 | /* set clock div */ | ||
242 | wm8758_write(CLKCTRL, 1 | (0 << 2) | (2 << 5)); | ||
243 | |||
244 | /* setup PLL for MHZ=11.2896 */ | ||
245 | wm8758_write(PLLN, (1 << 4) | 0x7); | ||
246 | wm8758_write(PLLK1, 0x21); | ||
247 | wm8758_write(PLLK2, 0x161); | ||
248 | wm8758_write(PLLK3, 0x26); | ||
249 | |||
250 | /* set clock div */ | ||
251 | wm8758_write(CLKCTRL, 1 | (0 << 2) | (2 << 5) | (1 << 8)); | ||
252 | |||
253 | /* set srate */ | ||
254 | wm8758_write(SRATECTRL, (0 << 1)); | ||
255 | } | ||
256 | |||
257 | void wmcodec_enable_recording(bool source_mic) | ||
258 | { | ||
259 | (void)source_mic; | ||
260 | } | ||
261 | |||
262 | void wmcodec_disable_recording(void) { | ||
263 | |||
264 | } | ||
265 | |||
266 | void wmcodec_set_recvol(int left, int right, int type) { | ||
267 | |||
268 | (void)left; | ||
269 | (void)right; | ||
270 | (void)type; | ||
271 | } | ||
272 | |||
273 | void wmcodec_set_monitor(int enable) { | ||
274 | |||
275 | (void)enable; | ||
276 | } | ||
diff --git a/firmware/drivers/wm8975.c b/firmware/drivers/wm8975.c index 54e245b61a..51c12f1505 100644 --- a/firmware/drivers/wm8975.c +++ b/firmware/drivers/wm8975.c | |||
@@ -41,7 +41,7 @@ | |||
41 | #include "wm8975.h" | 41 | #include "wm8975.h" |
42 | #include "pcf50605.h" | 42 | #include "pcf50605.h" |
43 | 43 | ||
44 | void wm8975_reset(void); | 44 | void wmcodec_reset(void); |
45 | 45 | ||
46 | #define IPOD_PCM_LEVEL 0x65 /* -6dB */ | 46 | #define IPOD_PCM_LEVEL 0x65 /* -6dB */ |
47 | 47 | ||
@@ -82,7 +82,7 @@ void wm8975_write(int reg, int data) | |||
82 | * Initialise the WM8975 for playback via headphone and line out. | 82 | * Initialise the WM8975 for playback via headphone and line out. |
83 | * Note, I'm using the WM8750 datasheet as its apparently close. | 83 | * Note, I'm using the WM8750 datasheet as its apparently close. |
84 | */ | 84 | */ |
85 | int wm8975_init(void) { | 85 | int wmcodec_init(void) { |
86 | /* reset I2C */ | 86 | /* reset I2C */ |
87 | i2c_init(); | 87 | i2c_init(); |
88 | 88 | ||
@@ -110,7 +110,7 @@ int wm8975_init(void) { | |||
110 | } | 110 | } |
111 | 111 | ||
112 | /* Silently enable / disable audio output */ | 112 | /* Silently enable / disable audio output */ |
113 | void wm8975_enable_output(bool enable) | 113 | void wmcodec_enable_output(bool enable) |
114 | { | 114 | { |
115 | if (enable) | 115 | if (enable) |
116 | { | 116 | { |
@@ -141,7 +141,7 @@ void wm8975_enable_output(bool enable) | |||
141 | wm8975_write(AINTFCE, 0x42); | 141 | wm8975_write(AINTFCE, 0x42); |
142 | 142 | ||
143 | /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */ | 143 | /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */ |
144 | wm8975_set_sample_rate(WM8975_44100HZ); | 144 | wmcodec_set_sample_rate(WM8975_44100HZ); |
145 | 145 | ||
146 | /* set the volume to -6dB */ | 146 | /* set the volume to -6dB */ |
147 | wm8975_write(LOUT1VOL, IPOD_PCM_LEVEL); | 147 | wm8975_write(LOUT1VOL, IPOD_PCM_LEVEL); |
@@ -158,13 +158,13 @@ void wm8975_enable_output(bool enable) | |||
158 | wm8975_write(MOUTMIX1, 0x0); /* Mono out Mix */ | 158 | wm8975_write(MOUTMIX1, 0x0); /* Mono out Mix */ |
159 | wm8975_write(MOUTMIX2, 0x0); | 159 | wm8975_write(MOUTMIX2, 0x0); |
160 | 160 | ||
161 | wm8975_mute(0); | 161 | wmcodec_mute(0); |
162 | } else { | 162 | } else { |
163 | wm8975_mute(1); | 163 | wmcodec_mute(1); |
164 | } | 164 | } |
165 | } | 165 | } |
166 | 166 | ||
167 | int wm8975_set_master_vol(int vol_l, int vol_r) | 167 | int wmcodec_set_master_vol(int vol_l, int vol_r) |
168 | { | 168 | { |
169 | /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ | 169 | /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */ |
170 | /* 1111111 == +6dB */ | 170 | /* 1111111 == +6dB */ |
@@ -183,7 +183,7 @@ int wm8975_set_master_vol(int vol_l, int vol_r) | |||
183 | return 0; | 183 | return 0; |
184 | } | 184 | } |
185 | 185 | ||
186 | int wm8975_set_mixer_vol(int channel1, int channel2) | 186 | int wmcodec_set_mixer_vol(int channel1, int channel2) |
187 | { | 187 | { |
188 | (void)channel1; | 188 | (void)channel1; |
189 | (void)channel2; | 189 | (void)channel2; |
@@ -192,7 +192,7 @@ int wm8975_set_mixer_vol(int channel1, int channel2) | |||
192 | } | 192 | } |
193 | 193 | ||
194 | /* We are using Linear bass control */ | 194 | /* We are using Linear bass control */ |
195 | void wm8975_set_bass(int value) | 195 | void wmcodec_set_bass(int value) |
196 | { | 196 | { |
197 | int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0}; | 197 | int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0}; |
198 | 198 | ||
@@ -202,7 +202,7 @@ void wm8975_set_bass(int value) | |||
202 | } | 202 | } |
203 | } | 203 | } |
204 | 204 | ||
205 | void wm8975_set_treble(int value) | 205 | void wmcodec_set_treble(int value) |
206 | { | 206 | { |
207 | int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0}; | 207 | int regvalues[]={11, 10, 10, 9, 8, 8, 0xf , 6, 6, 5, 4, 4, 3, 2, 1, 0}; |
208 | 208 | ||
@@ -212,7 +212,7 @@ void wm8975_set_treble(int value) | |||
212 | } | 212 | } |
213 | } | 213 | } |
214 | 214 | ||
215 | int wm8975_mute(int mute) | 215 | int wmcodec_mute(int mute) |
216 | { | 216 | { |
217 | if (mute) | 217 | if (mute) |
218 | { | 218 | { |
@@ -227,7 +227,7 @@ int wm8975_mute(int mute) | |||
227 | } | 227 | } |
228 | 228 | ||
229 | /* Nice shutdown of WM8975 codec */ | 229 | /* Nice shutdown of WM8975 codec */ |
230 | void wm8975_close(void) | 230 | void wmcodec_close(void) |
231 | { | 231 | { |
232 | /* 1. Set DACMU = 1 to soft-mute the audio DACs. */ | 232 | /* 1. Set DACMU = 1 to soft-mute the audio DACs. */ |
233 | wm8975_write(DACCTRL, 0x8); | 233 | wm8975_write(DACCTRL, 0x8); |
@@ -240,35 +240,35 @@ void wm8975_close(void) | |||
240 | } | 240 | } |
241 | 241 | ||
242 | /* Change the order of the noise shaper, 5th order is recommended above 32kHz */ | 242 | /* Change the order of the noise shaper, 5th order is recommended above 32kHz */ |
243 | void wm8975_set_nsorder(int order) | 243 | void wmcodec_set_nsorder(int order) |
244 | { | 244 | { |
245 | (void)order; | 245 | (void)order; |
246 | } | 246 | } |
247 | 247 | ||
248 | /* Note: Disable output before calling this function */ | 248 | /* Note: Disable output before calling this function */ |
249 | void wm8975_set_sample_rate(int sampling_control) { | 249 | void wmcodec_set_sample_rate(int sampling_control) { |
250 | 250 | ||
251 | wm8975_write(0x08, sampling_control); | 251 | wm8975_write(0x08, sampling_control); |
252 | 252 | ||
253 | } | 253 | } |
254 | 254 | ||
255 | void wm8975_enable_recording(bool source_mic) { | 255 | void wmcodec_enable_recording(bool source_mic) { |
256 | 256 | ||
257 | (void)source_mic; | 257 | (void)source_mic; |
258 | } | 258 | } |
259 | 259 | ||
260 | void wm8975_disable_recording(void) { | 260 | void wmcodec_disable_recording(void) { |
261 | 261 | ||
262 | } | 262 | } |
263 | 263 | ||
264 | void wm8975_set_recvol(int left, int right, int type) { | 264 | void wmcodec_set_recvol(int left, int right, int type) { |
265 | 265 | ||
266 | (void)left; | 266 | (void)left; |
267 | (void)right; | 267 | (void)right; |
268 | (void)type; | 268 | (void)type; |
269 | } | 269 | } |
270 | 270 | ||
271 | void wm8975_set_monitor(int enable) { | 271 | void wmcodec_set_monitor(int enable) { |
272 | 272 | ||
273 | (void)enable; | 273 | (void)enable; |
274 | } | 274 | } |