a bit of code cleanup.. use a single function to get the statusbar height (or lack...
[Rockbox.git] / firmware / drivers / i2c.c
blob66b6340f2bbdd30c13e4390cb638ef1d6642dec3
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "lcd.h"
20 #include "cpu.h"
21 #include "kernel.h"
22 #include "thread.h"
23 #include "debug.h"
24 #include "system.h"
25 #include "i2c.h"
27 /* cute little functions, atomic read-modify-write */
29 /* SDA is PB7 */
30 #define SDA_LO and_b(~0x80, &PBDRL)
31 #define SDA_HI or_b(0x80, &PBDRL)
32 #define SDA_INPUT and_b(~0x80, &PBIORL)
33 #define SDA_OUTPUT or_b(0x80, &PBIORL)
34 #define SDA (PBDRL & 0x80)
36 #if CONFIG_I2C == I2C_ONDIO
37 /* Ondio pinout, SCL moved to PB6 */
38 #define SCL_INPUT and_b(~0x40, &PBIORL)
39 #define SCL_OUTPUT or_b(0x40, &PBIORL)
40 #define SCL_LO and_b(~0x40, &PBDRL)
41 #define SCL_HI or_b(0x40, &PBDRL)
42 #define SCL (PBDRL & 0x40)
43 #else
44 /* "classic" pinout, SCL is PB13 */
45 #define SCL_INPUT and_b(~0x20, &PBIORH)
46 #define SCL_OUTPUT or_b(0x20, &PBIORH)
47 #define SCL_LO and_b(~0x20, &PBDRH)
48 #define SCL_HI or_b(0x20, &PBDRH)
49 #define SCL (PBDRH & 0x20)
50 #endif
52 /* arbitrary delay loop */
53 #define DELAY do { int _x; for(_x=0;_x<20;_x++);} while (0)
55 static struct mutex i2c_mtx;
57 void i2c_begin(void)
59 mutex_lock(&i2c_mtx);
62 void i2c_end(void)
64 mutex_unlock(&i2c_mtx);
67 void i2c_start(void)
69 SDA_OUTPUT;
70 SDA_HI;
71 SCL_HI;
72 SDA_LO;
73 DELAY;
74 SCL_LO;
77 void i2c_stop(void)
79 SDA_LO;
80 SCL_HI;
81 DELAY;
82 SDA_HI;
85 void i2c_init(void)
87 int i;
89 #if CONFIG_I2C == I2C_ONDIO
90 /* make PB6 & PB7 general I/O */
91 PBCR2 &= ~0xf000;
92 #else /* not Ondio */
93 /* make PB7 & PB13 general I/O */
94 PBCR1 &= ~0x0c00; /* PB13 */
95 PBCR2 &= ~0xc000; /* PB7 */
96 #endif
98 SCL_OUTPUT;
99 SDA_OUTPUT;
100 SDA_HI;
101 SCL_LO;
102 for (i=0;i<3;i++)
103 i2c_stop();
106 void i2c_ack(int bit)
108 /* Here's the deal. The MAS is slow, and sometimes needs to wait
109 before it can receive the acknowledge. Therefore it forces the clock
110 low until it is ready. We need to poll the clock line until it goes
111 high before we release the ack. */
113 SCL_LO; /* Set the clock low */
114 if ( bit )
116 SDA_HI;
118 else
120 SDA_LO;
123 SCL_INPUT; /* Set the clock to input */
124 while(!SCL) /* and wait for the MAS to release it */
125 sleep(0);
127 DELAY;
128 SCL_OUTPUT;
129 SCL_LO;
132 int i2c_getack(void)
134 int ret = 1;
136 /* Here's the deal. The MAS is slow, and sometimes needs to wait
137 before it can send the acknowledge. Therefore it forces the clock
138 low until it is ready. We need to poll the clock line until it goes
139 high before we read the ack. */
141 #ifdef HAVE_I2C_LOW_FIRST
142 SDA_LO; /* First, discharge the data line */
143 #endif
144 SDA_INPUT; /* And set to input */
145 SCL_INPUT; /* Set the clock to input */
146 while(!SCL) /* and wait for the MAS to release it */
147 sleep(0);
149 if (SDA)
150 /* ack failed */
151 ret = 0;
153 SCL_OUTPUT;
154 SCL_LO;
155 SDA_HI;
156 SDA_OUTPUT;
157 return ret;
160 void i2c_outb(unsigned char byte)
162 int i;
164 /* clock out each bit, MSB first */
165 for ( i=0x80; i; i>>=1 ) {
166 if ( i & byte )
168 SDA_HI;
170 else
172 SDA_LO;
174 SCL_HI;
175 SCL_LO;
178 SDA_HI;
181 unsigned char i2c_inb(int ack)
183 int i;
184 unsigned char byte = 0;
186 /* clock in each bit, MSB first */
187 for ( i=0x80; i; i>>=1 ) {
188 #ifdef HAVE_I2C_LOW_FIRST
189 /* Tricky business. Here we discharge the data line by driving it low
190 and then set it to input to see if it stays low or goes high */
191 SDA_LO; /* First, discharge the data line */
192 #endif
193 SDA_INPUT; /* And set to input */
194 SCL_HI;
195 if ( SDA )
196 byte |= i;
197 SCL_LO;
198 SDA_OUTPUT;
201 i2c_ack(ack);
203 return byte;
206 int i2c_write(int address, const unsigned char* buf, int count )
208 int i,x=0;
210 i2c_start();
211 i2c_outb(address & 0xfe);
212 if (i2c_getack())
214 for (i=0; i<count; i++)
216 i2c_outb(buf[i]);
217 if (!i2c_getack())
219 x=-2;
220 break;
224 else
226 debugf("i2c_write() - no ack\n");
227 x=-1;
229 i2c_stop();
230 return x;
233 int i2c_read(int address, unsigned char* buf, int count )
235 int i,x=0;
237 i2c_start();
238 i2c_outb(address | 1);
239 if (i2c_getack()) {
240 for (i=0; i<count; i++) {
241 buf[i] = i2c_inb(0);
244 else
245 x=-1;
246 i2c_stop();
247 return x;