1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#include <common.h>
30#include <asm/arch/s3c24x0_cpu.h>
31
32#include <asm/io.h>
33#include <i2c.h>
34
35#ifdef CONFIG_HARD_I2C
36
37#define I2C_WRITE 0
38#define I2C_READ 1
39
40#define I2C_OK 0
41#define I2C_NOK 1
42#define I2C_NACK 2
43#define I2C_NOK_LA 3
44#define I2C_NOK_TOUT 4
45
46#define I2CSTAT_BSY 0x20
47#define I2CSTAT_NACK 0x01
48#define I2CCON_IRPND 0x10
49#define I2C_MODE_MT 0xC0
50#define I2C_MODE_MR 0x80
51#define I2C_START_STOP 0x20
52#define I2C_TXRX_ENA 0x10
53
54#define I2C_TIMEOUT 1
55
56static int GetI2CSDA(void)
57{
58 struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
59
60#ifdef CONFIG_S3C2410
61 return (readl(&gpio->gpedat) & 0x8000) >> 15;
62#endif
63#ifdef CONFIG_S3C2400
64 return (readl(&gpio->pgdat) & 0x0020) >> 5;
65#endif
66}
67
68#if 0
69static void SetI2CSDA(int x)
70{
71 rGPEDAT = (rGPEDAT & ~0x8000) | (x & 1) << 15;
72}
73#endif
74
75static void SetI2CSCL(int x)
76{
77 struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
78
79#ifdef CONFIG_S3C2410
80 writel((readl(&gpio->gpedat) & ~0x4000) | (x & 1) << 14, &gpio->gpedat);
81#endif
82#ifdef CONFIG_S3C2400
83 writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat);
84#endif
85}
86
87static int WaitForXfer(void)
88{
89 struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
90 int i;
91
92 i = I2C_TIMEOUT * 10000;
93 while (!(readl(&i2c->iiccon) & I2CCON_IRPND) && (i > 0)) {
94 udelay(100);
95 i--;
96 }
97
98 return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
99}
100
101static int IsACK(void)
102{
103 struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
104
105 return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
106}
107
108static void ReadWriteByte(void)
109{
110 struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
111
112 writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
113}
114
115void i2c_init(int speed, int slaveadd)
116{
117 struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
118 struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
119 ulong freq, pres = 16, div;
120 int i;
121
122
123
124 i = I2C_TIMEOUT * 1000;
125 while ((readl(&i2c->iicstat) && I2CSTAT_BSY) && (i > 0)) {
126 udelay(1000);
127 i--;
128 }
129
130 if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) {
131#ifdef CONFIG_S3C2410
132 ulong old_gpecon = readl(&gpio->gpecon);
133#endif
134#ifdef CONFIG_S3C2400
135 ulong old_gpecon = readl(&gpio->pgcon);
136#endif
137
138
139
140#ifdef CONFIG_S3C2410
141
142 writel((readl(&gpio->gpecon) & ~0xF0000000) | 0x10000000,
143 &gpio->gpecon);
144#endif
145#ifdef CONFIG_S3C2400
146
147 writel((readl(&gpio->pgcon) & ~0x00003c00) | 0x00001000,
148 &gpio->pgcon);
149#endif
150
151
152 SetI2CSCL(0);
153 udelay(1000);
154 i = 10;
155 while ((i > 0) && (GetI2CSDA() != 1)) {
156 SetI2CSCL(1);
157 udelay(1000);
158 SetI2CSCL(0);
159 udelay(1000);
160 i--;
161 }
162 SetI2CSCL(1);
163 udelay(1000);
164
165
166#ifdef CONFIG_S3C2410
167 writel(old_gpecon, &gpio->gpecon);
168#endif
169#ifdef CONFIG_S3C2400
170 writel(old_gpecon, &gpio->pgcon);
171#endif
172 }
173
174
175 freq = get_PCLK();
176 if ((freq / pres / (16 + 1)) > speed)
177
178 pres = 512;
179
180 div = 0;
181 while ((freq / pres / (div + 1)) > speed)
182 div++;
183
184
185
186 writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
187
188
189 writel(0, &i2c->iicstat);
190 writel(slaveadd, &i2c->iicadd);
191
192 writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
193
194}
195
196
197
198
199
200
201
202
203static
204int i2c_transfer(unsigned char cmd_type,
205 unsigned char chip,
206 unsigned char addr[],
207 unsigned char addr_len,
208 unsigned char data[], unsigned short data_len)
209{
210 struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
211 int i, result;
212
213 if (data == 0 || data_len == 0) {
214
215 printf("i2c_transfer: bad call\n");
216 return I2C_NOK;
217 }
218
219
220 i = I2C_TIMEOUT * 1000;
221 while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) {
222 udelay(1000);
223 i--;
224 }
225
226 if (readl(&i2c->iicstat) & I2CSTAT_BSY)
227 return I2C_NOK_TOUT;
228
229 writel(readl(&i2c->iiccon) | 0x80, &i2c->iiccon);
230 result = I2C_OK;
231
232 switch (cmd_type) {
233 case I2C_WRITE:
234 if (addr && addr_len) {
235 writel(chip, &i2c->iicds);
236
237 writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
238 &i2c->iicstat);
239 i = 0;
240 while ((i < addr_len) && (result == I2C_OK)) {
241 result = WaitForXfer();
242 writel(addr[i], &i2c->iicds);
243 ReadWriteByte();
244 i++;
245 }
246 i = 0;
247 while ((i < data_len) && (result == I2C_OK)) {
248 result = WaitForXfer();
249 writel(data[i], &i2c->iicds);
250 ReadWriteByte();
251 i++;
252 }
253 } else {
254 writel(chip, &i2c->iicds);
255
256 writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
257 &i2c->iicstat);
258 i = 0;
259 while ((i < data_len) && (result = I2C_OK)) {
260 result = WaitForXfer();
261 writel(data[i], &i2c->iicds);
262 ReadWriteByte();
263 i++;
264 }
265 }
266
267 if (result == I2C_OK)
268 result = WaitForXfer();
269
270
271 writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
272 ReadWriteByte();
273 break;
274
275 case I2C_READ:
276 if (addr && addr_len) {
277 writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
278 writel(chip, &i2c->iicds);
279
280 writel(readl(&i2c->iicstat) | I2C_START_STOP,
281 &i2c->iicstat);
282 result = WaitForXfer();
283 if (IsACK()) {
284 i = 0;
285 while ((i < addr_len) && (result == I2C_OK)) {
286 writel(addr[i], &i2c->iicds);
287 ReadWriteByte();
288 result = WaitForXfer();
289 i++;
290 }
291
292 writel(chip, &i2c->iicds);
293
294 writel(I2C_MODE_MR | I2C_TXRX_ENA |
295 I2C_START_STOP, &i2c->iicstat);
296 ReadWriteByte();
297 result = WaitForXfer();
298 i = 0;
299 while ((i < data_len) && (result == I2C_OK)) {
300
301 if (i == data_len - 1)
302 writel(readl(&i2c->iiccon)
303 & ~0x80, &i2c->iiccon);
304 ReadWriteByte();
305 result = WaitForXfer();
306 data[i] = readl(&i2c->iicds);
307 i++;
308 }
309 } else {
310 result = I2C_NACK;
311 }
312
313 } else {
314 writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
315 writel(chip, &i2c->iicds);
316
317 writel(readl(&i2c->iicstat) | I2C_START_STOP,
318 &i2c->iicstat);
319 result = WaitForXfer();
320
321 if (IsACK()) {
322 i = 0;
323 while ((i < data_len) && (result == I2C_OK)) {
324
325 if (i == data_len - 1)
326 writel(readl(&i2c->iiccon) &
327 ~0x80, &i2c->iiccon);
328 ReadWriteByte();
329 result = WaitForXfer();
330 data[i] = readl(&i2c->iicds);
331 i++;
332 }
333 } else {
334 result = I2C_NACK;
335 }
336 }
337
338
339 writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
340 ReadWriteByte();
341 break;
342
343 default:
344 printf("i2c_transfer: bad call\n");
345 result = I2C_NOK;
346 break;
347 }
348
349 return (result);
350}
351
352int i2c_probe(uchar chip)
353{
354 uchar buf[1];
355
356 buf[0] = 0;
357
358
359
360
361
362
363 return i2c_transfer(I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
364}
365
366int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
367{
368 uchar xaddr[4];
369 int ret;
370
371 if (alen > 4) {
372 printf("I2C read: addr len %d not supported\n", alen);
373 return 1;
374 }
375
376 if (alen > 0) {
377 xaddr[0] = (addr >> 24) & 0xFF;
378 xaddr[1] = (addr >> 16) & 0xFF;
379 xaddr[2] = (addr >> 8) & 0xFF;
380 xaddr[3] = addr & 0xFF;
381 }
382
383#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
384
385
386
387
388
389
390
391
392
393
394
395 if (alen > 0)
396 chip |= ((addr >> (alen * 8)) &
397 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
398#endif
399 if ((ret =
400 i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen,
401 buffer, len)) != 0) {
402 printf("I2c read: failed %d\n", ret);
403 return 1;
404 }
405 return 0;
406}
407
408int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
409{
410 uchar xaddr[4];
411
412 if (alen > 4) {
413 printf("I2C write: addr len %d not supported\n", alen);
414 return 1;
415 }
416
417 if (alen > 0) {
418 xaddr[0] = (addr >> 24) & 0xFF;
419 xaddr[1] = (addr >> 16) & 0xFF;
420 xaddr[2] = (addr >> 8) & 0xFF;
421 xaddr[3] = addr & 0xFF;
422 }
423#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
424
425
426
427
428
429
430
431
432
433
434
435 if (alen > 0)
436 chip |= ((addr >> (alen * 8)) &
437 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
438#endif
439 return (i2c_transfer
440 (I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
441 len) != 0);
442}
443#endif
444