]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/mpc85xx/i2c.c
* Patches by Xianghua Xiao, 15 Oct 2003:
[karo-tx-uboot.git] / cpu / mpc85xx / i2c.c
1 /*
2  * (C) Copyright 2003,Motorola Inc.
3  * Xianghua Xiao <x.xiao@motorola.com>
4  * Adapted for Motorola 85xx chip.
5  *
6  * (C) Copyright 2003
7  * Gleb Natapov <gnatapov@mrv.com>
8  * Some bits are taken from linux driver writen by adrian@humboldt.co.uk
9  *
10  * Hardware I2C driver for MPC107 PCI bridge.
11  *
12  * See file CREDITS for list of people who contributed to this
13  * project.
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License as
17  * published by the Free Software Foundation; either version 2 of
18  * the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28  * MA 02111-1307 USA
29  */
30
31 #include <common.h>
32 #include <command.h>
33
34 #define DEBUG
35
36 #if defined(DEBUG)
37 #define DEB(x)      x
38 #else
39 #define DEB(x)
40 #endif
41
42 #ifdef CONFIG_HARD_I2C
43 #include <i2c.h>
44
45 #define TIMEOUT (CFG_HZ/4)
46
47 #define I2C_Addr ((unsigned *)(CFG_CCSRBAR + 0x3000))
48
49 #define I2CADR  &I2C_Addr[0]
50 #define I2CFDR  &I2C_Addr[1]
51 #define I2CCCR  &I2C_Addr[2]
52 #define I2CCSR  &I2C_Addr[3]
53 #define I2CCDR  &I2C_Addr[4]
54 #define I2CDFSRR &I2C_Addr[5]
55
56 #define I2C_READ  1
57 #define I2C_WRITE 0
58
59 /* taken from linux include/asm-ppc/io.h */
60 inline unsigned in_le32(volatile unsigned *addr)
61 {
62   unsigned ret;
63
64   __asm__ __volatile__("lwbrx %0,0,%1;\n"
65                        "twi 0,%0,0;\n"
66                        "isync" : "=r" (ret) :
67                        "r" (addr), "m" (*addr));
68   return ret;
69 }
70
71 inline void out_le32(volatile unsigned *addr, int val)
72 {
73   __asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
74                        "r" (val), "r" (addr));
75 }
76
77 #define writel(val, addr) out_le32(addr, val)
78 #define readl(addr) in_le32(addr)
79
80 void
81 i2c_init(int speed, int slaveadd)
82 {
83   /* stop I2C controller */
84   writel (0x0, I2CCCR);
85   /* set clock */
86   writel (0x3f, I2CFDR);
87   /* set default filter */
88   writel (0x10,I2CDFSRR);
89   /* write slave address */
90   writel (slaveadd, I2CADR);
91   /* clear status register */
92   writel (0x0, I2CCSR);
93   /* start I2C controller */
94   writel (MPC85xx_I2CCR_MEN, I2CCCR);
95 }
96
97 static __inline__ int
98 i2c_wait4bus (void)
99 {
100   ulong timeval = get_timer (0);
101
102   while (readl (I2CCSR) & MPC85xx_I2CSR_MBB)
103     if (get_timer (timeval) > TIMEOUT)
104       return -1;
105
106   return 0;
107 }
108
109 static __inline__ int
110 i2c_wait (int write)
111 {
112   u32 csr;
113   ulong timeval = get_timer (0);
114
115   do
116     {
117       csr  = readl (I2CCSR);
118
119       if (!(csr & MPC85xx_I2CSR_MIF))
120         continue;
121
122       writel (0x0, I2CCSR);
123
124       if (csr & MPC85xx_I2CSR_MAL)
125         {
126           DEB(printf ("i2c_wait: MAL\n"));
127           return -1;
128         }
129
130       if (!(csr & MPC85xx_I2CSR_MCF))
131         {
132           DEB(printf ("i2c_wait: unfinished\n"));
133           return -1;
134         }
135
136       if (write == I2C_WRITE && (csr & MPC85xx_I2CSR_RXAK))
137         {
138           DEB(printf ("i2c_wait: No RXACK\n"));
139           return -1;
140         }
141
142       return 0;
143     } while (get_timer (timeval) < TIMEOUT);
144
145   DEB(printf ("i2c_wait: timed out\n"));
146   return -1;
147 }
148
149 static __inline__ int
150 i2c_write_addr (u8 dev, u8 dir, int rsta)
151 {
152   writel (MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | MPC85xx_I2CCR_MTX |
153           (rsta?MPC85xx_I2CCR_RSTA:0), I2CCCR);
154
155   writel ((dev << 1) | dir, I2CCDR);
156
157   if (i2c_wait (I2C_WRITE) < 0)
158     return 0;
159
160   return 1;
161 }
162
163 static __inline__ int
164 __i2c_write (u8 *data, int length)
165 {
166   int i;
167
168   writel (MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA | MPC85xx_I2CCR_MTX, I2CCCR);
169
170   for (i=0; i < length; i++)
171     {
172       writel (data[i], I2CCDR);
173
174       if (i2c_wait (I2C_WRITE) < 0)
175         break;
176     }
177
178   return i;
179 }
180
181 static __inline__ int
182 __i2c_read (u8 *data, int length)
183 {
184   int i;
185
186   writel (MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA |
187           ((length == 1) ? MPC85xx_I2CCR_TXAK : 0), I2CCCR);
188
189   /* dummy read */
190   readl (I2CCDR);
191
192   for (i=0; i < length; i++)
193     {
194       if (i2c_wait (I2C_READ) < 0)
195         break;
196
197       /* Generate ack on last next to last byte */
198       if (i == length - 2)
199         writel (MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_MSTA |
200                 MPC85xx_I2CCR_TXAK, I2CCCR);
201
202       /* Generate stop on last byte */
203       if (i == length - 1)
204         writel (MPC85xx_I2CCR_MEN | MPC85xx_I2CCR_TXAK, I2CCCR);
205
206       data[i] = readl (I2CCDR);
207     }
208
209   return i;
210 }
211
212 int
213 i2c_read (u8 dev, uint addr, int alen, u8 *data, int length)
214 {
215   int i = 0;
216   u8 *a = (u8*)&addr;
217
218   if (i2c_wait4bus () < 0)
219     goto exit;
220
221   if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
222     goto exit;
223
224   if (__i2c_write (&a[4 - alen], alen) != alen)
225     goto exit;
226
227   if (i2c_write_addr (dev, I2C_READ, 1) == 0)
228     goto exit;
229
230   i = __i2c_read (data, length);
231
232  exit:
233   writel (MPC85xx_I2CCR_MEN, I2CCCR);
234
235   return !(i == length);
236 }
237
238 int
239 i2c_write (u8 dev, uint addr, int alen, u8 *data, int length)
240 {
241   int i = 0;
242   u8 *a = (u8*)&addr;
243
244   if (i2c_wait4bus () < 0)
245     goto exit;
246
247   if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
248     goto exit;
249
250   if (__i2c_write (&a[4 - alen], alen) != alen)
251     goto exit;
252
253   i = __i2c_write (data, length);
254
255  exit:
256   writel (MPC85xx_I2CCR_MEN, I2CCCR);
257
258   return !(i == length);
259 }
260
261 int i2c_probe (uchar chip)
262 {
263         int tmp;
264
265         /*
266          * Try to read the first location of the chip.  The underlying
267          * driver doesn't appear to support sending just the chip address
268          * and looking for an <ACK> back.
269          */
270         udelay(10000);
271         return i2c_read (chip, 0, 1, (char *)&tmp, 1);
272 }
273
274 uchar i2c_reg_read (uchar i2c_addr, uchar reg)
275 {
276         char buf[1];
277
278         i2c_read (i2c_addr, reg, 1, buf, 1);
279
280         return (buf[0]);
281 }
282
283 void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val)
284 {
285         i2c_write (i2c_addr, reg, 1, &val, 1);
286 }
287
288 #endif /* CONFIG_HARD_I2C */