Merge branch 'master' of git://git.denx.de/u-boot-arm
[platform/kernel/u-boot.git] / drivers / i2c / s3c44b0_i2c.c
1 /*
2  * (C) Copyright 2004
3  * DAVE Srl
4  * http://www.dave-tech.it
5  * http://www.wawnet.biz
6  * mailto:info@wawnet.biz
7  *
8  * See file CREDITS for list of people who contributed to this
9  * project.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24  * MA 02111-1307 USA
25  */
26
27 #include <common.h>
28 #include <command.h>
29 #include <asm/hardware.h>
30
31 /*
32  * Initialization, must be called once on start up, may be called
33  * repeatedly to change the speed and slave addresses.
34  */
35 void i2c_init(int speed, int slaveaddr)
36 {
37         /*
38                 setting up I2C support
39         */
40         unsigned int save_F,save_PF,rIICCON,rPCONA,rPDATA,rPCONF,rPUPF;
41
42         save_F = PCONF;
43         save_PF = PUPF;
44
45         rPCONF = ((save_F & ~(0xF))| 0xa);
46         rPUPF = (save_PF | 0x3);
47         PCONF = rPCONF; /*PF0:IICSCL, PF1:IICSDA*/
48         PUPF = rPUPF; /* Disable pull-up */
49
50         /* Configuring pin for WC pin of EEprom */
51         rPCONA = PCONA;
52         rPCONA &= ~(1<<9);
53         PCONA = rPCONA;
54
55         rPDATA = PDATA;
56         rPDATA &= ~(1<<9);
57         PDATA = rPDATA;
58
59         /*
60                 Enable ACK, IICCLK=MCLK/16, enable interrupt
61                 75MHz/16/(12+1) = 390625 Hz
62         */
63         rIICCON=(1<<7)|(0<<6)|(1<<5)|(0xC);
64         IICCON = rIICCON;
65
66         IICADD = slaveaddr;
67 }
68
69 /*
70  * Probe the given I2C chip address.  Returns 0 if a chip responded,
71  * not 0 on failure.
72  */
73 int i2c_probe(uchar chip)
74 {
75         /*
76                 not implemented
77         */
78
79         printf("i2c_probe chip %d\n", (int) chip);
80         return -1;
81 }
82
83 /*
84  * Read/Write interface:
85  *   chip:    I2C chip address, range 0..127
86  *   addr:    Memory (register) address within the chip
87  *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
88  *              memories, 0 for register type devices with only one
89  *              register)
90  *   buffer:  Where to read/write the data
91  *   len:     How many bytes to read/write
92  *
93  *   Returns: 0 on success, not 0 on failure
94  */
95
96 #define S3C44B0X_rIIC_INTPEND               (1<<4)
97 #define S3C44B0X_rIIC_LAST_RECEIV_BIT       (1<<0)
98 #define S3C44B0X_rIIC_INTERRUPT_ENABLE      (1<<5)
99 #define S3C44B0_IIC_TIMEOUT 100
100
101 int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
102 {
103
104         int k, j, temp;
105         u32 rIICSTAT;
106
107         /*
108                 send the device offset
109         */
110
111         rIICSTAT = 0xD0;
112         IICSTAT = rIICSTAT;
113
114         IICDS = chip;   /* this is a write operation... */
115
116         rIICSTAT |= (1<<5);
117         IICSTAT = rIICSTAT;
118
119         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
120                 temp = IICCON;
121                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
122                 break;
123                 udelay(2000);
124         }
125         if (k==S3C44B0_IIC_TIMEOUT)
126                 return -1;
127
128         /* wait and check ACK */
129         temp = IICSTAT;
130         if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
131                 return -1;
132
133         IICDS = addr;
134         IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
135
136         /* wait and check ACK */
137         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
138                 temp = IICCON;
139                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
140                 break;
141                 udelay(2000);
142         }
143         if (k==S3C44B0_IIC_TIMEOUT)
144                 return -1;
145
146         temp = IICSTAT;
147         if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
148                 return -1;
149
150         /*
151                 now we can start with the read operation...
152         */
153
154         IICDS = chip | 0x01;    /* this is a read operation... */
155
156         rIICSTAT = 0x90; /*master recv*/
157         rIICSTAT |= (1<<5);
158         IICSTAT = rIICSTAT;
159
160         IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
161
162         /* wait and check ACK */
163         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
164                 temp = IICCON;
165                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
166                 break;
167                 udelay(2000);
168         }
169         if (k==S3C44B0_IIC_TIMEOUT)
170                 return -1;
171
172         temp = IICSTAT;
173         if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
174                 return -1;
175
176         for (j=0; j<len-1; j++) {
177
178         /*clear pending bit to resume */
179
180         temp = IICCON & ~(S3C44B0X_rIIC_INTPEND);
181         IICCON = temp;
182
183         /* wait and check ACK */
184         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
185                 temp = IICCON;
186                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
187                 break;
188                 udelay(2000);
189         }
190         if (k==S3C44B0_IIC_TIMEOUT)
191                 return -1;
192
193
194                 buffer[j] = IICDS; /*save readed data*/
195
196     } /*end for(j)*/
197
198         /*
199                 reading the last data
200                 unset ACK generation
201         */
202         temp = IICCON & ~(S3C44B0X_rIIC_INTPEND | (1<<7));
203         IICCON = temp;
204
205         /* wait but NOT check ACK */
206         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
207                 temp = IICCON;
208                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
209                 break;
210                 udelay(2000);
211         }
212         if (k==S3C44B0_IIC_TIMEOUT)
213                 return -1;
214
215         buffer[j] = IICDS; /*save readed data*/
216
217         rIICSTAT = 0x90; /*master recv*/
218
219         /* Write operation Terminate sending STOP */
220         IICSTAT = rIICSTAT;
221         /*Clear Int Pending Bit to RESUME*/
222         temp = IICCON;
223         IICCON = temp & (~S3C44B0X_rIIC_INTPEND);
224
225         IICCON = IICCON | (1<<7);       /*restore ACK generation*/
226
227         return 0;
228 }
229
230 int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
231 {
232         int j, k;
233         u32 rIICSTAT, temp;
234
235
236         /*
237                 send the device offset
238         */
239
240         rIICSTAT = 0xD0;
241         IICSTAT = rIICSTAT;
242
243         IICDS = chip;   /* this is a write operation... */
244
245         rIICSTAT |= (1<<5);
246         IICSTAT = rIICSTAT;
247
248         IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
249
250         /* wait and check ACK */
251         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
252                 temp = IICCON;
253                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
254                 break;
255                 udelay(2000);
256         }
257         if (k==S3C44B0_IIC_TIMEOUT)
258                 return -1;
259
260         temp = IICSTAT;
261         if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
262                 return -1;
263
264         IICDS = addr;
265         IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
266
267         /* wait and check ACK */
268         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
269                 temp = IICCON;
270                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
271                 break;
272                 udelay(2000);
273         }
274         if (k==S3C44B0_IIC_TIMEOUT)
275           return -1;
276
277         temp = IICSTAT;
278         if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
279                 return -1;
280
281         /*
282                 now we can start with the read write operation
283         */
284         for (j=0; j<len; j++) {
285
286                 IICDS = buffer[j]; /*prerare data to write*/
287
288                 /*clear pending bit to resume*/
289
290                 temp = IICCON & ~(S3C44B0X_rIIC_INTPEND);
291                 IICCON = temp;
292
293                 /* wait but NOT check ACK */
294                 for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
295                         temp = IICCON;
296                         if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
297                         break;
298
299                         udelay(2000);
300                 }
301
302                 if (k==S3C44B0_IIC_TIMEOUT)
303                         return -1;
304
305         } /* end for(j) */
306
307         /* sending stop to terminate */
308         rIICSTAT = 0xD0;  /*master send*/
309         IICSTAT = rIICSTAT;
310         /*Clear Int Pending Bit to RESUME*/
311         temp = IICCON;
312         IICCON = temp & (~S3C44B0X_rIIC_INTPEND);
313
314         return 0;
315 }