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