fuzev2: prevent button light flickering when accessing µSD
[kugel-rb.git] / firmware / drivers / sw_i2c.c
blob028995e768c4282e1bd68d9603a65dbcf85215a4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Miika Pekkarinen
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "system.h"
22 #include "logf.h"
23 #include "inttypes.h"
25 #include "sw_i2c.h"
27 /**
28 * I2C-functions are copied and ported from fmradio.c.
29 * later fixed, adapted and moved to a seperate file so they can be re-used
30 * by the rtc-ds1339c and later by the m:robe-100 code by Robert Kukla
33 /* cute little functions, atomic read-modify-write */
35 #ifdef MROBE_100
37 /* SCL is GPIOC, 4 */
38 #define SCL (GPIOC_INPUT_VAL & 0x00000010)
39 #define SCL_OUT_LO GPIOC_OUTPUT_VAL&=~0x00000010
40 #define SCL_LO GPIOC_OUTPUT_EN |= 0x00000010
41 #define SCL_HI GPIOC_OUTPUT_EN &=~0x00000010
43 /* SDA is GPIOC, 5 */
44 #define SDA (GPIOC_INPUT_VAL & 0x00000020)
45 #define SDA_OUT_LO GPIOC_OUTPUT_VAL&=~0x00000020
46 #define SDA_LO GPIOC_OUTPUT_EN |= 0x00000020
47 #define SDA_HI GPIOC_OUTPUT_EN &=~0x00000020
49 #define DELAY do { volatile int _x; for(_x=0;_x<22;_x++);} while(0)
51 #else
53 /* SCL is GPIO, 12 */
54 #define SCL ( 0x00001000 & GPIO_READ)
55 #define SCL_OUT_LO and_l(~0x00001000, &GPIO_OUT)
56 #define SCL_LO or_l( 0x00001000, &GPIO_ENABLE)
57 #define SCL_HI and_l(~0x00001000, &GPIO_ENABLE)
59 /* SDA is GPIO1, 13 */
60 #define SDA ( 0x00002000 & GPIO1_READ)
61 #define SDA_OUT_LO and_l(~0x00002000, &GPIO1_OUT)
62 #define SDA_LO or_l( 0x00002000, &GPIO1_ENABLE)
63 #define SDA_HI and_l(~0x00002000, &GPIO1_ENABLE)
65 /* delay loop to achieve 400kHz at 120MHz CPU frequency */
66 #define DELAY \
67 ({ \
68 int _x_; \
69 asm volatile ( \
70 "move.l #21, %[_x_] \r\n" \
71 "1: \r\n" \
72 "subq.l #1, %[_x_] \r\n" \
73 "bhi.b 1b \r\n" \
74 : [_x_]"=&d"(_x_) \
75 ); \
78 #endif
80 void sw_i2c_init(void)
82 #ifndef MROBE_100
83 or_l(0x00001000, &GPIO_FUNCTION);
84 or_l(0x00002000, &GPIO1_FUNCTION);
85 #endif
87 SDA_HI;
88 SCL_HI;
89 SDA_OUT_LO;
90 SCL_OUT_LO;
93 /* in: C=? D=?
94 * out: C=L D=L
96 static void sw_i2c_start(void)
98 SCL_LO;
99 DELAY;
100 SDA_HI;
101 DELAY;
102 SCL_HI;
103 DELAY;
104 SDA_LO;
105 DELAY;
106 SCL_LO;
109 /* in: C=L D=?
110 * out: C=H D=H
112 static void sw_i2c_stop(void)
114 SDA_LO;
115 DELAY;
116 SCL_HI;
117 DELAY;
118 SDA_HI;
121 /* in: C=L D=H
122 * out: C=L D=L
124 static void sw_i2c_ack(void)
126 SDA_LO;
127 DELAY;
129 SCL_HI;
130 DELAY;
131 SCL_LO;
134 /* in: C=L D=H
135 * out: C=L D=H
137 static void sw_i2c_nack(void)
139 SDA_HI; /* redundant */
140 DELAY;
142 SCL_HI;
143 DELAY;
144 SCL_LO;
147 /* in: C=L D=?
148 * out: C=L D=H
150 static bool sw_i2c_getack(void)
152 bool ret = true;
153 /* int count = 10; */
155 SDA_HI; /* sets to input */
156 DELAY;
157 SCL_HI;
158 DELAY;
160 /* while (SDA && count--) */
161 /* DELAY; */
163 if (SDA)
164 /* ack failed */
165 ret = false;
167 SCL_LO;
169 return ret;
172 /* in: C=L D=?
173 * out: C=L D=?
175 static void sw_i2c_outb(unsigned char byte)
177 int i;
179 /* clock out each bit, MSB first */
180 for ( i=0x80; i; i>>=1 )
182 if ( i & byte )
183 SDA_HI;
184 else
185 SDA_LO;
186 DELAY;
188 SCL_HI;
189 DELAY;
190 SCL_LO;
194 /* in: C=L D=?
195 * out: C=L D=H
197 static unsigned char sw_i2c_inb(void)
199 int i;
200 unsigned char byte = 0;
202 SDA_HI; /* sets to input */
204 /* clock in each bit, MSB first */
205 for ( i=0x80; i; i>>=1 )
207 DELAY;
208 do {
209 SCL_HI;
210 DELAY;
212 while(SCL==0); /* wait for any SCL clock stretching */
213 if ( SDA )
214 byte |= i;
215 SCL_LO;
218 return byte;
221 int sw_i2c_write(unsigned char chip, unsigned char location, unsigned char* buf, int count)
223 int i;
225 sw_i2c_start();
226 sw_i2c_outb((chip & 0xfe) | SW_I2C_WRITE);
227 if (!sw_i2c_getack())
229 sw_i2c_stop();
230 return -1;
233 #ifdef MROBE_100 /* does not use register addressing */
234 (void) location;
235 #else
236 sw_i2c_outb(location);
237 if (!sw_i2c_getack())
239 sw_i2c_stop();
240 return -2;
242 #endif
244 for (i=0; i<count; i++)
246 sw_i2c_outb(buf[i]);
247 if (!sw_i2c_getack())
249 sw_i2c_stop();
250 return -3;
254 sw_i2c_stop();
256 return 0;
259 int sw_i2c_read(unsigned char chip, unsigned char location, unsigned char* buf, int count)
261 int i;
263 #ifdef MROBE_100 /* does not use register addressing */
264 (void) location;
265 #else
266 sw_i2c_start();
267 sw_i2c_outb((chip & 0xfe) | SW_I2C_WRITE);
268 if (!sw_i2c_getack())
270 sw_i2c_stop();
271 return -1;
274 sw_i2c_outb(location);
275 if (!sw_i2c_getack())
277 sw_i2c_stop();
278 return -2;
280 #endif
282 sw_i2c_start();
283 sw_i2c_outb((chip & 0xfe) | SW_I2C_READ);
284 if (!sw_i2c_getack())
286 sw_i2c_stop();
287 return -3;
290 for (i=0; i<count-1; i++)
292 buf[i] = sw_i2c_inb();
293 sw_i2c_ack();
296 /* 1byte min */
297 buf[i] = sw_i2c_inb();
298 sw_i2c_nack();
300 sw_i2c_stop();
302 return 0;