summaryrefslogtreecommitdiff
path: root/firmware/drivers/fmradio_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/fmradio_i2c.c')
-rw-r--r--firmware/drivers/fmradio_i2c.c179
1 files changed, 172 insertions, 7 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
30void 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
49static 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
59static void fmradio_i2c_stop(void)
60{
61 SDA_LO;
62 SCL_HI;
63 DELAY;
64 SDA_HI;
65}
66
67
68static 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
95static 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
121static 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
142static 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
162int 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 */ 189int fmradio_i2c_read(int address, unsigned char* buf, int count)
36void 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