summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
authorCástor Muñoz <cmvidal@gmail.com>2014-12-06 19:00:34 +0100
committerCástor Muñoz <cmvidal@gmail.com>2015-10-07 06:15:03 +0200
commit291b2338c98c211794d55a68c9585d278fc86563 (patch)
treec894f7d5db4e93b94c153b8125bec344e590e93c /firmware/target
parent42abc6a49670cd546737a4dc7542f9f3f62e3831 (diff)
downloadrockbox-291b2338c98c211794d55a68c9585d278fc86563.tar.gz
rockbox-291b2338c98c211794d55a68c9585d278fc86563.zip
ipod Classic: implement HAVE_RECORDING
This patch has been tested on iPod 80 and 160slim, actually it works but some updates must be done to the final version: - unlimitted input buffer - decrease CHUNK_SIZE - use non-cached addresses instead of discard d-cache ??? Capture hardware versions: Ver iPod models capture support --- ----------- --------------- 0 80/160fat dock line-in 1 120/160slim dock line-in + jack mic HW version 1 includes an amplifier for the jack plug mic. Capture HW detection only tested on iPod 80 and 160slim. CODEC power: AFAIK, OF powers CS42L55 at VA=2.4V for capture (1.8V for playback) and turns on the ADC charge pump. CODEC datasheet recommmends to disable the charge pump for VA>2.1V. CS42L55 DS, s4.13 (Required Initialization Settings): for VA>2.1V, some adjustments "must" be done using undocummented "control port compensation" registers. OF does not modifies these registers when VA=2.4V. This patch configures capture HW in the same way as OF does. TODO: - ADC full scale voltage depends on VA, perform tests to find clipping levels for VA=1.8V and VA=2.4V Change-Id: I7e20fd3ecaa83b1c58d5c746f5153fe5c3891d75
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/s5l8702/debug-s5l8702.c5
-rw-r--r--firmware/target/arm/s5l8702/gpio-s5l8702.c39
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/audio-ipod6g.c32
-rw-r--r--firmware/target/arm/s5l8702/pcm-s5l8702.c176
-rw-r--r--firmware/target/arm/s5l8702/system-s5l8702.c2
5 files changed, 242 insertions, 12 deletions
diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c
index 74f765e447..c49737756c 100644
--- a/firmware/target/arm/s5l8702/debug-s5l8702.c
+++ b/firmware/target/arm/s5l8702/debug-s5l8702.c
@@ -39,6 +39,8 @@
39#define _DEBUG_PRINTF(a, varargs...) lcd_putsf(0, line++, (a), ##varargs); 39#define _DEBUG_PRINTF(a, varargs...) lcd_putsf(0, line++, (a), ##varargs);
40 40
41extern int lcd_type; 41extern int lcd_type;
42extern int rec_hw_ver;
43
42bool dbg_hw_info(void) 44bool dbg_hw_info(void)
43{ 45{
44 int line; 46 int line;
@@ -70,6 +72,9 @@ bool dbg_hw_info(void)
70 72
71 _DEBUG_PRINTF("LCD type: %d", lcd_type); 73 _DEBUG_PRINTF("LCD type: %d", lcd_type);
72 line++; 74 line++;
75
76 _DEBUG_PRINTF("capture HW: %d", rec_hw_ver);
77 line++;
73 } 78 }
74 else if(state==1) 79 else if(state==1)
75 { 80 {
diff --git a/firmware/target/arm/s5l8702/gpio-s5l8702.c b/firmware/target/arm/s5l8702/gpio-s5l8702.c
index d3ccb032bc..bd87005ad8 100644
--- a/firmware/target/arm/s5l8702/gpio-s5l8702.c
+++ b/firmware/target/arm/s5l8702/gpio-s5l8702.c
@@ -26,6 +26,40 @@
26#include "gpio-s5l8702.h" 26#include "gpio-s5l8702.h"
27#include "panic.h" 27#include "panic.h"
28 28
29int rec_hw_ver;
30
31void INIT_ATTR gpio_init(void)
32{
33 /* Capture hardware versions:
34 *
35 * HW version 1 includes an amplifier for the jack plug
36 * microphone, it is activated configuring GPIO E7 as output
37 * high. It is posible to detect capture HW version (even
38 * when HP are not plugged) reading GPIO E7:
39 *
40 * Ver GPIO E7 models capture support
41 * --- ------- ------ ---------------
42 * 0 1 80/160fat dock line-in
43 * 1 0 120/160slim dock line-in + jack mic
44 */
45 GPIOCMD = 0xe0700;
46 rec_hw_ver = (PDAT(14) & (1 << 7)) ? 0 : 1;
47
48 /* default GPIO configuration */
49 GPIOCMD = 0xe070e;
50 if (rec_hw_ver == 0) {
51 GPIOCMD = 0xe060e;
52 }
53 else {
54 /* GPIO E6 is connected to mikey IRQ line (active low),
55 configure it as pull-up input */
56 GPIOCMD = 0xe0600;
57 PUNB(14) |= (1 << 6);
58 }
59
60 /* TODO: initialize GPIO ports for minimum power consumption */
61}
62
29 63
30/* 64/*
31 * XXX: disabled, not used and never tested! 65 * XXX: disabled, not used and never tested!
@@ -47,11 +81,6 @@ static int n_handlers = 0;
47 81
48 82
49/* API */ 83/* API */
50void INIT_ATTR gpio_init(void)
51{
52 /* TODO: initialize GPIO ports for minimum power consumption */
53}
54
55uint32_t gpio_group_get(int group) 84uint32_t gpio_group_get(int group)
56{ 85{
57 uint32_t pcon = PCON(group); 86 uint32_t pcon = PCON(group);
diff --git a/firmware/target/arm/s5l8702/ipod6g/audio-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/audio-ipod6g.c
index 6ede3d0c30..6a3bab06d6 100644
--- a/firmware/target/arm/s5l8702/ipod6g/audio-ipod6g.c
+++ b/firmware/target/arm/s5l8702/ipod6g/audio-ipod6g.c
@@ -22,6 +22,9 @@
22#include "cpu.h" 22#include "cpu.h"
23#include "audio.h" 23#include "audio.h"
24#include "sound.h" 24#include "sound.h"
25#include "pmu-target.h"
26
27extern int rec_hw_ver;
25 28
26#if INPUT_SRC_CAPS != 0 29#if INPUT_SRC_CAPS != 0
27void audio_set_output_source(int source) 30void audio_set_output_source(int source)
@@ -46,13 +49,42 @@ void audio_input_mux(int source, unsigned flags)
46 { 49 {
47 audiohw_set_monitor(false); 50 audiohw_set_monitor(false);
48 audiohw_disable_recording(); 51 audiohw_disable_recording();
52
53 /* Vcodec = 1800mV (900mV + value*100mV) */
54 pmu_ldo_set_voltage(3, 0x9);
55
56 if (rec_hw_ver == 1)
57 GPIOCMD = 0xe070e;
49 } 58 }
50#endif 59#endif
51 break; 60 break;
61
62#ifdef HAVE_MIC_REC
63 case AUDIO_SRC_MIC: /* recording only */
64 if (source != last_source)
65 {
66 if (rec_hw_ver == 1)
67 GPIOCMD = 0xe070f;
68
69 /* Vcodec = 2400mV (900mV + value*100mV) */
70 pmu_ldo_set_voltage(3, 0xf);
71
72 audiohw_set_monitor(false);
73 audiohw_enable_recording(true); /* source mic */
74 }
75 break;
76#endif
77
52#ifdef HAVE_LINE_REC 78#ifdef HAVE_LINE_REC
53 case AUDIO_SRC_LINEIN: /* recording only */ 79 case AUDIO_SRC_LINEIN: /* recording only */
54 if (source != last_source) 80 if (source != last_source)
55 { 81 {
82 if (rec_hw_ver == 1)
83 GPIOCMD = 0xe070e;
84
85 /* Vcodec = 2400mV (900mV + value*100mV) */
86 pmu_ldo_set_voltage(3, 0xf);
87
56 audiohw_set_monitor(false); 88 audiohw_set_monitor(false);
57 audiohw_enable_recording(false); /* source line */ 89 audiohw_enable_recording(false); /* source line */
58 } 90 }
diff --git a/firmware/target/arm/s5l8702/pcm-s5l8702.c b/firmware/target/arm/s5l8702/pcm-s5l8702.c
index a4ea56edce..446be24008 100644
--- a/firmware/target/arm/s5l8702/pcm-s5l8702.c
+++ b/firmware/target/arm/s5l8702/pcm-s5l8702.c
@@ -250,37 +250,201 @@ void * pcm_dma_addr(void *addr)
250 ** Recording DMA transfer 250 ** Recording DMA transfer
251 **/ 251 **/
252#ifdef HAVE_RECORDING 252#ifdef HAVE_RECORDING
253static volatile int rec_locked = 0;
254static void *rec_dma_addr;
255static size_t rec_dma_size;
256static bool pcm_rec_initialized = false;
257static int completed_task;
258
259/* ahead capture buffer */
260#define PCM_AHEADBUF_SAMPLES 128
261#define AHEADBUF_SZ (PCM_AHEADBUF_SAMPLES * 4)
262static unsigned char ahead_buf[AHEADBUF_SZ] CACHEALIGN_ATTR;
263
264/* DMA configuration */
265static void dma_rec_callback(void *cb_data) ICODE_ATTR;
266
267enum { /* cb_data */
268 TASK_AHEADBUF,
269 TASK_RECBUF
270};
271
272#define DMA_REC_TSKBUF_SZ 2 /* N tasks, MUST be pow2 */
273#define DMA_REC_LLIBUF_SZ 8 /* N LLIs, MUST be pow2 */
274static struct dmac_tsk dma_rec_tskbuf[DMA_REC_TSKBUF_SZ];
275static struct dmac_lli volatile \
276 dma_rec_llibuf[DMA_REC_LLIBUF_SZ] CACHEALIGN_ATTR;
277
278static struct dmac_ch dma_rec_ch = {
279 .dmac = &s5l8702_dmac0,
280 .prio = DMAC_CH_PRIO(1),
281 .cb_fn = dma_rec_callback,
282
283 .llibuf = dma_rec_llibuf,
284 .llibuf_mask = DMA_REC_LLIBUF_SZ - 1,
285 .llibuf_bus = DMAC_MASTER_AHB1,
286
287 .tskbuf = dma_rec_tskbuf,
288 .tskbuf_mask = DMA_REC_TSKBUF_SZ - 1,
289 .queue_mode = QUEUE_LINK,
290};
291
292static struct dmac_ch_cfg dma_rec_ch_cfg = {
293 .srcperi = S5L8702_DMAC0_PERI_IIS0_RX,
294 .dstperi = S5L8702_DMAC0_PERI_MEM,
295 .sbsize = DMACCxCONTROL_BSIZE_4,
296 .dbsize = DMACCxCONTROL_BSIZE_4,
297 .swidth = DMACCxCONTROL_WIDTH_16,
298 .dwidth = DMACCxCONTROL_WIDTH_16,
299 .sbus = DMAC_MASTER_AHB1,
300 .dbus = DMAC_MASTER_AHB1,
301 .sinc = DMACCxCONTROL_INC_DISABLE,
302 .dinc = DMACCxCONTROL_INC_ENABLE,
303 .prot = DMAC_PROT_CACH | DMAC_PROT_BUFF | DMAC_PROT_PRIV,
304 /* align LLI transfers to L-R pairs (samples) */
305 .lli_xfer_max_count = DMAC_LLI_MAX_COUNT & ~1,
306};
307
308/* maximum and minimum supported block sizes in bytes */
309#define MIN_SIZE ((size_t) (AHEADBUF_SZ * 2))
310#define MAX_SIZE ((size_t) (AHEADBUF_SZ + ((DMA_REC_LLIBUF_SZ - 1) * \
311 (dma_rec_ch_cfg.lli_xfer_max_count << dma_rec_ch_cfg.swidth))))
312
313#if 0
314#define SIZE_PANIC(sz) { \
315 if (((sz) < MIN_SIZE) || ((sz) > MAX_SIZE)) \
316 panicf("pcm record: unsupported size: %d", (sz)); \
317}
318#else
319#define SIZE_PANIC(sz) {}
320#endif
321
322
323static void rec_dmac_ch_queue(void *addr, size_t size, int cb_data)
324{
325 discard_dcache_range(addr, size);
326 dmac_ch_queue(&dma_rec_ch, (void*)S5L8702_DADDR_PERI_IIS0_RX,
327 addr, size, (void *)cb_data);
328}
329
330static void dma_rec_callback(void *cb_data)
331{
332 completed_task = (int)cb_data;
333
334 if (completed_task == TASK_AHEADBUF)
335 {
336 /* safety check */
337 if (rec_dma_addr == NULL)
338 return; /* capture finished */
339
340 /* move ahead buffer to record buffer and queue
341 next capture-ahead task */
342 memcpy(rec_dma_addr, ahead_buf, AHEADBUF_SZ);
343 rec_dmac_ch_queue(ahead_buf, AHEADBUF_SZ, TASK_AHEADBUF);
344 }
345 else /* TASK_RECBUF */
346 {
347 /* Inform middle layer */
348 if (pcm_rec_dma_complete_callback(
349 PCM_DMAST_OK, &rec_dma_addr, &rec_dma_size))
350 {
351 SIZE_PANIC(rec_dma_size);
352 rec_dmac_ch_queue(rec_dma_addr + AHEADBUF_SZ,
353 rec_dma_size - AHEADBUF_SZ, TASK_RECBUF);
354 pcm_rec_dma_status_callback(PCM_DMAST_STARTED);
355 }
356 }
357}
358
253void pcm_rec_lock(void) 359void pcm_rec_lock(void)
254{ 360{
361 if ((rec_locked++ == 0) && pcm_rec_initialized)
362 dmac_ch_lock_int(&dma_rec_ch);
255} 363}
256 364
257void pcm_rec_unlock(void) 365void pcm_rec_unlock(void)
258{ 366{
367 if ((--rec_locked == 0) && pcm_rec_initialized)
368 dmac_ch_unlock_int(&dma_rec_ch);
259} 369}
260 370
261void pcm_rec_dma_stop(void) 371void pcm_rec_dma_stop(void)
262{ 372{
373 if (!pcm_rec_initialized)
374 return;
375
376 dmac_ch_stop(&dma_rec_ch);
377
378 I2SRXCOM = 0x2; /* stop Rx I2S */
263} 379}
264 380
265void pcm_rec_dma_start(void *addr, size_t size) 381void pcm_rec_dma_start(void *addr, size_t size)
266{ 382{
267 (void)addr; 383 SIZE_PANIC(size);
268 (void)size; 384
385 pcm_rec_dma_stop();
386
387 rec_dma_addr = addr;
388 rec_dma_size = size;
389 completed_task = -1;
390
391 /* launch first DMA transfer to capture into ahead buffer,
392 link the second task to capture into record buffer */
393 rec_dmac_ch_queue(ahead_buf, AHEADBUF_SZ, TASK_AHEADBUF);
394 rec_dmac_ch_queue(addr + AHEADBUF_SZ, size - AHEADBUF_SZ, TASK_RECBUF);
395
396 I2SRXCOM = 0x6; /* start Rx I2S */
269} 397}
270 398
271void pcm_rec_dma_close(void) 399void pcm_rec_dma_close(void)
272{ 400{
401 pcm_rec_dma_stop();
273} 402}
274 403
275
276void pcm_rec_dma_init(void) 404void pcm_rec_dma_init(void)
277{ 405{
278} 406 if (pcm_rec_initialized)
407 return;
279 408
409 PWRCON(0) &= ~(1 << 4);
410 PWRCON(0) &= ~(1 << 7);
411
412 dmac_ch_init(&dma_rec_ch, &dma_rec_ch_cfg);
413
414 /* synchronize lock status */
415 if (rec_locked)
416 dmac_ch_lock_int(&dma_rec_ch);
417
418 I2SRXCON = 0x1000;
419 I2SCLKCON = 1;
420
421 pcm_rec_initialized = true;
422}
280 423
281const void * pcm_rec_dma_get_peak_buffer(void) 424const void * pcm_rec_dma_get_peak_buffer(void)
282{ 425{
283 return NULL; 426 void *dstaddr;
284} 427
428 pcm_rec_lock();
285 429
430 if (completed_task == TASK_AHEADBUF) {
431 dstaddr = dmac_ch_get_info(&dma_rec_ch, NULL, NULL);
432
433 if ((dstaddr < rec_dma_addr) ||
434 (dstaddr > rec_dma_addr + rec_dma_size))
435 /* At this moment, interrupt for TASK_RECBUF is waiting to
436 be handled. TASK_RECBUF is already finished and HW is
437 transfering next TASK_AHEADBUF. Return whole block. */
438 dstaddr = rec_dma_addr + rec_dma_size;
439 }
440 else {
441 /* Ahead buffer not yet captured _and_ moved to
442 record buffer. Return nothing. */
443 dstaddr = rec_dma_addr;
444 }
445
446 pcm_rec_unlock();
447
448 return CACHEALIGN_DOWN(dstaddr);
449}
286#endif /* HAVE_RECORDING */ 450#endif /* HAVE_RECORDING */
diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c
index 6a06c29694..a9db7e1b8d 100644
--- a/firmware/target/arm/s5l8702/system-s5l8702.c
+++ b/firmware/target/arm/s5l8702/system-s5l8702.c
@@ -182,7 +182,7 @@ void fiq_dummy(void)
182 182
183void system_init(void) 183void system_init(void)
184{ 184{
185 /*gpio_init();*/ 185 gpio_init();
186 pmu_init(); 186 pmu_init();
187 dma_init(); 187 dma_init();
188 VIC0INTENABLE = 1 << IRQ_WHEEL; 188 VIC0INTENABLE = 1 << IRQ_WHEEL;