]>
Commit | Line | Data |
---|---|---|
debb7354 | 1 | /* |
7237c033 | 2 | * Copyright 2006 Freescale Semiconductor, Inc. |
debb7354 JL |
3 | * |
4 | * This program is free software; you can redistribute it and/or | |
7237c033 JL |
5 | * modify it under the terms of the GNU General Public License |
6 | * Version 2 as published by the Free Software Foundation. | |
debb7354 JL |
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 | ||
19 | #include <common.h> | |
debb7354 | 20 | |
20476726 | 21 | #ifdef CONFIG_FSL_I2C |
debb7354 | 22 | #ifdef CONFIG_HARD_I2C |
debb7354 | 23 | |
4d45f69e | 24 | #include <command.h> |
20476726 JL |
25 | #include <i2c.h> /* Functional interface */ |
26 | ||
7237c033 | 27 | #include <asm/io.h> |
20476726 | 28 | #include <asm/fsl_i2c.h> /* HW definitions */ |
debb7354 | 29 | |
7237c033 | 30 | #define I2C_TIMEOUT (CFG_HZ / 4) |
debb7354 | 31 | |
be5e6181 TT |
32 | /* Initialize the bus pointer to whatever one the SPD EEPROM is on. |
33 | * Default is bus 0. This is necessary because the DDR initialization | |
34 | * runs from ROM, and we can't switch buses because we can't modify | |
35 | * the global variables. | |
36 | */ | |
37 | #ifdef CFG_SPD_BUS_NUM | |
38 | static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = CFG_SPD_BUS_NUM; | |
39 | #else | |
40 | static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0; | |
41 | #endif | |
42 | ||
43 | static volatile struct fsl_i2c *i2c_dev[2] = { | |
44 | (struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET), | |
45 | #ifdef CFG_I2C2_OFFSET | |
46 | (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET) | |
47 | #endif | |
48 | }; | |
debb7354 JL |
49 | |
50 | void | |
51 | i2c_init(int speed, int slaveadd) | |
52 | { | |
be5e6181 TT |
53 | volatile struct fsl_i2c *dev; |
54 | ||
55 | dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET); | |
56 | ||
57 | writeb(0, &dev->cr); /* stop I2C controller */ | |
58 | writeb(0x3F, &dev->fdr); /* set bus speed */ | |
59 | writeb(0x3F, &dev->dfsrr); /* set default filter */ | |
60 | writeb(slaveadd, &dev->adr); /* write slave address */ | |
61 | writeb(0x0, &dev->sr); /* clear status register */ | |
62 | writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */ | |
63 | ||
64 | #ifdef CFG_I2C2_OFFSET | |
65 | dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET); | |
66 | ||
67 | writeb(0, &dev->cr); /* stop I2C controller */ | |
68 | writeb(0x3F, &dev->fdr); /* set bus speed */ | |
69 | writeb(0x3F, &dev->dfsrr); /* set default filter */ | |
70 | writeb(slaveadd, &dev->adr); /* write slave address */ | |
71 | writeb(0x0, &dev->sr); /* clear status register */ | |
72 | writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */ | |
73 | #endif /* CFG_I2C2_OFFSET */ | |
debb7354 JL |
74 | } |
75 | ||
76 | static __inline__ int | |
5c9efb36 | 77 | i2c_wait4bus(void) |
debb7354 | 78 | { |
20476726 | 79 | ulong timeval = get_timer(0); |
debb7354 | 80 | |
be5e6181 | 81 | while (readb(&i2c_dev[i2c_bus_num]->sr) & I2C_SR_MBB) { |
7237c033 | 82 | if (get_timer(timeval) > I2C_TIMEOUT) { |
debb7354 JL |
83 | return -1; |
84 | } | |
85 | } | |
86 | ||
5c9efb36 | 87 | return 0; |
debb7354 JL |
88 | } |
89 | ||
90 | static __inline__ int | |
5c9efb36 | 91 | i2c_wait(int write) |
debb7354 JL |
92 | { |
93 | u32 csr; | |
ffff3ae5 | 94 | ulong timeval = get_timer(0); |
debb7354 JL |
95 | |
96 | do { | |
be5e6181 | 97 | csr = readb(&i2c_dev[i2c_bus_num]->sr); |
7237c033 | 98 | if (!(csr & I2C_SR_MIF)) |
debb7354 JL |
99 | continue; |
100 | ||
be5e6181 | 101 | writeb(0x0, &i2c_dev[i2c_bus_num]->sr); |
debb7354 | 102 | |
7237c033 | 103 | if (csr & I2C_SR_MAL) { |
debb7354 JL |
104 | debug("i2c_wait: MAL\n"); |
105 | return -1; | |
106 | } | |
107 | ||
7237c033 | 108 | if (!(csr & I2C_SR_MCF)) { |
debb7354 JL |
109 | debug("i2c_wait: unfinished\n"); |
110 | return -1; | |
111 | } | |
112 | ||
7237c033 | 113 | if (write == I2C_WRITE && (csr & I2C_SR_RXAK)) { |
debb7354 JL |
114 | debug("i2c_wait: No RXACK\n"); |
115 | return -1; | |
116 | } | |
117 | ||
118 | return 0; | |
7237c033 | 119 | } while (get_timer (timeval) < I2C_TIMEOUT); |
debb7354 JL |
120 | |
121 | debug("i2c_wait: timed out\n"); | |
122 | return -1; | |
123 | } | |
124 | ||
125 | static __inline__ int | |
7237c033 | 126 | i2c_write_addr (u8 dev, u8 dir, int rsta) |
debb7354 | 127 | { |
7237c033 JL |
128 | writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX |
129 | | (rsta ? I2C_CR_RSTA : 0), | |
be5e6181 | 130 | &i2c_dev[i2c_bus_num]->cr); |
debb7354 | 131 | |
be5e6181 | 132 | writeb((dev << 1) | dir, &i2c_dev[i2c_bus_num]->dr); |
debb7354 | 133 | |
5c9efb36 | 134 | if (i2c_wait(I2C_WRITE) < 0) |
debb7354 JL |
135 | return 0; |
136 | ||
137 | return 1; | |
138 | } | |
139 | ||
140 | static __inline__ int | |
ffff3ae5 | 141 | __i2c_write(u8 *data, int length) |
debb7354 JL |
142 | { |
143 | int i; | |
5c9efb36 | 144 | |
7237c033 | 145 | writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX, |
be5e6181 | 146 | &i2c_dev[i2c_bus_num]->cr); |
debb7354 | 147 | |
5c9efb36 | 148 | for (i = 0; i < length; i++) { |
be5e6181 | 149 | writeb(data[i], &i2c_dev[i2c_bus_num]->dr); |
debb7354 | 150 | |
5c9efb36 | 151 | if (i2c_wait(I2C_WRITE) < 0) |
debb7354 JL |
152 | break; |
153 | } | |
154 | ||
155 | return i; | |
156 | } | |
157 | ||
158 | static __inline__ int | |
ffff3ae5 | 159 | __i2c_read(u8 *data, int length) |
debb7354 JL |
160 | { |
161 | int i; | |
162 | ||
7237c033 | 163 | writeb(I2C_CR_MEN | I2C_CR_MSTA | ((length == 1) ? I2C_CR_TXAK : 0), |
be5e6181 | 164 | &i2c_dev[i2c_bus_num]->cr); |
debb7354 JL |
165 | |
166 | /* dummy read */ | |
be5e6181 | 167 | readb(&i2c_dev[i2c_bus_num]->dr); |
debb7354 | 168 | |
5c9efb36 JL |
169 | for (i = 0; i < length; i++) { |
170 | if (i2c_wait(I2C_READ) < 0) | |
debb7354 JL |
171 | break; |
172 | ||
173 | /* Generate ack on last next to last byte */ | |
174 | if (i == length - 2) | |
7237c033 | 175 | writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_TXAK, |
be5e6181 | 176 | &i2c_dev[i2c_bus_num]->cr); |
debb7354 JL |
177 | |
178 | /* Generate stop on last byte */ | |
179 | if (i == length - 1) | |
be5e6181 | 180 | writeb(I2C_CR_MEN | I2C_CR_TXAK, &i2c_dev[i2c_bus_num]->cr); |
debb7354 | 181 | |
be5e6181 | 182 | data[i] = readb(&i2c_dev[i2c_bus_num]->dr); |
debb7354 | 183 | } |
5c9efb36 | 184 | |
debb7354 JL |
185 | return i; |
186 | } | |
187 | ||
188 | int | |
ffff3ae5 | 189 | i2c_read(u8 dev, uint addr, int alen, u8 *data, int length) |
debb7354 JL |
190 | { |
191 | int i = 0; | |
7237c033 | 192 | u8 *a = (u8*)&addr; |
debb7354 | 193 | |
4d45f69e JL |
194 | if (i2c_wait4bus() >= 0 |
195 | && i2c_write_addr(dev, I2C_WRITE, 0) != 0 | |
196 | && __i2c_write(&a[4 - alen], alen) == alen | |
197 | && i2c_write_addr(dev, I2C_READ, 1) != 0) { | |
198 | i = __i2c_read(data, length); | |
199 | } | |
debb7354 | 200 | |
be5e6181 | 201 | writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr); |
debb7354 | 202 | |
4d45f69e JL |
203 | if (i == length) |
204 | return 0; | |
205 | ||
206 | return -1; | |
debb7354 JL |
207 | } |
208 | ||
209 | int | |
ffff3ae5 | 210 | i2c_write(u8 dev, uint addr, int alen, u8 *data, int length) |
debb7354 JL |
211 | { |
212 | int i = 0; | |
7237c033 | 213 | u8 *a = (u8*)&addr; |
debb7354 | 214 | |
4d45f69e JL |
215 | if (i2c_wait4bus() >= 0 |
216 | && i2c_write_addr(dev, I2C_WRITE, 0) != 0 | |
217 | && __i2c_write(&a[4 - alen], alen) == alen) { | |
218 | i = __i2c_write(data, length); | |
219 | } | |
debb7354 | 220 | |
be5e6181 | 221 | writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr); |
debb7354 | 222 | |
4d45f69e JL |
223 | if (i == length) |
224 | return 0; | |
225 | ||
226 | return -1; | |
debb7354 JL |
227 | } |
228 | ||
ffff3ae5 JL |
229 | int |
230 | i2c_probe(uchar chip) | |
debb7354 JL |
231 | { |
232 | int tmp; | |
233 | ||
234 | /* | |
235 | * Try to read the first location of the chip. The underlying | |
236 | * driver doesn't appear to support sending just the chip address | |
237 | * and looking for an <ACK> back. | |
238 | */ | |
239 | udelay(10000); | |
240 | ||
7237c033 | 241 | return i2c_read(chip, 0, 1, (uchar *)&tmp, 1); |
debb7354 JL |
242 | } |
243 | ||
ffff3ae5 JL |
244 | uchar |
245 | i2c_reg_read(uchar i2c_addr, uchar reg) | |
debb7354 | 246 | { |
7237c033 | 247 | uchar buf[1]; |
debb7354 | 248 | |
5c9efb36 | 249 | i2c_read(i2c_addr, reg, 1, buf, 1); |
debb7354 | 250 | |
5c9efb36 | 251 | return buf[0]; |
debb7354 JL |
252 | } |
253 | ||
ffff3ae5 JL |
254 | void |
255 | i2c_reg_write(uchar i2c_addr, uchar reg, uchar val) | |
debb7354 | 256 | { |
5c9efb36 | 257 | i2c_write(i2c_addr, reg, 1, &val, 1); |
debb7354 JL |
258 | } |
259 | ||
be5e6181 TT |
260 | int i2c_set_bus_num(unsigned int bus) |
261 | { | |
262 | #ifdef CFG_I2C2_OFFSET | |
263 | if (bus > 1) { | |
264 | #else | |
265 | if (bus > 0) { | |
266 | #endif | |
267 | return -1; | |
268 | } | |
269 | ||
270 | i2c_bus_num = bus; | |
271 | ||
272 | return 0; | |
273 | } | |
274 | ||
275 | int i2c_set_bus_speed(unsigned int speed) | |
276 | { | |
277 | return -1; | |
278 | } | |
279 | ||
280 | unsigned int i2c_get_bus_num(void) | |
281 | { | |
282 | return i2c_bus_num; | |
283 | } | |
284 | ||
285 | unsigned int i2c_get_bus_speed(void) | |
286 | { | |
287 | return 0; | |
288 | } | |
debb7354 | 289 | #endif /* CONFIG_HARD_I2C */ |
20476726 | 290 | #endif /* CONFIG_FSL_I2C */ |