summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorDaniel Ankers <dan@weirdo.org.uk>2007-03-11 17:38:08 +0000
committerDaniel Ankers <dan@weirdo.org.uk>2007-03-11 17:38:08 +0000
commitdfad406aa14a735b2cd071d8d399c79be0f98e43 (patch)
tree2993687589af53e570e27e6a025fe1c24b8f1a96 /firmware
parente21d21720556bb069f7ceb5669c5b693138838bb (diff)
downloadrockbox-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
Diffstat (limited to 'firmware')
-rw-r--r--firmware/SOURCES2
-rw-r--r--firmware/drivers/as3514.c229
-rw-r--r--firmware/export/as3514.h78
-rw-r--r--firmware/export/config-e200.h7
-rw-r--r--firmware/sound.c29
-rw-r--r--firmware/target/arm/i2s-pp.c6
-rw-r--r--firmware/target/arm/pcm-pp.c67
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
205drivers/wm8758.c 205drivers/wm8758.c
206#elif defined(HAVE_WM8731) || defined(HAVE_WM8721) 206#elif defined(HAVE_WM8731) || defined(HAVE_WM8721)
207drivers/wm8731l.c 207drivers/wm8731l.c
208#elif defined(HAVE_AS3514)
209drivers/as3514.c
208#elif defined(HAVE_TLV320) 210#elif defined(HAVE_TLV320)
209drivers/tlv320.c 211drivers/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 */
41int 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 */
59int 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
71void audiohw_reset(void);
72
73/*
74 * Initialise the PP I2C and I2S.
75 */
76int 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
111void audiohw_postinit(void)
112{
113}
114
115/* Silently enable / disable audio output */
116void 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
131int 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
141int 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
149int 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 */
158void audiohw_set_bass(int value)
159{
160 (void)value;
161}
162
163void audiohw_set_treble(int value)
164{
165 (void)value;
166}
167
168int 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 */
184void audiohw_close(void)
185{
186 audiohw_mute(1);
187}
188
189/* Change the order of the noise shaper, 5th order is recommended above 32kHz */
190void audiohw_set_nsorder(int order)
191{
192 (void)order;
193}
194
195void audiohw_set_sample_rate(int sampling_control)
196{
197 (void)sampling_control;
198 /* TODO: Implement this by adjusting the I2S Master clock */
199}
200
201void audiohw_enable_recording(bool source_mic)
202{
203 (void)source_mic;
204 /* TODO */
205}
206
207void audiohw_disable_recording(void) {
208 /* TODO */
209}
210
211void audiohw_set_recvol(int left, int right, int type) {
212
213 (void)left;
214 (void)right;
215 (void)type;
216}
217
218void audiohw_set_monitor(int enable) {
219
220 (void)enable;
221}
222
223void 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
23extern int tenthdb2master(int db);
24extern int tenthdb2mixer(int db);
25
26extern void audiohw_reset(void);
27extern int audiohw_init(void);
28extern void audiohw_enable_output(bool enable);
29extern int audiohw_set_master_vol(int vol_l, int vol_r);
30extern int audiohw_set_lineout_vol(int vol_l, int vol_r);
31extern int audiohw_set_mixer_vol(int channel1, int channel2);
32extern void audiohw_set_bass(int value);
33extern void audiohw_set_treble(int value);
34extern int audiohw_mute(int mute);
35extern void audiohw_close(void);
36extern void audiohw_set_nsorder(int order);
37extern void audiohw_set_sample_rate(int sampling_control);
38
39extern void audiohw_enable_recording(bool source_mic);
40extern void audiohw_disable_recording(void);
41extern void audiohw_set_recvol(int left, int right, int type);
42extern void audiohw_set_monitor(int enable);
43
44extern 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
58void fiq(void) ICODE_ATTR __attribute__((naked)); 56void fiq(void) ICODE_ATTR __attribute__((naked));
59void fiq(void) 57void 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")));
155void fiq(void) 163void 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
265void pcm_play_pause_pause(void) 272void 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
326void pcm_init(void)
327{
328}
329void pcm_postinit(void)
330{
331}
332#else
333void pcm_init(void) 332void 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)
431void pcm_rec_dma_stop(void) 428void 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. */