FreeBSD/Linux Kernel Cross Reference
sys/arm/mv/twsi.c
1 /*-
2 * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
3 * All rights reserved.
4 *
5 * Developed by Semihalf.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of MARVELL nor the names of contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * Driver for the TWSI (aka I2C, aka IIC) bus controller found on Marvell
34 * SoCs. Supports master operation only, and works in polling mode.
35 *
36 * Calls to DELAY() are needed per Application Note AN-179 "TWSI Software
37 * Guidelines for Discovery(TM), Horizon (TM) and Feroceon(TM) Devices".
38 */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD: releng/9.0/sys/arm/mv/twsi.c 209131 2010-06-13 13:28:53Z raj $");
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/bus.h>
46 #include <sys/kernel.h>
47 #include <sys/module.h>
48 #include <sys/resource.h>
49
50 #include <machine/bus.h>
51 #include <machine/resource.h>
52
53 #include <sys/rman.h>
54
55 #include <sys/lock.h>
56 #include <sys/mutex.h>
57
58 #include <dev/iicbus/iiconf.h>
59 #include <dev/iicbus/iicbus.h>
60 #include <dev/ofw/ofw_bus.h>
61 #include <dev/ofw/ofw_bus_subr.h>
62
63 #include "iicbus_if.h"
64
65 #define MV_TWSI_NAME "twsi"
66
67 #define TWSI_SLAVE_ADDR 0x00
68 #define TWSI_EXT_SLAVE_ADDR 0x10
69 #define TWSI_DATA 0x04
70
71 #define TWSI_CONTROL 0x08
72 #define TWSI_CONTROL_ACK (1 << 2)
73 #define TWSI_CONTROL_IFLG (1 << 3)
74 #define TWSI_CONTROL_STOP (1 << 4)
75 #define TWSI_CONTROL_START (1 << 5)
76 #define TWSI_CONTROL_TWSIEN (1 << 6)
77 #define TWSI_CONTROL_INTEN (1 << 7)
78
79 #define TWSI_STATUS 0x0c
80 #define TWSI_STATUS_START 0x08
81 #define TWSI_STATUS_RPTD_START 0x10
82 #define TWSI_STATUS_ADDR_W_ACK 0x18
83 #define TWSI_STATUS_DATA_WR_ACK 0x28
84 #define TWSI_STATUS_ADDR_R_ACK 0x40
85 #define TWSI_STATUS_DATA_RD_ACK 0x50
86 #define TWSI_STATUS_DATA_RD_NOACK 0x58
87
88 #define TWSI_BAUD_RATE 0x0c
89 #define TWSI_BAUD_RATE_94DOT3 0x53 /* N=3, M=10 */
90 #define TWSI_BAUD_RATE_74DOT1 0x6b /* N=3, M=13 */
91 #define TWSI_BAUD_RATE_51DOT8 0x4c /* N=4, M=9 */
92 #define TWSI_BAUD_RATE_99DOT7 0x66 /* N=6, M=12 */
93
94 #define TWSI_SOFT_RESET 0x1c
95
96 #define TWSI_DEBUG
97 #undef TWSI_DEBUG
98
99 #ifdef TWSI_DEBUG
100 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
101 #else
102 #define debugf(fmt, args...)
103 #endif
104
105 struct mv_twsi_softc {
106 device_t dev;
107 struct resource *res[1]; /* SYS_RES_MEMORY */
108 struct mtx mutex;
109 device_t iicbus;
110 };
111
112 static int mv_twsi_probe(device_t);
113 static int mv_twsi_attach(device_t);
114 static int mv_twsi_detach(device_t);
115
116 static int mv_twsi_reset(device_t dev, u_char speed, u_char addr,
117 u_char *oldaddr);
118 static int mv_twsi_repeated_start(device_t dev, u_char slave, int timeout);
119 static int mv_twsi_start(device_t dev, u_char slave, int timeout);
120 static int mv_twsi_stop(device_t dev);
121 static int mv_twsi_read(device_t dev, char *buf, int len, int *read, int last,
122 int delay);
123 static int mv_twsi_write(device_t dev, const char *buf, int len, int *sent,
124 int timeout);
125
126 static struct resource_spec res_spec[] = {
127 { SYS_RES_MEMORY, 0, RF_ACTIVE },
128 { -1, 0 }
129 };
130
131 static device_method_t mv_twsi_methods[] = {
132 /* device interface */
133 DEVMETHOD(device_probe, mv_twsi_probe),
134 DEVMETHOD(device_attach, mv_twsi_attach),
135 DEVMETHOD(device_detach, mv_twsi_detach),
136
137 /* iicbus interface */
138 DEVMETHOD(iicbus_callback, iicbus_null_callback),
139 DEVMETHOD(iicbus_repeated_start, mv_twsi_repeated_start),
140 DEVMETHOD(iicbus_start, mv_twsi_start),
141 DEVMETHOD(iicbus_stop, mv_twsi_stop),
142 DEVMETHOD(iicbus_write, mv_twsi_write),
143 DEVMETHOD(iicbus_read, mv_twsi_read),
144 DEVMETHOD(iicbus_reset, mv_twsi_reset),
145 DEVMETHOD(iicbus_transfer, iicbus_transfer_gen),
146 { 0, 0 }
147 };
148
149 static devclass_t mv_twsi_devclass;
150
151 static driver_t mv_twsi_driver = {
152 MV_TWSI_NAME,
153 mv_twsi_methods,
154 sizeof(struct mv_twsi_softc),
155 };
156
157 DRIVER_MODULE(twsi, simplebus, mv_twsi_driver, mv_twsi_devclass, 0, 0);
158 DRIVER_MODULE(iicbus, twsi, iicbus_driver, iicbus_devclass, 0, 0);
159 MODULE_DEPEND(twsi, iicbus, 1, 1, 1);
160
161 static __inline uint32_t
162 TWSI_READ(struct mv_twsi_softc *sc, bus_size_t off)
163 {
164
165 return (bus_read_4(sc->res[0], off));
166 }
167
168 static __inline void
169 TWSI_WRITE(struct mv_twsi_softc *sc, bus_size_t off, uint32_t val)
170 {
171
172 bus_write_4(sc->res[0], off, val);
173 }
174
175 static __inline void
176 twsi_control_clear(struct mv_twsi_softc *sc, uint32_t mask)
177 {
178 uint32_t val;
179
180 val = TWSI_READ(sc, TWSI_CONTROL);
181 val &= ~mask;
182 TWSI_WRITE(sc, TWSI_CONTROL, val);
183 }
184
185 static __inline void
186 twsi_control_set(struct mv_twsi_softc *sc, uint32_t mask)
187 {
188 uint32_t val;
189
190 val = TWSI_READ(sc, TWSI_CONTROL);
191 val |= mask;
192 TWSI_WRITE(sc, TWSI_CONTROL, val);
193 }
194
195 static __inline void
196 twsi_clear_iflg(struct mv_twsi_softc *sc)
197 {
198
199 DELAY(1000);
200 twsi_control_clear(sc, TWSI_CONTROL_IFLG);
201 DELAY(1000);
202 }
203
204
205 /*
206 * timeout given in us
207 * returns
208 * 0 on sucessfull mask change
209 * non-zero on timeout
210 */
211 static int
212 twsi_poll_ctrl(struct mv_twsi_softc *sc, int timeout, uint32_t mask)
213 {
214
215 timeout /= 10;
216 while (!(TWSI_READ(sc, TWSI_CONTROL) & mask)) {
217 DELAY(10);
218 if (--timeout < 0)
219 return (timeout);
220 }
221 return (0);
222 }
223
224
225 /*
226 * 'timeout' is given in us. Note also that timeout handling is not exact --
227 * twsi_locked_start() total wait can be more than 2 x timeout
228 * (twsi_poll_ctrl() is called twice). 'mask' can be either TWSI_STATUS_START
229 * or TWSI_STATUS_RPTD_START
230 */
231 static int
232 twsi_locked_start(device_t dev, struct mv_twsi_softc *sc, int32_t mask,
233 u_char slave, int timeout)
234 {
235 int read_access, iflg_set = 0;
236 uint32_t status;
237
238 mtx_assert(&sc->mutex, MA_OWNED);
239
240 if (mask == TWSI_STATUS_RPTD_START)
241 /* read IFLG to know if it should be cleared later; from NBSD */
242 iflg_set = TWSI_READ(sc, TWSI_CONTROL) & TWSI_CONTROL_IFLG;
243
244 twsi_control_set(sc, TWSI_CONTROL_START);
245
246 if (mask == TWSI_STATUS_RPTD_START && iflg_set) {
247 debugf("IFLG set, clearing\n");
248 twsi_clear_iflg(sc);
249 }
250
251 /*
252 * Without this delay we timeout checking IFLG if the timeout is 0.
253 * NBSD driver always waits here too.
254 */
255 DELAY(1000);
256
257 if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
258 debugf("timeout sending %sSTART condition\n",
259 mask == TWSI_STATUS_START ? "" : "repeated ");
260 return (IIC_ETIMEOUT);
261 }
262
263 status = TWSI_READ(sc, TWSI_STATUS);
264 if (status != mask) {
265 debugf("wrong status (%02x) after sending %sSTART condition\n",
266 status, mask == TWSI_STATUS_START ? "" : "repeated ");
267 return (IIC_ESTATUS);
268 }
269
270 TWSI_WRITE(sc, TWSI_DATA, slave);
271 DELAY(1000);
272 twsi_clear_iflg(sc);
273
274 if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
275 debugf("timeout sending slave address\n");
276 return (IIC_ETIMEOUT);
277 }
278
279 read_access = (slave & 0x1) ? 1 : 0;
280 status = TWSI_READ(sc, TWSI_STATUS);
281 if (status != (read_access ?
282 TWSI_STATUS_ADDR_R_ACK : TWSI_STATUS_ADDR_W_ACK)) {
283 debugf("no ACK (status: %02x) after sending slave address\n",
284 status);
285 return (IIC_ENOACK);
286 }
287
288 return (IIC_NOERR);
289 }
290
291 static int
292 mv_twsi_probe(device_t dev)
293 {
294
295 if (!ofw_bus_is_compatible(dev, "mrvl,twsi"))
296 return (ENXIO);
297
298 device_set_desc(dev, "Marvell Integrated I2C Bus Controller");
299 return (BUS_PROBE_DEFAULT);
300 }
301
302 static int
303 mv_twsi_attach(device_t dev)
304 {
305 struct mv_twsi_softc *sc;
306
307 sc = device_get_softc(dev);
308 sc->dev = dev;
309
310 mtx_init(&sc->mutex, device_get_nameunit(dev), MV_TWSI_NAME, MTX_DEF);
311
312 /* Allocate IO resources */
313 if (bus_alloc_resources(dev, res_spec, sc->res)) {
314 device_printf(dev, "could not allocate resources\n");
315 mv_twsi_detach(dev);
316 return (ENXIO);
317 }
318
319 sc->iicbus = device_add_child(dev, "iicbus", -1);
320 if (sc->iicbus == NULL) {
321 device_printf(dev, "could not add iicbus child\n");
322 mv_twsi_detach(dev);
323 return (ENXIO);
324 }
325
326 bus_generic_attach(dev);
327 return (0);
328 }
329
330 static int
331 mv_twsi_detach(device_t dev)
332 {
333 struct mv_twsi_softc *sc;
334 int rv;
335
336 sc = device_get_softc(dev);
337
338 if ((rv = bus_generic_detach(dev)) != 0)
339 return (rv);
340
341 if (sc->iicbus != NULL)
342 if ((rv = device_delete_child(dev, sc->iicbus)) != 0)
343 return (rv);
344
345 bus_release_resources(dev, res_spec, sc->res);
346
347 mtx_destroy(&sc->mutex);
348 return (0);
349 }
350
351 /*
352 * Only slave mode supported, disregard [old]addr
353 */
354 static int
355 mv_twsi_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
356 {
357 struct mv_twsi_softc *sc;
358 uint32_t baud_rate;
359
360 sc = device_get_softc(dev);
361
362 switch (speed) {
363 case IIC_SLOW:
364 baud_rate = TWSI_BAUD_RATE_51DOT8;
365 break;
366 case IIC_FAST:
367 baud_rate = TWSI_BAUD_RATE_51DOT8;
368 break;
369 case IIC_UNKNOWN:
370 case IIC_FASTEST:
371 default:
372 baud_rate = TWSI_BAUD_RATE_99DOT7;
373 break;
374 }
375
376 mtx_lock(&sc->mutex);
377 TWSI_WRITE(sc, TWSI_SOFT_RESET, 0x0);
378 DELAY(2000);
379 TWSI_WRITE(sc, TWSI_BAUD_RATE, baud_rate);
380 TWSI_WRITE(sc, TWSI_CONTROL, TWSI_CONTROL_TWSIEN | TWSI_CONTROL_ACK);
381 DELAY(1000);
382 mtx_unlock(&sc->mutex);
383
384 return (0);
385 }
386
387 /*
388 * timeout is given in us
389 */
390 static int
391 mv_twsi_repeated_start(device_t dev, u_char slave, int timeout)
392 {
393 struct mv_twsi_softc *sc;
394 int rv;
395
396 sc = device_get_softc(dev);
397
398 mtx_lock(&sc->mutex);
399 rv = twsi_locked_start(dev, sc, TWSI_STATUS_RPTD_START, slave,
400 timeout);
401 mtx_unlock(&sc->mutex);
402
403 if (rv) {
404 mv_twsi_stop(dev);
405 return (rv);
406 } else
407 return (IIC_NOERR);
408 }
409
410 /*
411 * timeout is given in us
412 */
413 static int
414 mv_twsi_start(device_t dev, u_char slave, int timeout)
415 {
416 struct mv_twsi_softc *sc;
417 int rv;
418
419 sc = device_get_softc(dev);
420
421 mtx_lock(&sc->mutex);
422 rv = twsi_locked_start(dev, sc, TWSI_STATUS_START, slave, timeout);
423 mtx_unlock(&sc->mutex);
424
425 if (rv) {
426 mv_twsi_stop(dev);
427 return (rv);
428 } else
429 return (IIC_NOERR);
430 }
431
432 static int
433 mv_twsi_stop(device_t dev)
434 {
435 struct mv_twsi_softc *sc;
436
437 sc = device_get_softc(dev);
438
439 mtx_lock(&sc->mutex);
440 twsi_control_set(sc, TWSI_CONTROL_STOP);
441 DELAY(1000);
442 twsi_clear_iflg(sc);
443 mtx_unlock(&sc->mutex);
444
445 return (IIC_NOERR);
446 }
447
448 static int
449 mv_twsi_read(device_t dev, char *buf, int len, int *read, int last, int delay)
450 {
451 struct mv_twsi_softc *sc;
452 uint32_t status;
453 int last_byte, rv;
454
455 sc = device_get_softc(dev);
456
457 mtx_lock(&sc->mutex);
458 *read = 0;
459 while (*read < len) {
460 /*
461 * Check if we are reading last byte of the last buffer,
462 * do not send ACK then, per I2C specs
463 */
464 last_byte = ((*read == len - 1) && last) ? 1 : 0;
465 if (last_byte)
466 twsi_control_clear(sc, TWSI_CONTROL_ACK);
467 else
468 twsi_control_set(sc, TWSI_CONTROL_ACK);
469
470 DELAY (1000);
471 twsi_clear_iflg(sc);
472
473 if (twsi_poll_ctrl(sc, delay, TWSI_CONTROL_IFLG)) {
474 debugf("timeout reading data\n");
475 rv = IIC_ETIMEOUT;
476 goto out;
477 }
478
479 status = TWSI_READ(sc, TWSI_STATUS);
480 if (status != (last_byte ?
481 TWSI_STATUS_DATA_RD_NOACK : TWSI_STATUS_DATA_RD_ACK)) {
482 debugf("wrong status (%02x) while reading\n", status);
483 rv = IIC_ESTATUS;
484 goto out;
485 }
486
487 *buf++ = TWSI_READ(sc, TWSI_DATA);
488 (*read)++;
489 }
490 rv = IIC_NOERR;
491 out:
492 mtx_unlock(&sc->mutex);
493 return (rv);
494 }
495
496 static int
497 mv_twsi_write(device_t dev, const char *buf, int len, int *sent, int timeout)
498 {
499 struct mv_twsi_softc *sc;
500 uint32_t status;
501 int rv;
502
503 sc = device_get_softc(dev);
504
505 mtx_lock(&sc->mutex);
506 *sent = 0;
507 while (*sent < len) {
508 TWSI_WRITE(sc, TWSI_DATA, *buf++);
509
510 twsi_clear_iflg(sc);
511 if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
512 debugf("timeout writing data\n");
513 rv = IIC_ETIMEOUT;
514 goto out;
515 }
516
517 status = TWSI_READ(sc, TWSI_STATUS);
518 if (status != TWSI_STATUS_DATA_WR_ACK) {
519 debugf("wrong status (%02x) while writing\n", status);
520 rv = IIC_ESTATUS;
521 goto out;
522 }
523 (*sent)++;
524 }
525 rv = IIC_NOERR;
526 out:
527 mtx_unlock(&sc->mutex);
528 return (rv);
529 }
Cache object: abf492957329630d065e42f346fe6aa6
|