blob: 678460325dd874752186484e7d75d5ee867b956a [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
wdenk8ed96042005-01-09 23:16:25 +000025#include <asm/arch/i2c.h>
26#include <asm/io.h>
27
wdenk8ed96042005-01-09 23:16:25 +000028static void wait_for_bb (void);
29static u16 wait_for_pin (void);
Wolfgang Denk49a75812005-09-25 18:41:04 +020030static void flush_fifo(void);
wdenk8ed96042005-01-09 23:16:25 +000031
32void i2c_init (int speed, int slaveadd)
33{
34 u16 scl;
35
Dirk Behmee23c7c92008-11-10 20:15:25 +010036 writew(0x2, I2C_SYSC); /* for ES2 after soft reset */
Wolfgang Denk49a75812005-09-25 18:41:04 +020037 udelay(1000);
Dirk Behmee23c7c92008-11-10 20:15:25 +010038 writew(0x0, I2C_SYSC); /* will probably self clear but */
Wolfgang Denk49a75812005-09-25 18:41:04 +020039
Dirk Behmee23c7c92008-11-10 20:15:25 +010040 if (readw (I2C_CON) & I2C_CON_EN) {
41 writew (0, I2C_CON);
wdenk8ed96042005-01-09 23:16:25 +000042 udelay (50000);
43 }
44
Wolfgang Denk8ed44d92008-10-19 02:35:50 +020045 /* 12MHz I2C module clock */
Dirk Behmee23c7c92008-11-10 20:15:25 +010046 writew (0, I2C_PSC);
wdenk082acfd2005-01-10 00:01:04 +000047 speed = speed/1000; /* 100 or 400 */
48 scl = ((12000/(speed*2)) - 7); /* use 7 when PSC = 0 */
Dirk Behmee23c7c92008-11-10 20:15:25 +010049 writew (scl, I2C_SCLL);
50 writew (scl, I2C_SCLH);
wdenk8ed96042005-01-09 23:16:25 +000051 /* own address */
Dirk Behmee23c7c92008-11-10 20:15:25 +010052 writew (slaveadd, I2C_OA);
53 writew (I2C_CON_EN, I2C_CON);
Wolfgang Denk49a75812005-09-25 18:41:04 +020054
wdenk8ed96042005-01-09 23:16:25 +000055 /* have to enable intrrupts or OMAP i2c module doesn't work */
Dirk Behmee23c7c92008-11-10 20:15:25 +010056 writew (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
57 I2C_IE_NACK_IE | I2C_IE_AL_IE, I2C_IE);
wdenk8ed96042005-01-09 23:16:25 +000058 udelay (1000);
Wolfgang Denk49a75812005-09-25 18:41:04 +020059 flush_fifo();
Dirk Behmee23c7c92008-11-10 20:15:25 +010060 writew (0xFFFF, I2C_STAT);
61 writew (0, I2C_CNT);
wdenk8ed96042005-01-09 23:16:25 +000062}
63
64static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value)
65{
66 int i2c_error = 0;
67 u16 status;
68
69 /* wait until bus not busy */
70 wait_for_bb ();
71
72 /* one byte only */
Dirk Behmee23c7c92008-11-10 20:15:25 +010073 writew (1, I2C_CNT);
wdenk8ed96042005-01-09 23:16:25 +000074 /* set slave address */
Dirk Behmee23c7c92008-11-10 20:15:25 +010075 writew (devaddr, I2C_SA);
wdenk8ed96042005-01-09 23:16:25 +000076 /* no stop bit needed here */
Dirk Behmee23c7c92008-11-10 20:15:25 +010077 writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, I2C_CON);
wdenk8ed96042005-01-09 23:16:25 +000078
79 status = wait_for_pin ();
80
81 if (status & I2C_STAT_XRDY) {
82 /* Important: have to use byte access */
Dirk Behmee23c7c92008-11-10 20:15:25 +010083 writeb (regoffset, I2C_DATA);
wdenk8ed96042005-01-09 23:16:25 +000084 udelay (20000);
Dirk Behmee23c7c92008-11-10 20:15:25 +010085 if (readw (I2C_STAT) & I2C_STAT_NACK) {
wdenk8ed96042005-01-09 23:16:25 +000086 i2c_error = 1;
87 }
88 } else {
89 i2c_error = 1;
90 }
91
92 if (!i2c_error) {
93 /* free bus, otherwise we can't use a combined transction */
Dirk Behmee23c7c92008-11-10 20:15:25 +010094 writew (0, I2C_CON);
95 while (readw (I2C_STAT) || (readw (I2C_CON) & I2C_CON_MST)) {
wdenk8ed96042005-01-09 23:16:25 +000096 udelay (10000);
97 /* Have to clear pending interrupt to clear I2C_STAT */
Dirk Behmee23c7c92008-11-10 20:15:25 +010098 writew (0xFFFF, I2C_STAT);
wdenk8ed96042005-01-09 23:16:25 +000099 }
100
101 wait_for_bb ();
102 /* set slave address */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100103 writew (devaddr, I2C_SA);
wdenk8ed96042005-01-09 23:16:25 +0000104 /* read one byte from slave */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100105 writew (1, I2C_CNT);
wdenk8ed96042005-01-09 23:16:25 +0000106 /* need stop bit here */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100107 writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
108 I2C_CON);
wdenk8ed96042005-01-09 23:16:25 +0000109
110 status = wait_for_pin ();
111 if (status & I2C_STAT_RRDY) {
Dirk Behme7d264c12008-12-14 09:47:18 +0100112#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
113 *value = readb (I2C_DATA);
114#else
Dirk Behmee23c7c92008-11-10 20:15:25 +0100115 *value = readw (I2C_DATA);
Dirk Behme7d264c12008-12-14 09:47:18 +0100116#endif
wdenk8ed96042005-01-09 23:16:25 +0000117 udelay (20000);
118 } else {
119 i2c_error = 1;
120 }
121
122 if (!i2c_error) {
Dirk Behmee23c7c92008-11-10 20:15:25 +0100123 writew (I2C_CON_EN, I2C_CON);
124 while (readw (I2C_STAT)
125 || (readw (I2C_CON) & I2C_CON_MST)) {
wdenk8ed96042005-01-09 23:16:25 +0000126 udelay (10000);
Dirk Behmee23c7c92008-11-10 20:15:25 +0100127 writew (0xFFFF, I2C_STAT);
wdenk8ed96042005-01-09 23:16:25 +0000128 }
129 }
130 }
131 flush_fifo();
Dirk Behmee23c7c92008-11-10 20:15:25 +0100132 writew (0xFFFF, I2C_STAT);
133 writew (0, I2C_CNT);
wdenk8ed96042005-01-09 23:16:25 +0000134 return i2c_error;
135}
136
137static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value)
138{
139 int i2c_error = 0;
140 u16 status, stat;
141
142 /* wait until bus not busy */
143 wait_for_bb ();
144
145 /* two bytes */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100146 writew (2, I2C_CNT);
wdenk8ed96042005-01-09 23:16:25 +0000147 /* set slave address */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100148 writew (devaddr, I2C_SA);
wdenk8ed96042005-01-09 23:16:25 +0000149 /* stop bit needed here */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100150 writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
151 I2C_CON_STP, I2C_CON);
wdenk8ed96042005-01-09 23:16:25 +0000152
153 /* wait until state change */
154 status = wait_for_pin ();
155
156 if (status & I2C_STAT_XRDY) {
Dirk Behme7d264c12008-12-14 09:47:18 +0100157#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
158 /* send out 1 byte */
159 writeb (regoffset, I2C_DATA);
160 writew (I2C_STAT_XRDY, I2C_STAT);
161
162 status = wait_for_pin ();
163 if ((status & I2C_STAT_XRDY)) {
164 /* send out next 1 byte */
165 writeb (value, I2C_DATA);
166 writew (I2C_STAT_XRDY, I2C_STAT);
167 } else {
168 i2c_error = 1;
169 }
170#else
wdenk8ed96042005-01-09 23:16:25 +0000171 /* send out two bytes */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100172 writew ((value << 8) + regoffset, I2C_DATA);
Dirk Behme7d264c12008-12-14 09:47:18 +0100173#endif
wdenk8ed96042005-01-09 23:16:25 +0000174 /* must have enough delay to allow BB bit to go low */
175 udelay (50000);
Dirk Behmee23c7c92008-11-10 20:15:25 +0100176 if (readw (I2C_STAT) & I2C_STAT_NACK) {
wdenk8ed96042005-01-09 23:16:25 +0000177 i2c_error = 1;
178 }
179 } else {
180 i2c_error = 1;
181 }
182
183 if (!i2c_error) {
Wolfgang Denk49a75812005-09-25 18:41:04 +0200184 int eout = 200;
185
Dirk Behmee23c7c92008-11-10 20:15:25 +0100186 writew (I2C_CON_EN, I2C_CON);
187 while ((stat = readw (I2C_STAT)) || (readw (I2C_CON) & I2C_CON_MST)) {
wdenk8ed96042005-01-09 23:16:25 +0000188 udelay (1000);
189 /* have to read to clear intrrupt */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100190 writew (0xFFFF, I2C_STAT);
Wolfgang Denk49a75812005-09-25 18:41:04 +0200191 if(--eout == 0) /* better leave with error than hang */
192 break;
wdenk8ed96042005-01-09 23:16:25 +0000193 }
194 }
195 flush_fifo();
Dirk Behmee23c7c92008-11-10 20:15:25 +0100196 writew (0xFFFF, I2C_STAT);
197 writew (0, I2C_CNT);
wdenk8ed96042005-01-09 23:16:25 +0000198 return i2c_error;
199}
200
Wolfgang Denk49a75812005-09-25 18:41:04 +0200201static void flush_fifo(void)
wdenk8ed96042005-01-09 23:16:25 +0000202{ u16 stat;
wdenk082acfd2005-01-10 00:01:04 +0000203
204 /* note: if you try and read data when its not there or ready
205 * you get a bus error
206 */
wdenk8ed96042005-01-09 23:16:25 +0000207 while(1){
Dirk Behmee23c7c92008-11-10 20:15:25 +0100208 stat = readw(I2C_STAT);
wdenk8ed96042005-01-09 23:16:25 +0000209 if(stat == I2C_STAT_RRDY){
Dirk Behme7d264c12008-12-14 09:47:18 +0100210#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
211 readb(I2C_DATA);
212#else
Dirk Behmee23c7c92008-11-10 20:15:25 +0100213 readw(I2C_DATA);
Dirk Behme7d264c12008-12-14 09:47:18 +0100214#endif
Dirk Behmee23c7c92008-11-10 20:15:25 +0100215 writew(I2C_STAT_RRDY,I2C_STAT);
wdenk8ed96042005-01-09 23:16:25 +0000216 udelay(1000);
217 }else
218 break;
219 }
220}
221
222int i2c_probe (uchar chip)
223{
224 int res = 1; /* default = fail */
225
Dirk Behmee23c7c92008-11-10 20:15:25 +0100226 if (chip == readw (I2C_OA)) {
wdenk8ed96042005-01-09 23:16:25 +0000227 return res;
228 }
229
230 /* wait until bus not busy */
231 wait_for_bb ();
232
233 /* try to read one byte */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100234 writew (1, I2C_CNT);
wdenk8ed96042005-01-09 23:16:25 +0000235 /* set slave address */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100236 writew (chip, I2C_SA);
wdenk8ed96042005-01-09 23:16:25 +0000237 /* stop bit needed here */
Dirk Behmee23c7c92008-11-10 20:15:25 +0100238 writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, I2C_CON);
wdenk8ed96042005-01-09 23:16:25 +0000239 /* enough delay for the NACK bit set */
240 udelay (50000);
241
Dirk Behmee23c7c92008-11-10 20:15:25 +0100242 if (!(readw (I2C_STAT) & I2C_STAT_NACK)) {
wdenk082acfd2005-01-10 00:01:04 +0000243 res = 0; /* success case */
wdenk8ed96042005-01-09 23:16:25 +0000244 flush_fifo();
Dirk Behmee23c7c92008-11-10 20:15:25 +0100245 writew(0xFFFF, I2C_STAT);
wdenk8ed96042005-01-09 23:16:25 +0000246 } else {
Dirk Behmee23c7c92008-11-10 20:15:25 +0100247 writew(0xFFFF, I2C_STAT); /* failue, clear sources*/
248 writew (readw (I2C_CON) | I2C_CON_STP, I2C_CON); /* finish up xfer */
wdenk8ed96042005-01-09 23:16:25 +0000249 udelay(20000);
250 wait_for_bb ();
251 }
252 flush_fifo();
Dirk Behmee23c7c92008-11-10 20:15:25 +0100253 writew (0, I2C_CNT); /* don't allow any more data in...we don't want it.*/
254 writew(0xFFFF, I2C_STAT);
wdenk8ed96042005-01-09 23:16:25 +0000255 return res;
256}
257
258int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
259{
260 int i;
261
262 if (alen > 1) {
263 printf ("I2C read: addr len %d not supported\n", alen);
264 return 1;
265 }
266
267 if (addr + len > 256) {
268 printf ("I2C read: address out of range\n");
269 return 1;
270 }
271
272 for (i = 0; i < len; i++) {
273 if (i2c_read_byte (chip, addr + i, &buffer[i])) {
274 printf ("I2C read: I/O error\n");
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200275 i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
wdenk8ed96042005-01-09 23:16:25 +0000276 return 1;
277 }
278 }
279
280 return 0;
281}
282
283int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
284{
285 int i;
286
287 if (alen > 1) {
288 printf ("I2C read: addr len %d not supported\n", alen);
289 return 1;
290 }
291
292 if (addr + len > 256) {
293 printf ("I2C read: address out of range\n");
294 return 1;
295 }
296
297 for (i = 0; i < len; i++) {
298 if (i2c_write_byte (chip, addr + i, buffer[i])) {
299 printf ("I2C read: I/O error\n");
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200300 i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
wdenk8ed96042005-01-09 23:16:25 +0000301 return 1;
302 }
303 }
304
305 return 0;
306}
307
308static void wait_for_bb (void)
309{
310 int timeout = 10;
311 u16 stat;
312
Dirk Behmee23c7c92008-11-10 20:15:25 +0100313 writew(0xFFFF, I2C_STAT); /* clear current interruts...*/
314 while ((stat = readw (I2C_STAT) & I2C_STAT_BB) && timeout--) {
315 writew (stat, I2C_STAT);
wdenk8ed96042005-01-09 23:16:25 +0000316 udelay (50000);
317 }
318
319 if (timeout <= 0) {
320 printf ("timed out in wait_for_bb: I2C_STAT=%x\n",
Dirk Behmee23c7c92008-11-10 20:15:25 +0100321 readw (I2C_STAT));
wdenk8ed96042005-01-09 23:16:25 +0000322 }
Dirk Behmee23c7c92008-11-10 20:15:25 +0100323 writew(0xFFFF, I2C_STAT); /* clear delayed stuff*/
wdenk8ed96042005-01-09 23:16:25 +0000324}
325
326static u16 wait_for_pin (void)
327{
328 u16 status;
329 int timeout = 10;
330
331 do {
332 udelay (1000);
Dirk Behmee23c7c92008-11-10 20:15:25 +0100333 status = readw (I2C_STAT);
wdenk8ed96042005-01-09 23:16:25 +0000334 } while ( !(status &
335 (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
336 I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
337 I2C_STAT_AL)) && timeout--);
338
339 if (timeout <= 0) {
340 printf ("timed out in wait_for_pin: I2C_STAT=%x\n",
Dirk Behmee23c7c92008-11-10 20:15:25 +0100341 readw (I2C_STAT));
342 writew(0xFFFF, I2C_STAT);
wdenk8ed96042005-01-09 23:16:25 +0000343}
344 return status;
345}