]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/gpio/gpioiic.c
Update ena-com HAL to v1.1.4.3 and update driver accordingly
[FreeBSD/FreeBSD.git] / sys / dev / gpio / gpioiic.c
1 /*-
2  * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
3  * Copyright (c) 2010 Luiz Otavio O Souza
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include "opt_platform.h"
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/gpio.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39
40 #ifdef FDT
41 #include <dev/fdt/fdt_common.h>
42 #include <dev/ofw/ofw_bus.h>
43 #endif
44
45 #include <dev/gpio/gpiobusvar.h>
46 #include <dev/iicbus/iiconf.h>
47 #include <dev/iicbus/iicbus.h>
48
49 #include "gpiobus_if.h"
50 #include "iicbb_if.h"
51
52 #define GPIOIIC_SCL_DFLT        0
53 #define GPIOIIC_SDA_DFLT        1
54 #define GPIOIIC_MIN_PINS        2
55
56 struct gpioiic_softc 
57 {
58         device_t        sc_dev;
59         device_t        sc_busdev;
60         int             scl_pin;
61         int             sda_pin;
62 };
63
64 static int gpioiic_probe(device_t);
65 static int gpioiic_attach(device_t);
66
67 /* iicbb interface */
68 static void gpioiic_reset_bus(device_t);
69 static void gpioiic_setsda(device_t, int);
70 static void gpioiic_setscl(device_t, int);
71 static int gpioiic_getsda(device_t);
72 static int gpioiic_getscl(device_t);
73 static int gpioiic_reset(device_t, u_char, u_char, u_char *);
74
75 static int
76 gpioiic_probe(device_t dev)
77 {
78         struct gpiobus_ivar *devi;
79
80 #ifdef FDT
81         if (!ofw_bus_status_okay(dev))
82                 return (ENXIO);
83         if (!ofw_bus_is_compatible(dev, "gpioiic"))
84                 return (ENXIO);
85 #endif
86         devi = GPIOBUS_IVAR(dev);
87         if (devi->npins < GPIOIIC_MIN_PINS) {
88                 device_printf(dev,
89                     "gpioiic needs at least %d GPIO pins (only %d given).\n",
90                     GPIOIIC_MIN_PINS, devi->npins);
91                 return (ENXIO);
92         }
93         device_set_desc(dev, "GPIO I2C bit-banging driver");
94
95         return (BUS_PROBE_DEFAULT);
96 }
97
98 static int
99 gpioiic_attach(device_t dev)
100 {
101         device_t                bitbang;
102 #ifdef FDT
103         phandle_t               node;
104         pcell_t                 pin;
105 #endif
106         struct gpiobus_ivar     *devi;
107         struct gpioiic_softc    *sc;
108
109         sc = device_get_softc(dev);
110         sc->sc_dev = dev;
111         sc->sc_busdev = device_get_parent(dev);
112         if (resource_int_value(device_get_name(dev),
113                 device_get_unit(dev), "scl", &sc->scl_pin))
114                 sc->scl_pin = GPIOIIC_SCL_DFLT;
115         if (resource_int_value(device_get_name(dev),
116                 device_get_unit(dev), "sda", &sc->sda_pin))
117                 sc->sda_pin = GPIOIIC_SDA_DFLT;
118
119 #ifdef FDT
120         if ((node = ofw_bus_get_node(dev)) == -1)
121                 return (ENXIO);
122         if (OF_getencprop(node, "scl", &pin, sizeof(pin)) > 0)
123                 sc->scl_pin = (int)pin;
124         if (OF_getencprop(node, "sda", &pin, sizeof(pin)) > 0)
125                 sc->sda_pin = (int)pin;
126 #endif
127
128         if (sc->scl_pin < 0 || sc->scl_pin > 1)
129                 sc->scl_pin = GPIOIIC_SCL_DFLT;
130         if (sc->sda_pin < 0 || sc->sda_pin > 1)
131                 sc->sda_pin = GPIOIIC_SDA_DFLT;
132
133         devi = GPIOBUS_IVAR(dev);
134         device_printf(dev, "SCL pin: %d, SDA pin: %d\n",
135             devi->pins[sc->scl_pin], devi->pins[sc->sda_pin]);
136
137         /* add generic bit-banging code */
138         bitbang = device_add_child(dev, "iicbb", -1);
139         device_probe_and_attach(bitbang);
140
141         return (0);
142 }
143
144 /*
145  * Reset bus by setting SDA first and then SCL. 
146  * Must always be called with gpio bus locked.
147  */
148 static void
149 gpioiic_reset_bus(device_t dev)
150 {
151         struct gpioiic_softc            *sc = device_get_softc(dev);
152
153         GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin,
154             GPIO_PIN_INPUT);
155         GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin,
156             GPIO_PIN_INPUT);
157 }
158
159 static void
160 gpioiic_setsda(device_t dev, int val)
161 {
162         struct gpioiic_softc            *sc = device_get_softc(dev);
163
164         if (val == 0) {
165                 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, sc->sda_pin, 0);
166                 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin,
167                     GPIO_PIN_OUTPUT);
168         } else {
169                 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin,
170                     GPIO_PIN_INPUT);
171         }
172 }
173
174 static void
175 gpioiic_setscl(device_t dev, int val)
176 {
177         struct gpioiic_softc            *sc = device_get_softc(dev);
178
179         if (val == 0) {
180                 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, sc->scl_pin, 0);
181                 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin,
182                     GPIO_PIN_OUTPUT);
183         } else {
184                 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin,
185                     GPIO_PIN_INPUT);
186         }
187 }
188
189 static int
190 gpioiic_getscl(device_t dev)
191 {
192         struct gpioiic_softc            *sc = device_get_softc(dev);
193         unsigned int                    val;
194
195         GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->scl_pin,
196             GPIO_PIN_INPUT);
197         GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, sc->scl_pin, &val);
198
199         return ((int)val);
200 }
201
202 static int
203 gpioiic_getsda(device_t dev)
204 {
205         struct gpioiic_softc            *sc = device_get_softc(dev);
206         unsigned int                    val;
207
208         GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, sc->sda_pin,
209             GPIO_PIN_INPUT);
210         GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, sc->sda_pin, &val);
211
212         return ((int)val);
213 }
214
215 static int
216 gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
217 {
218         struct gpioiic_softc            *sc;
219
220         sc = device_get_softc(dev);
221         gpioiic_reset_bus(sc->sc_dev);
222
223         return (IIC_ENOADDR);
224 }
225
226 #ifdef FDT
227 static phandle_t
228 gpioiic_get_node(device_t bus, device_t dev)
229 {
230
231         /* We only have one child, the iicbb, which needs our own node. */
232         return (ofw_bus_get_node(bus));
233 }
234 #endif
235
236 static devclass_t gpioiic_devclass;
237
238 static device_method_t gpioiic_methods[] = {
239         /* Device interface */
240         DEVMETHOD(device_probe,         gpioiic_probe),
241         DEVMETHOD(device_attach,        gpioiic_attach),
242         DEVMETHOD(device_detach,        bus_generic_detach),
243
244         /* iicbb interface */
245         DEVMETHOD(iicbb_setsda,         gpioiic_setsda),
246         DEVMETHOD(iicbb_setscl,         gpioiic_setscl),
247         DEVMETHOD(iicbb_getsda,         gpioiic_getsda),
248         DEVMETHOD(iicbb_getscl,         gpioiic_getscl),
249         DEVMETHOD(iicbb_reset,          gpioiic_reset),
250
251 #ifdef FDT
252         /* OFW bus interface */
253         DEVMETHOD(ofw_bus_get_node,     gpioiic_get_node),
254 #endif
255
256         DEVMETHOD_END
257 };
258
259 static driver_t gpioiic_driver = {
260         "gpioiic",
261         gpioiic_methods,
262         sizeof(struct gpioiic_softc),
263 };
264
265 DRIVER_MODULE(gpioiic, gpiobus, gpioiic_driver, gpioiic_devclass, 0, 0);
266 DRIVER_MODULE(iicbb, gpioiic, iicbb_driver, iicbb_devclass, 0, 0);
267 MODULE_DEPEND(gpioiic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
268 MODULE_DEPEND(gpioiic, gpiobus, 1, 1, 1);