]>
Commit | Line | Data |
---|---|---|
1 | /* | |
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 | ||
19 | #include <common.h> | |
20 | ||
21 | #ifdef CONFIG_FSL_I2C | |
22 | #ifdef CONFIG_HARD_I2C | |
23 | ||
24 | #include <command.h> | |
25 | #include <i2c.h> /* Functional interface */ | |
26 | ||
27 | #include <asm/io.h> | |
28 | #include <asm/fsl_i2c.h> /* HW definitions */ | |
29 | ||
30 | #define I2C_TIMEOUT (CFG_HZ / 4) | |
31 | ||
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 | }; | |
49 | ||
50 | void | |
51 | i2c_init(int speed, int slaveadd) | |
52 | { | |
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 */ | |
74 | } | |
75 | ||
76 | static __inline__ int | |
77 | i2c_wait4bus(void) | |
78 | { | |
79 | ulong timeval = get_timer(0); | |
80 | ||
81 | while (readb(&i2c_dev[i2c_bus_num]->sr) & I2C_SR_MBB) { | |
82 | if (get_timer(timeval) > I2C_TIMEOUT) { | |
83 | return -1; | |
84 | } | |
85 | } | |
86 | ||
87 | return 0; | |
88 | } | |
89 | ||
90 | static __inline__ int | |
91 | i2c_wait(int write) | |
92 | { | |
93 | u32 csr; | |
94 | ulong timeval = get_timer(0); | |
95 | ||
96 | do { | |
97 | csr = readb(&i2c_dev[i2c_bus_num]->sr); | |
98 | if (!(csr & I2C_SR_MIF)) | |
99 | continue; | |
100 | ||
101 | writeb(0x0, &i2c_dev[i2c_bus_num]->sr); | |
102 | ||
103 | if (csr & I2C_SR_MAL) { | |
104 | debug("i2c_wait: MAL\n"); | |
105 | return -1; | |
106 | } | |
107 | ||
108 | if (!(csr & I2C_SR_MCF)) { | |
109 | debug("i2c_wait: unfinished\n"); | |
110 | return -1; | |
111 | } | |
112 | ||
113 | if (write == I2C_WRITE && (csr & I2C_SR_RXAK)) { | |
114 | debug("i2c_wait: No RXACK\n"); | |
115 | return -1; | |
116 | } | |
117 | ||
118 | return 0; | |
119 | } while (get_timer (timeval) < I2C_TIMEOUT); | |
120 | ||
121 | debug("i2c_wait: timed out\n"); | |
122 | return -1; | |
123 | } | |
124 | ||
125 | static __inline__ int | |
126 | i2c_write_addr (u8 dev, u8 dir, int rsta) | |
127 | { | |
128 | writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX | |
129 | | (rsta ? I2C_CR_RSTA : 0), | |
130 | &i2c_dev[i2c_bus_num]->cr); | |
131 | ||
132 | writeb((dev << 1) | dir, &i2c_dev[i2c_bus_num]->dr); | |
133 | ||
134 | if (i2c_wait(I2C_WRITE) < 0) | |
135 | return 0; | |
136 | ||
137 | return 1; | |
138 | } | |
139 | ||
140 | static __inline__ int | |
141 | __i2c_write(u8 *data, int length) | |
142 | { | |
143 | int i; | |
144 | ||
145 | writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX, | |
146 | &i2c_dev[i2c_bus_num]->cr); | |
147 | ||
148 | for (i = 0; i < length; i++) { | |
149 | writeb(data[i], &i2c_dev[i2c_bus_num]->dr); | |
150 | ||
151 | if (i2c_wait(I2C_WRITE) < 0) | |
152 | break; | |
153 | } | |
154 | ||
155 | return i; | |
156 | } | |
157 | ||
158 | static __inline__ int | |
159 | __i2c_read(u8 *data, int length) | |
160 | { | |
161 | int i; | |
162 | ||
163 | writeb(I2C_CR_MEN | I2C_CR_MSTA | ((length == 1) ? I2C_CR_TXAK : 0), | |
164 | &i2c_dev[i2c_bus_num]->cr); | |
165 | ||
166 | /* dummy read */ | |
167 | readb(&i2c_dev[i2c_bus_num]->dr); | |
168 | ||
169 | for (i = 0; i < length; i++) { | |
170 | if (i2c_wait(I2C_READ) < 0) | |
171 | break; | |
172 | ||
173 | /* Generate ack on last next to last byte */ | |
174 | if (i == length - 2) | |
175 | writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_TXAK, | |
176 | &i2c_dev[i2c_bus_num]->cr); | |
177 | ||
178 | /* Generate stop on last byte */ | |
179 | if (i == length - 1) | |
180 | writeb(I2C_CR_MEN | I2C_CR_TXAK, &i2c_dev[i2c_bus_num]->cr); | |
181 | ||
182 | data[i] = readb(&i2c_dev[i2c_bus_num]->dr); | |
183 | } | |
184 | ||
185 | return i; | |
186 | } | |
187 | ||
188 | int | |
189 | i2c_read(u8 dev, uint addr, int alen, u8 *data, int length) | |
190 | { | |
191 | int i = 0; | |
192 | u8 *a = (u8*)&addr; | |
193 | ||
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 | } | |
200 | ||
201 | writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr); | |
202 | ||
203 | if (i == length) | |
204 | return 0; | |
205 | ||
206 | return -1; | |
207 | } | |
208 | ||
209 | int | |
210 | i2c_write(u8 dev, uint addr, int alen, u8 *data, int length) | |
211 | { | |
212 | int i = 0; | |
213 | u8 *a = (u8*)&addr; | |
214 | ||
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 | } | |
220 | ||
221 | writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr); | |
222 | ||
223 | if (i == length) | |
224 | return 0; | |
225 | ||
226 | return -1; | |
227 | } | |
228 | ||
229 | int | |
230 | i2c_probe(uchar chip) | |
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 | ||
241 | return i2c_read(chip, 0, 1, (uchar *)&tmp, 1); | |
242 | } | |
243 | ||
244 | uchar | |
245 | i2c_reg_read(uchar i2c_addr, uchar reg) | |
246 | { | |
247 | uchar buf[1]; | |
248 | ||
249 | i2c_read(i2c_addr, reg, 1, buf, 1); | |
250 | ||
251 | return buf[0]; | |
252 | } | |
253 | ||
254 | void | |
255 | i2c_reg_write(uchar i2c_addr, uchar reg, uchar val) | |
256 | { | |
257 | i2c_write(i2c_addr, reg, 1, &val, 1); | |
258 | } | |
259 | ||
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 | } | |
289 | #endif /* CONFIG_HARD_I2C */ | |
290 | #endif /* CONFIG_FSL_I2C */ |