]>
Commit | Line | Data |
---|---|---|
43d9616c WD |
1 | /* |
2 | * (C) Copyright 2000 | |
3 | * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), [email protected] | |
4 | * | |
5 | * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
6 | * Marius Groeger <[email protected]> | |
7 | * | |
8 | * (C) Copyright 2003 Pengutronix e.K. | |
9 | * Robert Schwebel <[email protected]> | |
10 | * | |
3df619ec LW |
11 | * (C) Copyright 2011 Marvell Inc. |
12 | * Lei Wen <[email protected]> | |
13 | * | |
1a459660 | 14 | * SPDX-License-Identifier: GPL-2.0+ |
43d9616c WD |
15 | * |
16 | * Back ported to the 8xx platform (from the 8260 platform) by | |
17 | * [email protected], 27-Jan-01. | |
18 | */ | |
19 | ||
43d9616c | 20 | #include <common.h> |
3ba8bf7c | 21 | #include <asm/io.h> |
43d9616c WD |
22 | |
23 | #ifdef CONFIG_HARD_I2C | |
43d9616c | 24 | #include <i2c.h> |
3df619ec | 25 | #include "mv_i2c.h" |
43d9616c WD |
26 | |
27 | #ifdef DEBUG_I2C | |
28 | #define PRINTD(x) printf x | |
29 | #else | |
30 | #define PRINTD(x) | |
31 | #endif | |
32 | ||
43d9616c | 33 | /* All transfers are described by this data structure */ |
fffff726 | 34 | struct mv_i2c_msg { |
43d9616c | 35 | u8 condition; |
8bde7f77 WD |
36 | u8 acknack; |
37 | u8 direction; | |
43d9616c WD |
38 | u8 data; |
39 | }; | |
40 | ||
3df619ec LW |
41 | struct mv_i2c { |
42 | u32 ibmr; | |
43 | u32 pad0; | |
44 | u32 idbr; | |
45 | u32 pad1; | |
46 | u32 icr; | |
47 | u32 pad2; | |
48 | u32 isr; | |
49 | u32 pad3; | |
50 | u32 isar; | |
51 | }; | |
52 | ||
adb00bb6 | 53 | static struct mv_i2c *base; |
d308c9d3 LW |
54 | static void i2c_board_init(struct mv_i2c *base) |
55 | { | |
56 | #ifdef CONFIG_SYS_I2C_INIT_BOARD | |
57 | u32 icr; | |
58 | /* | |
59 | * call board specific i2c bus reset routine before accessing the | |
60 | * environment, which might be in a chip on that bus. For details | |
61 | * about this problem see doc/I2C_Edge_Conditions. | |
62 | * | |
63 | * disable I2C controller first, otherwhise it thinks we want to | |
64 | * talk to the slave port... | |
65 | */ | |
66 | icr = readl(&base->icr); | |
67 | writel(readl(&base->icr) & ~(ICR_SCLE | ICR_IUE), &base->icr); | |
68 | ||
69 | i2c_init_board(); | |
70 | ||
71 | writel(icr, &base->icr); | |
72 | #endif | |
73 | } | |
74 | ||
adb00bb6 | 75 | #ifdef CONFIG_I2C_MULTI_BUS |
e6fbc3e4 | 76 | static unsigned long i2c_regs[CONFIG_MV_I2C_NUM] = CONFIG_MV_I2C_REG; |
adb00bb6 LW |
77 | static unsigned int bus_initialized[CONFIG_MV_I2C_NUM]; |
78 | static unsigned int current_bus; | |
79 | ||
80 | int i2c_set_bus_num(unsigned int bus) | |
81 | { | |
82 | if ((bus < 0) || (bus >= CONFIG_MV_I2C_NUM)) { | |
83 | printf("Bad bus: %d\n", bus); | |
84 | return -1; | |
85 | } | |
86 | ||
87 | base = (struct mv_i2c *)i2c_regs[bus]; | |
88 | current_bus = bus; | |
89 | ||
90 | if (!bus_initialized[current_bus]) { | |
d308c9d3 | 91 | i2c_board_init(base); |
adb00bb6 LW |
92 | bus_initialized[current_bus] = 1; |
93 | } | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
98 | unsigned int i2c_get_bus_num(void) | |
99 | { | |
100 | return current_bus; | |
101 | } | |
102 | #endif | |
3df619ec | 103 | |
68432c27 | 104 | /* |
3df619ec | 105 | * i2c_reset: - reset the host controller |
43d9616c WD |
106 | * |
107 | */ | |
68432c27 | 108 | static void i2c_reset(void) |
43d9616c | 109 | { |
3df619ec LW |
110 | writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */ |
111 | writel(readl(&base->icr) | ICR_UR, &base->icr); /* reset the unit */ | |
8bde7f77 | 112 | udelay(100); |
3df619ec LW |
113 | writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */ |
114 | ||
115 | i2c_clk_enable(); | |
116 | ||
117 | writel(CONFIG_SYS_I2C_SLAVE, &base->isar); /* set our slave address */ | |
118 | writel(I2C_ICR_INIT, &base->icr); /* set control reg values */ | |
119 | writel(I2C_ISR_INIT, &base->isr); /* set clear interrupt bits */ | |
120 | writel(readl(&base->icr) | ICR_IUE, &base->icr); /* enable unit */ | |
8bde7f77 | 121 | udelay(100); |
43d9616c WD |
122 | } |
123 | ||
68432c27 | 124 | /* |
8bde7f77 | 125 | * i2c_isr_set_cleared: - wait until certain bits of the I2C status register |
43d9616c WD |
126 | * are set and cleared |
127 | * | |
ba70d6a4 | 128 | * @return: 1 in case of success, 0 means timeout (no match within 10 ms). |
43d9616c | 129 | */ |
68432c27 LW |
130 | static int i2c_isr_set_cleared(unsigned long set_mask, |
131 | unsigned long cleared_mask) | |
43d9616c | 132 | { |
3df619ec | 133 | int timeout = 1000, isr; |
43d9616c | 134 | |
3df619ec LW |
135 | do { |
136 | isr = readl(&base->isr); | |
68432c27 LW |
137 | udelay(10); |
138 | if (timeout-- < 0) | |
139 | return 0; | |
3df619ec LW |
140 | } while (((isr & set_mask) != set_mask) |
141 | || ((isr & cleared_mask) != 0)); | |
43d9616c | 142 | |
8bde7f77 | 143 | return 1; |
43d9616c WD |
144 | } |
145 | ||
68432c27 | 146 | /* |
43d9616c WD |
147 | * i2c_transfer: - Transfer one byte over the i2c bus |
148 | * | |
8bde7f77 WD |
149 | * This function can tranfer a byte over the i2c bus in both directions. |
150 | * It is used by the public API functions. | |
43d9616c WD |
151 | * |
152 | * @return: 0: transfer successful | |
153 | * -1: message is empty | |
154 | * -2: transmit timeout | |
155 | * -3: ACK missing | |
156 | * -4: receive timeout | |
157 | * -5: illegal parameters | |
158 | * -6: bus is busy and couldn't be aquired | |
8bde7f77 | 159 | */ |
fffff726 | 160 | int i2c_transfer(struct mv_i2c_msg *msg) |
43d9616c WD |
161 | { |
162 | int ret; | |
163 | ||
8bde7f77 | 164 | if (!msg) |
43d9616c WD |
165 | goto transfer_error_msg_empty; |
166 | ||
68432c27 | 167 | switch (msg->direction) { |
43d9616c | 168 | case I2C_WRITE: |
43d9616c | 169 | /* check if bus is not busy */ |
68432c27 | 170 | if (!i2c_isr_set_cleared(0, ISR_IBB)) |
43d9616c WD |
171 | goto transfer_error_bus_busy; |
172 | ||
173 | /* start transmission */ | |
3df619ec LW |
174 | writel(readl(&base->icr) & ~ICR_START, &base->icr); |
175 | writel(readl(&base->icr) & ~ICR_STOP, &base->icr); | |
176 | writel(msg->data, &base->idbr); | |
3ba8bf7c | 177 | if (msg->condition == I2C_COND_START) |
3df619ec | 178 | writel(readl(&base->icr) | ICR_START, &base->icr); |
3ba8bf7c | 179 | if (msg->condition == I2C_COND_STOP) |
3df619ec | 180 | writel(readl(&base->icr) | ICR_STOP, &base->icr); |
3ba8bf7c | 181 | if (msg->acknack == I2C_ACKNAK_SENDNAK) |
3df619ec | 182 | writel(readl(&base->icr) | ICR_ACKNAK, &base->icr); |
3ba8bf7c | 183 | if (msg->acknack == I2C_ACKNAK_SENDACK) |
3df619ec LW |
184 | writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr); |
185 | writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr); | |
186 | writel(readl(&base->icr) | ICR_TB, &base->icr); | |
43d9616c WD |
187 | |
188 | /* transmit register empty? */ | |
68432c27 | 189 | if (!i2c_isr_set_cleared(ISR_ITE, 0)) |
43d9616c WD |
190 | goto transfer_error_transmit_timeout; |
191 | ||
192 | /* clear 'transmit empty' state */ | |
3df619ec | 193 | writel(readl(&base->isr) | ISR_ITE, &base->isr); |
43d9616c WD |
194 | |
195 | /* wait for ACK from slave */ | |
196 | if (msg->acknack == I2C_ACKNAK_WAITACK) | |
68432c27 | 197 | if (!i2c_isr_set_cleared(0, ISR_ACKNAK)) |
43d9616c WD |
198 | goto transfer_error_ack_missing; |
199 | break; | |
200 | ||
201 | case I2C_READ: | |
202 | ||
203 | /* check if bus is not busy */ | |
68432c27 | 204 | if (!i2c_isr_set_cleared(0, ISR_IBB)) |
43d9616c WD |
205 | goto transfer_error_bus_busy; |
206 | ||
207 | /* start receive */ | |
3df619ec LW |
208 | writel(readl(&base->icr) & ~ICR_START, &base->icr); |
209 | writel(readl(&base->icr) & ~ICR_STOP, &base->icr); | |
3ba8bf7c | 210 | if (msg->condition == I2C_COND_START) |
3df619ec | 211 | writel(readl(&base->icr) | ICR_START, &base->icr); |
3ba8bf7c | 212 | if (msg->condition == I2C_COND_STOP) |
3df619ec | 213 | writel(readl(&base->icr) | ICR_STOP, &base->icr); |
3ba8bf7c | 214 | if (msg->acknack == I2C_ACKNAK_SENDNAK) |
3df619ec | 215 | writel(readl(&base->icr) | ICR_ACKNAK, &base->icr); |
3ba8bf7c | 216 | if (msg->acknack == I2C_ACKNAK_SENDACK) |
3df619ec LW |
217 | writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr); |
218 | writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr); | |
219 | writel(readl(&base->icr) | ICR_TB, &base->icr); | |
43d9616c WD |
220 | |
221 | /* receive register full? */ | |
68432c27 | 222 | if (!i2c_isr_set_cleared(ISR_IRF, 0)) |
8bde7f77 | 223 | goto transfer_error_receive_timeout; |
43d9616c | 224 | |
3df619ec | 225 | msg->data = readl(&base->idbr); |
43d9616c WD |
226 | |
227 | /* clear 'receive empty' state */ | |
3df619ec | 228 | writel(readl(&base->isr) | ISR_IRF, &base->isr); |
43d9616c | 229 | break; |
43d9616c | 230 | default: |
43d9616c | 231 | goto transfer_error_illegal_param; |
43d9616c WD |
232 | } |
233 | ||
8bde7f77 | 234 | return 0; |
43d9616c | 235 | |
8bde7f77 | 236 | transfer_error_msg_empty: |
43d9616c WD |
237 | PRINTD(("i2c_transfer: error: 'msg' is empty\n")); |
238 | ret = -1; goto i2c_transfer_finish; | |
239 | ||
240 | transfer_error_transmit_timeout: | |
241 | PRINTD(("i2c_transfer: error: transmit timeout\n")); | |
242 | ret = -2; goto i2c_transfer_finish; | |
243 | ||
244 | transfer_error_ack_missing: | |
245 | PRINTD(("i2c_transfer: error: ACK missing\n")); | |
246 | ret = -3; goto i2c_transfer_finish; | |
247 | ||
248 | transfer_error_receive_timeout: | |
249 | PRINTD(("i2c_transfer: error: receive timeout\n")); | |
250 | ret = -4; goto i2c_transfer_finish; | |
251 | ||
252 | transfer_error_illegal_param: | |
253 | PRINTD(("i2c_transfer: error: illegal parameters\n")); | |
254 | ret = -5; goto i2c_transfer_finish; | |
255 | ||
256 | transfer_error_bus_busy: | |
257 | PRINTD(("i2c_transfer: error: bus is busy\n")); | |
258 | ret = -6; goto i2c_transfer_finish; | |
259 | ||
260 | i2c_transfer_finish: | |
2be1ed34 | 261 | PRINTD(("i2c_transfer: ISR: 0x%04x\n", readl(&base->isr))); |
43d9616c WD |
262 | i2c_reset(); |
263 | return ret; | |
43d9616c WD |
264 | } |
265 | ||
266 | /* ------------------------------------------------------------------------ */ | |
267 | /* API Functions */ | |
268 | /* ------------------------------------------------------------------------ */ | |
43d9616c WD |
269 | void i2c_init(int speed, int slaveaddr) |
270 | { | |
adb00bb6 | 271 | #ifdef CONFIG_I2C_MULTI_BUS |
d308c9d3 | 272 | current_bus = 0; |
adb00bb6 LW |
273 | base = (struct mv_i2c *)i2c_regs[current_bus]; |
274 | #else | |
275 | base = (struct mv_i2c *)CONFIG_MV_I2C_REG; | |
276 | #endif | |
277 | ||
d308c9d3 | 278 | i2c_board_init(base); |
43d9616c WD |
279 | } |
280 | ||
68432c27 | 281 | /* |
43d9616c WD |
282 | * i2c_probe: - Test if a chip answers for a given i2c address |
283 | * | |
8bde7f77 | 284 | * @chip: address of the chip which is searched for |
53677ef1 | 285 | * @return: 0 if a chip was found, -1 otherwhise |
43d9616c | 286 | */ |
43d9616c WD |
287 | int i2c_probe(uchar chip) |
288 | { | |
fffff726 | 289 | struct mv_i2c_msg msg; |
43d9616c WD |
290 | |
291 | i2c_reset(); | |
292 | ||
293 | msg.condition = I2C_COND_START; | |
294 | msg.acknack = I2C_ACKNAK_WAITACK; | |
295 | msg.direction = I2C_WRITE; | |
296 | msg.data = (chip << 1) + 1; | |
68432c27 LW |
297 | if (i2c_transfer(&msg)) |
298 | return -1; | |
43d9616c WD |
299 | |
300 | msg.condition = I2C_COND_STOP; | |
301 | msg.acknack = I2C_ACKNAK_SENDNAK; | |
302 | msg.direction = I2C_READ; | |
303 | msg.data = 0x00; | |
68432c27 LW |
304 | if (i2c_transfer(&msg)) |
305 | return -1; | |
43d9616c WD |
306 | |
307 | return 0; | |
308 | } | |
309 | ||
68432c27 | 310 | /* |
43d9616c WD |
311 | * i2c_read: - Read multiple bytes from an i2c device |
312 | * | |
313 | * The higher level routines take into account that this function is only | |
8bde7f77 | 314 | * called with len < page length of the device (see configuration file) |
43d9616c WD |
315 | * |
316 | * @chip: address of the chip which is to be read | |
317 | * @addr: i2c data address within the chip | |
318 | * @alen: length of the i2c data address (1..2 bytes) | |
319 | * @buffer: where to write the data | |
320 | * @len: how much byte do we want to read | |
321 | * @return: 0 in case of success | |
322 | */ | |
43d9616c WD |
323 | int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) |
324 | { | |
fffff726 | 325 | struct mv_i2c_msg msg; |
43d9616c | 326 | u8 addr_bytes[3]; /* lowest...highest byte of data address */ |
43d9616c | 327 | |
68432c27 LW |
328 | PRINTD(("i2c_read(chip=0x%02x, addr=0x%02x, alen=0x%02x, " |
329 | "len=0x%02x)\n", chip, addr, alen, len)); | |
43d9616c WD |
330 | |
331 | i2c_reset(); | |
332 | ||
333 | /* dummy chip address write */ | |
334 | PRINTD(("i2c_read: dummy chip address write\n")); | |
335 | msg.condition = I2C_COND_START; | |
336 | msg.acknack = I2C_ACKNAK_WAITACK; | |
337 | msg.direction = I2C_WRITE; | |
68432c27 LW |
338 | msg.data = (chip << 1); |
339 | msg.data &= 0xFE; | |
340 | if (i2c_transfer(&msg)) | |
341 | return -1; | |
8bde7f77 | 342 | |
43d9616c | 343 | /* |
8bde7f77 WD |
344 | * send memory address bytes; |
345 | * alen defines how much bytes we have to send. | |
43d9616c | 346 | */ |
6d0f6bcf | 347 | /*addr &= ((1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS)-1); */ |
43d9616c WD |
348 | addr_bytes[0] = (u8)((addr >> 0) & 0x000000FF); |
349 | addr_bytes[1] = (u8)((addr >> 8) & 0x000000FF); | |
350 | addr_bytes[2] = (u8)((addr >> 16) & 0x000000FF); | |
351 | ||
352 | while (--alen >= 0) { | |
68432c27 | 353 | PRINTD(("i2c_read: send memory word address byte %1d\n", alen)); |
43d9616c WD |
354 | msg.condition = I2C_COND_NORMAL; |
355 | msg.acknack = I2C_ACKNAK_WAITACK; | |
356 | msg.direction = I2C_WRITE; | |
357 | msg.data = addr_bytes[alen]; | |
68432c27 LW |
358 | if (i2c_transfer(&msg)) |
359 | return -1; | |
43d9616c | 360 | } |
8bde7f77 | 361 | |
43d9616c WD |
362 | /* start read sequence */ |
363 | PRINTD(("i2c_read: start read sequence\n")); | |
364 | msg.condition = I2C_COND_START; | |
365 | msg.acknack = I2C_ACKNAK_WAITACK; | |
366 | msg.direction = I2C_WRITE; | |
367 | msg.data = (chip << 1); | |
368 | msg.data |= 0x01; | |
68432c27 LW |
369 | if (i2c_transfer(&msg)) |
370 | return -1; | |
43d9616c WD |
371 | |
372 | /* read bytes; send NACK at last byte */ | |
373 | while (len--) { | |
68432c27 | 374 | if (len == 0) { |
43d9616c WD |
375 | msg.condition = I2C_COND_STOP; |
376 | msg.acknack = I2C_ACKNAK_SENDNAK; | |
377 | } else { | |
378 | msg.condition = I2C_COND_NORMAL; | |
379 | msg.acknack = I2C_ACKNAK_SENDACK; | |
380 | } | |
381 | ||
382 | msg.direction = I2C_READ; | |
383 | msg.data = 0x00; | |
68432c27 LW |
384 | if (i2c_transfer(&msg)) |
385 | return -1; | |
43d9616c | 386 | |
ba70d6a4 | 387 | *buffer = msg.data; |
68432c27 LW |
388 | PRINTD(("i2c_read: reading byte (0x%08x)=0x%02x\n", |
389 | (unsigned int)buffer, *buffer)); | |
ba70d6a4 | 390 | buffer++; |
43d9616c WD |
391 | } |
392 | ||
393 | i2c_reset(); | |
394 | ||
395 | return 0; | |
396 | } | |
397 | ||
68432c27 | 398 | /* |
43d9616c WD |
399 | * i2c_write: - Write multiple bytes to an i2c device |
400 | * | |
401 | * The higher level routines take into account that this function is only | |
8bde7f77 | 402 | * called with len < page length of the device (see configuration file) |
43d9616c WD |
403 | * |
404 | * @chip: address of the chip which is to be written | |
405 | * @addr: i2c data address within the chip | |
406 | * @alen: length of the i2c data address (1..2 bytes) | |
8bde7f77 | 407 | * @buffer: where to find the data to be written |
43d9616c WD |
408 | * @len: how much byte do we want to read |
409 | * @return: 0 in case of success | |
410 | */ | |
43d9616c WD |
411 | int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) |
412 | { | |
fffff726 | 413 | struct mv_i2c_msg msg; |
43d9616c WD |
414 | u8 addr_bytes[3]; /* lowest...highest byte of data address */ |
415 | ||
68432c27 LW |
416 | PRINTD(("i2c_write(chip=0x%02x, addr=0x%02x, alen=0x%02x, " |
417 | "len=0x%02x)\n", chip, addr, alen, len)); | |
43d9616c WD |
418 | |
419 | i2c_reset(); | |
420 | ||
421 | /* chip address write */ | |
422 | PRINTD(("i2c_write: chip address write\n")); | |
423 | msg.condition = I2C_COND_START; | |
424 | msg.acknack = I2C_ACKNAK_WAITACK; | |
425 | msg.direction = I2C_WRITE; | |
68432c27 LW |
426 | msg.data = (chip << 1); |
427 | msg.data &= 0xFE; | |
428 | if (i2c_transfer(&msg)) | |
429 | return -1; | |
8bde7f77 | 430 | |
43d9616c | 431 | /* |
8bde7f77 WD |
432 | * send memory address bytes; |
433 | * alen defines how much bytes we have to send. | |
43d9616c WD |
434 | */ |
435 | addr_bytes[0] = (u8)((addr >> 0) & 0x000000FF); | |
436 | addr_bytes[1] = (u8)((addr >> 8) & 0x000000FF); | |
437 | addr_bytes[2] = (u8)((addr >> 16) & 0x000000FF); | |
438 | ||
439 | while (--alen >= 0) { | |
43d9616c WD |
440 | PRINTD(("i2c_write: send memory word address\n")); |
441 | msg.condition = I2C_COND_NORMAL; | |
442 | msg.acknack = I2C_ACKNAK_WAITACK; | |
443 | msg.direction = I2C_WRITE; | |
444 | msg.data = addr_bytes[alen]; | |
68432c27 LW |
445 | if (i2c_transfer(&msg)) |
446 | return -1; | |
43d9616c | 447 | } |
8bde7f77 | 448 | |
43d9616c WD |
449 | /* write bytes; send NACK at last byte */ |
450 | while (len--) { | |
68432c27 LW |
451 | PRINTD(("i2c_write: writing byte (0x%08x)=0x%02x\n", |
452 | (unsigned int)buffer, *buffer)); | |
43d9616c | 453 | |
68432c27 | 454 | if (len == 0) |
43d9616c WD |
455 | msg.condition = I2C_COND_STOP; |
456 | else | |
457 | msg.condition = I2C_COND_NORMAL; | |
458 | ||
459 | msg.acknack = I2C_ACKNAK_WAITACK; | |
460 | msg.direction = I2C_WRITE; | |
461 | msg.data = *(buffer++); | |
8bde7f77 | 462 | |
68432c27 LW |
463 | if (i2c_transfer(&msg)) |
464 | return -1; | |
43d9616c WD |
465 | } |
466 | ||
467 | i2c_reset(); | |
468 | ||
469 | return 0; | |
43d9616c | 470 | } |
43d9616c | 471 | #endif /* CONFIG_HARD_I2C */ |