]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/samsung/exynos/exynos5_i2c.c
Change POSIX compliance level for visibility of strerror_l(3).
[FreeBSD/FreeBSD.git] / sys / arm / samsung / exynos / exynos5_i2c.c
1 /*-
2  * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28  * Samsung Exynos 5 Inter-Integrated Circuit (I2C)
29  * Chapter 13, Exynos 5 Dual User's Manual Public Rev 1.00
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/kernel.h>
39 #include <sys/module.h>
40 #include <sys/malloc.h>
41 #include <sys/rman.h>
42 #include <sys/timeet.h>
43 #include <sys/timetc.h>
44
45 #include <dev/iicbus/iiconf.h>
46 #include <dev/iicbus/iicbus.h>
47
48 #include "iicbus_if.h"
49
50 #include <dev/ofw/openfirm.h>
51 #include <dev/ofw/ofw_bus.h>
52 #include <dev/ofw/ofw_bus_subr.h>
53
54 #include <machine/bus.h>
55 #include <machine/cpu.h>
56 #include <machine/intr.h>
57
58 #include <arm/samsung/exynos/exynos5_common.h>
59
60 #define I2CCON          0x00    /* Control register */
61 #define  ACKGEN         (1 << 7) /* Acknowledge Enable */
62 /*
63  * Source Clock of I2C-bus Transmit Clock Prescaler
64  *
65  * 0 = I2CCLK = fPCLK/16
66  * 1 = I2CCLK = fPCLK/512
67  */
68 #define  I2CCLK         (1 << 6)
69 #define  IRQ_EN         (1 << 5)        /* Tx/Rx Interrupt Enable/Disable */
70 #define  IPEND          (1 << 4)        /* Tx/Rx Interrupt Pending Flag */
71 #define  CLKVAL_M       0xf             /* Transmit Clock Prescaler Mask */
72 #define  CLKVAL_S       0
73 #define I2CSTAT         0x04            /* Control/status register */
74 #define  I2CMODE_M      0x3             /* Master/Slave Tx/Rx Mode Select */
75 #define  I2CMODE_S      6
76 #define  I2CMODE_SR     0x0             /* Slave Receive Mode */
77 #define  I2CMODE_ST     0x1             /* Slave Transmit Mode */
78 #define  I2CMODE_MR     0x2             /* Master Receive Mode */
79 #define  I2CMODE_MT     0x3             /* Master Transmit Mode */
80 #define  I2CSTAT_BSY    (1 << 5)        /* Busy Signal Status bit */
81 #define  I2C_START_STOP (1 << 5)        /* Busy Signal Status bit */
82 #define  RXTX_EN        (1 << 4)        /* Data Output Enable/Disable */
83 #define  ARBST          (1 << 3)        /* Arbitration status flag */
84 #define  ADDAS          (1 << 2)        /* Address-as-slave Status Flag */
85 #define  ADDZERO        (1 << 1)        /* Address Zero Status Flag */
86 #define  ACKRECVD       (1 << 0)        /* Last-received Bit Status Flag */
87 #define I2CADD          0x08            /* Address register */
88 #define I2CDS           0x0C            /* Transmit/receive data shift */
89 #define I2CLC           0x10            /* Multi-master line control */
90 #define  FILTER_EN      (1 << 2)        /* Filter Enable bit */
91 #define  SDAOUT_DELAY_M 0x3             /* SDA Line Delay Length */
92 #define  SDAOUT_DELAY_S 0
93
94 #ifdef DEBUG
95 #define DPRINTF(fmt, args...) \
96         printf(fmt, ##args)
97 #else
98 #define DPRINTF(fmt, args...)
99 #endif
100
101 static int i2c_start(device_t, u_char, int);
102 static int i2c_stop(device_t);
103 static int i2c_reset(device_t, u_char, u_char, u_char *);
104 static int i2c_read(device_t, char *, int, int *, int, int);
105 static int i2c_write(device_t, const char *, int, int *, int);
106
107 struct i2c_softc {
108         struct resource         *res[2];
109         bus_space_tag_t         bst;
110         bus_space_handle_t      bsh;
111         device_t                dev;
112         device_t                iicbus;
113         struct mtx              mutex;
114         void                    *ih;
115         int                     intr;
116 };
117
118 static struct resource_spec i2c_spec[] = {
119         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
120         { SYS_RES_IRQ,          0,      RF_ACTIVE },
121         { -1, 0 }
122 };
123
124 static int
125 i2c_probe(device_t dev)
126 {
127
128         if (!ofw_bus_status_okay(dev))
129                 return (ENXIO);
130
131         if (!ofw_bus_is_compatible(dev, "exynos,i2c"))
132                 return (ENXIO);
133
134         device_set_desc(dev, "Samsung Exynos 5 I2C controller");
135         return (BUS_PROBE_DEFAULT);
136 }
137
138 static int
139 clear_ipend(struct i2c_softc *sc)
140 {
141         int reg;
142
143         reg = READ1(sc, I2CCON);
144         reg &= ~(IPEND);
145         WRITE1(sc, I2CCON, reg);
146
147         return (0);
148 }
149
150 static int
151 i2c_attach(device_t dev)
152 {
153         struct i2c_softc *sc;
154         int reg;
155
156         sc = device_get_softc(dev);
157         sc->dev = dev;
158
159         mtx_init(&sc->mutex, device_get_nameunit(dev), "I2C", MTX_DEF);
160
161         if (bus_alloc_resources(dev, i2c_spec, sc->res)) {
162                 device_printf(dev, "could not allocate resources\n");
163                 return (ENXIO);
164         }
165
166         /* Memory interface */
167         sc->bst = rman_get_bustag(sc->res[0]);
168         sc->bsh = rman_get_bushandle(sc->res[0]);
169
170         sc->iicbus = device_add_child(dev, "iicbus", -1);
171         if (sc->iicbus == NULL) {
172                 device_printf(dev, "could not add iicbus child");
173                 mtx_destroy(&sc->mutex);
174                 return (ENXIO);
175         }
176
177         WRITE1(sc, I2CSTAT, 0);
178         WRITE1(sc, I2CADD, 0x00);
179
180         /* Mode */
181         reg = (RXTX_EN);
182         reg |= (I2CMODE_MT << I2CMODE_S);
183         WRITE1(sc, I2CSTAT, reg);
184
185         bus_generic_attach(dev);
186
187         return (0);
188 }
189
190 static int
191 wait_for_iif(struct i2c_softc *sc)
192 {
193         int retry;
194         int reg;
195
196         retry = 1000;
197         while (retry --) {
198                 reg = READ1(sc, I2CCON);
199                 if (reg & IPEND) {
200                         return (IIC_NOERR);
201                 }
202                 DELAY(50);
203         }
204
205         return (IIC_ETIMEOUT);
206 }
207
208 static int
209 wait_for_nibb(struct i2c_softc *sc)
210 {
211         int retry;
212
213         retry = 1000;
214         while (retry --) {
215                 if ((READ1(sc, I2CSTAT) & I2CSTAT_BSY) == 0)
216                         return (IIC_NOERR);
217                 DELAY(10);
218         }
219
220         return (IIC_ETIMEOUT);
221 }
222
223 static int
224 is_ack(struct i2c_softc *sc)
225 {
226         int stat;
227
228         stat = READ1(sc, I2CSTAT);
229         if (!(stat & 1)) {
230                 /* ACK received */
231                 return (1);
232         }
233
234         return (0);
235 }
236
237 static int
238 i2c_start(device_t dev, u_char slave, int timeout)
239 {
240         struct i2c_softc *sc;
241         int error;
242         int reg;
243
244         sc = device_get_softc(dev);
245
246         DPRINTF("i2c start\n");
247
248         mtx_lock(&sc->mutex);
249
250 #if 0
251         DPRINTF("I2CCON == 0x%08x\n", READ1(sc, I2CCON));
252         DPRINTF("I2CSTAT == 0x%08x\n", READ1(sc, I2CSTAT));
253 #endif
254
255         if (slave & 1) {
256                 slave &= ~(1);
257                 slave <<= 1;
258                 slave |= 1;
259         } else {
260                 slave <<= 1;
261         }
262
263         error = wait_for_nibb(sc);
264         if (error) {
265                 mtx_unlock(&sc->mutex);
266                 DPRINTF("cant i2c start: IIC_EBUSERR\n");
267                 return (IIC_EBUSERR);
268         }
269
270         reg = READ1(sc, I2CCON);
271         reg |= (IRQ_EN | ACKGEN);
272         WRITE1(sc, I2CCON, reg);
273
274         WRITE1(sc, I2CDS, slave);
275         DELAY(50);
276
277         reg = (RXTX_EN);
278         reg |= I2C_START_STOP;
279         reg |= (I2CMODE_MT << I2CMODE_S);
280         WRITE1(sc, I2CSTAT, reg);
281
282         error = wait_for_iif(sc);
283         if (error) {
284                 DPRINTF("cant i2c start: iif error\n");
285
286                 mtx_unlock(&sc->mutex);
287                 return (error);
288         }
289
290         if (!is_ack(sc)) {
291                 DPRINTF("cant i2c start: no ack\n");
292
293                 mtx_unlock(&sc->mutex);
294                 return (IIC_ENOACK);
295         }
296
297         mtx_unlock(&sc->mutex);
298         return (IIC_NOERR);
299 }
300
301 static int
302 i2c_stop(device_t dev)
303 {
304         struct i2c_softc *sc;
305         int reg;
306         int error;
307
308         sc = device_get_softc(dev);
309
310         DPRINTF("i2c stop\n");
311
312         mtx_lock(&sc->mutex);
313
314         reg = READ1(sc, I2CSTAT);
315         int mode = (reg >> I2CMODE_S) & I2CMODE_M;
316
317         reg = (RXTX_EN);
318         reg |= (mode << I2CMODE_S);
319         WRITE1(sc, I2CSTAT, reg);
320
321         clear_ipend(sc);
322
323         error = wait_for_nibb(sc);
324         if (error) {
325                 DPRINTF("cant i2c stop: nibb error\n");
326                 return (error);
327         }
328
329         mtx_unlock(&sc->mutex);
330         return (IIC_NOERR);
331 }
332
333 static int
334 i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldadr)
335 {
336         struct i2c_softc *sc;
337
338         sc = device_get_softc(dev);
339
340         DPRINTF("i2c reset\n");
341
342         mtx_lock(&sc->mutex);
343
344         /* TODO */
345
346         mtx_unlock(&sc->mutex);
347
348         return (IIC_NOERR);
349 }
350
351 static int
352 i2c_read(device_t dev, char *buf, int len,
353     int *read, int last, int delay)
354 {
355         struct i2c_softc *sc;
356         int error;
357         int reg;
358         uint8_t d;
359
360         sc = device_get_softc(dev);
361
362         DPRINTF("i2c read\n");
363
364         reg = (RXTX_EN);
365         reg |= (I2CMODE_MR << I2CMODE_S);
366         reg |= I2C_START_STOP;
367         WRITE1(sc, I2CSTAT, reg);
368
369         *read = 0;
370         mtx_lock(&sc->mutex);
371
372         /* dummy read */
373         clear_ipend(sc);
374         error = wait_for_iif(sc);
375         if (error) {
376                 DPRINTF("cant i2c read: iif error\n");
377                 mtx_unlock(&sc->mutex);
378                 return (error);
379         }
380         READ1(sc, I2CDS);
381
382         DPRINTF("Read ");
383         while (*read < len) {
384                 /* Do not ack last read */
385                 if (*read == (len - 1)) {
386                         reg = READ1(sc, I2CCON);
387                         reg &= ~(ACKGEN);
388                         WRITE1(sc, I2CCON, reg);
389                 }
390
391                 clear_ipend(sc);
392
393                 error = wait_for_iif(sc);
394                 if (error) {
395                         DPRINTF("cant i2c read: iif error\n");
396                         mtx_unlock(&sc->mutex);
397                         return (error);
398                 }
399
400                 d = READ1(sc, I2CDS);
401                 DPRINTF("0x%02x ", d);
402                 *buf++ = d;
403                 (*read)++;
404         }
405         DPRINTF("\n");
406
407         mtx_unlock(&sc->mutex);
408         return (IIC_NOERR);
409 }
410
411 static int
412 i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout)
413 {
414         struct i2c_softc *sc;
415         int error;
416
417         sc = device_get_softc(dev);
418
419         DPRINTF("i2c write\n");
420
421         *sent = 0;
422
423         mtx_lock(&sc->mutex);
424
425         DPRINTF("writing ");
426         while (*sent < len) {
427                 uint8_t d = *buf++;
428                 DPRINTF("0x%02x ", d);
429
430                 WRITE1(sc, I2CDS, d);
431                 DELAY(50);
432
433                 clear_ipend(sc);
434
435                 error = wait_for_iif(sc);
436                 if (error) {
437                         DPRINTF("cant i2c write: iif error\n");
438                         mtx_unlock(&sc->mutex);
439                         return (error);
440                 }
441
442                 if (!is_ack(sc)) {
443                         DPRINTF("cant i2c write: no ack\n");
444                         mtx_unlock(&sc->mutex);
445                         return (IIC_ENOACK);
446                 }
447
448                 (*sent)++;
449         }
450         DPRINTF("\n");
451
452         mtx_unlock(&sc->mutex);
453         return (IIC_NOERR);
454 }
455
456 static device_method_t i2c_methods[] = {
457         DEVMETHOD(device_probe,         i2c_probe),
458         DEVMETHOD(device_attach,        i2c_attach),
459
460         DEVMETHOD(iicbus_callback,              iicbus_null_callback),
461         DEVMETHOD(iicbus_start,                 i2c_start),
462         DEVMETHOD(iicbus_stop,                  i2c_stop),
463         DEVMETHOD(iicbus_reset,                 i2c_reset),
464         DEVMETHOD(iicbus_read,                  i2c_read),
465         DEVMETHOD(iicbus_write,                 i2c_write),
466         DEVMETHOD(iicbus_transfer,              iicbus_transfer_gen),
467         { 0, 0 }
468 };
469
470 static driver_t i2c_driver = {
471         "i2c",
472         i2c_methods,
473         sizeof(struct i2c_softc),
474 };
475
476 static devclass_t i2c_devclass;
477
478 DRIVER_MODULE(i2c, simplebus, i2c_driver, i2c_devclass, 0, 0);
479 DRIVER_MODULE(iicbus, i2c, iicbus_driver, iicbus_devclass, 0, 0);