aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorManuel Lauss <mano@roarinelk.homelinux.net>2008-04-22 16:16:47 -0400
committerJean Delvare <khali@hyperion.delvare>2008-04-22 16:16:47 -0400
commita26c20b1fa6d16fd3c402785b943a5e915eda30a (patch)
treeb02bf7183098c1dbf3cc51114a7bbbea22561765 /drivers
parentdba7997a87cd12b815c0d58b2a0522a8bb0cf5ec (diff)
i2c: Renesas SH7760 I2C master driver
Driver for I2C interfaces in master mode on SH7760. Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/Kconfig9
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-sh7760.c577
3 files changed, 587 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 1577bcad288a..d01d0b175e1c 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -683,4 +683,13 @@ config I2C_PMCMSP
683 This driver can also be built as module. If so, the module 683 This driver can also be built as module. If so, the module
684 will be called i2c-pmcmsp. 684 will be called i2c-pmcmsp.
685 685
686config I2C_SH7760
687 tristate "Renesas SH7760 I2C Controller"
688 depends on CPU_SUBTYPE_SH7760
689 help
690 This driver supports the 2 I2C interfaces on the Renesas SH7760.
691
692 This driver can also be built as a module. If so, the module
693 will be called i2c-sh7760.
694
686endmenu 695endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 378d5c07e048..8e72b2649dc7 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
38obj-$(CONFIG_I2C_PXA) += i2c-pxa.o 38obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
39obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o 39obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
40obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o 40obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
41obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
41obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o 42obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
42obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o 43obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
43obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o 44obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
new file mode 100644
index 000000000000..5e0e254976de
--- /dev/null
+++ b/drivers/i2c/busses/i2c-sh7760.c
@@ -0,0 +1,577 @@
1/*
2 * I2C bus driver for the SH7760 I2C Interfaces.
3 *
4 * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
5 *
6 * licensed under the terms outlined in the file COPYING.
7 *
8 */
9
10#include <linux/completion.h>
11#include <linux/delay.h>
12#include <linux/err.h>
13#include <linux/i2c.h>
14#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/ioport.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19
20#include <asm/clock.h>
21#include <asm/i2c-sh7760.h>
22#include <asm/io.h>
23
24/* register offsets */
25#define I2CSCR 0x0 /* slave ctrl */
26#define I2CMCR 0x4 /* master ctrl */
27#define I2CSSR 0x8 /* slave status */
28#define I2CMSR 0xC /* master status */
29#define I2CSIER 0x10 /* slave irq enable */
30#define I2CMIER 0x14 /* master irq enable */
31#define I2CCCR 0x18 /* clock dividers */
32#define I2CSAR 0x1c /* slave address */
33#define I2CMAR 0x20 /* master address */
34#define I2CRXTX 0x24 /* data port */
35#define I2CFCR 0x28 /* fifo control */
36#define I2CFSR 0x2C /* fifo status */
37#define I2CFIER 0x30 /* fifo irq enable */
38#define I2CRFDR 0x34 /* rx fifo count */
39#define I2CTFDR 0x38 /* tx fifo count */
40
41#define REGSIZE 0x3C
42
43#define MCR_MDBS 0x80 /* non-fifo mode switch */
44#define MCR_FSCL 0x40 /* override SCL pin */
45#define MCR_FSDA 0x20 /* override SDA pin */
46#define MCR_OBPC 0x10 /* override pins */
47#define MCR_MIE 0x08 /* master if enable */
48#define MCR_TSBE 0x04
49#define MCR_FSB 0x02 /* force stop bit */
50#define MCR_ESG 0x01 /* en startbit gen. */
51
52#define MSR_MNR 0x40 /* nack received */
53#define MSR_MAL 0x20 /* arbitration lost */
54#define MSR_MST 0x10 /* sent a stop */
55#define MSR_MDE 0x08
56#define MSR_MDT 0x04
57#define MSR_MDR 0x02
58#define MSR_MAT 0x01 /* slave addr xfer done */
59
60#define MIE_MNRE 0x40 /* nack irq en */
61#define MIE_MALE 0x20 /* arblos irq en */
62#define MIE_MSTE 0x10 /* stop irq en */
63#define MIE_MDEE 0x08
64#define MIE_MDTE 0x04
65#define MIE_MDRE 0x02
66#define MIE_MATE 0x01 /* address sent irq en */
67
68#define FCR_RFRST 0x02 /* reset rx fifo */
69#define FCR_TFRST 0x01 /* reset tx fifo */
70
71#define FSR_TEND 0x04 /* last byte sent */
72#define FSR_RDF 0x02 /* rx fifo trigger */
73#define FSR_TDFE 0x01 /* tx fifo empty */
74
75#define FIER_TEIE 0x04 /* tx fifo empty irq en */
76#define FIER_RXIE 0x02 /* rx fifo trig irq en */
77#define FIER_TXIE 0x01 /* tx fifo trig irq en */
78
79#define FIFO_SIZE 16
80
81struct cami2c {
82 void __iomem *iobase;
83 struct i2c_adapter adap;
84
85 /* message processing */
86 struct i2c_msg *msg;
87#define IDF_SEND 1
88#define IDF_RECV 2
89#define IDF_STOP 4
90 int flags;
91
92#define IDS_DONE 1
93#define IDS_ARBLOST 2
94#define IDS_NACK 4
95 int status;
96 struct completion xfer_done;
97
98 int irq;
99 struct resource *ioarea;
100};
101
102static inline void OUT32(struct cami2c *cam, int reg, unsigned long val)
103{
104 ctrl_outl(val, (unsigned long)cam->iobase + reg);
105}
106
107static inline unsigned long IN32(struct cami2c *cam, int reg)
108{
109 return ctrl_inl((unsigned long)cam->iobase + reg);
110}
111
112static irqreturn_t sh7760_i2c_irq(int irq, void *ptr)
113{
114 struct cami2c *id = ptr;
115 struct i2c_msg *msg = id->msg;
116 char *data = msg->buf;
117 unsigned long msr, fsr, fier, len;
118
119 msr = IN32(id, I2CMSR);
120 fsr = IN32(id, I2CFSR);
121
122 /* arbitration lost */
123 if (msr & MSR_MAL) {
124 OUT32(id, I2CMCR, 0);
125 OUT32(id, I2CSCR, 0);
126 OUT32(id, I2CSAR, 0);
127 id->status |= IDS_DONE | IDS_ARBLOST;
128 goto out;
129 }
130
131 if (msr & MSR_MNR) {
132 /* NACK handling is very screwed up. After receiving a
133 * NAK IRQ one has to wait a bit before writing to any
134 * registers, or the ctl will lock up. After that delay
135 * do a normal i2c stop. Then wait at least 1 ms before
136 * attempting another transfer or ctl will stop working
137 */
138 udelay(100); /* wait or risk ctl hang */
139 OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
140 OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
141 OUT32(id, I2CFIER, 0);
142 OUT32(id, I2CMIER, MIE_MSTE);
143 OUT32(id, I2CSCR, 0);
144 OUT32(id, I2CSAR, 0);
145 id->status |= IDS_NACK;
146 msr &= ~MSR_MAT;
147 fsr = 0;
148 /* In some cases the MST bit is also set. */
149 }
150
151 /* i2c-stop was sent */
152 if (msr & MSR_MST) {
153 id->status |= IDS_DONE;
154 goto out;
155 }
156
157 /* i2c slave addr was sent; set to "normal" operation */
158 if (msr & MSR_MAT)
159 OUT32(id, I2CMCR, MCR_MIE);
160
161 fier = IN32(id, I2CFIER);
162
163 if (fsr & FSR_RDF) {
164 len = IN32(id, I2CRFDR);
165 if (msg->len <= len) {
166 if (id->flags & IDF_STOP) {
167 OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
168 OUT32(id, I2CFIER, 0);
169 /* manual says: wait >= 0.5 SCL times */
170 udelay(5);
171 /* next int should be MST */
172 } else {
173 id->status |= IDS_DONE;
174 /* keep the RDF bit: ctrl holds SCL low
175 * until the setup for the next i2c_msg
176 * clears this bit.
177 */
178 fsr &= ~FSR_RDF;
179 }
180 }
181 while (msg->len && len) {
182 *data++ = IN32(id, I2CRXTX);
183 msg->len--;
184 len--;
185 }
186
187 if (msg->len) {
188 len = (msg->len >= FIFO_SIZE) ? FIFO_SIZE - 1
189 : msg->len - 1;
190
191 OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xf) << 4));
192 }
193
194 } else if (id->flags & IDF_SEND) {
195 if ((fsr & FSR_TEND) && (msg->len < 1)) {
196 if (id->flags & IDF_STOP) {
197 OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
198 } else {
199 id->status |= IDS_DONE;
200 /* keep the TEND bit: ctl holds SCL low
201 * until the setup for the next i2c_msg
202 * clears this bit.
203 */
204 fsr &= ~FSR_TEND;
205 }
206 }
207 if (fsr & FSR_TDFE) {
208 while (msg->len && (IN32(id, I2CTFDR) < FIFO_SIZE)) {
209 OUT32(id, I2CRXTX, *data++);
210 msg->len--;
211 }
212
213 if (msg->len < 1) {
214 fier &= ~FIER_TXIE;
215 OUT32(id, I2CFIER, fier);
216 } else {
217 len = (msg->len >= FIFO_SIZE) ? 2 : 0;
218 OUT32(id, I2CFCR,
219 FCR_RFRST | ((len & 3) << 2));
220 }
221 }
222 }
223out:
224 if (id->status & IDS_DONE) {
225 OUT32(id, I2CMIER, 0);
226 OUT32(id, I2CFIER, 0);
227 id->msg = NULL;
228 complete(&id->xfer_done);
229 }
230 /* clear status flags and ctrl resumes work */
231 OUT32(id, I2CMSR, ~msr);
232 OUT32(id, I2CFSR, ~fsr);
233 OUT32(id, I2CSSR, 0);
234
235 return IRQ_HANDLED;
236}
237
238
239/* prepare and start a master receive operation */
240static void sh7760_i2c_mrecv(struct cami2c *id)
241{
242 int len;
243
244 id->flags |= IDF_RECV;
245
246 /* set the slave addr reg; otherwise rcv wont work! */
247 OUT32(id, I2CSAR, 0xfe);
248 OUT32(id, I2CMAR, (id->msg->addr << 1) | 1);
249
250 /* adjust rx fifo trigger */
251 if (id->msg->len >= FIFO_SIZE)
252 len = FIFO_SIZE - 1; /* trigger at fifo full */
253 else
254 len = id->msg->len - 1; /* trigger before all received */
255
256 OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
257 OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xF) << 4));
258
259 OUT32(id, I2CMSR, 0);
260 OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
261 OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
262 OUT32(id, I2CFIER, FIER_RXIE);
263}
264
265/* prepare and start a master send operation */
266static void sh7760_i2c_msend(struct cami2c *id)
267{
268 int len;
269
270 id->flags |= IDF_SEND;
271
272 /* set the slave addr reg; otherwise xmit wont work! */
273 OUT32(id, I2CSAR, 0xfe);
274 OUT32(id, I2CMAR, (id->msg->addr << 1) | 0);
275
276 /* adjust tx fifo trigger */
277 if (id->msg->len >= FIFO_SIZE)
278 len = 2; /* trig: 2 bytes left in TX fifo */
279 else
280 len = 0; /* trig: 8 bytes left in TX fifo */
281
282 OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
283 OUT32(id, I2CFCR, FCR_RFRST | ((len & 3) << 2));
284
285 while (id->msg->len && IN32(id, I2CTFDR) < FIFO_SIZE) {
286 OUT32(id, I2CRXTX, *(id->msg->buf));
287 (id->msg->len)--;
288 (id->msg->buf)++;
289 }
290
291 OUT32(id, I2CMSR, 0);
292 OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
293 OUT32(id, I2CFSR, 0);
294 OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
295 OUT32(id, I2CFIER, FIER_TEIE | (id->msg->len ? FIER_TXIE : 0));
296}
297
298static inline int sh7760_i2c_busy_check(struct cami2c *id)
299{
300 return (IN32(id, I2CMCR) & MCR_FSDA);
301}
302
303static int sh7760_i2c_master_xfer(struct i2c_adapter *adap,
304 struct i2c_msg *msgs,
305 int num)
306{
307 struct cami2c *id = adap->algo_data;
308 int i, retr;
309
310 if (sh7760_i2c_busy_check(id)) {
311 dev_err(&adap->dev, "sh7760-i2c%d: bus busy!\n", adap->nr);
312 return -EBUSY;
313 }
314
315 i = 0;
316 while (i < num) {
317 retr = adap->retries;
318retry:
319 id->flags = ((i == (num-1)) ? IDF_STOP : 0);
320 id->status = 0;
321 id->msg = msgs;
322 init_completion(&id->xfer_done);
323
324 if (msgs->flags & I2C_M_RD)
325 sh7760_i2c_mrecv(id);
326 else
327 sh7760_i2c_msend(id);
328
329 wait_for_completion(&id->xfer_done);
330
331 if (id->status == 0) {
332 num = -EIO;
333 break;
334 }
335
336 if (id->status & IDS_NACK) {
337 /* wait a bit or i2c module stops working */
338 mdelay(1);
339 num = -EREMOTEIO;
340 break;
341 }
342
343 if (id->status & IDS_ARBLOST) {
344 if (retr--) {
345 mdelay(2);
346 goto retry;
347 }
348 num = -EREMOTEIO;
349 break;
350 }
351
352 msgs++;
353 i++;
354 }
355
356 id->msg = NULL;
357 id->flags = 0;
358 id->status = 0;
359
360 OUT32(id, I2CMCR, 0);
361 OUT32(id, I2CMSR, 0);
362 OUT32(id, I2CMIER, 0);
363 OUT32(id, I2CFIER, 0);
364
365 /* reset slave module registers too: master mode enables slave
366 * module for receive ops (ack, data). Without this reset,
367 * eternal bus activity might be reported after NACK / ARBLOST.
368 */
369 OUT32(id, I2CSCR, 0);
370 OUT32(id, I2CSAR, 0);
371 OUT32(id, I2CSSR, 0);
372
373 return num;
374}
375
376static u32 sh7760_i2c_func(struct i2c_adapter *adap)
377{
378 return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
379}
380
381static const struct i2c_algorithm sh7760_i2c_algo = {
382 .master_xfer = sh7760_i2c_master_xfer,
383 .functionality = sh7760_i2c_func,
384};
385
386/* calculate CCR register setting for a desired scl clock. SCL clock is
387 * derived from I2C module clock (iclk) which in turn is derived from
388 * peripheral module clock (mclk, usually around 33MHz):
389 * iclk = mclk/(CDF + 1). iclk must be < 20MHz.
390 * scl = iclk/(SCGD*8 + 20).
391 */
392static int __devinit calc_CCR(unsigned long scl_hz)
393{
394 struct clk *mclk;
395 unsigned long mck, m1, dff, odff, iclk;
396 signed char cdf, cdfm;
397 int scgd, scgdm, scgds;
398
399 mclk = clk_get(NULL, "module_clk");
400 if (IS_ERR(mclk)) {
401 return PTR_ERR(mclk);
402 } else {
403 mck = mclk->rate;
404 clk_put(mclk);
405 }
406
407 odff = scl_hz;
408 scgdm = cdfm = m1 = 0;
409 for (cdf = 3; cdf >= 0; cdf--) {
410 iclk = mck / (1 + cdf);
411 if (iclk >= 20000000)
412 continue;
413 scgds = ((iclk / scl_hz) - 20) >> 3;
414 for (scgd = scgds; (scgd < 63) && scgd <= scgds + 1; scgd++) {
415 m1 = iclk / (20 + (scgd << 3));
416 dff = abs(scl_hz - m1);
417 if (dff < odff) {
418 odff = dff;
419 cdfm = cdf;
420 scgdm = scgd;
421 }
422 }
423 }
424 /* fail if more than 25% off of requested SCL */
425 if (odff > (scl_hz >> 2))
426 return -EINVAL;
427
428 /* create a CCR register value */
429 return ((scgdm << 2) | cdfm);
430}
431
432static int __devinit sh7760_i2c_probe(struct platform_device *pdev)
433{
434 struct sh7760_i2c_platdata *pd;
435 struct resource *res;
436 struct cami2c *id;
437 int ret;
438
439 pd = pdev->dev.platform_data;
440 if (!pd) {
441 dev_err(&pdev->dev, "no platform_data!\n");
442 ret = -ENODEV;
443 goto out0;
444 }
445
446 id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
447 if (!id) {
448 dev_err(&pdev->dev, "no mem for private data\n");
449 ret = -ENOMEM;
450 goto out0;
451 }
452
453 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
454 if (!res) {
455 dev_err(&pdev->dev, "no mmio resources\n");
456 ret = -ENODEV;
457 goto out1;
458 }
459
460 id->ioarea = request_mem_region(res->start, REGSIZE, pdev->name);
461 if (!id->ioarea) {
462 dev_err(&pdev->dev, "mmio already reserved\n");
463 ret = -EBUSY;
464 goto out1;
465 }
466
467 id->iobase = ioremap(res->start, REGSIZE);
468 if (!id->iobase) {
469 dev_err(&pdev->dev, "cannot ioremap\n");
470 ret = -ENODEV;
471 goto out2;
472 }
473
474 id->irq = platform_get_irq(pdev, 0);
475
476 id->adap.nr = pdev->id;
477 id->adap.algo = &sh7760_i2c_algo;
478 id->adap.class = I2C_CLASS_ALL;
479 id->adap.retries = 3;
480 id->adap.algo_data = id;
481 id->adap.dev.parent = &pdev->dev;
482 snprintf(id->adap.name, sizeof(id->adap.name),
483 "SH7760 I2C at %08lx", (unsigned long)res->start);
484
485 OUT32(id, I2CMCR, 0);
486 OUT32(id, I2CMSR, 0);
487 OUT32(id, I2CMIER, 0);
488 OUT32(id, I2CMAR, 0);
489 OUT32(id, I2CSIER, 0);
490 OUT32(id, I2CSAR, 0);
491 OUT32(id, I2CSCR, 0);
492 OUT32(id, I2CSSR, 0);
493 OUT32(id, I2CFIER, 0);
494 OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
495 OUT32(id, I2CFSR, 0);
496
497 ret = calc_CCR(pd->speed_khz * 1000);
498 if (ret < 0) {
499 dev_err(&pdev->dev, "invalid SCL clock: %dkHz\n",
500 pd->speed_khz);
501 goto out3;
502 }
503 OUT32(id, I2CCCR, ret);
504
505 if (request_irq(id->irq, sh7760_i2c_irq, IRQF_DISABLED,
506 SH7760_I2C_DEVNAME, id)) {
507 dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
508 ret = -EBUSY;
509 goto out3;
510 }
511
512 ret = i2c_add_numbered_adapter(&id->adap);
513 if (ret < 0) {
514 dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
515 goto out4;
516 }
517
518 platform_set_drvdata(pdev, id);
519
520 dev_info(&pdev->dev, "%d kHz mmio %08x irq %d\n",
521 pd->speed_khz, res->start, id->irq);
522
523 return 0;
524
525out4:
526 free_irq(id->irq, id);
527out3:
528 iounmap(id->iobase);
529out2:
530 release_resource(id->ioarea);
531 kfree(id->ioarea);
532out1:
533 kfree(id);
534out0:
535 return ret;
536}
537
538static int __devexit sh7760_i2c_remove(struct platform_device *pdev)
539{
540 struct cami2c *id = platform_get_drvdata(pdev);
541
542 i2c_del_adapter(&id->adap);
543 free_irq(id->irq, id);
544 iounmap(id->iobase);
545 release_resource(id->ioarea);
546 kfree(id->ioarea);
547 kfree(id);
548 platform_set_drvdata(pdev, NULL);
549
550 return 0;
551}
552
553static struct platform_driver sh7760_i2c_drv = {
554 .driver = {
555 .name = SH7760_I2C_DEVNAME,
556 .owner = THIS_MODULE,
557 },
558 .probe = sh7760_i2c_probe,
559 .remove = __devexit_p(sh7760_i2c_remove),
560};
561
562static int __init sh7760_i2c_init(void)
563{
564 return platform_driver_register(&sh7760_i2c_drv);
565}
566
567static void __exit sh7760_i2c_exit(void)
568{
569 platform_driver_unregister(&sh7760_i2c_drv);
570}
571
572module_init(sh7760_i2c_init);
573module_exit(sh7760_i2c_exit);
574
575MODULE_LICENSE("GPL");
576MODULE_DESCRIPTION("SH7760 I2C bus driver");
577MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");