diff options
author | Linus Nielsen Feltzing <linus@haxx.se> | 2006-07-21 08:42:28 +0000 |
---|---|---|
committer | Linus Nielsen Feltzing <linus@haxx.se> | 2006-07-21 08:42:28 +0000 |
commit | ed4d7a33bdeba5ce11512ee617398a2840797203 (patch) | |
tree | 1027077148ace8e13c8fa49ae3794b2038a2d67a | |
parent | e8818efbe9c814ad3b46ee0e5d0ae250b7c96cf4 (diff) | |
download | rockbox-ed4d7a33bdeba5ce11512ee617398a2840797203.tar.gz rockbox-ed4d7a33bdeba5ce11512ee617398a2840797203.zip |
Patch #5347 by Rani Hod - Adds FM radio and recording features to the iAudio X5.
Also includes a rewrite of the Coldfire I2C driver to include both read and write.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10272 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/main.c | 4 | ||||
-rw-r--r-- | apps/recorder/radio.c | 57 | ||||
-rw-r--r-- | apps/recorder/recording.c | 16 | ||||
-rw-r--r-- | firmware/drivers/fmradio_i2c.c | 17 | ||||
-rw-r--r-- | firmware/drivers/i2c-coldfire.c | 229 | ||||
-rw-r--r-- | firmware/drivers/tlv320.c | 119 | ||||
-rw-r--r-- | firmware/drivers/uda1380.c | 26 | ||||
-rw-r--r-- | firmware/export/config-iaudiox5.h | 7 | ||||
-rw-r--r-- | firmware/export/fmradio_i2c.h | 4 | ||||
-rw-r--r-- | firmware/export/i2c-coldfire.h | 10 | ||||
-rw-r--r-- | firmware/export/sound.h | 2 | ||||
-rw-r--r-- | firmware/export/tlv320.h | 3 | ||||
-rw-r--r-- | firmware/pcm_record.c | 83 | ||||
-rw-r--r-- | firmware/sound.c | 25 | ||||
-rw-r--r-- | firmware/target/coldfire/iaudio/x5/power-x5.c | 14 |
15 files changed, 449 insertions, 167 deletions
diff --git a/apps/main.c b/apps/main.c index 4f31cdb58a..8ee6adfe4f 100644 --- a/apps/main.c +++ b/apps/main.c | |||
@@ -72,7 +72,7 @@ | |||
72 | #else | 72 | #else |
73 | #define pcmbuf_init() | 73 | #define pcmbuf_init() |
74 | #endif | 74 | #endif |
75 | #if (defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)) && !defined(SIMULATOR) | 75 | #if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && !defined(SIMULATOR) |
76 | #include "pcm_record.h" | 76 | #include "pcm_record.h" |
77 | #define SETTINGS_RESET BUTTON_REC | 77 | #define SETTINGS_RESET BUTTON_REC |
78 | #endif | 78 | #endif |
@@ -425,7 +425,7 @@ void init(void) | |||
425 | talk_init(); | 425 | talk_init(); |
426 | 426 | ||
427 | audio_init(); | 427 | audio_init(); |
428 | #if (defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)) && !defined(SIMULATOR) | 428 | #if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && !defined(SIMULATOR) |
429 | pcm_rec_init(); | 429 | pcm_rec_init(); |
430 | #endif | 430 | #endif |
431 | 431 | ||
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c index 291079b4b0..a29620b46c 100644 --- a/apps/recorder/radio.c +++ b/apps/recorder/radio.c | |||
@@ -64,7 +64,13 @@ | |||
64 | #ifdef CONFIG_TUNER | 64 | #ifdef CONFIG_TUNER |
65 | 65 | ||
66 | #if CONFIG_CODEC == SWCODEC | 66 | #if CONFIG_CODEC == SWCODEC |
67 | #ifdef HAVE_UDA1380 | ||
67 | #include "uda1380.h" | 68 | #include "uda1380.h" |
69 | #endif | ||
70 | #ifdef HAVE_TLV320 | ||
71 | #include "tlv320.h" | ||
72 | #endif | ||
73 | |||
68 | #include "pcm_record.h" | 74 | #include "pcm_record.h" |
69 | #endif | 75 | #endif |
70 | 76 | ||
@@ -109,6 +115,35 @@ | |||
109 | #define FM_STOP BUTTON_OFF | 115 | #define FM_STOP BUTTON_OFF |
110 | #define FM_RC_STOP BUTTON_RC_STOP | 116 | #define FM_RC_STOP BUTTON_RC_STOP |
111 | 117 | ||
118 | #elif (CONFIG_KEYPAD == IAUDIO_X5_PAD) | ||
119 | /* pause/play - short PLAY */ | ||
120 | #define FM_PLAY_PRE BUTTON_PLAY | ||
121 | #define FM_RC_PLAY_PRE BUTTON_RC_PLAY | ||
122 | #define FM_PLAY (BUTTON_PLAY | BUTTON_REL) | ||
123 | #define FM_RC_PLAY (BUTTON_RC_PLAY | BUTTON_REL) | ||
124 | /* preset/scan mode - long PLAY */ | ||
125 | #define FM_MODE (BUTTON_PLAY | BUTTON_REPEAT) | ||
126 | #define FM_RC_MODE (BUTTON_RC_PLAY | BUTTON_REPEAT) | ||
127 | /* preset menu - short SELECT */ | ||
128 | #define FM_PRESET_PRE BUTTON_SELECT | ||
129 | #define FM_RC_PRESET_PRE BUTTON_RC_MENU | ||
130 | #define FM_PRESET (BUTTON_SELECT | BUTTON_REL) | ||
131 | #define FM_RC_PRESET (BUTTON_RC_MENU | BUTTON_REL) | ||
132 | /* fm menu - long SELECT */ | ||
133 | #define FM_MENU (BUTTON_SELECT | BUTTON_REPEAT) | ||
134 | #define FM_RC_MENU (BUTTON_RC_MENU | BUTTON_REPEAT) | ||
135 | /* main menu(exit radio while playing) - REC */ | ||
136 | #define FM_EXIT_PRE BUTTON_REC | ||
137 | #define FM_EXIT (BUTTON_REC | BUTTON_REL) | ||
138 | #define FM_RC_EXIT_PRE BUTTON_RC_MODE | ||
139 | #define FM_RC_EXIT (BUTTON_RC_MODE | BUTTON_REL) | ||
140 | /* prev/next preset on the remote - REW/FF */ | ||
141 | #define FM_NEXT_PRESET (BUTTON_RC_FF | BUTTON_REL) | ||
142 | #define FM_PREV_PRESET (BUTTON_RC_REW | BUTTON_REL) | ||
143 | /* stop and exit radio - ON */ | ||
144 | #define FM_STOP BUTTON_POWER | ||
145 | #define FM_RC_STOP (BUTTON_RC_MODE | BUTTON_REPEAT) | ||
146 | |||
112 | #elif CONFIG_KEYPAD == ONDIO_PAD /* restricted keypad */ | 147 | #elif CONFIG_KEYPAD == ONDIO_PAD /* restricted keypad */ |
113 | #define FM_MENU (BUTTON_MENU | BUTTON_REPEAT) | 148 | #define FM_MENU (BUTTON_MENU | BUTTON_REPEAT) |
114 | #define FM_RECORD_DBLPRE BUTTON_MENU | 149 | #define FM_RECORD_DBLPRE BUTTON_MENU |
@@ -158,7 +193,7 @@ int radio_get(int setting); | |||
158 | #if CONFIG_TUNER == S1A0903X01 /* FM recorder */ | 193 | #if CONFIG_TUNER == S1A0903X01 /* FM recorder */ |
159 | #define radio_set samsung_set | 194 | #define radio_set samsung_set |
160 | #define radio_get samsung_get | 195 | #define radio_get samsung_get |
161 | #elif CONFIG_TUNER == TEA5767 /* Iriver */ | 196 | #elif CONFIG_TUNER == TEA5767 /* iriver, iaudio */ |
162 | #define radio_set philips_set | 197 | #define radio_set philips_set |
163 | #define radio_get philips_get | 198 | #define radio_get philips_get |
164 | #elif CONFIG_TUNER == (S1A0903X01 | TEA5767) /* OndioFM */ | 199 | #elif CONFIG_TUNER == (S1A0903X01 | TEA5767) /* OndioFM */ |
@@ -387,8 +422,15 @@ bool radio_screen(void) | |||
387 | 422 | ||
388 | #else | 423 | #else |
389 | peak_meter_enabled = false; | 424 | peak_meter_enabled = false; |
425 | |||
426 | #ifdef HAVE_UDA1380 | ||
390 | uda1380_enable_recording(false); | 427 | uda1380_enable_recording(false); |
391 | uda1380_set_monitor(true); | 428 | uda1380_set_monitor(true); |
429 | #elif defined(HAVE_TLV320) | ||
430 | //tlv320_enable_recording(false); | ||
431 | tlv320_set_recvol(23, 23, AUDIO_GAIN_LINEIN); /* 0dB */ | ||
432 | tlv320_set_monitor(true); | ||
433 | #endif | ||
392 | 434 | ||
393 | /* Set the input multiplexer to FM */ | 435 | /* Set the input multiplexer to FM */ |
394 | pcm_rec_mux(1); | 436 | pcm_rec_mux(1); |
@@ -971,7 +1013,7 @@ bool radio_screen(void) | |||
971 | while(1) | 1013 | while(1) |
972 | { | 1014 | { |
973 | button = button_get(true); | 1015 | button = button_get(true); |
974 | if(button == (BUTTON_OFF | BUTTON_REL)) | 1016 | if(button == (FM_STOP | BUTTON_REL)) |
975 | break; | 1017 | break; |
976 | } | 1018 | } |
977 | } | 1019 | } |
@@ -1004,6 +1046,11 @@ bool radio_screen(void) | |||
1004 | radio_stop(); | 1046 | radio_stop(); |
1005 | #ifndef SIMULATOR /* SIMULATOR. Catch FMRADIO_OFF status for the sim. */ | 1047 | #ifndef SIMULATOR /* SIMULATOR. Catch FMRADIO_OFF status for the sim. */ |
1006 | #if CONFIG_CODEC == SWCODEC | 1048 | #if CONFIG_CODEC == SWCODEC |
1049 | #ifdef HAVE_TLV320 | ||
1050 | //tlv320_disable_recording(); | ||
1051 | tlv320_set_monitor(false); | ||
1052 | #endif | ||
1053 | |||
1007 | pcm_rec_mux(0); /* Line In */ | 1054 | pcm_rec_mux(0); /* Line In */ |
1008 | peak_meter_enabled = true; | 1055 | peak_meter_enabled = true; |
1009 | #endif | 1056 | #endif |
@@ -1320,7 +1367,7 @@ int handle_radio_presets_cb(int key, int m) | |||
1320 | key = BUTTON_NONE; | 1367 | key = BUTTON_NONE; |
1321 | break; | 1368 | break; |
1322 | #endif | 1369 | #endif |
1323 | #if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) | 1370 | #if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) && (CONFIG_KEYPAD != IAUDIO_X5_PAD) |
1324 | #ifdef FM_PRESET | 1371 | #ifdef FM_PRESET |
1325 | case FM_PRESET: | 1372 | case FM_PRESET: |
1326 | menu_draw(m); | 1373 | menu_draw(m); |
@@ -1565,7 +1612,7 @@ int radio_menu_cb(int key, int m) | |||
1565 | (void)m; | 1612 | (void)m; |
1566 | switch(key) | 1613 | switch(key) |
1567 | { | 1614 | { |
1568 | #if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) | 1615 | #if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) && (CONFIG_KEYPAD != IAUDIO_X5_PAD) |
1569 | #ifdef MENU_ENTER2 | 1616 | #ifdef MENU_ENTER2 |
1570 | case MENU_ENTER2: | 1617 | case MENU_ENTER2: |
1571 | #endif | 1618 | #endif |
@@ -1574,7 +1621,7 @@ int radio_menu_cb(int key, int m) | |||
1574 | key = BUTTON_NONE; /* eat the downpress, next menu reacts on release */ | 1621 | key = BUTTON_NONE; /* eat the downpress, next menu reacts on release */ |
1575 | break; | 1622 | break; |
1576 | 1623 | ||
1577 | #if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) | 1624 | #if (CONFIG_KEYPAD != IRIVER_H100_PAD) && (CONFIG_KEYPAD != IRIVER_H300_PAD) && (CONFIG_KEYPAD != IAUDIO_X5_PAD) |
1578 | #ifdef MENU_ENTER2 | 1625 | #ifdef MENU_ENTER2 |
1579 | case MENU_ENTER2 | BUTTON_REL: | 1626 | case MENU_ENTER2 | BUTTON_REL: |
1580 | #endif | 1627 | #endif |
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index 09ec0f43f5..d4094a2511 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c | |||
@@ -34,6 +34,9 @@ | |||
34 | #ifdef HAVE_UDA1380 | 34 | #ifdef HAVE_UDA1380 |
35 | #include "uda1380.h" | 35 | #include "uda1380.h" |
36 | #endif | 36 | #endif |
37 | #ifdef HAVE_TLV320 | ||
38 | #include "tlv320.h" | ||
39 | #endif | ||
37 | 40 | ||
38 | #include "mp3_playback.h" | 41 | #include "mp3_playback.h" |
39 | #include "mas.h" | 42 | #include "mas.h" |
@@ -109,6 +112,16 @@ | |||
109 | #define REC_RC_PREV BUTTON_RC_REW | 112 | #define REC_RC_PREV BUTTON_RC_REW |
110 | #define REC_RC_SETTINGS BUTTON_RC_MODE | 113 | #define REC_RC_SETTINGS BUTTON_RC_MODE |
111 | 114 | ||
115 | #elif (CONFIG_KEYPAD == IAUDIO_X5_PAD) | ||
116 | #define REC_SHUTDOWN (BUTTON_POWER | BUTTON_REPEAT) | ||
117 | #define REC_STOPEXIT BUTTON_POWER | ||
118 | #define REC_RECPAUSE BUTTON_REC | ||
119 | #define REC_INC BUTTON_RIGHT | ||
120 | #define REC_DEC BUTTON_LEFT | ||
121 | #define REC_NEXT BUTTON_DOWN | ||
122 | #define REC_PREV BUTTON_UP | ||
123 | #define REC_SETTINGS BUTTON_PLAY | ||
124 | |||
112 | #elif CONFIG_KEYPAD == GMINI100_PAD | 125 | #elif CONFIG_KEYPAD == GMINI100_PAD |
113 | #define REC_SHUTDOWN (BUTTON_OFF | BUTTON_REPEAT) | 126 | #define REC_SHUTDOWN (BUTTON_OFF | BUTTON_REPEAT) |
114 | #define REC_STOPEXIT BUTTON_OFF | 127 | #define REC_STOPEXIT BUTTON_OFF |
@@ -362,6 +375,9 @@ bool recording_screen(void) | |||
362 | audio_stop(); | 375 | audio_stop(); |
363 | /* Set peak meter to recording mode */ | 376 | /* Set peak meter to recording mode */ |
364 | peak_meter_playback(false); | 377 | peak_meter_playback(false); |
378 | #ifdef IAUDIO_X5 | ||
379 | pcm_rec_mux(0); /* select line-in (not radio) */ | ||
380 | #endif | ||
365 | 381 | ||
366 | #if defined(HAVE_SPDIF_IN) && !defined(SIMULATOR) | 382 | #if defined(HAVE_SPDIF_IN) && !defined(SIMULATOR) |
367 | if (global_settings.rec_source == SOURCE_SPDIF) | 383 | if (global_settings.rec_source == SOURCE_SPDIF) |
diff --git a/firmware/drivers/fmradio_i2c.c b/firmware/drivers/fmradio_i2c.c index 2475084696..6f87e15b3e 100644 --- a/firmware/drivers/fmradio_i2c.c +++ b/firmware/drivers/fmradio_i2c.c | |||
@@ -27,6 +27,22 @@ | |||
27 | 27 | ||
28 | #if (CONFIG_TUNER & TEA5767) | 28 | #if (CONFIG_TUNER & TEA5767) |
29 | #if (CONFIG_I2C == I2C_COLDFIRE) | 29 | #if (CONFIG_I2C == I2C_COLDFIRE) |
30 | |||
31 | #ifdef IAUDIO_X5 | ||
32 | #include "i2c-coldfire.h" | ||
33 | |||
34 | int fmradio_i2c_write(unsigned char address, const unsigned char* buf, | ||
35 | int count) | ||
36 | { | ||
37 | return i2c_write(I2C_IFACE_0, address, buf, count); | ||
38 | } | ||
39 | |||
40 | int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count) | ||
41 | { | ||
42 | return i2c_read(I2C_IFACE_0, address, buf, count); | ||
43 | } | ||
44 | #else | ||
45 | |||
30 | /* cute little functions, atomic read-modify-write */ | 46 | /* cute little functions, atomic read-modify-write */ |
31 | /* SDA is GPIO1,23 */ | 47 | /* SDA is GPIO1,23 */ |
32 | 48 | ||
@@ -242,6 +258,7 @@ int fmradio_i2c_read(int address, unsigned char* buf, int count) | |||
242 | fmradio_i2c_stop(); | 258 | fmradio_i2c_stop(); |
243 | return x; | 259 | return x; |
244 | } | 260 | } |
261 | #endif /* ! IAUDIO_X5 */ | ||
245 | #else | 262 | #else |
246 | /* cute little functions, atomic read-modify-write */ | 263 | /* cute little functions, atomic read-modify-write */ |
247 | /* SDA is PB4 */ | 264 | /* SDA is PB4 */ |
diff --git a/firmware/drivers/i2c-coldfire.c b/firmware/drivers/i2c-coldfire.c index 47aeba757f..a628ce5f0e 100644 --- a/firmware/drivers/i2c-coldfire.c +++ b/firmware/drivers/i2c-coldfire.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * | ||
8 | * $Id$ | 9 | * $Id$ |
9 | * | 10 | * |
10 | * Copyright (C) 2005 by Andy Young | 11 | * Copyright (C) 2005 by Andy Young |
@@ -23,17 +24,16 @@ | |||
23 | #include "system.h" | 24 | #include "system.h" |
24 | #include "i2c-coldfire.h" | 25 | #include "i2c-coldfire.h" |
25 | 26 | ||
26 | #define I2C_DEVICE_1 ((volatile unsigned char *)&MADR) | ||
27 | #define I2C_DEVICE_2 ((volatile unsigned char *)&MADR2) | ||
28 | 27 | ||
29 | /* Local functions definitions */ | 28 | /* --- Local functions - declarations --- */ |
29 | |||
30 | static int i2c_start(volatile unsigned char *iface); | ||
31 | static int i2c_wait_for_slave(volatile unsigned char *iface); | ||
32 | static int i2c_outb(volatile unsigned char *iface, unsigned char byte); | ||
33 | inline void i2c_stop(volatile unsigned char *iface); | ||
30 | 34 | ||
31 | static int i2c_write_byte(int device, unsigned char data); | ||
32 | static int i2c_gen_start(int device); | ||
33 | static void i2c_gen_stop(int device); | ||
34 | static volatile unsigned char *i2c_get_addr(int device); | ||
35 | 35 | ||
36 | /* Public functions */ | 36 | /* --- Public functions - implementation --- */ |
37 | 37 | ||
38 | void i2c_init(void) | 38 | void i2c_init(void) |
39 | { | 39 | { |
@@ -55,14 +55,15 @@ void i2c_init(void) | |||
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | /* I2C Clock divisor = 160 => 124.1556 MHz / 2 / 160 = 388.08 kHz */ | 57 | /* I2C Clock divisor = 160 => 124.1556 MHz / 2 / 160 = 388.08 kHz */ |
58 | MFDR = 0x0d; | 58 | MFDR = 0x0d; |
59 | MFDR2 = 0x0d; | 59 | MFDR2 = 0x0d; |
60 | 60 | ||
61 | #ifdef IAUDIO_X5 | 61 | #ifdef IAUDIO_X5 |
62 | MBCR = IEN; /* Enable interface */ | 62 | MBCR = IEN; /* Enable interface */ |
63 | MBCR2 = IEN; | ||
63 | #endif | 64 | #endif |
64 | 65 | ||
65 | #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) | 66 | #if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) |
66 | /* Audio Codec */ | 67 | /* Audio Codec */ |
67 | MBDR = 0; /* iRiver firmware does this */ | 68 | MBDR = 0; /* iRiver firmware does this */ |
68 | MBCR = IEN; /* Enable interface */ | 69 | MBCR = IEN; /* Enable interface */ |
@@ -72,109 +73,169 @@ void i2c_init(void) | |||
72 | void i2c_close(void) | 73 | void i2c_close(void) |
73 | { | 74 | { |
74 | MBCR = 0; | 75 | MBCR = 0; |
76 | MBCR2 = 0; | ||
75 | } | 77 | } |
76 | 78 | ||
77 | /** | 79 | /* |
78 | * Writes bytes to the selected device. | 80 | * Writes bytes to a I2C device. |
79 | * | 81 | * |
80 | * Use device=1 for bus 1 at 0x40000280 | 82 | * Returns number of bytes successfully sent or a negative value on error. |
81 | * Use device=2 for bus 2 at 0x80000440 | ||
82 | * | ||
83 | * Returns number of bytes successfully send or -1 if START failed | ||
84 | */ | 83 | */ |
85 | int i2c_write(int device, unsigned char *buf, int count) | 84 | int i2c_write(volatile unsigned char *iface, unsigned char addr, |
85 | const unsigned char *buf, int count) | ||
86 | { | 86 | { |
87 | int i; | 87 | int i, rc; |
88 | int rc; | ||
89 | 88 | ||
90 | rc = i2c_gen_start(device); | 89 | if ( ! count) |
90 | return 0; | ||
91 | |||
92 | rc = i2c_start(iface); | ||
91 | if (rc < 0) | 93 | if (rc < 0) |
94 | return rc; | ||
95 | |||
96 | rc = i2c_outb(iface, addr & 0xfe); | ||
97 | if (rc < 0) | ||
98 | return rc; | ||
99 | |||
100 | for (i = 0; i < count; i++) | ||
92 | { | 101 | { |
93 | logf("i2c: gen_start failed (d=%d)", device); | 102 | rc = i2c_outb(iface, *buf++); |
94 | return rc*10 - 1; | ||
95 | } | ||
96 | |||
97 | for (i=0; i<count; i++) | ||
98 | { | ||
99 | rc = i2c_write_byte(device, buf[i]); | ||
100 | if (rc < 0) | 103 | if (rc < 0) |
101 | { | 104 | return rc; |
102 | logf("i2c: write failed at (d=%d,i=%d)", device, i); | ||
103 | return rc*10 - 2; | ||
104 | } | ||
105 | } | 105 | } |
106 | 106 | i2c_stop(iface); | |
107 | i2c_gen_stop(device); | 107 | |
108 | |||
109 | return count; | 108 | return count; |
110 | } | 109 | } |
111 | 110 | ||
112 | /* Write a byte to the interface, returns 0 on success, -1 otherwise. */ | 111 | /* |
113 | int i2c_write_byte(int device, unsigned char data) | 112 | * Reads bytes from a I2C device. |
113 | * | ||
114 | * Returns number of bytes successfully received or a negative value on error. | ||
115 | */ | ||
116 | int i2c_read(volatile unsigned char *iface, unsigned char addr, | ||
117 | unsigned char *buf, int count) | ||
114 | { | 118 | { |
115 | volatile unsigned char *regs = i2c_get_addr(device); | 119 | int i, rc; |
116 | 120 | ||
117 | long count = 0; | 121 | if ( ! count) |
122 | return 0; | ||
123 | |||
124 | rc = i2c_start(iface); | ||
125 | if (rc < 0) | ||
126 | return rc; | ||
118 | 127 | ||
119 | regs[O_MBDR] = data; /* Write data byte */ | 128 | rc = i2c_outb(iface, addr | 1); |
129 | if (rc < 0) | ||
130 | return rc; | ||
131 | |||
132 | /* Switch to Rx mode */ | ||
133 | iface[O_MBCR] &= ~MTX; | ||
134 | iface[O_MBCR] &= ~TXAK; | ||
135 | |||
136 | /* Dummy read */ | ||
137 | rc = (int) iface[O_MBDR]; | ||
138 | |||
139 | for (i = 0; i < count; i++) | ||
140 | { | ||
141 | rc = i2c_wait_for_slave(iface); | ||
142 | if (rc < 0) | ||
143 | return rc; | ||
120 | 144 | ||
121 | /* Wait for bus busy */ | 145 | if (i == count-2) |
122 | while (!(regs[O_MBSR] & IBB) && count < MAX_LOOP) | 146 | /* Don't ACK the next-to-last byte */ |
123 | count++; | 147 | iface[O_MBCR] |= TXAK; |
148 | |||
149 | if (i == count-1) | ||
150 | /* Generate STOP before reading last byte */ | ||
151 | i2c_stop(iface); | ||
124 | 152 | ||
125 | if (count >= MAX_LOOP) | 153 | *buf++ = iface[O_MBDR]; |
126 | return -1; | 154 | } |
155 | return count; | ||
156 | } | ||
127 | 157 | ||
128 | count = 0; | 158 | /* --- Local functions - implementation --- */ |
129 | 159 | ||
130 | /* Wait for interrupt flag */ | 160 | /* Begin I2C session on the given interface. |
131 | while (!(regs[O_MBSR] & IFF) && count < MAX_LOOP) | 161 | * |
132 | count++; | 162 | * Returns 0 on success, negative value on error. |
163 | */ | ||
164 | int i2c_start(volatile unsigned char *iface) | ||
165 | { | ||
166 | /* Wait for bus to become free */ | ||
167 | int j = MAX_LOOP; | ||
168 | while (--j && (iface[O_MBSR] & IBB)) | ||
169 | ; | ||
170 | if (!j) | ||
171 | { | ||
172 | logf("i2c: bus is busy (iface=%08x)", iface); | ||
173 | return -1; | ||
174 | } | ||
175 | |||
176 | /* Generate START and prepare for write */ | ||
177 | iface[O_MBCR] |= (MSTA | TXAK | MTX); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
133 | 181 | ||
134 | if (count >= MAX_LOOP) | 182 | /* Wait for slave to act on given I2C interface. |
183 | * | ||
184 | * Returns 0 on success, negative value on error. | ||
185 | */ | ||
186 | int i2c_wait_for_slave(volatile unsigned char *iface) | ||
187 | { | ||
188 | int j = MAX_LOOP; | ||
189 | while (--j && ! (iface[O_MBSR] & IFF)) | ||
190 | ; | ||
191 | if (!j) | ||
192 | { | ||
193 | logf("i2c: IFF not set (iface=%08x)", iface); | ||
194 | i2c_stop(iface); | ||
135 | return -2; | 195 | return -2; |
136 | 196 | } | |
137 | regs[O_MBSR] &= ~IFF; /* Clear interrupt flag */ | 197 | |
138 | 198 | /* Clear interrupt flag */ | |
139 | if (!(regs[O_MBSR] & ICF)) /* Check that transfer is complete */ | 199 | iface[O_MBSR] &= ~IFF; |
140 | return -3; | 200 | |
141 | |||
142 | if (regs[O_MBSR] & RXAK) /* Check that the byte has been ACKed */ | ||
143 | return -4; | ||
144 | |||
145 | return 0; | 201 | return 0; |
146 | } | 202 | } |
147 | 203 | ||
148 | 204 | /* Write the given byte to the given I2C interface. | |
149 | /* Returns 0 on success, -1 on failure */ | 205 | * |
150 | int i2c_gen_start(int device) | 206 | * Returns 0 on success, negative value on error. |
207 | */ | ||
208 | int i2c_outb(volatile unsigned char *iface, unsigned char byte) | ||
151 | { | 209 | { |
152 | volatile unsigned char *regs = i2c_get_addr(device); | 210 | int rc; |
153 | long count = 0; | ||
154 | |||
155 | /* Wait for bus to become free */ | ||
156 | while ((regs[O_MBSR] & IBB) && (count < MAX_LOOP)) | ||
157 | count++; | ||
158 | |||
159 | if (count >= MAX_LOOP) | ||
160 | return -1; | ||
161 | 211 | ||
162 | regs[O_MBCR] |= MSTA | MTX; /* Generate START */ | 212 | iface[O_MBDR] = byte; |
163 | 213 | ||
214 | rc = i2c_wait_for_slave(iface); | ||
215 | if (rc < 0) | ||
216 | return rc; | ||
217 | |||
218 | /* Check that transfer is complete */ | ||
219 | if ( !(iface[O_MBSR] & ICF)) | ||
220 | { | ||
221 | logf("i2c: transfer error (iface=%08x)", iface); | ||
222 | i2c_stop(iface); | ||
223 | return -3; | ||
224 | } | ||
225 | |||
226 | /* Check that the byte has been ACKed */ | ||
227 | if (iface[O_MBSR] & RXAK) | ||
228 | { | ||
229 | logf("i2c: no ACK (iface=%08x)", iface); | ||
230 | i2c_stop(iface); | ||
231 | return -4; | ||
232 | } | ||
233 | |||
164 | return 0; | 234 | return 0; |
165 | } | ||
166 | |||
167 | void i2c_gen_stop(int device) | ||
168 | { | ||
169 | volatile unsigned char *regs = i2c_get_addr(device); | ||
170 | regs[O_MBCR] &= ~MSTA; /* Clear MSTA to generate STOP */ | ||
171 | } | 235 | } |
172 | 236 | ||
173 | 237 | /* End I2C session on the given interface. */ | |
174 | volatile unsigned char *i2c_get_addr(int device) | 238 | inline void i2c_stop(volatile unsigned char *iface) |
175 | { | 239 | { |
176 | if (device == 1) | 240 | iface[O_MBCR] &= ~MSTA; |
177 | return I2C_DEVICE_1; | ||
178 | |||
179 | return I2C_DEVICE_2; | ||
180 | } | 241 | } |
diff --git a/firmware/drivers/tlv320.c b/firmware/drivers/tlv320.c index 8ef32919ce..39cd2a5536 100644 --- a/firmware/drivers/tlv320.c +++ b/firmware/drivers/tlv320.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "string.h" | 28 | #include "string.h" |
29 | #include "file.h" | 29 | #include "file.h" |
30 | #include "buffer.h" | 30 | #include "buffer.h" |
31 | #include "audio.h" | ||
31 | 32 | ||
32 | #include "i2c-coldfire.h" | 33 | #include "i2c-coldfire.h" |
33 | #include "tlv320.h" | 34 | #include "tlv320.h" |
@@ -46,14 +47,13 @@ unsigned tlv320_regs[0xf]; | |||
46 | 47 | ||
47 | void tlv320_write_reg(unsigned reg, unsigned value) | 48 | void tlv320_write_reg(unsigned reg, unsigned value) |
48 | { | 49 | { |
49 | unsigned char data[3]; | 50 | unsigned char data[2]; |
50 | 51 | ||
51 | data[0] = TLV320_ADDR; | ||
52 | /* The register address is the high 7 bits and the data the low 9 bits */ | 52 | /* The register address is the high 7 bits and the data the low 9 bits */ |
53 | data[1] = (reg << 1) | ((value >> 8) & 1); | 53 | data[0] = (reg << 1) | ((value >> 8) & 1); |
54 | data[2] = value & 0xff; | 54 | data[1] = value & 0xff; |
55 | 55 | ||
56 | if (i2c_write(1, data, 3) != 3) | 56 | if (i2c_write(I2C_IFACE_0, TLV320_ADDR, data, 2) != 2) |
57 | { | 57 | { |
58 | logf("tlv320 error reg=0x%x", reg); | 58 | logf("tlv320 error reg=0x%x", reg); |
59 | return; | 59 | return; |
@@ -73,15 +73,16 @@ void tlv320_init(void) | |||
73 | 73 | ||
74 | /* Initialize all registers */ | 74 | /* Initialize all registers */ |
75 | 75 | ||
76 | tlv320_write_reg(REG_PC, 0x00); /* All ON */ | 76 | tlv320_write_reg(REG_PC, PC_ADC|PC_MIC|PC_LINE); /* All ON except ADC, MIC and LINE */ |
77 | tlv320_set_linein_vol(0, 0); | 77 | tlv320_set_recvol(0, 0, AUDIO_GAIN_MIC); |
78 | tlv320_set_recvol(0, 0, AUDIO_GAIN_LINEIN); | ||
78 | tlv320_mute(true); | 79 | tlv320_mute(true); |
79 | tlv320_write_reg(REG_AAP, AAP_DAC|AAP_MICM); | 80 | tlv320_write_reg(REG_AAP, AAP_DAC|AAP_MICM); |
80 | tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ | 81 | tlv320_write_reg(REG_DAP, 0x00); /* No deemphasis */ |
81 | tlv320_write_reg(REG_DAIF, DAIF_IWL_16|DAIF_FOR_I2S); | 82 | tlv320_write_reg(REG_DAIF, DAIF_IWL_16|DAIF_FOR_I2S); |
82 | tlv320_set_headphone_vol(0, 0); | 83 | tlv320_set_headphone_vol(0, 0); |
83 | tlv320_write_reg(REG_DIA, DIA_ACT); | 84 | tlv320_write_reg(REG_DIA, DIA_ACT); |
84 | tlv320_write_reg(REG_SRC, (8 << 2)); /* 44.1kHz */ | 85 | tlv320_write_reg(REG_SRC, (1 << 5)); /* 44.1kHz */ |
85 | } | 86 | } |
86 | 87 | ||
87 | /** | 88 | /** |
@@ -114,18 +115,30 @@ void tlv320_set_headphone_vol(int vol_l, int vol_r) | |||
114 | } | 115 | } |
115 | 116 | ||
116 | /** | 117 | /** |
117 | * Sets left and right linein volume (31(max) to 0(muted)) | 118 | * Set recording volume |
119 | * | ||
120 | * Line in : 0 .. 31 => Volume -34.5 .. 12 dB | ||
121 | * Mic (left): 0 .. 1 => Volume 0 .. 20 dB | ||
122 | * | ||
118 | */ | 123 | */ |
119 | void tlv320_set_linein_vol(int vol_l, int vol_r) | 124 | void tlv320_set_recvol(int left, int right, int type) |
120 | { | 125 | { |
121 | unsigned value_l = tlv320_regs[REG_LLIV]; | 126 | if (type == AUDIO_GAIN_MIC) |
122 | unsigned value_r = tlv320_regs[REG_RLIV]; | 127 | { |
123 | 128 | unsigned value_aap = tlv320_regs[REG_AAP]; | |
124 | value_l |= LLIV_LIV(vol_l); | 129 | |
125 | value_r |= RLIV_RIV(vol_r); | 130 | if (left) |
126 | 131 | value_aap |= AAP_MICB; /* Enable mic boost (20dB) */ | |
127 | tlv320_write_reg(REG_LLIV, value_l); | 132 | else |
128 | tlv320_write_reg(REG_RLIV, value_r); | 133 | value_aap &= ~AAP_MICB; |
134 | |||
135 | tlv320_write_reg(REG_AAP, value_aap); | ||
136 | |||
137 | } else if (type == AUDIO_GAIN_LINEIN) | ||
138 | { | ||
139 | tlv320_write_reg(REG_LLIV, LLIV_LIV(left)); | ||
140 | tlv320_write_reg(REG_RLIV, RLIV_RIV(right)); | ||
141 | } | ||
129 | } | 142 | } |
130 | 143 | ||
131 | /** | 144 | /** |
@@ -148,10 +161,11 @@ void tlv320_mute(bool mute) | |||
148 | value_r = RHV_RHV(tlv320.vol_r); | 161 | value_r = RHV_RHV(tlv320.vol_r); |
149 | } | 162 | } |
150 | 163 | ||
151 | tlv320_write_reg(REG_LHV, value_r); | 164 | tlv320_write_reg(REG_LHV, value_l); |
152 | tlv320_write_reg(REG_RHV, value_r); | 165 | tlv320_write_reg(REG_RHV, value_r); |
153 | } | 166 | } |
154 | 167 | ||
168 | /* Nice shutdown of TLV320 codec */ | ||
155 | void tlv320_close() | 169 | void tlv320_close() |
156 | { | 170 | { |
157 | tlv320_write_reg(REG_PC, 0xFF); /* All OFF */ | 171 | tlv320_write_reg(REG_PC, 0xFF); /* All OFF */ |
@@ -159,35 +173,66 @@ void tlv320_close() | |||
159 | 173 | ||
160 | void tlv320_enable_recording(bool source_mic) | 174 | void tlv320_enable_recording(bool source_mic) |
161 | { | 175 | { |
162 | unsigned value_pc = tlv320_regs[REG_PC]; | 176 | unsigned value_daif = tlv320_regs[REG_DAIF]; |
163 | unsigned value_aap = tlv320_regs[REG_AAP]; | 177 | unsigned value_aap, value_pc; |
164 | 178 | ||
165 | /* select source*/ | ||
166 | if (source_mic) | 179 | if (source_mic) |
167 | { | 180 | { |
168 | value_aap &= ~AAP_INSEL; | 181 | /* select mic and enable mic boost (20 dB) */ |
169 | value_pc |= PC_MIC; | 182 | value_aap = AAP_DAC | AAP_INSEL | AAP_MICB; |
183 | value_pc = PC_LINE; /* power down line-in */ | ||
170 | } | 184 | } |
171 | else | 185 | else |
172 | { | 186 | { |
173 | value_aap |= AAP_INSEL; | 187 | value_aap = AAP_DAC | AAP_MICM; |
174 | value_pc |= PC_LINE; | 188 | value_pc = PC_MIC; /* power down mic */ |
175 | } | 189 | } |
176 | 190 | ||
177 | /* poweron adc */ | 191 | tlv320_write_reg(REG_PC, value_pc); |
178 | value_pc |= PC_ADC; | 192 | sleep(HZ/8); |
179 | 193 | ||
180 | tlv320_write_reg(REG_AAP, value_aap); | 194 | tlv320_write_reg(REG_AAP, value_aap); |
181 | tlv320_write_reg(REG_PC, value_pc); | 195 | sleep(HZ/8); |
196 | |||
197 | /* Enable MASTER mode (start sending I2S data to the CPU) */ | ||
198 | value_daif |= DAIF_MS; | ||
199 | tlv320_write_reg(REG_DAIF, value_daif); | ||
182 | } | 200 | } |
183 | 201 | ||
184 | void tlv320_disable_recording() | 202 | void tlv320_disable_recording() |
185 | { | 203 | { |
186 | unsigned value = tlv320_regs[REG_PC]; | 204 | unsigned value_pc = tlv320_regs[REG_PC]; |
187 | 205 | unsigned value_aap = tlv320_regs[REG_AAP]; | |
188 | /* powerdown mic, linein and adc */ | 206 | unsigned value_daif = tlv320_regs[REG_DAIF]; |
189 | value &= ~(PC_MIC | PC_LINE | PC_ADC); | 207 | |
208 | value_daif &= ~DAIF_MS; /* disable MASTER mode */ | ||
209 | tlv320_write_reg(REG_DAIF, value_daif); | ||
210 | |||
211 | value_aap |= AAP_MICM; /* mute mic */ | ||
212 | tlv320_write_reg(REG_PC, value_aap); | ||
213 | |||
214 | value_pc |= (PC_MIC|PC_LINE|PC_ADC); /* power down mic, line-in and adc */ | ||
215 | tlv320_write_reg(REG_PC, value_pc); | ||
216 | |||
217 | sleep(HZ/8); | ||
218 | } | ||
190 | 219 | ||
191 | /* powerdown mic, linein and adc */ | 220 | void tlv320_set_monitor(bool enable) |
192 | tlv320_write_reg(REG_PC, value); | 221 | { |
222 | unsigned value_aap, value_pc; | ||
223 | if (enable) | ||
224 | { | ||
225 | value_aap = AAP_BYPASS | AAP_MICM; | ||
226 | value_pc = (PC_MIC|PC_DAC|PC_ADC); /* power down mic, dac and adc */ | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | value_aap = AAP_DAC | AAP_MICM; | ||
231 | value_pc = (PC_MIC|PC_LINE|PC_ADC); /* power down mic, line-in and adc */ | ||
232 | } | ||
233 | tlv320_write_reg(REG_AAP, value_aap); | ||
234 | tlv320_write_reg(REG_PC, value_pc); | ||
235 | |||
236 | sleep(HZ/8); | ||
193 | } | 237 | } |
238 | |||
diff --git a/firmware/drivers/uda1380.c b/firmware/drivers/uda1380.c index ef19dcf1c5..241a117385 100644 --- a/firmware/drivers/uda1380.c +++ b/firmware/drivers/uda1380.c | |||
@@ -76,14 +76,13 @@ unsigned short uda1380_defaults[2*NUM_DEFAULT_REGS] = | |||
76 | /* Returns 0 if register was written or -1 if write failed */ | 76 | /* Returns 0 if register was written or -1 if write failed */ |
77 | int uda1380_write_reg(unsigned char reg, unsigned short value) | 77 | int uda1380_write_reg(unsigned char reg, unsigned short value) |
78 | { | 78 | { |
79 | unsigned char data[4]; | 79 | unsigned char data[3]; |
80 | 80 | ||
81 | data[0] = UDA1380_ADDR; | 81 | data[0] = reg; |
82 | data[1] = reg; | 82 | data[1] = value >> 8; |
83 | data[2] = value >> 8; | 83 | data[2] = value & 0xff; |
84 | data[3] = value & 0xff; | ||
85 | 84 | ||
86 | if (i2c_write(1, data, 4) != 4) | 85 | if (i2c_write(I2C_IFACE_0, UDA1380_ADDR, data, 3) != 3) |
87 | { | 86 | { |
88 | DEBUGF("uda1380 error reg=0x%x", reg); | 87 | DEBUGF("uda1380 error reg=0x%x", reg); |
89 | return -1; | 88 | return -1; |
@@ -322,21 +321,20 @@ void uda1380_set_recvol(int left, int right, int type) | |||
322 | { | 321 | { |
323 | /* for this order we can combine both registers, | 322 | /* for this order we can combine both registers, |
324 | making the glitch even smaller */ | 323 | making the glitch even smaller */ |
325 | unsigned char data[6]; | 324 | unsigned char data[5]; |
326 | unsigned short value_dec; | 325 | unsigned short value_dec; |
327 | unsigned short value_pga; | 326 | unsigned short value_pga; |
328 | value_dec = DEC_VOLL(left) | DEC_VOLR(right); | 327 | value_dec = DEC_VOLL(left) | DEC_VOLR(right); |
329 | value_pga = (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) | 328 | value_pga = (uda1380_regs[REG_PGA] & ~PGA_GAIN_MASK) |
330 | | PGA_GAINL(left_ag) | PGA_GAINR(right_ag); | 329 | | PGA_GAINL(left_ag) | PGA_GAINR(right_ag); |
331 | 330 | ||
332 | data[0] = UDA1380_ADDR; | 331 | data[0] = REG_DEC_VOL; |
333 | data[1] = REG_DEC_VOL; | 332 | data[1] = value_dec >> 8; |
334 | data[2] = value_dec >> 8; | 333 | data[2] = value_dec & 0xff; |
335 | data[3] = value_dec & 0xff; | 334 | data[3] = value_pga >> 8; |
336 | data[4] = value_pga >> 8; | 335 | data[4] = value_pga & 0xff; |
337 | data[5] = value_pga & 0xff; | ||
338 | 336 | ||
339 | if (i2c_write(1, data, 6) != 6) | 337 | if (i2c_write(I2C_IFACE_0, UDA1380_ADDR, data, 5) != 5) |
340 | { | 338 | { |
341 | DEBUGF("uda1380 error reg=combi rec gain"); | 339 | DEBUGF("uda1380 error reg=combi rec gain"); |
342 | } | 340 | } |
diff --git a/firmware/export/config-iaudiox5.h b/firmware/export/config-iaudiox5.h index d224b3b45e..cd77dc3c48 100644 --- a/firmware/export/config-iaudiox5.h +++ b/firmware/export/config-iaudiox5.h | |||
@@ -6,7 +6,7 @@ | |||
6 | #define MODEL_NUMBER 10 | 6 | #define MODEL_NUMBER 10 |
7 | 7 | ||
8 | /* define this if you have recording possibility */ | 8 | /* define this if you have recording possibility */ |
9 | /*#define HAVE_RECORDING 1*/ | 9 | #define HAVE_RECORDING 1 |
10 | 10 | ||
11 | /* define this if you have a bitmap LCD display */ | 11 | /* define this if you have a bitmap LCD display */ |
12 | #define HAVE_LCD_BITMAP 1 | 12 | #define HAVE_LCD_BITMAP 1 |
@@ -53,6 +53,11 @@ | |||
53 | /* The number of bytes reserved for loadable plugins */ | 53 | /* The number of bytes reserved for loadable plugins */ |
54 | #define PLUGIN_BUFFER_SIZE 0x80000 | 54 | #define PLUGIN_BUFFER_SIZE 0x80000 |
55 | 55 | ||
56 | /* FM Tuner */ | ||
57 | #define CONFIG_TUNER TEA5767 | ||
58 | #define CONFIG_TUNER_XTAL 32768 | ||
59 | |||
60 | |||
56 | #define BATTERY_CAPACITY_DEFAULT 950 /* default battery capacity */ | 61 | #define BATTERY_CAPACITY_DEFAULT 950 /* default battery capacity */ |
57 | 62 | ||
58 | #ifndef SIMULATOR | 63 | #ifndef SIMULATOR |
diff --git a/firmware/export/fmradio_i2c.h b/firmware/export/fmradio_i2c.h index b7007a80dd..6483594d04 100644 --- a/firmware/export/fmradio_i2c.h +++ b/firmware/export/fmradio_i2c.h | |||
@@ -20,7 +20,7 @@ | |||
20 | #ifndef FMRADIO_I2C_H | 20 | #ifndef FMRADIO_I2C_H |
21 | #define FMRADIO_I2C_H | 21 | #define FMRADIO_I2C_H |
22 | 22 | ||
23 | int fmradio_i2c_write(int address, const unsigned char* buf, int count); | 23 | int fmradio_i2c_write(unsigned char address, const unsigned char* buf, int count); |
24 | int fmradio_i2c_read(int address, unsigned char* buf, int count); | 24 | int fmradio_i2c_read(unsigned char address, unsigned char* buf, int count); |
25 | 25 | ||
26 | #endif | 26 | #endif |
diff --git a/firmware/export/i2c-coldfire.h b/firmware/export/i2c-coldfire.h index d4a5781116..544a3169cf 100644 --- a/firmware/export/i2c-coldfire.h +++ b/firmware/export/i2c-coldfire.h | |||
@@ -26,10 +26,18 @@ | |||
26 | #ifndef _I2C_COLDFIRE_H | 26 | #ifndef _I2C_COLDFIRE_H |
27 | #define _I2C_COLDFIRE_H | 27 | #define _I2C_COLDFIRE_H |
28 | 28 | ||
29 | #include "cpu.h" | ||
30 | |||
29 | void i2c_init(void); | 31 | void i2c_init(void); |
30 | int i2c_write(int device, unsigned char *buf, int count); | 32 | int i2c_read (volatile unsigned char *iface, unsigned char addr, |
33 | unsigned char *buf, int count); | ||
34 | int i2c_write(volatile unsigned char *iface, unsigned char addr, | ||
35 | const unsigned char *buf, int count); | ||
31 | void i2c_close(void); | 36 | void i2c_close(void); |
37 | void i2c_adjust_prescale(int multiplier); | ||
32 | 38 | ||
39 | #define I2C_IFACE_0 ((volatile unsigned char *)&MADR) | ||
40 | #define I2C_IFACE_1 ((volatile unsigned char *)&MADR2) | ||
33 | 41 | ||
34 | #define MAX_LOOP 0x100 /* TODO: select a better value */ | 42 | #define MAX_LOOP 0x100 /* TODO: select a better value */ |
35 | 43 | ||
diff --git a/firmware/export/sound.h b/firmware/export/sound.h index a49cb99263..33175e4166 100644 --- a/firmware/export/sound.h +++ b/firmware/export/sound.h | |||
@@ -36,7 +36,7 @@ enum { | |||
36 | SOUND_MDB_ENABLE, | 36 | SOUND_MDB_ENABLE, |
37 | SOUND_SUPERBASS, | 37 | SOUND_SUPERBASS, |
38 | #endif | 38 | #endif |
39 | #if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) | 39 | #if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320) |
40 | SOUND_LEFT_GAIN, | 40 | SOUND_LEFT_GAIN, |
41 | SOUND_RIGHT_GAIN, | 41 | SOUND_RIGHT_GAIN, |
42 | SOUND_MIC_GAIN, | 42 | SOUND_MIC_GAIN, |
diff --git a/firmware/export/tlv320.h b/firmware/export/tlv320.h index 93a79780c0..45ebfee569 100644 --- a/firmware/export/tlv320.h +++ b/firmware/export/tlv320.h | |||
@@ -26,11 +26,12 @@ extern void tlv320_init(void); | |||
26 | extern void tlv320_reset(void); | 26 | extern void tlv320_reset(void); |
27 | extern void tlv320_enable_output(bool enable); | 27 | extern void tlv320_enable_output(bool enable); |
28 | extern void tlv320_set_headphone_vol(int vol_l, int vol_r); | 28 | extern void tlv320_set_headphone_vol(int vol_l, int vol_r); |
29 | extern void tlv320_set_linein_vol(int vol_l, int vol_r); | 29 | extern void tlv320_set_recvol(int left, int right, int type); |
30 | extern void tlv320_mute(bool mute); | 30 | extern void tlv320_mute(bool mute); |
31 | extern void tlv320_close(void); | 31 | extern void tlv320_close(void); |
32 | extern void tlv320_enable_recording(bool source_mic); | 32 | extern void tlv320_enable_recording(bool source_mic); |
33 | extern void tlv320_disable_recording(void); | 33 | extern void tlv320_disable_recording(void); |
34 | extern void tlv320_set_monitor(bool enable); | ||
34 | 35 | ||
35 | #define HEADPHONE_MUTE 0x30 /* 0110000 = -73db */ | 36 | #define HEADPHONE_MUTE 0x30 /* 0110000 = -73db */ |
36 | 37 | ||
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index 2d9c65a7e4..fee2bbd35b 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c | |||
@@ -31,7 +31,12 @@ | |||
31 | #include "cpu.h" | 31 | #include "cpu.h" |
32 | #include "i2c.h" | 32 | #include "i2c.h" |
33 | #include "power.h" | 33 | #include "power.h" |
34 | #ifdef HAVE_UDA1380 | ||
34 | #include "uda1380.h" | 35 | #include "uda1380.h" |
36 | #endif | ||
37 | #ifdef HAVE_TLV320 | ||
38 | #include "tlv320.h" | ||
39 | #endif | ||
35 | #include "system.h" | 40 | #include "system.h" |
36 | #include "usb.h" | 41 | #include "usb.h" |
37 | 42 | ||
@@ -51,14 +56,14 @@ extern int boost_counter; /* used for boost check */ | |||
51 | 56 | ||
52 | /***************************************************************************/ | 57 | /***************************************************************************/ |
53 | 58 | ||
54 | static volatile bool is_recording; /* We are recording */ | 59 | static bool is_recording; /* We are recording */ |
55 | static volatile bool is_stopping; /* Are we going to stop */ | 60 | static bool is_stopping; /* Are we going to stop */ |
56 | static volatile bool is_paused; /* We have paused */ | 61 | static bool is_paused; /* We have paused */ |
57 | static volatile bool is_error; /* An error has occured */ | 62 | static bool is_error; /* An error has occured */ |
58 | 63 | ||
59 | static volatile unsigned long num_rec_bytes; /* Num bytes recorded */ | 64 | static unsigned long num_rec_bytes; /* Num bytes recorded */ |
60 | static volatile unsigned long num_file_bytes; /* Num bytes written to current file */ | 65 | static unsigned long num_file_bytes; /* Num bytes written to current file */ |
61 | static volatile int error_count; /* Number of DMA errors */ | 66 | static int error_count; /* Number of DMA errors */ |
62 | 67 | ||
63 | static long record_start_time; /* Value of current_tick when recording was started */ | 68 | static long record_start_time; /* Value of current_tick when recording was started */ |
64 | static long pause_start_time; /* Value of current_tick when pause was started */ | 69 | static long pause_start_time; /* Value of current_tick when pause was started */ |
@@ -69,7 +74,7 @@ static int rec_source; /* Current recording source */ | |||
69 | static int wav_file; | 74 | static int wav_file; |
70 | static char recording_filename[MAX_PATH]; | 75 | static char recording_filename[MAX_PATH]; |
71 | 76 | ||
72 | static volatile bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done; | 77 | static bool init_done, close_done, record_done, stop_done, pause_done, resume_done, new_file_done; |
73 | 78 | ||
74 | static short peak_left, peak_right; | 79 | static short peak_left, peak_right; |
75 | 80 | ||
@@ -90,16 +95,23 @@ static unsigned int rec_buffer_offset; | |||
90 | static unsigned char *rec_buffer; /* Circular recording buffer */ | 95 | static unsigned char *rec_buffer; /* Circular recording buffer */ |
91 | static int num_chunks; /* Number of chunks available in rec_buffer */ | 96 | static int num_chunks; /* Number of chunks available in rec_buffer */ |
92 | 97 | ||
93 | 98 | #ifdef IAUDIO_X5 | |
99 | #define SET_IIS_PLAY(x) IIS1CONFIG = (x); | ||
100 | #define SET_IIS_REC(x) IIS1CONFIG = (x); | ||
101 | #else | ||
102 | #define SET_IIS_PLAY(x) IIS2CONFIG = (x); | ||
103 | #define SET_IIS_REC(x) IIS1CONFIG = (x); | ||
104 | #endif | ||
105 | |||
94 | /* | 106 | /* |
95 | Overrun occures when DMA needs to write a new chunk and write_index == read_index | 107 | Overrun occures when DMA needs to write a new chunk and write_index == read_index |
96 | Solution to this is to optimize pcmrec_callback, use cpu_boost or save to disk | 108 | Solution to this is to optimize pcmrec_callback, use cpu_boost or save to disk |
97 | more often. | 109 | more often. |
98 | */ | 110 | */ |
99 | 111 | ||
100 | static volatile int write_index; /* Current chunk the DMA is writing to */ | 112 | static int write_index; /* Current chunk the DMA is writing to */ |
101 | static volatile int read_index; /* Oldest chunk that is not written to disk */ | 113 | static int read_index; /* Oldest chunk that is not written to disk */ |
102 | static volatile int read2_index; /* Latest chunk that has not been converted to little endian */ | 114 | static int read2_index; /* Latest chunk that has not been converted to little endian */ |
103 | static long pre_record_ticks; /* pre-record time expressed in ticks */ | 115 | static long pre_record_ticks; /* pre-record time expressed in ticks */ |
104 | static int pre_record_chunks; /* pre-record time expressed in chunks */ | 116 | static int pre_record_chunks; /* pre-record time expressed in chunks */ |
105 | 117 | ||
@@ -137,7 +149,7 @@ void pcm_rec_init(void) | |||
137 | 149 | ||
138 | 150 | ||
139 | /* Initializes recording: | 151 | /* Initializes recording: |
140 | * - Set up the UDA1380 for recording | 152 | * - Set up the UDA1380/TLV320 for recording |
141 | * - Prepare for DMA transfers | 153 | * - Prepare for DMA transfers |
142 | */ | 154 | */ |
143 | 155 | ||
@@ -292,14 +304,26 @@ void audio_set_recording_options(int frequency, int quality, | |||
292 | case 0: | 304 | case 0: |
293 | /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ | 305 | /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ |
294 | DATAINCONTROL = 0xc020; | 306 | DATAINCONTROL = 0xc020; |
307 | |||
308 | #ifdef HAVE_UDA1380 | ||
295 | uda1380_enable_recording(true); | 309 | uda1380_enable_recording(true); |
310 | #endif | ||
311 | #ifdef HAVE_TLV320 | ||
312 | tlv320_enable_recording(true); | ||
313 | #endif | ||
296 | break; | 314 | break; |
297 | 315 | ||
298 | /* line-in */ | 316 | /* line-in */ |
299 | case 1: | 317 | case 1: |
300 | /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ | 318 | /* Generate int. when 6 samples in FIFO, PDIR2 src = IIS1recv */ |
301 | DATAINCONTROL = 0xc020; | 319 | DATAINCONTROL = 0xc020; |
320 | |||
321 | #ifdef HAVE_UDA1380 | ||
302 | uda1380_enable_recording(false); | 322 | uda1380_enable_recording(false); |
323 | #endif | ||
324 | #ifdef HAVE_TLV320 | ||
325 | tlv320_enable_recording(false); | ||
326 | #endif | ||
303 | break; | 327 | break; |
304 | #ifdef HAVE_SPDIF_IN | 328 | #ifdef HAVE_SPDIF_IN |
305 | /* SPDIF */ | 329 | /* SPDIF */ |
@@ -322,7 +346,8 @@ void audio_set_recording_options(int frequency, int quality, | |||
322 | 346 | ||
323 | /* Monitoring: route the signals through the coldfire audio interface. */ | 347 | /* Monitoring: route the signals through the coldfire audio interface. */ |
324 | 348 | ||
325 | IIS2CONFIG = 0x800; /* Reset before reprogram */ | 349 | SET_IIS_PLAY(0x800); /* Reset before reprogram */ |
350 | |||
326 | #ifdef HAVE_SPDIF_IN | 351 | #ifdef HAVE_SPDIF_IN |
327 | if (source == 2) { | 352 | if (source == 2) { |
328 | /* SCLK2 = Audioclk/4 (can't use EBUin clock), TXSRC = EBU1rcv, 64 bclk/wclk */ | 353 | /* SCLK2 = Audioclk/4 (can't use EBUin clock), TXSRC = EBU1rcv, 64 bclk/wclk */ |
@@ -340,21 +365,27 @@ void audio_set_recording_options(int frequency, int quality, | |||
340 | } | 365 | } |
341 | #else | 366 | #else |
342 | /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ | 367 | /* SCLK2 follow IIS1 (UDA clock), TXSRC = IIS1rcv, 64 bclk/wclk */ |
343 | IIS2CONFIG = (8 << 12) | (4 << 8) | (4 << 2); | 368 | SET_IIS_PLAY( (8 << 12) | (4 << 8) | (4 << 2) ); |
344 | #endif | 369 | #endif |
345 | } | 370 | } |
346 | 371 | ||
347 | 372 | ||
348 | /** | 373 | /** |
349 | * Note that microphone is mono, only left value is used | 374 | * Note that microphone is mono, only left value is used |
350 | * See uda1380_set_recvol() for exact ranges. | 375 | * See {uda1380,tlv320}_set_recvol() for exact ranges. |
351 | * | 376 | * |
352 | * @param type 0=line-in (radio), 1=mic | 377 | * @param type 0=line-in (radio), 1=mic |
353 | * | 378 | * |
354 | */ | 379 | */ |
355 | void audio_set_recording_gain(int left, int right, int type) | 380 | void audio_set_recording_gain(int left, int right, int type) |
356 | { | 381 | { |
382 | //logf("rcmrec: t=%d l=%d r=%d", type, left, right); | ||
383 | #ifdef HAVE_UDA1380 | ||
357 | uda1380_set_recvol(left, right, type); | 384 | uda1380_set_recvol(left, right, type); |
385 | #endif | ||
386 | #ifdef HAVE_TLV320 | ||
387 | tlv320_set_recvol(left, right, type); | ||
388 | #endif | ||
358 | } | 389 | } |
359 | 390 | ||
360 | 391 | ||
@@ -987,7 +1018,7 @@ static void pcmrec_init(void) | |||
987 | 1018 | ||
988 | logf("num_chunks: %d", num_chunks); | 1019 | logf("num_chunks: %d", num_chunks); |
989 | 1020 | ||
990 | IIS1CONFIG = 0x800; /* Stop any playback */ | 1021 | SET_IIS_PLAY(0x800); /* Stop any playback */ |
991 | AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ | 1022 | AUDIOGLOB |= 0x180; /* IIS1 fifo auto sync = on, PDIR2 auto sync = on */ |
992 | DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */ | 1023 | DATAINCONTROL = 0xc000; /* Generate Interrupt when 6 samples in fifo */ |
993 | 1024 | ||
@@ -1007,7 +1038,12 @@ static void pcmrec_init(void) | |||
1007 | 1038 | ||
1008 | static void pcmrec_close(void) | 1039 | static void pcmrec_close(void) |
1009 | { | 1040 | { |
1041 | #ifdef HAVE_UDA1380 | ||
1010 | uda1380_disable_recording(); | 1042 | uda1380_disable_recording(); |
1043 | #endif | ||
1044 | #ifdef HAVE_TLV320 | ||
1045 | tlv320_disable_recording(); | ||
1046 | #endif | ||
1011 | 1047 | ||
1012 | #ifdef HAVE_SPDIF_POWER | 1048 | #ifdef HAVE_SPDIF_POWER |
1013 | spdif_power_enable(spdif_power_setting); | 1049 | spdif_power_enable(spdif_power_setting); |
@@ -1091,7 +1127,7 @@ void pcm_rec_mux(int source) | |||
1091 | 1127 | ||
1092 | or_l(0x40000000, &GPIO_ENABLE); | 1128 | or_l(0x40000000, &GPIO_ENABLE); |
1093 | or_l(0x40000000, &GPIO_FUNCTION); | 1129 | or_l(0x40000000, &GPIO_FUNCTION); |
1094 | #else | 1130 | #elif defined(IRIVER_H100_SERIES) |
1095 | if(source == 0) | 1131 | if(source == 0) |
1096 | and_l(~0x00800000, &GPIO_OUT); /* Line In */ | 1132 | and_l(~0x00800000, &GPIO_OUT); /* Line In */ |
1097 | else | 1133 | else |
@@ -1099,5 +1135,16 @@ void pcm_rec_mux(int source) | |||
1099 | 1135 | ||
1100 | or_l(0x00800000, &GPIO_ENABLE); | 1136 | or_l(0x00800000, &GPIO_ENABLE); |
1101 | or_l(0x00800000, &GPIO_FUNCTION); | 1137 | or_l(0x00800000, &GPIO_FUNCTION); |
1138 | |||
1139 | #elif defined(IAUDIO_X5) | ||
1140 | if(source == 0) | ||
1141 | or_l((1<<29), &GPIO_OUT); /* Line In */ | ||
1142 | else | ||
1143 | and_l(~(1<<29), &GPIO_OUT); /* FM radio */ | ||
1144 | |||
1145 | or_l((1<<29), &GPIO_ENABLE); | ||
1146 | or_l((1<<29), &GPIO_FUNCTION); | ||
1147 | |||
1148 | /* iAudio x5 */ | ||
1102 | #endif | 1149 | #endif |
1103 | } | 1150 | } |
diff --git a/firmware/sound.c b/firmware/sound.c index 057cfc0995..5e4cd5db48 100644 --- a/firmware/sound.c +++ b/firmware/sound.c | |||
@@ -111,7 +111,11 @@ static const struct sound_settings_info sound_settings_table[] = { | |||
111 | [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL}, | 111 | [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL}, |
112 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL}, | 112 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0, NULL}, |
113 | [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16, NULL}, | 113 | [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16, NULL}, |
114 | #endif | 114 | #elif defined(HAVE_TLV320) |
115 | [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23, NULL}, | ||
116 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23, NULL}, | ||
117 | [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 1, NULL}, | ||
118 | #endif | ||
115 | }; | 119 | }; |
116 | 120 | ||
117 | const char *sound_unit(int setting) | 121 | const char *sound_unit(int setting) |
@@ -901,6 +905,25 @@ int sound_val2phys(int setting, int value) | |||
901 | break; | 905 | break; |
902 | } | 906 | } |
903 | return result; | 907 | return result; |
908 | #elif defined(HAVE_TLV320) | ||
909 | int result = 0; | ||
910 | |||
911 | switch(setting) | ||
912 | { | ||
913 | case SOUND_LEFT_GAIN: | ||
914 | case SOUND_RIGHT_GAIN: | ||
915 | result = (value - 23) * 15; /* (x - 23)/1.5 *10 */ | ||
916 | break; | ||
917 | |||
918 | case SOUND_MIC_GAIN: | ||
919 | result = value * 200; /* 0 or 20 dB */ | ||
920 | break; | ||
921 | |||
922 | default: | ||
923 | result = value; | ||
924 | break; | ||
925 | } | ||
926 | return result; | ||
904 | #else | 927 | #else |
905 | (void)setting; | 928 | (void)setting; |
906 | return value; | 929 | return value; |
diff --git a/firmware/target/coldfire/iaudio/x5/power-x5.c b/firmware/target/coldfire/iaudio/x5/power-x5.c index 14236cbb37..4199993637 100644 --- a/firmware/target/coldfire/iaudio/x5/power-x5.c +++ b/firmware/target/coldfire/iaudio/x5/power-x5.c | |||
@@ -64,6 +64,20 @@ void power_off(void) | |||
64 | yield(); | 64 | yield(); |
65 | } | 65 | } |
66 | 66 | ||
67 | static bool powered = false; | ||
68 | |||
69 | bool radio_powered() | ||
70 | { | ||
71 | return powered; | ||
72 | } | ||
73 | |||
74 | bool radio_power(bool status) | ||
75 | { | ||
76 | bool old_status = powered; | ||
77 | powered = status; | ||
78 | return old_status; | ||
79 | } | ||
80 | |||
67 | #else | 81 | #else |
68 | 82 | ||
69 | bool charger_inserted(void) | 83 | bool charger_inserted(void) |