]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/iicbus/twsi/twsi.c
Update ELF Tool Chain to upstream r3520
[FreeBSD/FreeBSD.git] / sys / dev / iicbus / twsi / 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  * and Allwinner 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$");
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/_inttypes.h>
51 #include <machine/bus.h>
52 #include <machine/resource.h>
53
54 #include <sys/rman.h>
55
56 #include <sys/lock.h>
57 #include <sys/mutex.h>
58
59 #include <dev/iicbus/iiconf.h>
60 #include <dev/iicbus/iicbus.h>
61 #include <dev/ofw/ofw_bus.h>
62 #include <dev/ofw/ofw_bus_subr.h>
63
64 #include <dev/iicbus/twsi/twsi.h>
65
66 #include "iicbus_if.h"
67
68 #define TWSI_CONTROL_ACK        (1 << 2)
69 #define TWSI_CONTROL_IFLG       (1 << 3)
70 #define TWSI_CONTROL_STOP       (1 << 4)
71 #define TWSI_CONTROL_START      (1 << 5)
72 #define TWSI_CONTROL_TWSIEN     (1 << 6)
73 #define TWSI_CONTROL_INTEN      (1 << 7)
74
75 #define TWSI_STATUS_START               0x08
76 #define TWSI_STATUS_RPTD_START          0x10
77 #define TWSI_STATUS_ADDR_W_ACK          0x18
78 #define TWSI_STATUS_DATA_WR_ACK         0x28
79 #define TWSI_STATUS_ADDR_R_ACK          0x40
80 #define TWSI_STATUS_DATA_RD_ACK         0x50
81 #define TWSI_STATUS_DATA_RD_NOACK       0x58
82
83 #define TWSI_DEBUG
84 #undef TWSI_DEBUG
85
86 #ifdef TWSI_DEBUG
87 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
88 #else
89 #define debugf(fmt, args...)
90 #endif
91
92 static struct resource_spec res_spec[] = {
93         { SYS_RES_MEMORY, 0, RF_ACTIVE },
94         { -1, 0 }
95 };
96
97 static __inline uint32_t
98 TWSI_READ(struct twsi_softc *sc, bus_size_t off)
99 {
100
101         return (bus_read_4(sc->res[0], off));
102 }
103
104 static __inline void
105 TWSI_WRITE(struct twsi_softc *sc, bus_size_t off, uint32_t val)
106 {
107
108         bus_write_4(sc->res[0], off, val);
109 }
110
111 static __inline void
112 twsi_control_clear(struct twsi_softc *sc, uint32_t mask)
113 {
114         uint32_t val;
115
116         val = TWSI_READ(sc, sc->reg_control);
117         val &= ~mask;
118         TWSI_WRITE(sc, sc->reg_control, val);
119 }
120
121 static __inline void
122 twsi_control_set(struct twsi_softc *sc, uint32_t mask)
123 {
124         uint32_t val;
125
126         val = TWSI_READ(sc, sc->reg_control);
127         val |= mask;
128         TWSI_WRITE(sc, sc->reg_control, val);
129 }
130
131 static __inline void
132 twsi_clear_iflg(struct twsi_softc *sc)
133 {
134
135         DELAY(1000);
136         twsi_control_clear(sc, TWSI_CONTROL_IFLG);
137         DELAY(1000);
138 }
139
140
141 /*
142  * timeout given in us
143  * returns
144  *   0 on successful mask change
145  *   non-zero on timeout
146  */
147 static int
148 twsi_poll_ctrl(struct twsi_softc *sc, int timeout, uint32_t mask)
149 {
150
151         timeout /= 10;
152         while (!(TWSI_READ(sc, sc->reg_control) & mask)) {
153                 DELAY(10);
154                 if (--timeout < 0)
155                         return (timeout);
156         }
157         return (0);
158 }
159
160
161 /*
162  * 'timeout' is given in us. Note also that timeout handling is not exact --
163  * twsi_locked_start() total wait can be more than 2 x timeout
164  * (twsi_poll_ctrl() is called twice). 'mask' can be either TWSI_STATUS_START
165  * or TWSI_STATUS_RPTD_START
166  */
167 static int
168 twsi_locked_start(device_t dev, struct twsi_softc *sc, int32_t mask,
169     u_char slave, int timeout)
170 {
171         int read_access, iflg_set = 0;
172         uint32_t status;
173
174         mtx_assert(&sc->mutex, MA_OWNED);
175
176         if (mask == TWSI_STATUS_RPTD_START)
177                 /* read IFLG to know if it should be cleared later; from NBSD */
178                 iflg_set = TWSI_READ(sc, sc->reg_control) & TWSI_CONTROL_IFLG;
179
180         twsi_control_set(sc, TWSI_CONTROL_START);
181
182         if (mask == TWSI_STATUS_RPTD_START && iflg_set) {
183                 debugf("IFLG set, clearing\n");
184                 twsi_clear_iflg(sc);
185         }
186
187         /*
188          * Without this delay we timeout checking IFLG if the timeout is 0.
189          * NBSD driver always waits here too.
190          */
191         DELAY(1000);
192
193         if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
194                 debugf("timeout sending %sSTART condition\n",
195                     mask == TWSI_STATUS_START ? "" : "repeated ");
196                 return (IIC_ETIMEOUT);
197         }
198
199         status = TWSI_READ(sc, sc->reg_status);
200         if (status != mask) {
201                 debugf("wrong status (%02x) after sending %sSTART condition\n",
202                     status, mask == TWSI_STATUS_START ? "" : "repeated ");
203                 return (IIC_ESTATUS);
204         }
205
206         TWSI_WRITE(sc, sc->reg_data, slave);
207         DELAY(1000);
208         twsi_clear_iflg(sc);
209
210         if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
211                 debugf("timeout sending slave address\n");
212                 return (IIC_ETIMEOUT);
213         }
214         
215         read_access = (slave & 0x1) ? 1 : 0;
216         status = TWSI_READ(sc, sc->reg_status);
217         if (status != (read_access ?
218             TWSI_STATUS_ADDR_R_ACK : TWSI_STATUS_ADDR_W_ACK)) {
219                 debugf("no ACK (status: %02x) after sending slave address\n",
220                     status);
221                 return (IIC_ENOACK);
222         }
223
224         return (IIC_NOERR);
225 }
226
227 /*
228  * Only slave mode supported, disregard [old]addr
229  */
230 static int
231 twsi_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
232 {
233         struct twsi_softc *sc;
234         uint32_t param;
235
236         sc = device_get_softc(dev);
237
238         switch (speed) {
239         case IIC_SLOW:
240         case IIC_FAST:
241                 param = sc->baud_rate[speed].param;
242                 break;
243         case IIC_FASTEST:
244         case IIC_UNKNOWN:
245         default:
246                 param = sc->baud_rate[IIC_FAST].param;
247                 break;
248         }
249
250         mtx_lock(&sc->mutex);
251         TWSI_WRITE(sc, sc->reg_soft_reset, 0x0);
252         DELAY(2000);
253         TWSI_WRITE(sc, sc->reg_baud_rate, param);
254         TWSI_WRITE(sc, sc->reg_control, TWSI_CONTROL_TWSIEN | TWSI_CONTROL_ACK);
255         DELAY(1000);
256         mtx_unlock(&sc->mutex);
257
258         return (0);
259 }
260
261 static int
262 twsi_stop(device_t dev)
263 {
264         struct twsi_softc *sc;
265
266         sc = device_get_softc(dev);
267
268         mtx_lock(&sc->mutex);
269         twsi_control_set(sc, TWSI_CONTROL_STOP);
270         DELAY(1000);
271         twsi_clear_iflg(sc);
272         mtx_unlock(&sc->mutex);
273
274         return (IIC_NOERR);
275 }
276
277 /*
278  * timeout is given in us
279  */
280 static int
281 twsi_repeated_start(device_t dev, u_char slave, int timeout)
282 {
283         struct twsi_softc *sc;
284         int rv;
285
286         sc = device_get_softc(dev);
287
288         mtx_lock(&sc->mutex);
289         rv = twsi_locked_start(dev, sc, TWSI_STATUS_RPTD_START, slave,
290             timeout);
291         mtx_unlock(&sc->mutex);
292
293         if (rv) {
294                 twsi_stop(dev);
295                 return (rv);
296         } else
297                 return (IIC_NOERR);
298 }
299
300 /*
301  * timeout is given in us
302  */
303 static int
304 twsi_start(device_t dev, u_char slave, int timeout)
305 {
306         struct twsi_softc *sc;
307         int rv;
308
309         sc = device_get_softc(dev);
310
311         mtx_lock(&sc->mutex);
312         rv = twsi_locked_start(dev, sc, TWSI_STATUS_START, slave, timeout);
313         mtx_unlock(&sc->mutex);
314
315         if (rv) {
316                 twsi_stop(dev);
317                 return (rv);
318         } else
319                 return (IIC_NOERR);
320 }
321
322 static int
323 twsi_read(device_t dev, char *buf, int len, int *read, int last, int delay)
324 {
325         struct twsi_softc *sc;
326         uint32_t status;
327         int last_byte, rv;
328
329         sc = device_get_softc(dev);
330
331         mtx_lock(&sc->mutex);
332         *read = 0;
333         while (*read < len) {
334                 /*
335                  * Check if we are reading last byte of the last buffer,
336                  * do not send ACK then, per I2C specs
337                  */
338                 last_byte = ((*read == len - 1) && last) ? 1 : 0;
339                 if (last_byte)
340                         twsi_control_clear(sc, TWSI_CONTROL_ACK);
341                 else
342                         twsi_control_set(sc, TWSI_CONTROL_ACK);
343
344                 DELAY (1000);
345                 twsi_clear_iflg(sc);
346
347                 if (twsi_poll_ctrl(sc, delay, TWSI_CONTROL_IFLG)) {
348                         debugf("timeout reading data\n");
349                         rv = IIC_ETIMEOUT;
350                         goto out;
351                 }
352
353                 status = TWSI_READ(sc, sc->reg_status);
354                 if (status != (last_byte ?
355                     TWSI_STATUS_DATA_RD_NOACK : TWSI_STATUS_DATA_RD_ACK)) {
356                         debugf("wrong status (%02x) while reading\n", status);
357                         rv = IIC_ESTATUS;
358                         goto out;
359                 }
360
361                 *buf++ = TWSI_READ(sc, sc->reg_data);
362                 (*read)++;
363         }
364         rv = IIC_NOERR;
365 out:
366         mtx_unlock(&sc->mutex);
367         return (rv);
368 }
369
370 static int
371 twsi_write(device_t dev, const char *buf, int len, int *sent, int timeout)
372 {
373         struct twsi_softc *sc;
374         uint32_t status;
375         int rv;
376
377         sc = device_get_softc(dev);
378
379         mtx_lock(&sc->mutex);
380         *sent = 0;
381         while (*sent < len) {
382                 TWSI_WRITE(sc, sc->reg_data, *buf++);
383
384                 twsi_clear_iflg(sc);
385                 if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
386                         debugf("timeout writing data\n");
387                         rv = IIC_ETIMEOUT;
388                         goto out;
389                 }
390
391                 status = TWSI_READ(sc, sc->reg_status);
392                 if (status != TWSI_STATUS_DATA_WR_ACK) {
393                         debugf("wrong status (%02x) while writing\n", status);
394                         rv = IIC_ESTATUS;
395                         goto out;
396                 }
397                 (*sent)++;
398         }
399         rv = IIC_NOERR;
400 out:
401         mtx_unlock(&sc->mutex);
402         return (rv);
403 }
404
405 int
406 twsi_attach(device_t dev)
407 {
408         struct twsi_softc *sc;
409
410         sc = device_get_softc(dev);
411         sc->dev = dev;
412
413         mtx_init(&sc->mutex, device_get_nameunit(dev), "twsi", MTX_DEF);
414
415         if (bus_alloc_resources(dev, res_spec, sc->res)) {
416                 device_printf(dev, "could not allocate resources\n");
417                 twsi_detach(dev);
418                 return (ENXIO);
419         }
420
421         /* Attach the iicbus. */
422         if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) {
423                 device_printf(dev, "could not allocate iicbus instance\n");
424                 twsi_detach(dev);
425                 return (ENXIO);
426         }
427         bus_generic_attach(dev);
428
429         return (0);
430 }
431
432 int
433 twsi_detach(device_t dev)
434 {
435         struct twsi_softc *sc;
436         int rv;
437
438         sc = device_get_softc(dev);
439
440         if ((rv = bus_generic_detach(dev)) != 0)
441                 return (rv);
442
443         if (sc->iicbus != NULL)
444                 if ((rv = device_delete_child(dev, sc->iicbus)) != 0)
445                         return (rv);
446
447         bus_release_resources(dev, res_spec, sc->res);
448
449         mtx_destroy(&sc->mutex);
450         return (0);
451 }
452
453 static device_method_t twsi_methods[] = {
454         /* device interface */
455         DEVMETHOD(device_detach,        twsi_detach),
456
457         /* Bus interface */
458         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
459         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
460         DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
461         DEVMETHOD(bus_release_resource, bus_generic_release_resource),
462         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
463         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
464         DEVMETHOD(bus_adjust_resource,  bus_generic_adjust_resource),
465         DEVMETHOD(bus_set_resource,     bus_generic_rl_set_resource),
466         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
467
468         /* iicbus interface */
469         DEVMETHOD(iicbus_callback, iicbus_null_callback),
470         DEVMETHOD(iicbus_repeated_start, twsi_repeated_start),
471         DEVMETHOD(iicbus_start,         twsi_start),
472         DEVMETHOD(iicbus_stop,          twsi_stop),
473         DEVMETHOD(iicbus_write,         twsi_write),
474         DEVMETHOD(iicbus_read,          twsi_read),
475         DEVMETHOD(iicbus_reset,         twsi_reset),
476         DEVMETHOD(iicbus_transfer,      iicbus_transfer_gen),
477         { 0, 0 }
478 };
479
480 DEFINE_CLASS_0(twsi, twsi_driver, twsi_methods,
481     sizeof(struct twsi_softc));