summaryrefslogtreecommitdiff
path: root/firmware/drivers/sw_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/sw_i2c.c')
-rw-r--r--firmware/drivers/sw_i2c.c301
1 files changed, 301 insertions, 0 deletions
diff --git a/firmware/drivers/sw_i2c.c b/firmware/drivers/sw_i2c.c
new file mode 100644
index 0000000000..c1f6868226
--- /dev/null
+++ b/firmware/drivers/sw_i2c.c
@@ -0,0 +1,301 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Miika Pekkarinen
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "system.h"
20#include "logf.h"
21#include "inttypes.h"
22
23#include "sw_i2c.h"
24
25/**
26 * I2C-functions are copied and ported from fmradio.c.
27 * later fixed, adapted and moved to a seperate file so they can be re-used
28 * by the rtc-ds1339c and later by the m:robe-100 code by Robert Kukla
29 */
30
31/* cute little functions, atomic read-modify-write */
32
33#ifdef MROBE_100
34
35/* SCL is GPIOC, 4 */
36#define SCL (GPIOC_INPUT_VAL & 0x00000010)
37#define SCL_OUT_LO GPIOC_OUTPUT_VAL&=~0x00000010
38#define SCL_LO GPIOC_OUTPUT_EN |= 0x00000010
39#define SCL_HI GPIOC_OUTPUT_EN &=~0x00000010
40
41/* SDA is GPIOC, 5 */
42#define SDA (GPIOC_INPUT_VAL & 0x00000020)
43#define SDA_OUT_LO GPIOC_OUTPUT_VAL&=~0x00000020
44#define SDA_LO GPIOC_OUTPUT_EN |= 0x00000020
45#define SDA_HI GPIOC_OUTPUT_EN &=~0x00000020
46
47#define DELAY do { volatile int _x; for(_x=0;_x<22;_x++);} while(0)
48
49#else
50
51/* SCL is GPIO, 12 */
52#define SCL ( 0x00001000 & GPIO_READ)
53#define SCL_OUT_LO and_l(~0x00001000, &GPIO_OUT)
54#define SCL_LO or_l( 0x00001000, &GPIO_ENABLE)
55#define SCL_HI and_l(~0x00001000, &GPIO_ENABLE)
56
57/* SDA is GPIO1, 13 */
58#define SDA ( 0x00002000 & GPIO1_READ)
59#define SDA_OUT_LO and_l(~0x00002000, &GPIO1_OUT)
60#define SDA_LO or_l( 0x00002000, &GPIO1_ENABLE)
61#define SDA_HI and_l(~0x00002000, &GPIO1_ENABLE)
62
63/* delay loop to achieve 400kHz at 120MHz CPU frequency */
64#define DELAY \
65 ({ \
66 int _x_; \
67 asm volatile ( \
68 "move.l #21, %[_x_] \r\n" \
69 "1: \r\n" \
70 "subq.l #1, %[_x_] \r\n" \
71 "bhi.b 1b \r\n" \
72 : [_x_]"=&d"(_x_) \
73 ); \
74 })
75
76#endif
77
78void sw_i2c_init(void)
79{
80#ifndef MROBE_100
81 or_l(0x00001000, &GPIO_FUNCTION);
82 or_l(0x00002000, &GPIO1_FUNCTION);
83#endif
84
85 SDA_HI;
86 SCL_HI;
87 SDA_OUT_LO;
88 SCL_OUT_LO;
89}
90
91/* in: C=? D=?
92 * out: C=L D=L
93 */
94static void sw_i2c_start(void)
95{
96 SCL_LO;
97 DELAY;
98 SDA_HI;
99 DELAY;
100 SCL_HI;
101 DELAY;
102 SDA_LO;
103 DELAY;
104 SCL_LO;
105}
106
107/* in: C=L D=?
108 * out: C=H D=H
109 */
110static void sw_i2c_stop(void)
111{
112 SDA_LO;
113 DELAY;
114 SCL_HI;
115 DELAY;
116 SDA_HI;
117}
118
119/* in: C=L D=H
120 * out: C=L D=L
121 */
122static void sw_i2c_ack(void)
123{
124 SDA_LO;
125 DELAY;
126
127 SCL_HI;
128 DELAY;
129 SCL_LO;
130}
131
132/* in: C=L D=H
133 * out: C=L D=H
134 */
135static void sw_i2c_nack(void)
136{
137 SDA_HI; /* redundant */
138 DELAY;
139
140 SCL_HI;
141 DELAY;
142 SCL_LO;
143}
144
145/* in: C=L D=?
146 * out: C=L D=H
147 */
148static bool sw_i2c_getack(void)
149{
150 bool ret = true;
151/* int count = 10; */
152
153 SDA_HI; /* sets to input */
154 DELAY;
155 SCL_HI;
156 DELAY;
157
158/* while (SDA && count--) */
159/* DELAY; */
160
161 if (SDA)
162 /* ack failed */
163 ret = false;
164
165 SCL_LO;
166
167 return ret;
168}
169
170/* in: C=L D=?
171 * out: C=L D=?
172 */
173static void sw_i2c_outb(unsigned char byte)
174{
175 int i;
176
177 /* clock out each bit, MSB first */
178 for ( i=0x80; i; i>>=1 )
179 {
180 if ( i & byte )
181 SDA_HI;
182 else
183 SDA_LO;
184 DELAY;
185
186 SCL_HI;
187 DELAY;
188 SCL_LO;
189 }
190}
191
192/* in: C=L D=?
193 * out: C=L D=H
194 */
195static unsigned char sw_i2c_inb(void)
196{
197 int i;
198 unsigned char byte = 0;
199
200 SDA_HI; /* sets to input */
201
202 /* clock in each bit, MSB first */
203 for ( i=0x80; i; i>>=1 )
204 {
205 DELAY;
206 do {
207 SCL_HI;
208 DELAY;
209 }
210 while(SCL==0); /* wait for any SCL clock stretching */
211 if ( SDA )
212 byte |= i;
213 SCL_LO;
214 }
215
216 return byte;
217}
218
219int sw_i2c_write(unsigned char chip, unsigned char location, unsigned char* buf, int count)
220{
221 int i;
222
223 sw_i2c_start();
224 sw_i2c_outb((chip & 0xfe) | SW_I2C_WRITE);
225 if (!sw_i2c_getack())
226 {
227 sw_i2c_stop();
228 return -1;
229 }
230
231#ifdef MROBE_100 /* does not use register addressing */
232 (void) location;
233#else
234 sw_i2c_outb(location);
235 if (!sw_i2c_getack())
236 {
237 sw_i2c_stop();
238 return -2;
239 }
240#endif
241
242 for (i=0; i<count; i++)
243 {
244 sw_i2c_outb(buf[i]);
245 if (!sw_i2c_getack())
246 {
247 sw_i2c_stop();
248 return -3;
249 }
250 }
251
252 sw_i2c_stop();
253
254 return 0;
255}
256
257int sw_i2c_read(unsigned char chip, unsigned char location, unsigned char* buf, int count)
258{
259 int i;
260
261#ifdef MROBE_100 /* does not use register addressing */
262 (void) location;
263#else
264 sw_i2c_start();
265 sw_i2c_outb((chip & 0xfe) | SW_I2C_WRITE);
266 if (!sw_i2c_getack())
267 {
268 sw_i2c_stop();
269 return -1;
270 }
271
272 sw_i2c_outb(location);
273 if (!sw_i2c_getack())
274 {
275 sw_i2c_stop();
276 return -2;
277 }
278#endif
279
280 sw_i2c_start();
281 sw_i2c_outb((chip & 0xfe) | SW_I2C_READ);
282 if (!sw_i2c_getack())
283 {
284 sw_i2c_stop();
285 return -3;
286 }
287
288 for (i=0; i<count-1; i++)
289 {
290 buf[i] = sw_i2c_inb();
291 sw_i2c_ack();
292 }
293
294 /* 1byte min */
295 buf[i] = sw_i2c_inb();
296 sw_i2c_nack();
297
298 sw_i2c_stop();
299
300 return 0;
301}