diff options
author | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-10-17 23:24:18 +0000 |
---|---|---|
committer | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-10-17 23:24:18 +0000 |
commit | 4adf929a90e1cc7bc559a69193a505166ddaba1b (patch) | |
tree | a436c69572d55459f2f5e46b282a2ef15fb04d0f | |
parent | ca45869a8866756c5c11cba307a7ff62566afb22 (diff) | |
download | rockbox-4adf929a90e1cc7bc559a69193a505166ddaba1b.tar.gz rockbox-4adf929a90e1cc7bc559a69193a505166ddaba1b.zip |
Philips tuner supported
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5300 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | firmware/drivers/fmradio_i2c.c | 179 | ||||
-rw-r--r-- | firmware/export/fmradio_i2c.h | 4 | ||||
-rw-r--r-- | firmware/tuner_philips.c | 25 |
3 files changed, 197 insertions, 11 deletions
diff --git a/firmware/drivers/fmradio_i2c.c b/firmware/drivers/fmradio_i2c.c index 93c5d2fa91..d503980391 100644 --- a/firmware/drivers/fmradio_i2c.c +++ b/firmware/drivers/fmradio_i2c.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * $Id$ | 8 | * $Id$ |
9 | * Physical interface of the Philips TEA5767 in Archos Ondio | 9 | * Physical interface of the Philips TEA5767 in Archos Ondio |
10 | * | 10 | * |
11 | * Copyright (C) 2004 by Jörg Hohensohn | 11 | * Copyright (C) 2002 by Linus Nielsen Feltzing |
12 | * | 12 | * |
13 | * All files in this archive are subject to the GNU General Public License. | 13 | * All files in this archive are subject to the GNU General Public License. |
14 | * See the file COPYING in the source tree root for full license agreement. | 14 | * See the file COPYING in the source tree root for full license agreement. |
@@ -26,16 +26,181 @@ | |||
26 | 26 | ||
27 | #ifdef CONFIG_TUNER | 27 | #ifdef CONFIG_TUNER |
28 | 28 | ||
29 | /* reads 5 byte */ | 29 | |
30 | void fmradio_i2c_read(unsigned char* p_data) | 30 | /* cute little functions, atomic read-modify-write */ |
31 | /* SDA is PB4 */ | ||
32 | #define SDA_LO and_b(~0x10, &PBDRL) | ||
33 | #define SDA_HI or_b(0x10, &PBDRL) | ||
34 | #define SDA_INPUT and_b(~0x10, &PBIORL) | ||
35 | #define SDA_OUTPUT or_b(0x10, &PBIORL) | ||
36 | #define SDA (PBDR & 0x0010) | ||
37 | |||
38 | /* SCL is PB1 */ | ||
39 | #define SCL_INPUT and_b(~0x02, &PBIORL) | ||
40 | #define SCL_OUTPUT or_b(0x02, &PBIORL) | ||
41 | #define SCL_LO and_b(~0x02, &PBDRL) | ||
42 | #define SCL_HI or_b(0x02, &PBDRL) | ||
43 | #define SCL (PBDR & 0x0002) | ||
44 | |||
45 | /* arbitrary delay loop */ | ||
46 | #define DELAY do { int _x; for(_x=0;_x<20;_x++);} while (0) | ||
47 | |||
48 | |||
49 | static void fmradio_i2c_start(void) | ||
50 | { | ||
51 | SDA_OUTPUT; | ||
52 | SDA_HI; | ||
53 | SCL_HI; | ||
54 | SDA_LO; | ||
55 | DELAY; | ||
56 | SCL_LO; | ||
57 | } | ||
58 | |||
59 | static void fmradio_i2c_stop(void) | ||
60 | { | ||
61 | SDA_LO; | ||
62 | SCL_HI; | ||
63 | DELAY; | ||
64 | SDA_HI; | ||
65 | } | ||
66 | |||
67 | |||
68 | static void fmradio_i2c_ack(int bit) | ||
69 | { | ||
70 | /* Here's the deal. The slave is slow, and sometimes needs to wait | ||
71 | before it can receive the acknowledge. Therefore it forces the clock | ||
72 | low until it is ready. We need to poll the clock line until it goes | ||
73 | high before we release the ack. */ | ||
74 | |||
75 | SCL_LO; /* Set the clock low */ | ||
76 | if ( bit ) | ||
77 | { | ||
78 | SDA_HI; | ||
79 | } | ||
80 | else | ||
81 | { | ||
82 | SDA_LO; | ||
83 | } | ||
84 | |||
85 | SCL_INPUT; /* Set the clock to input */ | ||
86 | while(!SCL) /* and wait for the slave to release it */ | ||
87 | sleep_thread(); | ||
88 | wake_up_thread(); | ||
89 | |||
90 | DELAY; | ||
91 | SCL_OUTPUT; | ||
92 | SCL_LO; | ||
93 | } | ||
94 | |||
95 | static int fmradio_i2c_getack(void) | ||
31 | { | 96 | { |
32 | (void)p_data; | 97 | int ret = 1; |
98 | |||
99 | /* Here's the deal. The slave is slow, and sometimes needs to wait | ||
100 | before it can send the acknowledge. Therefore it forces the clock | ||
101 | low until it is ready. We need to poll the clock line until it goes | ||
102 | high before we read the ack. */ | ||
103 | |||
104 | SDA_INPUT; /* And set to input */ | ||
105 | SCL_INPUT; /* Set the clock to input */ | ||
106 | while(!SCL) /* and wait for the slave to release it */ | ||
107 | sleep_thread(); | ||
108 | wake_up_thread(); | ||
109 | |||
110 | if (SDA) | ||
111 | /* ack failed */ | ||
112 | ret = 0; | ||
113 | |||
114 | SCL_OUTPUT; | ||
115 | SCL_LO; | ||
116 | SDA_HI; | ||
117 | SDA_OUTPUT; | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | static void fmradio_i2c_outb(unsigned char byte) | ||
122 | { | ||
123 | int i; | ||
124 | |||
125 | /* clock out each bit, MSB first */ | ||
126 | for ( i=0x80; i; i>>=1 ) { | ||
127 | if ( i & byte ) | ||
128 | { | ||
129 | SDA_HI; | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | SDA_LO; | ||
134 | } | ||
135 | SCL_HI; | ||
136 | SCL_LO; | ||
137 | } | ||
138 | |||
139 | SDA_HI; | ||
140 | } | ||
141 | |||
142 | static unsigned char fmradio_i2c_inb(int ack) | ||
143 | { | ||
144 | int i; | ||
145 | unsigned char byte = 0; | ||
146 | |||
147 | /* clock in each bit, MSB first */ | ||
148 | for ( i=0x80; i; i>>=1 ) { | ||
149 | SDA_INPUT; /* And set to input */ | ||
150 | SCL_HI; | ||
151 | if ( SDA ) | ||
152 | byte |= i; | ||
153 | SCL_LO; | ||
154 | SDA_OUTPUT; | ||
155 | } | ||
156 | |||
157 | fmradio_i2c_ack(ack); | ||
158 | |||
159 | return byte; | ||
160 | } | ||
161 | |||
162 | int fmradio_i2c_write(int address, const unsigned char* buf, int count) | ||
163 | { | ||
164 | int i,x=0; | ||
165 | |||
166 | fmradio_i2c_start(); | ||
167 | fmradio_i2c_outb(address & 0xfe); | ||
168 | if (fmradio_i2c_getack()) | ||
169 | { | ||
170 | for (i=0; i<count; i++) | ||
171 | { | ||
172 | fmradio_i2c_outb(buf[i]); | ||
173 | if (!fmradio_i2c_getack()) | ||
174 | { | ||
175 | x=-2; | ||
176 | break; | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | else | ||
181 | { | ||
182 | debugf("fmradio_i2c_write() - no ack\n"); | ||
183 | x=-1; | ||
184 | } | ||
185 | fmradio_i2c_stop(); | ||
186 | return x; | ||
33 | } | 187 | } |
34 | 188 | ||
35 | /* writes 5 bytes */ | 189 | int fmradio_i2c_read(int address, unsigned char* buf, int count) |
36 | void fmradio_i2c_set(const unsigned char* p_data) | ||
37 | { | 190 | { |
38 | (void)p_data; | 191 | int i,x=0; |
192 | |||
193 | fmradio_i2c_start(); | ||
194 | fmradio_i2c_outb(address | 1); | ||
195 | if (fmradio_i2c_getack()) { | ||
196 | for (i=0; i<count; i++) { | ||
197 | buf[i] = fmradio_i2c_inb(0); | ||
198 | } | ||
199 | } | ||
200 | else | ||
201 | x=-1; | ||
202 | fmradio_i2c_stop(); | ||
203 | return x; | ||
39 | } | 204 | } |
40 | 205 | ||
41 | #endif | 206 | #endif |
diff --git a/firmware/export/fmradio_i2c.h b/firmware/export/fmradio_i2c.h index 06b7f9f7b7..b7007a80dd 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 | void fmradio_i2c_read(unsigned char* p_data); /* reads 5 byte */ | 23 | int fmradio_i2c_write(int address, const unsigned char* buf, int count); |
24 | void fmradio_i2c_set(const unsigned char* p_data); /* writes 5 bytes */ | 24 | int fmradio_i2c_read(int address, unsigned char* buf, int count); |
25 | 25 | ||
26 | #endif | 26 | #endif |
diff --git a/firmware/tuner_philips.c b/firmware/tuner_philips.c index 50559af23e..e63d063bfd 100644 --- a/firmware/tuner_philips.c +++ b/firmware/tuner_philips.c | |||
@@ -19,10 +19,12 @@ | |||
19 | ****************************************************************************/ | 19 | ****************************************************************************/ |
20 | 20 | ||
21 | #include <stdbool.h> | 21 | #include <stdbool.h> |
22 | #include <string.h> | ||
22 | #include "tuner.h" /* tuner abstraction interface */ | 23 | #include "tuner.h" /* tuner abstraction interface */ |
23 | #include "fmradio_i2c.h" /* physical interface driver */ | 24 | #include "fmradio_i2c.h" /* physical interface driver */ |
24 | 25 | ||
25 | /* FIXME: this is just a dummy */ | 26 | #define I2C_ADR 0xC0 |
27 | static unsigned char write_bytes[5]; | ||
26 | 28 | ||
27 | /* tuner abstraction layer: set something to the tuner */ | 29 | /* tuner abstraction layer: set something to the tuner */ |
28 | void philips_set(int setting, int value) | 30 | void philips_set(int setting, int value) |
@@ -31,12 +33,22 @@ void philips_set(int setting, int value) | |||
31 | switch(setting) | 33 | switch(setting) |
32 | { | 34 | { |
33 | case RADIO_INIT: | 35 | case RADIO_INIT: |
36 | memset(write_bytes, 0, sizeof(write_bytes)); | ||
34 | break; | 37 | break; |
35 | 38 | ||
36 | case RADIO_FREQUENCY: | 39 | case RADIO_FREQUENCY: |
40 | { | ||
41 | int n; | ||
42 | n = (4 * (value - 225000)) / 50000; | ||
43 | write_bytes[0] = (write_bytes[0] & 0xC0) | (n >> 8); | ||
44 | write_bytes[1] = n & 0xFF; | ||
45 | fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); | ||
46 | } | ||
37 | break; | 47 | break; |
38 | 48 | ||
39 | case RADIO_MUTE: | 49 | case RADIO_MUTE: |
50 | write_bytes[0] = (write_bytes[0] & 0x7F) | (value ? 0x80 : 0); | ||
51 | fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); | ||
40 | break; | 52 | break; |
41 | 53 | ||
42 | case RADIO_IF_MEASUREMENT: | 54 | case RADIO_IF_MEASUREMENT: |
@@ -46,6 +58,8 @@ void philips_set(int setting, int value) | |||
46 | break; | 58 | break; |
47 | 59 | ||
48 | case RADIO_FORCE_MONO: | 60 | case RADIO_FORCE_MONO: |
61 | write_bytes[2] = (write_bytes[2] & 0xF7) | (value ? 0x08 : 0); | ||
62 | fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); | ||
49 | break; | 63 | break; |
50 | } | 64 | } |
51 | } | 65 | } |
@@ -53,17 +67,24 @@ void philips_set(int setting, int value) | |||
53 | /* tuner abstraction layer: read something from the tuner */ | 67 | /* tuner abstraction layer: read something from the tuner */ |
54 | int philips_get(int setting) | 68 | int philips_get(int setting) |
55 | { | 69 | { |
70 | unsigned char read_bytes[5]; | ||
56 | int val = -1; | 71 | int val = -1; |
72 | |||
73 | fmradio_i2c_read(I2C_ADR, read_bytes, sizeof(read_bytes)); | ||
74 | |||
57 | switch(setting) | 75 | switch(setting) |
58 | { | 76 | { |
59 | case RADIO_PRESENT: | 77 | case RADIO_PRESENT: |
60 | val = 0; /* false */ | 78 | val = 1; /* true */ |
61 | break; | 79 | break; |
62 | 80 | ||
63 | case RADIO_IF_MEASURED: | 81 | case RADIO_IF_MEASURED: |
82 | val = read_bytes[2] & 0x7F; | ||
83 | val = 1070 + (val-55)/2; | ||
64 | break; | 84 | break; |
65 | 85 | ||
66 | case RADIO_STEREO: | 86 | case RADIO_STEREO: |
87 | val = read_bytes[2] >> 7; | ||
67 | break; | 88 | break; |
68 | } | 89 | } |
69 | return val; | 90 | return val; |