diff options
author | Daniel Ankers <dan@weirdo.org.uk> | 2007-03-11 17:38:08 +0000 |
---|---|---|
committer | Daniel Ankers <dan@weirdo.org.uk> | 2007-03-11 17:38:08 +0000 |
commit | dfad406aa14a735b2cd071d8d399c79be0f98e43 (patch) | |
tree | 2993687589af53e570e27e6a025fe1c24b8f1a96 | |
parent | e21d21720556bb069f7ceb5669c5b693138838bb (diff) | |
download | rockbox-dfad406aa14a735b2cd071d8d399c79be0f98e43.tar.gz rockbox-dfad406aa14a735b2cd071d8d399c79be0f98e43.zip |
Sound for Sansa E200 - based on work by myself, Rene Peinthor, Barry Wardell and Christian Gmeiner from the AS3514 datasheet.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12727 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | firmware/SOURCES | 2 | ||||
-rw-r--r-- | firmware/drivers/as3514.c | 229 | ||||
-rw-r--r-- | firmware/export/as3514.h | 78 | ||||
-rw-r--r-- | firmware/export/config-e200.h | 7 | ||||
-rw-r--r-- | firmware/sound.c | 29 | ||||
-rw-r--r-- | firmware/target/arm/i2s-pp.c | 6 | ||||
-rw-r--r-- | firmware/target/arm/pcm-pp.c | 67 |
7 files changed, 362 insertions, 56 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index 945f400243..549e4af286 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -205,6 +205,8 @@ drivers/wm8975.c | |||
205 | drivers/wm8758.c | 205 | drivers/wm8758.c |
206 | #elif defined(HAVE_WM8731) || defined(HAVE_WM8721) | 206 | #elif defined(HAVE_WM8731) || defined(HAVE_WM8721) |
207 | drivers/wm8731l.c | 207 | drivers/wm8731l.c |
208 | #elif defined(HAVE_AS3514) | ||
209 | drivers/as3514.c | ||
208 | #elif defined(HAVE_TLV320) | 210 | #elif defined(HAVE_TLV320) |
209 | drivers/tlv320.c | 211 | drivers/tlv320.c |
210 | #endif /* defined(HAVE_*) */ | 212 | #endif /* defined(HAVE_*) */ |
diff --git a/firmware/drivers/as3514.c b/firmware/drivers/as3514.c new file mode 100644 index 0000000000..23d53a634e --- /dev/null +++ b/firmware/drivers/as3514.c | |||
@@ -0,0 +1,229 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Driver for AS3514 audio codec | ||
11 | * | ||
12 | * Copyright (c) 2007 Daniel Ankers | ||
13 | * | ||
14 | * All files in this archive are subject to the GNU General Public License. | ||
15 | * See the file COPYING in the source tree root for full license agreement. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "lcd.h" | ||
22 | #include "cpu.h" | ||
23 | #include "kernel.h" | ||
24 | #include "thread.h" | ||
25 | #include "power.h" | ||
26 | #include "debug.h" | ||
27 | #include "system.h" | ||
28 | #include "sprintf.h" | ||
29 | #include "button.h" | ||
30 | #include "string.h" | ||
31 | #include "file.h" | ||
32 | #include "buffer.h" | ||
33 | #include "audio.h" | ||
34 | #include "backlight.h" | ||
35 | |||
36 | #include "as3514.h" | ||
37 | #include "i2s.h" | ||
38 | #include "i2c-pp.h" | ||
39 | |||
40 | /* convert tenth of dB volume to master volume register value */ | ||
41 | int tenthdb2master(int db) | ||
42 | { | ||
43 | /* +1..07 to -45.43dB in 1.5dB steps == 32 levels = 5 bits */ | ||
44 | /* 11111 == +1.07dB (0x1f) = 31) */ | ||
45 | /* 11110 == -0.43dB (0x1e) = 30) */ | ||
46 | /* 00001 == -43.93dB (0x01) */ | ||
47 | /* 00000 == -45.43dB (0x00) */ | ||
48 | |||
49 | if (db < VOLUME_MIN) { | ||
50 | return 0x0; | ||
51 | } else if (db >= VOLUME_MAX) { | ||
52 | return 0x1f; | ||
53 | } else { | ||
54 | return((db-VOLUME_MIN)/15); /* VOLUME_MIN is negative */ | ||
55 | } | ||
56 | } | ||
57 | |||
58 | /* convert tenth of dB volume (-405..60) to mixer volume register value */ | ||
59 | int tenthdb2mixer(int db) | ||
60 | { | ||
61 | /* FIXME: Make this sensible */ | ||
62 | if (db < -405) { | ||
63 | return 0x0; | ||
64 | } else if (db >= 60) { | ||
65 | return 0x1f; | ||
66 | } else { | ||
67 | return((db+405)/15); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | void audiohw_reset(void); | ||
72 | |||
73 | /* | ||
74 | * Initialise the PP I2C and I2S. | ||
75 | */ | ||
76 | int audiohw_init(void) { | ||
77 | /* reset I2C */ | ||
78 | i2c_init(); | ||
79 | |||
80 | /* normal outputs for CDI and I2S pin groups */ | ||
81 | DEV_INIT &= ~0x300; | ||
82 | |||
83 | /*mini2?*/ | ||
84 | outl(inl(0x70000010) & ~0x3000000, 0x70000010); | ||
85 | /*mini2?*/ | ||
86 | |||
87 | /* device reset */ | ||
88 | DEV_RS |= 0x800; | ||
89 | DEV_RS &=~0x800; | ||
90 | |||
91 | /* device enable */ | ||
92 | DEV_EN |= 0x807; | ||
93 | |||
94 | /* enable external dev clock clocks */ | ||
95 | DEV_EN |= 0x2; | ||
96 | |||
97 | /* external dev clock to 24MHz */ | ||
98 | outl(inl(0x70000018) & ~0xc, 0x70000018); | ||
99 | |||
100 | i2s_reset(); | ||
101 | |||
102 | /* Set ADC off, mixer on, DAC on, line out off, line in off, mic off */ | ||
103 | pp_i2c_send(AS3514_I2C_ADDR, AUDIOSET1, 0x60); /* Turn on DAC and mixer */ | ||
104 | pp_i2c_send(AS3514_I2C_ADDR, PLLMODE, 0x04); | ||
105 | pp_i2c_send(AS3514_I2C_ADDR, DAC_L, 0x50); /* DAC mute off, -16.5dB gain */ | ||
106 | pp_i2c_send(AS3514_I2C_ADDR, DAC_R, 0x10); /* DAC -16.5dB gain to prevent overloading | ||
107 | the headphone amp */ | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | void audiohw_postinit(void) | ||
112 | { | ||
113 | } | ||
114 | |||
115 | /* Silently enable / disable audio output */ | ||
116 | void audiohw_enable_output(bool enable) | ||
117 | { | ||
118 | if (enable) | ||
119 | { | ||
120 | /* reset the I2S controller into known state */ | ||
121 | i2s_reset(); | ||
122 | |||
123 | pp_i2c_send(AS3514_I2C_ADDR, HPH_OUT_L, 0xc0); /* Mute on, power on */ | ||
124 | audiohw_mute(0); | ||
125 | } else { | ||
126 | audiohw_mute(1); | ||
127 | pp_i2c_send(AS3514_I2C_ADDR, HPH_OUT_L, 0x80); /* Mute on, power off */ | ||
128 | } | ||
129 | } | ||
130 | |||
131 | int audiohw_set_master_vol(int vol_l, int vol_r) | ||
132 | { | ||
133 | vol_l &= 0x1f; | ||
134 | vol_r &= 0x1f; | ||
135 | pp_i2c_send(AS3514_I2C_ADDR, HPH_OUT_R, 0x40 | vol_r); | ||
136 | pp_i2c_send(AS3514_I2C_ADDR, HPH_OUT_L, 0x40 | vol_l); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | int audiohw_set_lineout_vol(int vol_l, int vol_r) | ||
142 | { | ||
143 | pp_i2c_send(AS3514_I2C_ADDR, LINE_OUT_R, 0x40 | vol_r); | ||
144 | pp_i2c_send(AS3514_I2C_ADDR, LINE_OUT_L, 0x40 | vol_l); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | int audiohw_set_mixer_vol(int channel1, int channel2) | ||
150 | { | ||
151 | (void)channel1; | ||
152 | (void)channel2; | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | /* We are using Linear bass control */ | ||
158 | void audiohw_set_bass(int value) | ||
159 | { | ||
160 | (void)value; | ||
161 | } | ||
162 | |||
163 | void audiohw_set_treble(int value) | ||
164 | { | ||
165 | (void)value; | ||
166 | } | ||
167 | |||
168 | int audiohw_mute(int mute) | ||
169 | { | ||
170 | int curr; | ||
171 | |||
172 | curr = i2c_readbyte(AS3514_I2C_ADDR, HPH_OUT_L); | ||
173 | if (mute) | ||
174 | { | ||
175 | pp_i2c_send(AS3514_I2C_ADDR, HPH_OUT_L, curr | 0x80); | ||
176 | } else { | ||
177 | pp_i2c_send(AS3514_I2C_ADDR, HPH_OUT_L, curr & ~(0x80)); | ||
178 | } | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | /* Nice shutdown of WM8758 codec */ | ||
184 | void audiohw_close(void) | ||
185 | { | ||
186 | audiohw_mute(1); | ||
187 | } | ||
188 | |||
189 | /* Change the order of the noise shaper, 5th order is recommended above 32kHz */ | ||
190 | void audiohw_set_nsorder(int order) | ||
191 | { | ||
192 | (void)order; | ||
193 | } | ||
194 | |||
195 | void audiohw_set_sample_rate(int sampling_control) | ||
196 | { | ||
197 | (void)sampling_control; | ||
198 | /* TODO: Implement this by adjusting the I2S Master clock */ | ||
199 | } | ||
200 | |||
201 | void audiohw_enable_recording(bool source_mic) | ||
202 | { | ||
203 | (void)source_mic; | ||
204 | /* TODO */ | ||
205 | } | ||
206 | |||
207 | void audiohw_disable_recording(void) { | ||
208 | /* TODO */ | ||
209 | } | ||
210 | |||
211 | void audiohw_set_recvol(int left, int right, int type) { | ||
212 | |||
213 | (void)left; | ||
214 | (void)right; | ||
215 | (void)type; | ||
216 | } | ||
217 | |||
218 | void audiohw_set_monitor(int enable) { | ||
219 | |||
220 | (void)enable; | ||
221 | } | ||
222 | |||
223 | void audiohw_set_equalizer_band(int band, int freq, int bw, int gain) | ||
224 | { | ||
225 | (void)band; | ||
226 | (void)freq; | ||
227 | (void)bw; | ||
228 | (void)gain; | ||
229 | } | ||
diff --git a/firmware/export/as3514.h b/firmware/export/as3514.h new file mode 100644 index 0000000000..0bf87dbc46 --- /dev/null +++ b/firmware/export/as3514.h | |||
@@ -0,0 +1,78 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Daniel Ankers | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef _AS3514_H | ||
21 | #define _AS3514_H | ||
22 | |||
23 | extern int tenthdb2master(int db); | ||
24 | extern int tenthdb2mixer(int db); | ||
25 | |||
26 | extern void audiohw_reset(void); | ||
27 | extern int audiohw_init(void); | ||
28 | extern void audiohw_enable_output(bool enable); | ||
29 | extern int audiohw_set_master_vol(int vol_l, int vol_r); | ||
30 | extern int audiohw_set_lineout_vol(int vol_l, int vol_r); | ||
31 | extern int audiohw_set_mixer_vol(int channel1, int channel2); | ||
32 | extern void audiohw_set_bass(int value); | ||
33 | extern void audiohw_set_treble(int value); | ||
34 | extern int audiohw_mute(int mute); | ||
35 | extern void audiohw_close(void); | ||
36 | extern void audiohw_set_nsorder(int order); | ||
37 | extern void audiohw_set_sample_rate(int sampling_control); | ||
38 | |||
39 | extern void audiohw_enable_recording(bool source_mic); | ||
40 | extern void audiohw_disable_recording(void); | ||
41 | extern void audiohw_set_recvol(int left, int right, int type); | ||
42 | extern void audiohw_set_monitor(int enable); | ||
43 | |||
44 | extern void audiohw_set_equalizer_band(int band, int freq, int bw, int gain); | ||
45 | |||
46 | /* Register Descriptions */ | ||
47 | #define LINE_OUT_R 0x00 | ||
48 | #define LINE_OUT_L 0x01 | ||
49 | #define HPH_OUT_R 0x02 | ||
50 | #define HPH_OUT_L 0x03 | ||
51 | #define LSP_OUT_R 0x04 | ||
52 | #define LSP_OUT_L 0x05 | ||
53 | #define MIC1_R 0x06 | ||
54 | #define MIC1_L 0x07 | ||
55 | #define MIC2_R 0x08 | ||
56 | #define MIC2_L 0x09 | ||
57 | #define LINE_IN1_R 0x0a | ||
58 | #define LINE_IN1_L 0x0b | ||
59 | #define LINE_IN2_R 0x0c | ||
60 | #define LINE_IN2_L 0x0d | ||
61 | #define DAC_R 0x0e | ||
62 | #define DAC_L 0x0f | ||
63 | #define ADC_R 0x10 | ||
64 | #define ADC_L 0x11 | ||
65 | #define AUDIOSET1 0x14 | ||
66 | #define AUDIOSET2 0x15 | ||
67 | #define AUDIOSET3 0x16 | ||
68 | #define PLLMODE 0x1d | ||
69 | |||
70 | /* Headphone volume goes from -45.43 - 1.07dB */ | ||
71 | #define VOLUME_MIN -454 | ||
72 | #define VOLUME_MAX 10 | ||
73 | |||
74 | #ifdef SANSA_E200 | ||
75 | #define AS3514_I2C_ADDR 0x46 | ||
76 | #endif | ||
77 | |||
78 | #endif /* _AS3514_H */ | ||
diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h index afe2ebec89..1b3404a148 100644 --- a/firmware/export/config-e200.h +++ b/firmware/export/config-e200.h | |||
@@ -40,6 +40,10 @@ | |||
40 | 40 | ||
41 | /* Define this if you do software codec */ | 41 | /* Define this if you do software codec */ |
42 | #define CONFIG_CODEC SWCODEC | 42 | #define CONFIG_CODEC SWCODEC |
43 | /* There is no hardware tone control */ | ||
44 | #define HAVE_SW_TONE_CONTROLS | ||
45 | /* The PP5024 has a built-in AustriaMicrosystems AS3514 */ | ||
46 | #define HAVE_AS3514 | ||
43 | 47 | ||
44 | /* define this if you have a real-time clock */ | 48 | /* define this if you have a real-time clock */ |
45 | #ifndef BOOTLOADER | 49 | #ifndef BOOTLOADER |
@@ -58,9 +62,6 @@ | |||
58 | /* The number of bytes reserved for loadable plugins */ | 62 | /* The number of bytes reserved for loadable plugins */ |
59 | #define PLUGIN_BUFFER_SIZE 0x80000 | 63 | #define PLUGIN_BUFFER_SIZE 0x80000 |
60 | 64 | ||
61 | /* Use the built-in DAC on the PP5024 */ | ||
62 | #define HAVE_PP5024_CODEC | ||
63 | |||
64 | #define AB_REPEAT_ENABLE 1 | 65 | #define AB_REPEAT_ENABLE 1 |
65 | 66 | ||
66 | /* FM Tuner */ | 67 | /* FM Tuner */ |
diff --git a/firmware/sound.c b/firmware/sound.c index 7b29e1f13f..d3f4435058 100644 --- a/firmware/sound.c +++ b/firmware/sound.c | |||
@@ -77,9 +77,8 @@ static const struct sound_settings_info sound_settings_table[] = { | |||
77 | [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25, sound_set_volume}, | 77 | [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25, sound_set_volume}, |
78 | #elif (CONFIG_CPU == PNX0101) | 78 | #elif (CONFIG_CPU == PNX0101) |
79 | [SOUND_VOLUME] = {"dB", 0, 1, -48, 15, 0, sound_set_volume}, | 79 | [SOUND_VOLUME] = {"dB", 0, 1, -48, 15, 0, sound_set_volume}, |
80 | #elif defined(HAVE_PP5024_CODEC) | 80 | #elif defined(HAVE_AS3514) |
81 | /* TODO: Make this correct */ | 81 | [SOUND_VOLUME] = {"dB", 0, 1, -45, 1, -25, sound_set_volume}, |
82 | [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25, sound_set_volume}, | ||
83 | #else /* MAS3507D */ | 82 | #else /* MAS3507D */ |
84 | [SOUND_VOLUME] = {"dB", 0, 1, -78, 18, -18, sound_set_volume}, | 83 | [SOUND_VOLUME] = {"dB", 0, 1, -78, 18, -18, sound_set_volume}, |
85 | [SOUND_BASS] = {"dB", 0, 1, -15, 15, 7, sound_set_bass}, | 84 | [SOUND_BASS] = {"dB", 0, 1, -15, 15, 7, sound_set_bass}, |
@@ -292,17 +291,10 @@ static int tenthdb2reg(int db) | |||
292 | } | 291 | } |
293 | #endif | 292 | #endif |
294 | 293 | ||
295 | #if defined(HAVE_PP5024_CODEC) | ||
296 | /* TODO: Work out volume/balance/treble/bass interdependency */ | ||
297 | #define VOLUME_MIN 0 | ||
298 | #define VOLUME_MAX 1 | ||
299 | |||
300 | #endif | ||
301 | |||
302 | #if (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 \ | 294 | #if (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 \ |
303 | || defined HAVE_WM8975 || defined HAVE_WM8758 || defined(HAVE_WM8731) \ | 295 | || defined HAVE_WM8975 || defined HAVE_WM8758 || defined(HAVE_WM8731) \ |
304 | || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) \ | 296 | || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) \ |
305 | || defined(HAVE_PP5024_CODEC) | 297 | || defined(HAVE_AS3514) |
306 | /* volume/balance/treble/bass interdependency main part */ | 298 | /* volume/balance/treble/bass interdependency main part */ |
307 | #define VOLUME_RANGE (VOLUME_MAX - VOLUME_MIN) | 299 | #define VOLUME_RANGE (VOLUME_MAX - VOLUME_MIN) |
308 | 300 | ||
@@ -363,7 +355,8 @@ static void set_prescaled_volume(void) | |||
363 | #if CONFIG_CODEC == MAS3507D | 355 | #if CONFIG_CODEC == MAS3507D |
364 | dac_volume(tenthdb2reg(l), tenthdb2reg(r), false); | 356 | dac_volume(tenthdb2reg(l), tenthdb2reg(r), false); |
365 | #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | 357 | #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \ |
366 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) | 358 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) \ |
359 | || defined(HAVE_AS3514) | ||
367 | audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r)); | 360 | audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r)); |
368 | #if defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8751) | 361 | #if defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8751) |
369 | audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0)); | 362 | audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0)); |
@@ -479,7 +472,7 @@ void sound_set_volume(int value) | |||
479 | #elif (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 \ | 472 | #elif (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 \ |
480 | || defined HAVE_WM8975 || defined HAVE_WM8758 || defined HAVE_WM8731 \ | 473 | || defined HAVE_WM8975 || defined HAVE_WM8758 || defined HAVE_WM8731 \ |
481 | || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) \ | 474 | || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) \ |
482 | || defined(HAVE_PP5024_CODEC) | 475 | || defined(HAVE_AS3514) |
483 | current_volume = value * 10; /* tenth of dB */ | 476 | current_volume = value * 10; /* tenth of dB */ |
484 | set_prescaled_volume(); | 477 | set_prescaled_volume(); |
485 | #elif CONFIG_CPU == PNX0101 | 478 | #elif CONFIG_CPU == PNX0101 |
@@ -500,7 +493,7 @@ void sound_set_balance(int value) | |||
500 | || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) | 493 | || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) |
501 | current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */ | 494 | current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */ |
502 | set_prescaled_volume(); | 495 | set_prescaled_volume(); |
503 | #elif CONFIG_CPU == PNX0101 || defined(HAVE_PP5024_CODEC) | 496 | #elif CONFIG_CPU == PNX0101 || defined(HAVE_AS3514) |
504 | /* TODO: implement for iFP and Sansa */ | 497 | /* TODO: implement for iFP and Sansa */ |
505 | (void)value; | 498 | (void)value; |
506 | #endif | 499 | #endif |
@@ -530,8 +523,8 @@ void sound_set_bass(int value) | |||
530 | current_bass = value * 10; | 523 | current_bass = value * 10; |
531 | audiohw_set_bass(value); | 524 | audiohw_set_bass(value); |
532 | set_prescaled_volume(); | 525 | set_prescaled_volume(); |
533 | #elif CONFIG_CPU == PNX0101 || defined(HAVE_PP5024_CODEC) | 526 | #elif CONFIG_CPU == PNX0101 |
534 | /* TODO: implement for iFP and Sansa */ | 527 | /* TODO: implement for iFP */ |
535 | (void)value; | 528 | (void)value; |
536 | #endif | 529 | #endif |
537 | } | 530 | } |
@@ -560,8 +553,8 @@ void sound_set_treble(int value) | |||
560 | audiohw_set_treble(value); | 553 | audiohw_set_treble(value); |
561 | current_treble = value * 10; | 554 | current_treble = value * 10; |
562 | set_prescaled_volume(); | 555 | set_prescaled_volume(); |
563 | #elif CONFIG_CPU == PNX0101 || defined(HAVE_PP5024_CODEC) | 556 | #elif CONFIG_CPU == PNX0101 |
564 | /* TODO: implement for iFP and Sansa */ | 557 | /* TODO: implement for iFP */ |
565 | (void)value; | 558 | (void)value; |
566 | #endif | 559 | #endif |
567 | } | 560 | } |
diff --git a/firmware/target/arm/i2s-pp.c b/firmware/target/arm/i2s-pp.c index af698fddd6..a2a74bf72b 100644 --- a/firmware/target/arm/i2s-pp.c +++ b/firmware/target/arm/i2s-pp.c | |||
@@ -84,6 +84,12 @@ void i2s_reset(void) | |||
84 | /* FIFO.FORMAT */ | 84 | /* FIFO.FORMAT */ |
85 | /* If BIT.SIZE < FIFO.FORMAT low bits will be 0 */ | 85 | /* If BIT.SIZE < FIFO.FORMAT low bits will be 0 */ |
86 | IISCONFIG = ((IISCONFIG & ~FIFO_FORMAT_MASK) | FIFO_FORMAT_32LSB); | 86 | IISCONFIG = ((IISCONFIG & ~FIFO_FORMAT_MASK) | FIFO_FORMAT_32LSB); |
87 | #ifdef HAVE_AS3514 | ||
88 | /* AS3514 can only operate as I2S Slave */ | ||
89 | IISCONFIG |= I2S_MASTER; | ||
90 | /* Set I2S to 44.1kHz */ | ||
91 | outl((inl(0x70002808) & ~(0x1ff)) | 271, 0x70002808); | ||
92 | #endif | ||
87 | 93 | ||
88 | /* RX_ATN_LVL=1 == when 12 slots full */ | 94 | /* RX_ATN_LVL=1 == when 12 slots full */ |
89 | /* TX_ATN_LVL=1 == when 12 slots empty */ | 95 | /* TX_ATN_LVL=1 == when 12 slots empty */ |
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c index efe6c9b4e6..6ecc3dae31 100644 --- a/firmware/target/arm/pcm-pp.c +++ b/firmware/target/arm/pcm-pp.c | |||
@@ -30,12 +30,10 @@ static int rec_peak_left, rec_peak_right; | |||
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | /** DMA **/ | 32 | /** DMA **/ |
33 | #if CONFIG_CPU == PP5020 | 33 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
34 | #define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x3f000000) >> 24) | 34 | #define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x3f000000) >> 24) |
35 | #elif CONFIG_CPU == PP5002 | 35 | #elif CONFIG_CPU == PP5002 |
36 | #define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x7800000) >> 23) | 36 | #define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x7800000) >> 23) |
37 | #elif CONFIG_CPU == PP5024 | ||
38 | #define FIFO_FREE_COUNT 4 /* TODO: make this sensible */ | ||
39 | #endif | 37 | #endif |
40 | 38 | ||
41 | /**************************************************************************** | 39 | /**************************************************************************** |
@@ -54,7 +52,7 @@ size_t p_size IBSS_ATTR; | |||
54 | actually needs to do so when calling pcm_callback_for_more. C version is | 52 | actually needs to do so when calling pcm_callback_for_more. C version is |
55 | still included below for reference. | 53 | still included below for reference. |
56 | */ | 54 | */ |
57 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 | 55 | #ifdef CPU_PP |
58 | void fiq(void) ICODE_ATTR __attribute__((naked)); | 56 | void fiq(void) ICODE_ATTR __attribute__((naked)); |
59 | void fiq(void) | 57 | void fiq(void) |
60 | { | 58 | { |
@@ -94,10 +92,20 @@ void fiq(void) | |||
94 | #endif | 92 | #endif |
95 | "bls .fifo_full \n\t" /* FIFO full, exit */ | 93 | "bls .fifo_full \n\t" /* FIFO full, exit */ |
96 | "ldr r10, [r9], #4 \n\t" /* load two samples */ | 94 | "ldr r10, [r9], #4 \n\t" /* load two samples */ |
95 | #ifdef HAVE_AS3514 | ||
96 | /* The AS3514 reads 3 bytes at a time, it seems, ignoring the lowest. | ||
97 | This code seems to work well, but we may have to mask off the extra | ||
98 | bits - at the expense of a few extra cycles in the FIQ */ | ||
99 | "mov r10, r10, ror #2\n\t" /* put left sample at the top bits */ | ||
100 | "str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */ | ||
101 | "mov r10, r10, ror #16\n\t" /* put left sample at the top bits */ | ||
102 | "str r10, [r12, #0x40]\n\t" /* then write it */ | ||
103 | #else | ||
97 | "mov r10, r10, ror #16\n\t" /* put left sample at the top bits */ | 104 | "mov r10, r10, ror #16\n\t" /* put left sample at the top bits */ |
98 | "str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */ | 105 | "str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */ |
99 | "mov r10, r10, lsl #16\n\t" /* shift lower sample up */ | 106 | "mov r10, r10, lsl #16\n\t" /* shift lower sample up */ |
100 | "str r10, [r12, #0x40]\n\t" /* then write it */ | 107 | "str r10, [r12, #0x40]\n\t" /* then write it */ |
108 | #endif | ||
101 | "subs r8, r8, #4 \n\t" /* check if we have more samples */ | 109 | "subs r8, r8, #4 \n\t" /* check if we have more samples */ |
102 | "bne .fifo_loop \n\t" /* yes, continue */ | 110 | "bne .fifo_loop \n\t" /* yes, continue */ |
103 | ".more_data: \n\t" | 111 | ".more_data: \n\t" |
@@ -155,7 +163,7 @@ void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ"))); | |||
155 | void fiq(void) | 163 | void fiq(void) |
156 | { | 164 | { |
157 | /* Clear interrupt */ | 165 | /* Clear interrupt */ |
158 | #if CONFIG_CPU == PP5020 | 166 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
159 | IISCONFIG &= ~0x2; | 167 | IISCONFIG &= ~0x2; |
160 | #elif CONFIG_CPU == PP5002 | 168 | #elif CONFIG_CPU == PP5002 |
161 | inl(0xcf001040); | 169 | inl(0xcf001040); |
@@ -166,7 +174,7 @@ void fiq(void) | |||
166 | while (p_size) { | 174 | while (p_size) { |
167 | if (FIFO_FREE_COUNT < 2) { | 175 | if (FIFO_FREE_COUNT < 2) { |
168 | /* Enable interrupt */ | 176 | /* Enable interrupt */ |
169 | #if CONFIG_CPU == PP5020 | 177 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
170 | IISCONFIG |= 0x2; | 178 | IISCONFIG |= 0x2; |
171 | #elif CONFIG_CPU == PP5002 | 179 | #elif CONFIG_CPU == PP5002 |
172 | IISFIFO_CFG |= (1<<9); | 180 | IISFIFO_CFG |= (1<<9); |
@@ -197,10 +205,9 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
197 | 205 | ||
198 | pcm_playing = true; | 206 | pcm_playing = true; |
199 | 207 | ||
200 | #if CONFIG_CPU == PP5020 | 208 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
201 | CPU_INT_PRIORITY |= I2S_MASK; /* FIQ priority for I2S */ | 209 | CPU_INT_PRIORITY |= I2S_MASK; /* FIQ priority for I2S */ |
202 | CPU_INT_EN = I2S_MASK; /* Enable I2S interrupt */ | 210 | CPU_INT_EN = I2S_MASK; /* Enable I2S interrupt */ |
203 | #elif CONFIG_CPU == PP5024 | ||
204 | #else | 211 | #else |
205 | /* setup I2S interrupt for FIQ */ | 212 | /* setup I2S interrupt for FIQ */ |
206 | outl(inl(0xcf00102c) | DMA_OUT_MASK, 0xcf00102c); | 213 | outl(inl(0xcf00102c) | DMA_OUT_MASK, 0xcf00102c); |
@@ -212,7 +219,7 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
212 | enable_fiq(); | 219 | enable_fiq(); |
213 | 220 | ||
214 | /* Enable playback FIFO */ | 221 | /* Enable playback FIFO */ |
215 | #if CONFIG_CPU == PP5020 | 222 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
216 | IISCONFIG |= 0x20000000; | 223 | IISCONFIG |= 0x20000000; |
217 | #elif CONFIG_CPU == PP5002 | 224 | #elif CONFIG_CPU == PP5002 |
218 | IISCONFIG |= 0x4; | 225 | IISCONFIG |= 0x4; |
@@ -223,7 +230,7 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
223 | while (p_size > 0) { | 230 | while (p_size > 0) { |
224 | if (FIFO_FREE_COUNT < 2) { | 231 | if (FIFO_FREE_COUNT < 2) { |
225 | /* Enable interrupt */ | 232 | /* Enable interrupt */ |
226 | #if CONFIG_CPU == PP5020 | 233 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
227 | IISCONFIG |= 0x2; | 234 | IISCONFIG |= 0x2; |
228 | #elif CONFIG_CPU == PP5002 | 235 | #elif CONFIG_CPU == PP5002 |
229 | IISFIFO_CFG |= (1<<9); | 236 | IISFIFO_CFG |= (1<<9); |
@@ -242,7 +249,7 @@ void pcm_play_dma_stop(void) | |||
242 | { | 249 | { |
243 | pcm_playing = false; | 250 | pcm_playing = false; |
244 | 251 | ||
245 | #if CONFIG_CPU == PP5020 | 252 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
246 | 253 | ||
247 | /* Disable playback FIFO */ | 254 | /* Disable playback FIFO */ |
248 | IISCONFIG &= ~0x20000000; | 255 | IISCONFIG &= ~0x20000000; |
@@ -264,7 +271,7 @@ void pcm_play_dma_stop(void) | |||
264 | 271 | ||
265 | void pcm_play_pause_pause(void) | 272 | void pcm_play_pause_pause(void) |
266 | { | 273 | { |
267 | #if CONFIG_CPU == PP5020 | 274 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
268 | /* Disable the interrupt */ | 275 | /* Disable the interrupt */ |
269 | IISCONFIG &= ~0x2; | 276 | IISCONFIG &= ~0x2; |
270 | /* Disable playback FIFO */ | 277 | /* Disable playback FIFO */ |
@@ -286,7 +293,7 @@ void pcm_play_pause_unpause(void) | |||
286 | enable_fiq(); | 293 | enable_fiq(); |
287 | 294 | ||
288 | /* Enable playback FIFO */ | 295 | /* Enable playback FIFO */ |
289 | #if CONFIG_CPU == PP5020 | 296 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
290 | IISCONFIG |= 0x20000000; | 297 | IISCONFIG |= 0x20000000; |
291 | #elif CONFIG_CPU == PP5002 | 298 | #elif CONFIG_CPU == PP5002 |
292 | IISCONFIG |= 0x4; | 299 | IISCONFIG |= 0x4; |
@@ -297,7 +304,7 @@ void pcm_play_pause_unpause(void) | |||
297 | while (p_size > 0) { | 304 | while (p_size > 0) { |
298 | if (FIFO_FREE_COUNT < 2) { | 305 | if (FIFO_FREE_COUNT < 2) { |
299 | /* Enable interrupt */ | 306 | /* Enable interrupt */ |
300 | #if CONFIG_CPU == PP5020 | 307 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
301 | IISCONFIG |= 0x2; | 308 | IISCONFIG |= 0x2; |
302 | #elif CONFIG_CPU == PP5002 | 309 | #elif CONFIG_CPU == PP5002 |
303 | IISFIFO_CFG |= (1<<9); | 310 | IISFIFO_CFG |= (1<<9); |
@@ -322,14 +329,6 @@ size_t pcm_get_bytes_waiting(void) | |||
322 | return p_size; | 329 | return p_size; |
323 | } | 330 | } |
324 | 331 | ||
325 | #ifdef HAVE_PP5024_CODEC | ||
326 | void pcm_init(void) | ||
327 | { | ||
328 | } | ||
329 | void pcm_postinit(void) | ||
330 | { | ||
331 | } | ||
332 | #else | ||
333 | void pcm_init(void) | 332 | void pcm_init(void) |
334 | { | 333 | { |
335 | pcm_playing = false; | 334 | pcm_playing = false; |
@@ -338,7 +337,7 @@ void pcm_init(void) | |||
338 | 337 | ||
339 | /* Initialize default register values. */ | 338 | /* Initialize default register values. */ |
340 | audiohw_init(); | 339 | audiohw_init(); |
341 | 340 | ||
342 | /* Power on */ | 341 | /* Power on */ |
343 | audiohw_enable_output(true); | 342 | audiohw_enable_output(true); |
344 | 343 | ||
@@ -353,8 +352,6 @@ void pcm_postinit(void) | |||
353 | { | 352 | { |
354 | audiohw_postinit(); | 353 | audiohw_postinit(); |
355 | } | 354 | } |
356 | #endif /* HAVE_PP5024_CODEC */ | ||
357 | |||
358 | 355 | ||
359 | /**************************************************************************** | 356 | /**************************************************************************** |
360 | ** Recording DMA transfer | 357 | ** Recording DMA transfer |
@@ -370,7 +367,7 @@ void fiq_record(void) | |||
370 | int status = 0; | 367 | int status = 0; |
371 | 368 | ||
372 | /* Clear interrupt */ | 369 | /* Clear interrupt */ |
373 | #if CONFIG_CPU == PP5020 | 370 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
374 | IISCONFIG &= ~0x01; | 371 | IISCONFIG &= ~0x01; |
375 | #elif CONFIG_CPU == PP5002 | 372 | #elif CONFIG_CPU == PP5002 |
376 | /* TODO */ | 373 | /* TODO */ |
@@ -379,7 +376,7 @@ void fiq_record(void) | |||
379 | while (p_size > 0) { | 376 | while (p_size > 0) { |
380 | if (FIFO_FREE_COUNT < 2) { | 377 | if (FIFO_FREE_COUNT < 2) { |
381 | /* enable interrupt */ | 378 | /* enable interrupt */ |
382 | #if CONFIG_CPU == PP5020 | 379 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
383 | IISCONFIG |= 0x01; | 380 | IISCONFIG |= 0x01; |
384 | #elif CONFIG_CPU == PP5002 | 381 | #elif CONFIG_CPU == PP5002 |
385 | /* TODO */ | 382 | /* TODO */ |
@@ -405,7 +402,7 @@ void fiq_record(void) | |||
405 | peak_l = peak_r = 0; | 402 | peak_l = peak_r = 0; |
406 | } | 403 | } |
407 | } | 404 | } |
408 | 405 | ||
409 | more_ready = pcm_callback_more_ready; | 406 | more_ready = pcm_callback_more_ready; |
410 | 407 | ||
411 | if (more_ready != NULL && more_ready(status) >= 0) | 408 | if (more_ready != NULL && more_ready(status) >= 0) |
@@ -421,7 +418,7 @@ void pcm_record_more(void *start, size_t size) | |||
421 | rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */ | 418 | rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */ |
422 | p = start; | 419 | p = start; |
423 | p_size = size; /* Bytes to transfer */ | 420 | p_size = size; /* Bytes to transfer */ |
424 | #if CONFIG_CPU == PP5020 | 421 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024 |
425 | IISCONFIG |= 0x01; | 422 | IISCONFIG |= 0x01; |
426 | #elif CONFIG_CPU == PP5002 | 423 | #elif CONFIG_CPU == PP5002 |
427 | /* TODO */ | 424 | /* TODO */ |
@@ -431,12 +428,12 @@ void pcm_record_more(void *start, size_t size) | |||
431 | void pcm_rec_dma_stop(void) | 428 | void pcm_rec_dma_stop(void) |
432 | { | 429 | { |
433 | logf("pcm_rec_dma_stop"); | 430 | logf("pcm_rec_dma_stop"); |
434 | 431 | ||
435 | /* disable fifo */ | 432 | /* disable fifo */ |
436 | IISCONFIG &= ~0x10000000; | 433 | IISCONFIG &= ~0x10000000; |
437 | 434 | ||
438 | disable_fiq(); | 435 | disable_fiq(); |
439 | 436 | ||
440 | pcm_recording = false; | 437 | pcm_recording = false; |
441 | } | 438 | } |
442 | 439 | ||
@@ -445,11 +442,11 @@ void pcm_rec_dma_start(void *addr, size_t size) | |||
445 | logf("pcm_rec_dma_start"); | 442 | logf("pcm_rec_dma_start"); |
446 | 443 | ||
447 | pcm_recording = true; | 444 | pcm_recording = true; |
448 | 445 | ||
449 | peak_l = peak_r = 0; | 446 | peak_l = peak_r = 0; |
450 | p_size = size; | 447 | p_size = size; |
451 | p = addr; | 448 | p = addr; |
452 | 449 | ||
453 | /* setup FIQ */ | 450 | /* setup FIQ */ |
454 | CPU_INT_PRIORITY |= I2S_MASK; | 451 | CPU_INT_PRIORITY |= I2S_MASK; |
455 | CPU_INT_EN = I2S_MASK; | 452 | CPU_INT_EN = I2S_MASK; |
@@ -470,7 +467,7 @@ void pcm_close_recording(void) | |||
470 | 467 | ||
471 | pcm_rec_dma_stop(); | 468 | pcm_rec_dma_stop(); |
472 | 469 | ||
473 | #if (CONFIG_CPU == PP5020) | 470 | #if (CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024) |
474 | disable_fiq(); | 471 | disable_fiq(); |
475 | 472 | ||
476 | /* disable fifo */ | 473 | /* disable fifo */ |
@@ -488,7 +485,7 @@ void pcm_init_recording(void) | |||
488 | pcm_recording = false; | 485 | pcm_recording = false; |
489 | pcm_callback_more_ready = NULL; | 486 | pcm_callback_more_ready = NULL; |
490 | 487 | ||
491 | #if (CONFIG_CPU == PP5020) | 488 | #if (CONFIG_CPU == PP5020 || CONFIG_CPU == PP5024) |
492 | #if defined(IPOD_COLOR) || defined (IPOD_4G) | 489 | #if defined(IPOD_COLOR) || defined (IPOD_4G) |
493 | /* The usual magic from IPL - I'm guessing this configures the headphone | 490 | /* The usual magic from IPL - I'm guessing this configures the headphone |
494 | socket to be input or output - in this case, input. */ | 491 | socket to be input or output - in this case, input. */ |