xref: /freebsd/sys/dev/gpio/gpioiic.c (revision e17f5b1d)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
5  * Copyright (c) 2010 Luiz Otavio O Souza
6  * Copyright (c) 2019 Ian Lepore <ian@freebsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include "opt_platform.h"
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/gpio.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 
42 #include <dev/gpio/gpiobusvar.h>
43 #include <dev/iicbus/iiconf.h>
44 
45 #include "gpiobus_if.h"
46 #include "iicbb_if.h"
47 
48 #define	GPIOIIC_SCL_DFLT	0
49 #define	GPIOIIC_SDA_DFLT	1
50 #define	GPIOIIC_MIN_PINS	2
51 
52 struct gpioiic_softc
53 {
54 	device_t	dev;
55 	gpio_pin_t	sclpin;
56 	gpio_pin_t	sdapin;
57 };
58 
59 #ifdef FDT
60 
61 #include <dev/ofw/ofw_bus.h>
62 
63 static struct ofw_compat_data compat_data[] = {
64 	{"i2c-gpio",  true}, /* Standard devicetree compat string */
65 	{"gpioiic",   true}, /* Deprecated old freebsd compat string */
66 	{NULL,        false}
67 };
68 OFWBUS_PNP_INFO(compat_data);
69 SIMPLEBUS_PNP_INFO(compat_data);
70 
71 static phandle_t
72 gpioiic_get_node(device_t bus, device_t dev)
73 {
74 
75 	/* Share our fdt node with iicbus so it can find its child nodes. */
76 	return (ofw_bus_get_node(bus));
77 }
78 
79 static int
80 gpioiic_setup_fdt_pins(struct gpioiic_softc *sc)
81 {
82 	phandle_t node;
83 	int err;
84 
85 	node = ofw_bus_get_node(sc->dev);
86 
87 	/*
88 	 * Historically, we used the first two array elements of the gpios
89 	 * property.  The modern bindings specify separate scl-gpios and
90 	 * sda-gpios properties.  We cope with whichever is present.
91 	 */
92 	if (OF_hasprop(node, "gpios")) {
93 		if ((err = gpio_pin_get_by_ofw_idx(sc->dev, node,
94 		    GPIOIIC_SCL_DFLT, &sc->sclpin)) != 0) {
95 			device_printf(sc->dev, "invalid gpios property\n");
96 			return (err);
97 		}
98 		if ((err = gpio_pin_get_by_ofw_idx(sc->dev, node,
99 		    GPIOIIC_SDA_DFLT, &sc->sdapin)) != 0) {
100 			device_printf(sc->dev, "ivalid gpios property\n");
101 			return (err);
102 		}
103 	} else {
104 		if ((err = gpio_pin_get_by_ofw_property(sc->dev, node,
105 		    "scl-gpios", &sc->sclpin)) != 0) {
106 			device_printf(sc->dev, "missing scl-gpios property\n");
107 			return (err);
108 		}
109 		if ((err = gpio_pin_get_by_ofw_property(sc->dev, node,
110 		    "sda-gpios", &sc->sdapin)) != 0) {
111 			device_printf(sc->dev, "missing sda-gpios property\n");
112 			return (err);
113 		}
114 	}
115 	return (0);
116 }
117 #endif /* FDT */
118 
119 static int
120 gpioiic_setup_hinted_pins(struct gpioiic_softc *sc)
121 {
122 	device_t busdev;
123 	const char *busname, *devname;
124 	int err, numpins, sclnum, sdanum, unit;
125 
126 	devname = device_get_name(sc->dev);
127 	unit = device_get_unit(sc->dev);
128 	busdev = device_get_parent(sc->dev);
129 
130 	/*
131 	 * If there is not an "at" hint naming our actual parent, then we
132 	 * weren't instantiated as a child of gpiobus via hints, and we thus
133 	 * can't access ivars that only exist for such children.
134 	 */
135 	if (resource_string_value(devname, unit, "at", &busname) != 0 ||
136 	    (strcmp(busname, device_get_nameunit(busdev)) != 0 &&
137 	     strcmp(busname, device_get_name(busdev)) != 0)) {
138 		return (ENOENT);
139 	}
140 
141 	/* Make sure there were hints for at least two pins. */
142 	numpins = gpiobus_get_npins(sc->dev);
143 	if (numpins < GPIOIIC_MIN_PINS) {
144 #ifdef FDT
145 		/*
146 		 * Be silent when there are no hints on FDT systems; the FDT
147 		 * data will provide the pin config (we'll whine if it doesn't).
148 		 */
149 		if (numpins == 0) {
150 			return (ENOENT);
151 		}
152 #endif
153 		device_printf(sc->dev,
154 		    "invalid pins hint; it must contain at least %d pins\n",
155 		    GPIOIIC_MIN_PINS);
156 		return (EINVAL);
157 	}
158 
159 	/*
160 	 * Our parent bus has already parsed the pins hint and it will use that
161 	 * info when we call gpio_pin_get_by_child_index().  But we have to
162 	 * handle the scl/sda index hints that tell us which of the two pins is
163 	 * the clock and which is the data.  They're optional, but if present
164 	 * they must be a valid index (0 <= index < numpins).
165 	 */
166 	if ((err = resource_int_value(devname, unit, "scl", &sclnum)) != 0)
167 		sclnum = GPIOIIC_SCL_DFLT;
168 	else if (sclnum < 0 || sclnum >= numpins) {
169 		device_printf(sc->dev, "invalid scl hint %d\n", sclnum);
170 		return (EINVAL);
171 	}
172 	if ((err = resource_int_value(devname, unit, "sda", &sdanum)) != 0)
173 		sdanum = GPIOIIC_SDA_DFLT;
174 	else if (sdanum < 0 || sdanum >= numpins) {
175 		device_printf(sc->dev, "invalid sda hint %d\n", sdanum);
176 		return (EINVAL);
177 	}
178 
179 	/* Allocate gpiobus_pin structs for the pins we found above. */
180 	if ((err = gpio_pin_get_by_child_index(sc->dev, sclnum,
181 	    &sc->sclpin)) != 0)
182 		return (err);
183 	if ((err = gpio_pin_get_by_child_index(sc->dev, sdanum,
184 	    &sc->sdapin)) != 0)
185 		return (err);
186 
187 	return (0);
188 }
189 
190 static void
191 gpioiic_setsda(device_t dev, int val)
192 {
193 	struct gpioiic_softc *sc = device_get_softc(dev);
194 	int err;
195 
196 	/*
197 	 * Some controllers cannot set an output value while a pin is in input
198 	 * mode; in that case we set the pin again after changing mode.
199 	 */
200 	err = gpio_pin_set_active(sc->sdapin, val);
201 	gpio_pin_setflags(sc->sdapin, GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
202 	if (err != 0)
203 		gpio_pin_set_active(sc->sdapin, val);
204 }
205 
206 static void
207 gpioiic_setscl(device_t dev, int val)
208 {
209 	struct gpioiic_softc *sc = device_get_softc(dev);
210 
211 	gpio_pin_setflags(sc->sclpin, GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
212 	gpio_pin_set_active(sc->sclpin, val);
213 }
214 
215 static int
216 gpioiic_getscl(device_t dev)
217 {
218 	struct gpioiic_softc *sc = device_get_softc(dev);
219 	bool val;
220 
221 	gpio_pin_setflags(sc->sclpin, GPIO_PIN_INPUT);
222 	gpio_pin_is_active(sc->sclpin, &val);
223 	return (val);
224 }
225 
226 static int
227 gpioiic_getsda(device_t dev)
228 {
229 	struct gpioiic_softc *sc = device_get_softc(dev);
230 	bool val;
231 
232 	gpio_pin_setflags(sc->sdapin, GPIO_PIN_INPUT);
233 	gpio_pin_is_active(sc->sdapin, &val);
234 	return (val);
235 }
236 
237 static int
238 gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
239 {
240 	struct gpioiic_softc *sc = device_get_softc(dev);
241 
242 	/* Stop driving the bus pins. */
243 	gpio_pin_setflags(sc->sdapin, GPIO_PIN_INPUT);
244 	gpio_pin_setflags(sc->sclpin, GPIO_PIN_INPUT);
245 
246 	/* Indicate that we have no slave address (master mode). */
247 	return (IIC_ENOADDR);
248 }
249 
250 static void
251 gpioiic_cleanup(struct gpioiic_softc *sc)
252 {
253 
254 	device_delete_children(sc->dev);
255 
256 	if (sc->sclpin != NULL)
257 		gpio_pin_release(sc->sclpin);
258 
259 	if (sc->sdapin != NULL)
260 		gpio_pin_release(sc->sdapin);
261 }
262 
263 static int
264 gpioiic_probe(device_t dev)
265 {
266 	int rv;
267 
268 	/*
269 	 * By default we only bid to attach if specifically added by our parent
270 	 * (usually via hint.gpioiic.#.at=busname).  On FDT systems we bid as
271 	 * the default driver based on being configured in the FDT data.
272 	 */
273 	rv = BUS_PROBE_NOWILDCARD;
274 
275 #ifdef FDT
276 	if (ofw_bus_status_okay(dev) &&
277 	    ofw_bus_search_compatible(dev, compat_data)->ocd_data)
278                 rv = BUS_PROBE_DEFAULT;
279 #endif
280 
281 	device_set_desc(dev, "GPIO I2C");
282 
283 	return (rv);
284 }
285 
286 static int
287 gpioiic_attach(device_t dev)
288 {
289 	struct gpioiic_softc *sc = device_get_softc(dev);
290 	int err;
291 
292 	sc->dev = dev;
293 
294 	/* Acquire our gpio pins. */
295 	err = gpioiic_setup_hinted_pins(sc);
296 #ifdef FDT
297 	if (err != 0)
298 		err = gpioiic_setup_fdt_pins(sc);
299 #endif
300 	if (err != 0) {
301 		device_printf(sc->dev, "no pins configured\n");
302 		gpioiic_cleanup(sc);
303 		return (ENXIO);
304 	}
305 
306 	/*
307 	 * Say what we came up with for pin config.
308 	 * NB: in the !FDT case the controller driver might not be set up enough
309 	 * for GPIO_GET_BUS() to work.  Also, our parent is the only gpiobus
310 	 * that can provide our pins.
311 	 */
312 	device_printf(dev, "SCL pin: %s:%d, SDA pin: %s:%d\n",
313 #ifdef FDT
314 	    device_get_nameunit(GPIO_GET_BUS(sc->sclpin->dev)), sc->sclpin->pin,
315 	    device_get_nameunit(GPIO_GET_BUS(sc->sdapin->dev)), sc->sdapin->pin);
316 #else
317 	    device_get_nameunit(device_get_parent(dev)), sc->sclpin->pin,
318 	    device_get_nameunit(device_get_parent(dev)), sc->sdapin->pin);
319 #endif
320 
321 	/* Add the bitbang driver as our only child; it will add iicbus. */
322 	device_add_child(sc->dev, "iicbb", -1);
323 	return (bus_generic_attach(dev));
324 }
325 
326 static int
327 gpioiic_detach(device_t dev)
328 {
329 	struct gpioiic_softc *sc = device_get_softc(dev);
330 	int err;
331 
332 	if ((err = bus_generic_detach(dev)) != 0)
333 		return (err);
334 
335 	gpioiic_cleanup(sc);
336 
337 	return (0);
338 }
339 
340 static devclass_t gpioiic_devclass;
341 
342 static device_method_t gpioiic_methods[] = {
343 	/* Device interface */
344 	DEVMETHOD(device_probe,		gpioiic_probe),
345 	DEVMETHOD(device_attach,	gpioiic_attach),
346 	DEVMETHOD(device_detach,	gpioiic_detach),
347 
348 	/* iicbb interface */
349 	DEVMETHOD(iicbb_setsda,		gpioiic_setsda),
350 	DEVMETHOD(iicbb_setscl,		gpioiic_setscl),
351 	DEVMETHOD(iicbb_getsda,		gpioiic_getsda),
352 	DEVMETHOD(iicbb_getscl,		gpioiic_getscl),
353 	DEVMETHOD(iicbb_reset,		gpioiic_reset),
354 
355 #ifdef FDT
356 	/* OFW bus interface */
357 	DEVMETHOD(ofw_bus_get_node,	gpioiic_get_node),
358 #endif
359 
360 	DEVMETHOD_END
361 };
362 
363 static driver_t gpioiic_driver = {
364 	"gpioiic",
365 	gpioiic_methods,
366 	sizeof(struct gpioiic_softc),
367 };
368 
369 DRIVER_MODULE(gpioiic, gpiobus, gpioiic_driver, gpioiic_devclass, 0, 0);
370 DRIVER_MODULE(gpioiic, simplebus, gpioiic_driver, gpioiic_devclass, 0, 0);
371 DRIVER_MODULE(iicbb, gpioiic, iicbb_driver, iicbb_devclass, 0, 0);
372 MODULE_DEPEND(gpioiic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
373 MODULE_DEPEND(gpioiic, gpiobus, 1, 1, 1);
374