diff options
Diffstat (limited to 'firmware/drivers/fmradio_i2c.c')
-rw-r--r-- | firmware/drivers/fmradio_i2c.c | 179 |
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 | |
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 |