blob: 7dab78685dfb44102295a2cf138d49f48118b9ac [file] [log] [blame]
wdenk8ed96042005-01-09 23:16:25 +00001/*
2 * Basic I2C functions
3 *
4 * Copyright (c) 2004 Texas Instruments
5 *
6 * This package is free software; you can redistribute it and/or
7 * modify it under the terms of the license found in the file
8 * named COPYING that should have accompanied this file.
9 *
10 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
11 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
12 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 *
14 * Author: Jian Zhang jzhang@ti.com, Texas Instruments
15 *
16 * Copyright (c) 2003 Wolfgang Denk, wd@denx.de
17 * Rewritten to fit into the current U-Boot framework
18 *
19 * Adapted for OMAP2420 I2C, r-woodruff2@ti.com
20 *
21 */
22
23#include <common.h>
wdenk289f9322005-01-12 00:15:14 +000024
25#ifdef CONFIG_DRIVER_OMAP24XX_I2C
26
wdenk8ed96042005-01-09 23:16:25 +000027#include <asm/arch/i2c.h>
28#include <asm/io.h>
29
30#define inw(a) __raw_readw(a)
31#define outw(a,v) __raw_writew(a,v)
32
wdenk8ed96042005-01-09 23:16:25 +000033static void wait_for_bb (void);
34static u16 wait_for_pin (void);
Wolfgang Denk49a75812005-09-25 18:41:04 +020035static void flush_fifo(void);
wdenk8ed96042005-01-09 23:16:25 +000036
37void i2c_init (int speed, int slaveadd)
38{
39 u16 scl;
40
Wolfgang Denk49a75812005-09-25 18:41:04 +020041 outw(0x2, I2C_SYSC); /* for ES2 after soft reset */
42 udelay(1000);
43 outw(0x0, I2C_SYSC); /* will probably self clear but */
44
wdenk8ed96042005-01-09 23:16:25 +000045 if (inw (I2C_CON) & I2C_CON_EN) {
46 outw (0, I2C_CON);
47 udelay (50000);
48 }
49
50 /* 12Mhz I2C module clock */
51 outw (0, I2C_PSC);
wdenk082acfd2005-01-10 00:01:04 +000052 speed = speed/1000; /* 100 or 400 */
53 scl = ((12000/(speed*2)) - 7); /* use 7 when PSC = 0 */
wdenk8ed96042005-01-09 23:16:25 +000054 outw (scl, I2C_SCLL);
55 outw (scl, I2C_SCLH);
56 /* own address */
57 outw (slaveadd, I2C_OA);
58 outw (I2C_CON_EN, I2C_CON);
Wolfgang Denk49a75812005-09-25 18:41:04 +020059
wdenk8ed96042005-01-09 23:16:25 +000060 /* have to enable intrrupts or OMAP i2c module doesn't work */
61 outw (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
62 I2C_IE_NACK_IE | I2C_IE_AL_IE, I2C_IE);
63 udelay (1000);
Wolfgang Denk49a75812005-09-25 18:41:04 +020064 flush_fifo();
65 outw (0xFFFF, I2C_STAT);
66 outw (0, I2C_CNT);
wdenk8ed96042005-01-09 23:16:25 +000067}
68
69static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
70{
71 int i2c_error = 0;
72 u16 status;
73
74 /* wait until bus not busy */
75 wait_for_bb ();
76
77 /* one byte only */
78 outw (1, I2C_CNT);
79 /* set slave address */
80 outw (devaddr, I2C_SA);
81 /* no stop bit needed here */
82 outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, I2C_CON);
83
84 status = wait_for_pin ();
85
86 if (status & I2C_STAT_XRDY) {
87 /* Important: have to use byte access */
88 *(volatile u8 *) (I2C_DATA) = regoffset;
89 udelay (20000);
90 if (inw (I2C_STAT) & I2C_STAT_NACK) {
91 i2c_error = 1;
92 }
93 } else {
94 i2c_error = 1;
95 }
96
97 if (!i2c_error) {
98 /* free bus, otherwise we can't use a combined transction */
99 outw (0, I2C_CON);
100 while (inw (I2C_STAT) || (inw (I2C_CON) & I2C_CON_MST)) {
101 udelay (10000);
102 /* Have to clear pending interrupt to clear I2C_STAT */
103 outw (0xFFFF, I2C_STAT);
104 }
105
106 wait_for_bb ();
107 /* set slave address */
108 outw (devaddr, I2C_SA);
109 /* read one byte from slave */
110 outw (1, I2C_CNT);
111 /* need stop bit here */
112 outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
113 I2C_CON);
114
115 status = wait_for_pin ();
116 if (status & I2C_STAT_RRDY) {
117 *value = inw (I2C_DATA);
118 udelay (20000);
119 } else {
120 i2c_error = 1;
121 }
122
123 if (!i2c_error) {
124 outw (I2C_CON_EN, I2C_CON);
125 while (inw (I2C_STAT)
126 || (inw (I2C_CON) & I2C_CON_MST)) {
127 udelay (10000);
128 outw (0xFFFF, I2C_STAT);
129 }
130 }
131 }
132 flush_fifo();
133 outw (0xFFFF, I2C_STAT);
134 outw (0, I2C_CNT);
135 return i2c_error;
136}
137
138static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
139{
140 int i2c_error = 0;
141 u16 status, stat;
142
143 /* wait until bus not busy */
144 wait_for_bb ();
145
146 /* two bytes */
147 outw (2, I2C_CNT);
148 /* set slave address */
149 outw (devaddr, I2C_SA);
150 /* stop bit needed here */
151 outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
152 I2C_CON_STP, I2C_CON);
153
154 /* wait until state change */
155 status = wait_for_pin ();
156
157 if (status & I2C_STAT_XRDY) {
158 /* send out two bytes */
159 outw ((value << 8) + regoffset, I2C_DATA);
160 /* must have enough delay to allow BB bit to go low */
161 udelay (50000);
162 if (inw (I2C_STAT) & I2C_STAT_NACK) {
163 i2c_error = 1;
164 }
165 } else {
166 i2c_error = 1;
167 }
168
169 if (!i2c_error) {
Wolfgang Denk49a75812005-09-25 18:41:04 +0200170 int eout = 200;
171
wdenk8ed96042005-01-09 23:16:25 +0000172 outw (I2C_CON_EN, I2C_CON);
173 while ((stat = inw (I2C_STAT)) || (inw (I2C_CON) & I2C_CON_MST)) {
174 udelay (1000);
175 /* have to read to clear intrrupt */
176 outw (0xFFFF, I2C_STAT);
Wolfgang Denk49a75812005-09-25 18:41:04 +0200177 if(--eout == 0) /* better leave with error than hang */
178 break;
wdenk8ed96042005-01-09 23:16:25 +0000179 }
180 }
181 flush_fifo();
182 outw (0xFFFF, I2C_STAT);
183 outw (0, I2C_CNT);
184 return i2c_error;
185}
186
Wolfgang Denk49a75812005-09-25 18:41:04 +0200187static void flush_fifo(void)
wdenk8ed96042005-01-09 23:16:25 +0000188{ u16 stat;
wdenk082acfd2005-01-10 00:01:04 +0000189
190 /* note: if you try and read data when its not there or ready
191 * you get a bus error
192 */
wdenk8ed96042005-01-09 23:16:25 +0000193 while(1){
194 stat = inw(I2C_STAT);
195 if(stat == I2C_STAT_RRDY){
196 inw(I2C_DATA);
197 outw(I2C_STAT_RRDY,I2C_STAT);
198 udelay(1000);
199 }else
200 break;
201 }
202}
203
204int i2c_probe (uchar chip)
205{
206 int res = 1; /* default = fail */
207
208 if (chip == inw (I2C_OA)) {
209 return res;
210 }
211
212 /* wait until bus not busy */
213 wait_for_bb ();
214
215 /* try to read one byte */
216 outw (1, I2C_CNT);
217 /* set slave address */
218 outw (chip, I2C_SA);
219 /* stop bit needed here */
220 outw (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, I2C_CON);
221 /* enough delay for the NACK bit set */
222 udelay (50000);
223
224 if (!(inw (I2C_STAT) & I2C_STAT_NACK)) {
wdenk082acfd2005-01-10 00:01:04 +0000225 res = 0; /* success case */
wdenk8ed96042005-01-09 23:16:25 +0000226 flush_fifo();
227 outw(0xFFFF, I2C_STAT);
228 } else {
wdenk082acfd2005-01-10 00:01:04 +0000229 outw(0xFFFF, I2C_STAT); /* failue, clear sources*/
wdenk8ed96042005-01-09 23:16:25 +0000230 outw (inw (I2C_CON) | I2C_CON_STP, I2C_CON); /* finish up xfer */
231 udelay(20000);
232 wait_for_bb ();
233 }
234 flush_fifo();
235 outw (0, I2C_CNT); /* don't allow any more data in...we don't want it.*/
236 outw(0xFFFF, I2C_STAT);
237 return res;
238}
239
240int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
241{
242 int i;
243
244 if (alen > 1) {
245 printf ("I2C read: addr len %d not supported\n", alen);
246 return 1;
247 }
248
249 if (addr + len > 256) {
250 printf ("I2C read: address out of range\n");
251 return 1;
252 }
253
254 for (i = 0; i < len; i++) {
255 if (i2c_read_byte (chip, addr + i, &buffer[i])) {
256 printf ("I2C read: I/O error\n");
257 i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
258 return 1;
259 }
260 }
261
262 return 0;
263}
264
265int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
266{
267 int i;
268
269 if (alen > 1) {
270 printf ("I2C read: addr len %d not supported\n", alen);
271 return 1;
272 }
273
274 if (addr + len > 256) {
275 printf ("I2C read: address out of range\n");
276 return 1;
277 }
278
279 for (i = 0; i < len; i++) {
280 if (i2c_write_byte (chip, addr + i, buffer[i])) {
281 printf ("I2C read: I/O error\n");
282 i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
283 return 1;
284 }
285 }
286
287 return 0;
288}
289
290static void wait_for_bb (void)
291{
292 int timeout = 10;
293 u16 stat;
294
wdenk082acfd2005-01-10 00:01:04 +0000295 outw(0xFFFF, I2C_STAT); /* clear current interruts...*/
wdenk8ed96042005-01-09 23:16:25 +0000296 while ((stat = inw (I2C_STAT) & I2C_STAT_BB) && timeout--) {
297 outw (stat, I2C_STAT);
298 udelay (50000);
299 }
300
301 if (timeout <= 0) {
302 printf ("timed out in wait_for_bb: I2C_STAT=%x\n",
303 inw (I2C_STAT));
304 }
wdenk082acfd2005-01-10 00:01:04 +0000305 outw(0xFFFF, I2C_STAT); /* clear delayed stuff*/
wdenk8ed96042005-01-09 23:16:25 +0000306}
307
308static u16 wait_for_pin (void)
309{
310 u16 status;
311 int timeout = 10;
312
313 do {
314 udelay (1000);
315 status = inw (I2C_STAT);
316 } while ( !(status &
317 (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
318 I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
319 I2C_STAT_AL)) && timeout--);
320
321 if (timeout <= 0) {
322 printf ("timed out in wait_for_pin: I2C_STAT=%x\n",
323 inw (I2C_STAT));
wdenk082acfd2005-01-10 00:01:04 +0000324 outw(0xFFFF, I2C_STAT);
wdenk8ed96042005-01-09 23:16:25 +0000325}
326 return status;
327}
328
329#endif /* CONFIG_DRIVER_OMAP24XX_I2C */