unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / devs / i2c / arm / mxc / v2_0 / src / mxc_i2c.c
1 //==========================================================================
2 //
3 //      mxc_i2c.c
4 //
5 //      I2C support on Freescale MXC platforms
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41
42 #include <redboot.h>
43 #include <stdlib.h>
44 #include <pkgconf/hal.h>
45 #include <cyg/hal/hal_arch.h>
46 #include <cyg/hal/hal_cache.h>
47 #include <cyg/hal/hal_io.h>
48
49 #include <cyg/hal/fsl_board.h>
50 #include <cyg/io/mxc_i2c.h>
51
52 extern void mxc_i2c_init(unsigned int module_base);
53
54 //#define MXC_I2C_DEBUG
55 #undef MXC_I2C_DEBUG
56
57 #ifdef MXC_I2C_DEBUG
58 #define diag_printf1    diag_printf
59 #else
60 #define diag_printf1(fmt,args...)
61 #endif
62
63 struct clk_div_table {
64         int reg_value;
65         int div;
66 };
67
68 static const struct clk_div_table i2c_clk_table[] = {
69         {0x20, 22}, {0x21, 24}, {0x22, 26}, {0x23, 28},
70         {0, 30}, {1, 32}, {0x24, 32}, {2, 36},
71         {0x25, 36}, {0x26, 40}, {3, 42}, {0x27, 44},
72         {4, 48}, {0x28, 48}, {5, 52}, {0x29, 56},
73         {6, 60}, {0x2A, 64}, {7, 72}, {0x2B, 72},
74         {8, 80}, {0x2C, 80}, {9, 88}, {0x2D, 96},
75         {0xA, 104}, {0x2E, 112}, {0xB, 128}, {0x2F, 128},
76         {0xC, 144}, {0xD, 160}, {0x30, 160}, {0xE, 192},
77         {0x31, 192}, {0x32, 224}, {0xF, 240}, {0x33, 256},
78         {0x10, 288}, {0x11, 320}, {0x34, 320}, {0x12, 384},
79         {0x35, 384}, {0x36, 448}, {0x13, 480}, {0x37, 512},
80         {0x14, 576}, {0x15, 640}, {0x38, 640}, {0x16, 768},
81         {0x39, 768}, {0x3A, 896}, {0x17, 960}, {0x3B, 1024},
82         {0x18, 1152}, {0x19, 1280}, {0x3C, 1280}, {0x1A, 1536},
83         {0x3D, 1536}, {0x3E, 1792}, {0x1B, 1920}, {0x3F, 2048},
84         {0x1C, 2304}, {0x1D, 2560}, {0x1E, 3072}, {0x1F, 3840},
85         {0, 0}
86 };
87
88 #define ERR_TX              -1
89 #define ERR_RX              -2
90 #define ERR_ARB_LOST    -3
91 #define ERR_NO_ACK          -4
92 #define ERR_XFER            -5
93 #define ERR_RX_ACK      -6
94
95 static inline int wait_till_busy(unsigned int base)
96 {
97     int i = 10000;
98
99     while(((readw(base + I2C_I2SR) & I2C_I2SR_IBB) == 0) && (--i > 0)) {
100         if (readw(base + I2C_I2SR) & I2C_I2SR_IAL) {
101             diag_printf1("Error: arbitration lost!\n");
102             return ERR_ARB_LOST;
103         }
104     }
105
106     if (i <= 0) {
107         return -1;
108     }
109
110     return 0;
111 }
112
113 static unsigned int g_dev_addr_width, g_dev_data_width;
114 static unsigned char g_dev_value[4];
115 static unsigned int g_i2c_nr = -1;
116
117 static inline int is_bus_free(unsigned int base)
118 {
119     return ((readw(base + I2C_I2SR) & I2C_I2SR_IBB) == 0);
120 }
121
122 #define ASSERT_NO_ARBITRATION_LOST(stat)  \
123 { \
124         if (stat & I2C_I2SR_IAL) { \
125                 diag_printf("Error %d: Arbitration lost\n", __LINE__); \
126                 return ERR_ARB_LOST; \
127         } \
128 }
129
130 #define WAIT_RXAK_LOOPS     1000000
131
132 static inline unsigned short wait_op_done(unsigned int base, int is_tx)
133 {
134     volatile unsigned short v;
135     int i = WAIT_RXAK_LOOPS;
136
137     while ((((v = readw(base + I2C_I2SR)) & I2C_I2SR_IIF) == 0 ||
138            (v & I2C_I2SR_ICF) == 0) && --i > 0) {
139         if (v & I2C_I2SR_IAL) {
140             diag_printf1("Error %d: Arbitration lost\n", __LINE__);
141             return ERR_ARB_LOST;
142         }
143
144     }
145     if (i <= 0) {
146         diag_printf1("I2C Error: timeout unexpected\n");
147         return -1;
148     }
149     if (is_tx) {
150         if (v & I2C_I2SR_IAL) {
151             diag_printf1("Error %d: Arbitration lost\n", __LINE__);
152             return ERR_ARB_LOST;
153         }
154         if (v & I2C_I2SR_RXAK) {
155             diag_printf1("Error %d: no ack received\n", __LINE__);
156             return -1;
157         }
158     }
159     return 0;
160 }
161
162 //
163 // For master TX, always expect a RXAK signal to be set!
164 static int tx_byte(unsigned char *data, unsigned int base)
165 {
166     diag_printf1("%s(data=0x%02x, base=0x%x)\n", __FUNCTION__, *data, base);
167
168     // clear both IAL and IIF bits
169     writew(0, base + I2C_I2SR);
170
171     writew(*data, base + I2C_I2DR);
172     
173     if (wait_op_done(base, 1) != 0)
174         return -1;
175
176     return 0;
177 }
178
179 // For master RX
180 static int rx_bytes(unsigned char *data, unsigned int base, int sz)
181 {
182     unsigned short i2cr;
183     int i;
184
185     for (i = 0; sz > 0; sz--, i++) {
186         if (wait_op_done(base, 0) != 0)
187             return -1;
188
189         // clear both IAL and IIF bits
190         writew(0, base + I2C_I2SR);
191
192         // the next two if-statements setup for the next read control register value
193         if (sz == 1) {
194             // last byte --> generate STOP
195             i2cr = readw(base + I2C_I2CR);
196             writew(i2cr & ~(I2C_I2CR_MSTA | I2C_I2CR_MTX), base + I2C_I2CR);
197         }
198         if (sz == 2) {
199             // 2nd last byte --> set TXAK bit to NOT generate ACK
200             i2cr = readw(base + I2C_I2CR);
201             writew(i2cr | I2C_I2CR_TXAK, base + I2C_I2CR);
202         }
203
204         // read the true data
205         data[i] = readw(base + I2C_I2DR);
206         diag_printf1("OK 0x%02x\n", data[i]);
207     }
208     return 0;
209 }
210
211 int i2c_xfer(unsigned int i2c_nr, struct mxc_i2c_request *rq, int dir)
212 {
213     unsigned int base, reg;
214     unsigned char i, data;
215     unsigned short i2cr;
216     int ret = 0;
217     
218     if ( rq == NULL || i2c_nr >= i2c_num) {
219         diag_printf("Invalid request or invalid i2c port number\n");
220         return -1;
221     } 
222
223     base = i2c_base_addr[i2c_nr];
224     if (rq->reg_addr_sz == 0 || rq->buffer_sz == 0 || rq->buffer == NULL) {
225         diag_printf("Invalid register address size=%x, buffer size=%x, buffer=%x\n",
226                     rq->reg_addr_sz, rq->buffer_sz, (unsigned int)rq->buffer);
227         return -1;
228     }
229
230     // reset and enable I2C
231     writew(0, base + I2C_I2CR);
232
233     writew(I2C_I2CR_IEN, base + I2C_I2CR);
234
235     /* Need wait at least 2 cycles of per_clk*/
236     for (i = 0; i < 16; i++) {
237         asm("nop");
238     }
239     // Step 1: generate START signal
240     // 1.1 make sure bus is free
241     if (!is_bus_free(base)) {
242         return -1;
243     }
244     // 1.2 clear both IAL and IIF bits
245     writew(0, base + I2C_I2SR);
246
247     // 1.3 assert START signal and also indicate TX mode
248     i2cr = I2C_I2CR_IEN | I2C_I2CR_MSTA | I2C_I2CR_MTX;
249     writew(i2cr, base + I2C_I2CR);
250
251     // 1.4 make sure bus is busy after the START signal
252     if (wait_till_busy(base) != 0) {
253         return ERR_TX;
254     }
255
256     // Step 2: send slave address + read/write at the LSB
257     data = (rq->dev_addr << 1) | I2C_WRITE;
258     if (tx_byte(&data, base) != 0) {
259         return -1;
260     }
261
262     // Step 3: send I2C device register address
263     if (rq->reg_addr_sz > 4) {
264         diag_printf("Warning register address size %d should less than 4\n",
265                             rq->reg_addr_sz);
266         rq->reg_addr_sz = 4;
267     }
268     reg = rq->reg_addr;
269
270     for (i = 0; i <  rq->reg_addr_sz; i++, reg>>=8) {
271         data = reg & 0xFF;
272         diag_printf1("sending I2C=0x%x device register: data=0x%x, byte %d\n",
273                      base, data, i);
274         if (tx_byte(&data, base) != 0) {
275             return -1;
276         }
277     }
278     // Step 4: read/write data
279     if (dir == I2C_READ) {
280         // do repeat-start
281         i2cr = readw(base + I2C_I2CR);
282         writew(i2cr | I2C_I2CR_RSTA, base + I2C_I2CR);
283
284         // send slave address again, but indicate read operation
285         data = (rq->dev_addr << 1) | I2C_READ;
286         if (tx_byte(&data, base) != 0) {
287             return -1;
288         }
289
290         // change to receive mode
291         i2cr = readw(base + I2C_I2CR);
292         if (rq->buffer_sz == 1) {
293             // if only one byte to read, make sure don't send ack
294             i2cr |= I2C_I2CR_TXAK;
295         }
296         writew(i2cr & ~I2C_I2CR_MTX, base + I2C_I2CR);
297         // dummy read
298         readw(base + I2C_I2DR);
299
300         // now reading ...
301         if (rx_bytes(rq->buffer, base, rq->buffer_sz) != 0) {
302             return -1;
303         }
304     } else {
305         // I2C_WRITE
306         for (i = 0; i < rq->buffer_sz; i++) {
307             // send device register value
308             data = rq->buffer[i];
309             if ((ret = tx_byte(&data, base)) != 0) {
310                 break;
311             }
312         }
313         // generate STOP by clearing MSTA bit
314         writew(I2C_I2CR_IEN | I2C_I2CR_MTX, base + I2C_I2CR);
315     }
316
317     return ret;
318 }
319
320 /*!
321  * Initialize and enable a i2c module -- mainly enable the I2C clock, module
322  * itself and the I2C clock prescaler.
323  *
324  * @param   base        base address of i2c module (also assigned for I2Cx_CLK)
325  * @param   baue        the desired data rate
326  *
327  * @return              0 if successful; non-zero otherwise
328  */
329 int i2c_init(unsigned int base, unsigned int baud)
330 {
331     unsigned int clock = get_main_clock(IPG_PER_CLK);
332     int div = clock / baud;
333     struct clk_div_table *p = (struct clk_div_table *)&i2c_clk_table[0];
334
335     mxc_i2c_init(base);
336
337     // reset and enable I2C
338     writew(0, base + I2C_I2CR);
339     writew(I2C_I2CR_IEN, base + I2C_I2CR);
340
341     while (p->div != 0) {
342         if (div <= p->div)
343             break;
344         p++;
345     }
346     
347     if (p->div == 0) {
348         diag_printf("Error: can't meet I2C baud rate request (%d) for 0x%x)\n",
349                     baud, base);
350         return -1;
351     }
352
353     diag_printf1("baud=%d, div=%d, reg_val=%d\n", baud, p->div, p->reg_value);
354
355     writew(p->reg_value, base + I2C_IFDR);
356
357     diag_printf1("requested data rate is: %d, actual rate is: %d\n",
358                  baud, clock / p->div);
359
360     return 0;
361 }
362
363 static void do_i2c(int argc, char *argv[]);
364 RedBoot_cmd("i2c",
365             "i2c R/W operations as master",
366             "<i2c slave addr> <register index> [<regisetr val>]]",
367             do_i2c
368            );
369
370
371 static void do_i2c(int argc,char *argv[])
372 {
373     int dir = I2C_READ, i;
374     unsigned long v;
375     unsigned long dev_addr, dev_reg;
376     struct mxc_i2c_request rq;
377  
378     if (g_i2c_nr == -1) {
379         diag_printf("I2C module [%d] not initialized. Issue i2c_init first\n\n", g_i2c_nr);
380         return;
381     }
382     if (argc == 1) {
383         diag_printf("\tRead:  i2c <i2c_dev_addr> <dev_reg_addr>\n");
384         diag_printf("\tWrite: i2c <i2c_dev_addr> <dev_reg_addr> <dev_reg_val>\n");
385         return;
386     }
387
388     if (!parse_num(argv[1], &dev_addr, &argv[1], ":")) {
389         diag_printf("Error: Invalid parameter %d\n", __LINE__);
390         return;
391     }
392
393     if (!parse_num(argv[2], &dev_reg, &argv[2], ":")) {
394         diag_printf("Error: Invalid parameter %d\n", __LINE__);
395         return;
396     }
397
398     if (argc == 4) {
399         if (!parse_num(argv[3], &v, &argv[3], ":")) {
400             diag_printf("Error: Invalid parameter\n");
401             return;
402         }
403         dir = I2C_WRITE;
404         diag_printf("Writing I2C[%d] for addr 0x%x register 0x%x with value 0x%08lx\n",
405                     g_i2c_nr, dev_addr, dev_reg, v);
406         for (i = 0; i < g_dev_data_width; i++) {
407             g_dev_value[i] = v >> (8 * (g_dev_data_width - i - 1)) & 0xff;
408         }
409         diag_printf1("testing reversed data: 0x%08x\n", *(unsigned int*)g_dev_value);
410
411     } else {
412         diag_printf("Reading I2C [%d] from slave addr [0x%x] register [0x%x]\n",
413                     g_i2c_nr, dev_addr,  dev_reg);
414     }
415
416     rq.dev_addr = dev_addr;
417     rq.reg_addr = dev_reg;
418     rq.reg_addr_sz = g_dev_addr_width;
419     rq.buffer = g_dev_value;
420     rq.buffer_sz = g_dev_data_width;
421
422     if (i2c_xfer(g_i2c_nr, &rq, dir) != 0) {
423         diag_printf("Error I2C transfer 1\n\n");
424         return;
425     }
426
427     if (dir == I2C_READ) {
428         diag_printf("--->  ");
429         for (i = 0; i < g_dev_data_width; i++) {
430             diag_printf("0x%02x ", g_dev_value[i]);
431         }
432         diag_printf("\n\n");
433     }
434 }
435
436 static void do_i2c_init(int argc, char *argv[]);
437 RedBoot_cmd("i2c_init",
438             "Initialize i2c (i2c_num is 0-indexed)",
439             "<i2c_num> <frequency> <device addr width> <device reg width>",
440             do_i2c_init
441            );
442
443 static void do_i2c_init(int argc, char *argv[])
444 {
445     unsigned freq;
446
447     if (argc == 1 || argc != 5) {
448         diag_printf("\ni2c_init <i2c_num> <frequency> <device addr width> <device data width>\n\n");
449         return;
450     }
451
452     if (!parse_num(argv[1], (unsigned long *)&g_i2c_nr, &argv[1], ":")) {
453         diag_printf("Error: Invalid parameter\n");
454         return;
455     }
456     
457     if (g_i2c_nr > i2c_num - 1) {
458         diag_printf("invalide i2c number: %d, max number is: %d\n", g_i2c_nr, i2c_num - 1);
459         return;
460     }
461     diag_printf1("i2c max number is: %d\n", i2c_num - 1);
462
463     if (!parse_num(argv[2], (unsigned long *)&freq, &argv[2], ":")) {
464         diag_printf("Error: Invalid parameter\n");
465         return;
466     }
467     if (!parse_num(argv[3], (unsigned long *)&g_dev_addr_width, &argv[3], ":")) {
468         diag_printf("Error: Invalid parameter\n");
469         return;
470     }
471     if (!parse_num(argv[4], (unsigned long *)&g_dev_data_width, &argv[4], ":")) {
472         diag_printf("Error: Invalid parameter\n");
473         return;
474     }
475
476     i2c_init(i2c_base_addr[g_i2c_nr], freq);
477     
478     diag_printf("initializing i2c:%d, addr-width:%d, data-width:%d\n\n",
479                 g_i2c_nr, g_dev_addr_width, g_dev_data_width);
480 }