blob: ebae5af154ee95bcadd738e8a78a57372f66d7c7 [file] [log] [blame]
Jon Loeligere4773be2006-10-19 11:02:16 -05001/*
2 * Copyright 2006 Freescale Semiconductor, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * Version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
16 * MA 02111-1307 USA
17 */
18
Jon Loeligere4773be2006-10-19 11:02:16 -050019#include <common.h>
Jon Loeligere4773be2006-10-19 11:02:16 -050020
Jon Loeliger43d818f2006-10-20 15:50:15 -050021#ifdef CONFIG_FSL_I2C
Jon Loeligere4773be2006-10-19 11:02:16 -050022#ifdef CONFIG_HARD_I2C
23
Jon Loeliger24df9772006-10-19 12:02:24 -050024#include <command.h>
Jon Loeliger43d818f2006-10-20 15:50:15 -050025#include <i2c.h> /* Functional interface */
26
Jon Loeligere4773be2006-10-19 11:02:16 -050027#include <asm/io.h>
Jon Loeliger43d818f2006-10-20 15:50:15 -050028#include <asm/fsl_i2c.h> /* HW definitions */
Jon Loeligere4773be2006-10-19 11:02:16 -050029
30#define I2C_TIMEOUT (CFG_HZ / 4)
31
Joakim Tjernlundc32c5f72006-11-28 16:17:27 -060032#define I2C_READ_BIT 1
33#define I2C_WRITE_BIT 0
34
Timur Tabiab347542006-11-03 19:15:00 -060035/* Initialize the bus pointer to whatever one the SPD EEPROM is on.
36 * Default is bus 0. This is necessary because the DDR initialization
37 * runs from ROM, and we can't switch buses because we can't modify
38 * the global variables.
39 */
40#ifdef CFG_SPD_BUS_NUM
41static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = CFG_SPD_BUS_NUM;
42#else
43static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0;
44#endif
45
46static volatile struct fsl_i2c *i2c_dev[2] = {
47 (struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET),
48#ifdef CFG_I2C2_OFFSET
49 (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET)
50#endif
51};
Jon Loeligere4773be2006-10-19 11:02:16 -050052
53void
54i2c_init(int speed, int slaveadd)
55{
Timur Tabiab347542006-11-03 19:15:00 -060056 volatile struct fsl_i2c *dev;
Jon Loeligere4773be2006-10-19 11:02:16 -050057
Timur Tabiab347542006-11-03 19:15:00 -060058 dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET);
Jon Loeligere4773be2006-10-19 11:02:16 -050059
Timur Tabiab347542006-11-03 19:15:00 -060060 writeb(0, &dev->cr); /* stop I2C controller */
Joakim Tjernlundb648fe72007-01-31 11:04:19 +010061 udelay(5); /* let it shutdown in peace */
Timur Tabiab347542006-11-03 19:15:00 -060062 writeb(0x3F, &dev->fdr); /* set bus speed */
63 writeb(0x3F, &dev->dfsrr); /* set default filter */
Joakim Tjernlunda292af22006-11-28 16:17:18 -060064 writeb(slaveadd << 1, &dev->adr); /* write slave address */
Timur Tabiab347542006-11-03 19:15:00 -060065 writeb(0x0, &dev->sr); /* clear status register */
66 writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */
Jon Loeligere4773be2006-10-19 11:02:16 -050067
Timur Tabiab347542006-11-03 19:15:00 -060068#ifdef CFG_I2C2_OFFSET
69 dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET);
Jon Loeligere4773be2006-10-19 11:02:16 -050070
Timur Tabiab347542006-11-03 19:15:00 -060071 writeb(0, &dev->cr); /* stop I2C controller */
72 writeb(0x3F, &dev->fdr); /* set bus speed */
73 writeb(0x3F, &dev->dfsrr); /* set default filter */
74 writeb(slaveadd, &dev->adr); /* write slave address */
75 writeb(0x0, &dev->sr); /* clear status register */
76 writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */
77#endif /* CFG_I2C2_OFFSET */
Jon Loeligere4773be2006-10-19 11:02:16 -050078}
79
80static __inline__ int
81i2c_wait4bus(void)
82{
Jon Loeliger43d818f2006-10-20 15:50:15 -050083 ulong timeval = get_timer(0);
Jon Loeligere4773be2006-10-19 11:02:16 -050084
Timur Tabiab347542006-11-03 19:15:00 -060085 while (readb(&i2c_dev[i2c_bus_num]->sr) & I2C_SR_MBB) {
Jon Loeligere4773be2006-10-19 11:02:16 -050086 if (get_timer(timeval) > I2C_TIMEOUT) {
87 return -1;
88 }
89 }
90
91 return 0;
92}
93
94static __inline__ int
95i2c_wait(int write)
96{
97 u32 csr;
98 ulong timeval = get_timer(0);
99
100 do {
Timur Tabiab347542006-11-03 19:15:00 -0600101 csr = readb(&i2c_dev[i2c_bus_num]->sr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500102 if (!(csr & I2C_SR_MIF))
103 continue;
104
Timur Tabiab347542006-11-03 19:15:00 -0600105 writeb(0x0, &i2c_dev[i2c_bus_num]->sr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500106
107 if (csr & I2C_SR_MAL) {
108 debug("i2c_wait: MAL\n");
109 return -1;
110 }
111
112 if (!(csr & I2C_SR_MCF)) {
113 debug("i2c_wait: unfinished\n");
114 return -1;
115 }
116
Joakim Tjernlundc32c5f72006-11-28 16:17:27 -0600117 if (write == I2C_WRITE_BIT && (csr & I2C_SR_RXAK)) {
Jon Loeligere4773be2006-10-19 11:02:16 -0500118 debug("i2c_wait: No RXACK\n");
119 return -1;
120 }
121
122 return 0;
123 } while (get_timer (timeval) < I2C_TIMEOUT);
124
125 debug("i2c_wait: timed out\n");
126 return -1;
127}
128
129static __inline__ int
130i2c_write_addr (u8 dev, u8 dir, int rsta)
131{
132 writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX
133 | (rsta ? I2C_CR_RSTA : 0),
Timur Tabiab347542006-11-03 19:15:00 -0600134 &i2c_dev[i2c_bus_num]->cr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500135
Timur Tabiab347542006-11-03 19:15:00 -0600136 writeb((dev << 1) | dir, &i2c_dev[i2c_bus_num]->dr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500137
Joakim Tjernlundc32c5f72006-11-28 16:17:27 -0600138 if (i2c_wait(I2C_WRITE_BIT) < 0)
Jon Loeligere4773be2006-10-19 11:02:16 -0500139 return 0;
140
141 return 1;
142}
143
144static __inline__ int
145__i2c_write(u8 *data, int length)
146{
147 int i;
148
149 writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX,
Timur Tabiab347542006-11-03 19:15:00 -0600150 &i2c_dev[i2c_bus_num]->cr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500151
152 for (i = 0; i < length; i++) {
Timur Tabiab347542006-11-03 19:15:00 -0600153 writeb(data[i], &i2c_dev[i2c_bus_num]->dr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500154
Joakim Tjernlundc32c5f72006-11-28 16:17:27 -0600155 if (i2c_wait(I2C_WRITE_BIT) < 0)
Jon Loeligere4773be2006-10-19 11:02:16 -0500156 break;
157 }
158
159 return i;
160}
161
162static __inline__ int
163__i2c_read(u8 *data, int length)
164{
165 int i;
166
167 writeb(I2C_CR_MEN | I2C_CR_MSTA | ((length == 1) ? I2C_CR_TXAK : 0),
Timur Tabiab347542006-11-03 19:15:00 -0600168 &i2c_dev[i2c_bus_num]->cr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500169
170 /* dummy read */
Timur Tabiab347542006-11-03 19:15:00 -0600171 readb(&i2c_dev[i2c_bus_num]->dr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500172
173 for (i = 0; i < length; i++) {
Joakim Tjernlundc32c5f72006-11-28 16:17:27 -0600174 if (i2c_wait(I2C_READ_BIT) < 0)
Jon Loeligere4773be2006-10-19 11:02:16 -0500175 break;
176
177 /* Generate ack on last next to last byte */
178 if (i == length - 2)
179 writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_TXAK,
Timur Tabiab347542006-11-03 19:15:00 -0600180 &i2c_dev[i2c_bus_num]->cr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500181
182 /* Generate stop on last byte */
183 if (i == length - 1)
Timur Tabiab347542006-11-03 19:15:00 -0600184 writeb(I2C_CR_MEN | I2C_CR_TXAK, &i2c_dev[i2c_bus_num]->cr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500185
Timur Tabiab347542006-11-03 19:15:00 -0600186 data[i] = readb(&i2c_dev[i2c_bus_num]->dr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500187 }
188
189 return i;
190}
191
192int
193i2c_read(u8 dev, uint addr, int alen, u8 *data, int length)
194{
Joakim Tjernlundb648fe72007-01-31 11:04:19 +0100195 int i = -1; /* signal error */
Jon Loeligere4773be2006-10-19 11:02:16 -0500196 u8 *a = (u8*)&addr;
197
Jon Loeliger24df9772006-10-19 12:02:24 -0500198 if (i2c_wait4bus() >= 0
Joakim Tjernlundc32c5f72006-11-28 16:17:27 -0600199 && i2c_write_addr(dev, I2C_WRITE_BIT, 0) != 0
Joakim Tjernlundb648fe72007-01-31 11:04:19 +0100200 && __i2c_write(&a[4 - alen], alen) == alen)
201 i = 0; /* No error so far */
202
203 if (length
204 && i2c_write_addr(dev, I2C_READ_BIT, 1) != 0)
Jon Loeliger24df9772006-10-19 12:02:24 -0500205 i = __i2c_read(data, length);
Jon Loeligere4773be2006-10-19 11:02:16 -0500206
Timur Tabiab347542006-11-03 19:15:00 -0600207 writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500208
Jon Loeliger24df9772006-10-19 12:02:24 -0500209 if (i == length)
210 return 0;
211
212 return -1;
Jon Loeligere4773be2006-10-19 11:02:16 -0500213}
214
215int
216i2c_write(u8 dev, uint addr, int alen, u8 *data, int length)
217{
Joakim Tjernlundb648fe72007-01-31 11:04:19 +0100218 int i = -1; /* signal error */
Jon Loeligere4773be2006-10-19 11:02:16 -0500219 u8 *a = (u8*)&addr;
220
Jon Loeliger24df9772006-10-19 12:02:24 -0500221 if (i2c_wait4bus() >= 0
Joakim Tjernlundc32c5f72006-11-28 16:17:27 -0600222 && i2c_write_addr(dev, I2C_WRITE_BIT, 0) != 0
Jon Loeliger24df9772006-10-19 12:02:24 -0500223 && __i2c_write(&a[4 - alen], alen) == alen) {
224 i = __i2c_write(data, length);
225 }
Jon Loeligere4773be2006-10-19 11:02:16 -0500226
Timur Tabiab347542006-11-03 19:15:00 -0600227 writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr);
Jon Loeligere4773be2006-10-19 11:02:16 -0500228
Jon Loeliger24df9772006-10-19 12:02:24 -0500229 if (i == length)
230 return 0;
231
232 return -1;
Jon Loeligere4773be2006-10-19 11:02:16 -0500233}
234
235int
236i2c_probe(uchar chip)
237{
Joakim Tjernlundb648fe72007-01-31 11:04:19 +0100238 /* For unknow reason the controller will ACK when
239 * probing for a slave with the same address, so skip
240 * it.
Jon Loeligere4773be2006-10-19 11:02:16 -0500241 */
Joakim Tjernlundb648fe72007-01-31 11:04:19 +0100242 if (chip == (readb(&i2c_dev[i2c_bus_num]->adr) >> 1))
243 return -1;
Jon Loeligere4773be2006-10-19 11:02:16 -0500244
Joakim Tjernlundb648fe72007-01-31 11:04:19 +0100245 return i2c_read(chip, 0, 0, NULL, 0);
Jon Loeligere4773be2006-10-19 11:02:16 -0500246}
247
248uchar
249i2c_reg_read(uchar i2c_addr, uchar reg)
250{
251 uchar buf[1];
252
253 i2c_read(i2c_addr, reg, 1, buf, 1);
254
255 return buf[0];
256}
257
258void
259i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
260{
261 i2c_write(i2c_addr, reg, 1, &val, 1);
262}
263
Timur Tabiab347542006-11-03 19:15:00 -0600264int i2c_set_bus_num(unsigned int bus)
265{
266#ifdef CFG_I2C2_OFFSET
267 if (bus > 1) {
268#else
269 if (bus > 0) {
270#endif
271 return -1;
272 }
273
274 i2c_bus_num = bus;
275
276 return 0;
277}
278
279int i2c_set_bus_speed(unsigned int speed)
280{
281 return -1;
282}
283
284unsigned int i2c_get_bus_num(void)
285{
286 return i2c_bus_num;
287}
288
289unsigned int i2c_get_bus_speed(void)
290{
291 return 0;
292}
Jon Loeligere4773be2006-10-19 11:02:16 -0500293#endif /* CONFIG_HARD_I2C */
Jon Loeliger43d818f2006-10-20 15:50:15 -0500294#endif /* CONFIG_FSL_I2C */