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/interrupt.h> |
15 | #include <linux/ioport.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/slab.h> |
18 | #include <linux/io.h> |
19 | #include <linux/module.h> |
20 | |
21 | #include <asm/clock.h> |
22 | #include <asm/i2c-sh7760.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 | |
81 | struct 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 | |
102 | static inline void OUT32(struct cami2c *cam, int reg, unsigned long val) |
103 | { |
104 | __raw_writel(val, addr: (unsigned long)cam->iobase + reg); |
105 | } |
106 | |
107 | static inline unsigned long IN32(struct cami2c *cam, int reg) |
108 | { |
109 | return __raw_readl(addr: (unsigned long)cam->iobase + reg); |
110 | } |
111 | |
112 | static 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(cam: id, I2CMSR); |
120 | fsr = IN32(cam: id, I2CFSR); |
121 | |
122 | /* arbitration lost */ |
123 | if (msr & MSR_MAL) { |
124 | OUT32(cam: id, I2CMCR, val: 0); |
125 | OUT32(cam: id, I2CSCR, val: 0); |
126 | OUT32(cam: id, I2CSAR, val: 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(cam: id, I2CFCR, FCR_RFRST | FCR_TFRST); |
140 | OUT32(cam: id, I2CMCR, MCR_MIE | MCR_FSB); |
141 | OUT32(cam: id, I2CFIER, val: 0); |
142 | OUT32(cam: id, I2CMIER, MIE_MSTE); |
143 | OUT32(cam: id, I2CSCR, val: 0); |
144 | OUT32(cam: id, I2CSAR, val: 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(cam: id, I2CMCR, MCR_MIE); |
160 | |
161 | fier = IN32(cam: id, I2CFIER); |
162 | |
163 | if (fsr & FSR_RDF) { |
164 | len = IN32(cam: id, I2CRFDR); |
165 | if (msg->len <= len) { |
166 | if (id->flags & IDF_STOP) { |
167 | OUT32(cam: id, I2CMCR, MCR_MIE | MCR_FSB); |
168 | OUT32(cam: id, I2CFIER, val: 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(cam: 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(cam: 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(cam: 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(cam: id, I2CTFDR) < FIFO_SIZE)) { |
209 | OUT32(cam: id, I2CRXTX, val: *data++); |
210 | msg->len--; |
211 | } |
212 | |
213 | if (msg->len < 1) { |
214 | fier &= ~FIER_TXIE; |
215 | OUT32(cam: id, I2CFIER, val: fier); |
216 | } else { |
217 | len = (msg->len >= FIFO_SIZE) ? 2 : 0; |
218 | OUT32(cam: id, I2CFCR, |
219 | FCR_RFRST | ((len & 3) << 2)); |
220 | } |
221 | } |
222 | } |
223 | out: |
224 | if (id->status & IDS_DONE) { |
225 | OUT32(cam: id, I2CMIER, val: 0); |
226 | OUT32(cam: id, I2CFIER, val: 0); |
227 | id->msg = NULL; |
228 | complete(&id->xfer_done); |
229 | } |
230 | /* clear status flags and ctrl resumes work */ |
231 | OUT32(cam: id, I2CMSR, val: ~msr); |
232 | OUT32(cam: id, I2CFSR, val: ~fsr); |
233 | OUT32(cam: id, I2CSSR, val: 0); |
234 | |
235 | return IRQ_HANDLED; |
236 | } |
237 | |
238 | |
239 | /* prepare and start a master receive operation */ |
240 | static 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(cam: id, I2CSAR, val: 0xfe); |
248 | OUT32(cam: id, I2CMAR, val: (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(cam: id, I2CFCR, FCR_RFRST | FCR_TFRST); |
257 | OUT32(cam: id, I2CFCR, FCR_TFRST | ((len & 0xF) << 4)); |
258 | |
259 | OUT32(cam: id, I2CMSR, val: 0); |
260 | OUT32(cam: id, I2CMCR, MCR_MIE | MCR_ESG); |
261 | OUT32(cam: id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE); |
262 | OUT32(cam: id, I2CFIER, FIER_RXIE); |
263 | } |
264 | |
265 | /* prepare and start a master send operation */ |
266 | static 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(cam: id, I2CSAR, val: 0xfe); |
274 | OUT32(cam: id, I2CMAR, val: (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(cam: id, I2CFCR, FCR_RFRST | FCR_TFRST); |
283 | OUT32(cam: id, I2CFCR, FCR_RFRST | ((len & 3) << 2)); |
284 | |
285 | while (id->msg->len && IN32(cam: id, I2CTFDR) < FIFO_SIZE) { |
286 | OUT32(cam: id, I2CRXTX, val: *(id->msg->buf)); |
287 | (id->msg->len)--; |
288 | (id->msg->buf)++; |
289 | } |
290 | |
291 | OUT32(cam: id, I2CMSR, val: 0); |
292 | OUT32(cam: id, I2CMCR, MCR_MIE | MCR_ESG); |
293 | OUT32(cam: id, I2CFSR, val: 0); |
294 | OUT32(cam: id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE); |
295 | OUT32(cam: id, I2CFIER, FIER_TEIE | (id->msg->len ? FIER_TXIE : 0)); |
296 | } |
297 | |
298 | static inline int sh7760_i2c_busy_check(struct cami2c *id) |
299 | { |
300 | return (IN32(cam: id, I2CMCR) & MCR_FSDA); |
301 | } |
302 | |
303 | static 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; |
318 | retry: |
319 | id->flags = ((i == (num-1)) ? IDF_STOP : 0); |
320 | id->status = 0; |
321 | id->msg = msgs; |
322 | init_completion(x: &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(cam: id, I2CMCR, val: 0); |
361 | OUT32(cam: id, I2CMSR, val: 0); |
362 | OUT32(cam: id, I2CMIER, val: 0); |
363 | OUT32(cam: id, I2CFIER, val: 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(cam: id, I2CSCR, val: 0); |
370 | OUT32(cam: id, I2CSAR, val: 0); |
371 | OUT32(cam: id, I2CSSR, val: 0); |
372 | |
373 | return num; |
374 | } |
375 | |
376 | static u32 sh7760_i2c_func(struct i2c_adapter *adap) |
377 | { |
378 | return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); |
379 | } |
380 | |
381 | static 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 | */ |
392 | static int 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, "peripheral_clk" ); |
400 | if (IS_ERR(ptr: mclk)) { |
401 | return PTR_ERR(ptr: 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 | |
432 | static int 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 = dev_get_platdata(dev: &pdev->dev); |
440 | if (!pd) { |
441 | dev_err(&pdev->dev, "no platform_data!\n" ); |
442 | ret = -ENODEV; |
443 | goto out0; |
444 | } |
445 | |
446 | id = kzalloc(size: sizeof(*id), GFP_KERNEL); |
447 | if (!id) { |
448 | ret = -ENOMEM; |
449 | goto out0; |
450 | } |
451 | |
452 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
453 | if (!res) { |
454 | dev_err(&pdev->dev, "no mmio resources\n" ); |
455 | ret = -ENODEV; |
456 | goto out1; |
457 | } |
458 | |
459 | id->ioarea = request_mem_region(res->start, REGSIZE, pdev->name); |
460 | if (!id->ioarea) { |
461 | dev_err(&pdev->dev, "mmio already reserved\n" ); |
462 | ret = -EBUSY; |
463 | goto out1; |
464 | } |
465 | |
466 | id->iobase = ioremap(offset: res->start, REGSIZE); |
467 | if (!id->iobase) { |
468 | dev_err(&pdev->dev, "cannot ioremap\n" ); |
469 | ret = -ENODEV; |
470 | goto out2; |
471 | } |
472 | |
473 | ret = platform_get_irq(pdev, 0); |
474 | if (ret < 0) |
475 | goto out3; |
476 | id->irq = ret; |
477 | |
478 | id->adap.nr = pdev->id; |
479 | id->adap.algo = &sh7760_i2c_algo; |
480 | id->adap.class = I2C_CLASS_HWMON; |
481 | id->adap.retries = 3; |
482 | id->adap.algo_data = id; |
483 | id->adap.dev.parent = &pdev->dev; |
484 | snprintf(buf: id->adap.name, size: sizeof(id->adap.name), |
485 | fmt: "SH7760 I2C at %08lx" , (unsigned long)res->start); |
486 | |
487 | OUT32(cam: id, I2CMCR, val: 0); |
488 | OUT32(cam: id, I2CMSR, val: 0); |
489 | OUT32(cam: id, I2CMIER, val: 0); |
490 | OUT32(cam: id, I2CMAR, val: 0); |
491 | OUT32(cam: id, I2CSIER, val: 0); |
492 | OUT32(cam: id, I2CSAR, val: 0); |
493 | OUT32(cam: id, I2CSCR, val: 0); |
494 | OUT32(cam: id, I2CSSR, val: 0); |
495 | OUT32(cam: id, I2CFIER, val: 0); |
496 | OUT32(cam: id, I2CFCR, FCR_RFRST | FCR_TFRST); |
497 | OUT32(cam: id, I2CFSR, val: 0); |
498 | |
499 | ret = calc_CCR(scl_hz: pd->speed_khz * 1000); |
500 | if (ret < 0) { |
501 | dev_err(&pdev->dev, "invalid SCL clock: %dkHz\n" , |
502 | pd->speed_khz); |
503 | goto out3; |
504 | } |
505 | OUT32(cam: id, I2CCCR, val: ret); |
506 | |
507 | if (request_irq(irq: id->irq, handler: sh7760_i2c_irq, flags: 0, |
508 | name: SH7760_I2C_DEVNAME, dev: id)) { |
509 | dev_err(&pdev->dev, "cannot get irq %d\n" , id->irq); |
510 | ret = -EBUSY; |
511 | goto out3; |
512 | } |
513 | |
514 | ret = i2c_add_numbered_adapter(adap: &id->adap); |
515 | if (ret < 0) |
516 | goto out4; |
517 | |
518 | platform_set_drvdata(pdev, data: 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 | |
525 | out4: |
526 | free_irq(id->irq, id); |
527 | out3: |
528 | iounmap(addr: id->iobase); |
529 | out2: |
530 | release_resource(new: id->ioarea); |
531 | kfree(objp: id->ioarea); |
532 | out1: |
533 | kfree(objp: id); |
534 | out0: |
535 | return ret; |
536 | } |
537 | |
538 | static void sh7760_i2c_remove(struct platform_device *pdev) |
539 | { |
540 | struct cami2c *id = platform_get_drvdata(pdev); |
541 | |
542 | i2c_del_adapter(adap: &id->adap); |
543 | free_irq(id->irq, id); |
544 | iounmap(addr: id->iobase); |
545 | release_resource(new: id->ioarea); |
546 | kfree(objp: id->ioarea); |
547 | kfree(objp: id); |
548 | } |
549 | |
550 | static struct platform_driver sh7760_i2c_drv = { |
551 | .driver = { |
552 | .name = SH7760_I2C_DEVNAME, |
553 | }, |
554 | .probe = sh7760_i2c_probe, |
555 | .remove_new = sh7760_i2c_remove, |
556 | }; |
557 | |
558 | module_platform_driver(sh7760_i2c_drv); |
559 | |
560 | MODULE_LICENSE("GPL" ); |
561 | MODULE_DESCRIPTION("SH7760 I2C bus driver" ); |
562 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>" ); |
563 | |