xref: /freebsd/sys/dev/gpio/gpioiic.c (revision 6549718b70f0e660a15685369afb4f9caf2215ce)
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 #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 #include <dev/gpio/gpiobusvar.h>
41 #include <dev/iicbus/iiconf.h>
42 
43 #include "gpiobus_if.h"
44 #include "iicbb_if.h"
45 
46 #define	GPIOIIC_SCL_DFLT	0
47 #define	GPIOIIC_SDA_DFLT	1
48 #define	GPIOIIC_MIN_PINS	2
49 
50 struct gpioiic_softc
51 {
52 	device_t	dev;
53 	gpio_pin_t	sclpin;
54 	gpio_pin_t	sdapin;
55 };
56 
57 #ifdef FDT
58 
59 #include <dev/ofw/ofw_bus.h>
60 
61 static struct ofw_compat_data compat_data[] = {
62 	{"i2c-gpio",  true}, /* Standard devicetree compat string */
63 	{"gpioiic",   true}, /* Deprecated old freebsd compat string */
64 	{NULL,        false}
65 };
66 OFWBUS_PNP_INFO(compat_data);
67 SIMPLEBUS_PNP_INFO(compat_data);
68 
69 static phandle_t
70 gpioiic_get_node(device_t bus, device_t dev)
71 {
72 
73 	/* Share our fdt node with iicbus so it can find its child nodes. */
74 	return (ofw_bus_get_node(bus));
75 }
76 
77 static int
78 gpioiic_setup_fdt_pins(struct gpioiic_softc *sc)
79 {
80 	phandle_t node;
81 	int err;
82 
83 	node = ofw_bus_get_node(sc->dev);
84 
85 	/*
86 	 * Historically, we used the first two array elements of the gpios
87 	 * property.  The modern bindings specify separate scl-gpios and
88 	 * sda-gpios properties.  We cope with whichever is present.
89 	 */
90 	if (OF_hasprop(node, "gpios")) {
91 		if ((err = gpio_pin_get_by_ofw_idx(sc->dev, node,
92 		    GPIOIIC_SCL_DFLT, &sc->sclpin)) != 0) {
93 			device_printf(sc->dev, "invalid gpios property\n");
94 			return (err);
95 		}
96 		if ((err = gpio_pin_get_by_ofw_idx(sc->dev, node,
97 		    GPIOIIC_SDA_DFLT, &sc->sdapin)) != 0) {
98 			device_printf(sc->dev, "ivalid gpios property\n");
99 			return (err);
100 		}
101 	} else {
102 		if ((err = gpio_pin_get_by_ofw_property(sc->dev, node,
103 		    "scl-gpios", &sc->sclpin)) != 0) {
104 			device_printf(sc->dev, "missing scl-gpios property\n");
105 			return (err);
106 		}
107 		if ((err = gpio_pin_get_by_ofw_property(sc->dev, node,
108 		    "sda-gpios", &sc->sdapin)) != 0) {
109 			device_printf(sc->dev, "missing sda-gpios property\n");
110 			return (err);
111 		}
112 	}
113 	return (0);
114 }
115 #endif /* FDT */
116 
117 static int
118 gpioiic_setup_hinted_pins(struct gpioiic_softc *sc)
119 {
120 	device_t busdev;
121 	const char *busname, *devname;
122 	int err, numpins, sclnum, sdanum, unit;
123 
124 	devname = device_get_name(sc->dev);
125 	unit = device_get_unit(sc->dev);
126 	busdev = device_get_parent(sc->dev);
127 
128 	/*
129 	 * If there is not an "at" hint naming our actual parent, then we
130 	 * weren't instantiated as a child of gpiobus via hints, and we thus
131 	 * can't access ivars that only exist for such children.
132 	 */
133 	if (resource_string_value(devname, unit, "at", &busname) != 0 ||
134 	    (strcmp(busname, device_get_nameunit(busdev)) != 0 &&
135 	     strcmp(busname, device_get_name(busdev)) != 0)) {
136 		return (ENOENT);
137 	}
138 
139 	/* Make sure there were hints for at least two pins. */
140 	numpins = gpiobus_get_npins(sc->dev);
141 	if (numpins < GPIOIIC_MIN_PINS) {
142 #ifdef FDT
143 		/*
144 		 * Be silent when there are no hints on FDT systems; the FDT
145 		 * data will provide the pin config (we'll whine if it doesn't).
146 		 */
147 		if (numpins == 0) {
148 			return (ENOENT);
149 		}
150 #endif
151 		device_printf(sc->dev,
152 		    "invalid pins hint; it must contain at least %d pins\n",
153 		    GPIOIIC_MIN_PINS);
154 		return (EINVAL);
155 	}
156 
157 	/*
158 	 * Our parent bus has already parsed the pins hint and it will use that
159 	 * info when we call gpio_pin_get_by_child_index().  But we have to
160 	 * handle the scl/sda index hints that tell us which of the two pins is
161 	 * the clock and which is the data.  They're optional, but if present
162 	 * they must be a valid index (0 <= index < numpins).
163 	 */
164 	if ((err = resource_int_value(devname, unit, "scl", &sclnum)) != 0)
165 		sclnum = GPIOIIC_SCL_DFLT;
166 	else if (sclnum < 0 || sclnum >= numpins) {
167 		device_printf(sc->dev, "invalid scl hint %d\n", sclnum);
168 		return (EINVAL);
169 	}
170 	if ((err = resource_int_value(devname, unit, "sda", &sdanum)) != 0)
171 		sdanum = GPIOIIC_SDA_DFLT;
172 	else if (sdanum < 0 || sdanum >= numpins) {
173 		device_printf(sc->dev, "invalid sda hint %d\n", sdanum);
174 		return (EINVAL);
175 	}
176 
177 	/* Allocate gpiobus_pin structs for the pins we found above. */
178 	if ((err = gpio_pin_get_by_child_index(sc->dev, sclnum,
179 	    &sc->sclpin)) != 0)
180 		return (err);
181 	if ((err = gpio_pin_get_by_child_index(sc->dev, sdanum,
182 	    &sc->sdapin)) != 0)
183 		return (err);
184 
185 	return (0);
186 }
187 
188 static void
189 gpioiic_setsda(device_t dev, int val)
190 {
191 	struct gpioiic_softc *sc = device_get_softc(dev);
192 
193 	if (val) {
194 		gpio_pin_setflags(sc->sdapin, GPIO_PIN_INPUT);
195 	} else {
196 		gpio_pin_setflags(sc->sdapin,
197 		    GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
198 		gpio_pin_set_active(sc->sdapin, 0);
199 	}
200 }
201 
202 static void
203 gpioiic_setscl(device_t dev, int val)
204 {
205 	struct gpioiic_softc *sc = device_get_softc(dev);
206 
207 	if (val) {
208 		gpio_pin_setflags(sc->sclpin, GPIO_PIN_INPUT);
209 	} else {
210 		gpio_pin_setflags(sc->sclpin,
211 		    GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
212 		gpio_pin_set_active(sc->sclpin, 0);
213 	}
214 }
215 
216 static int
217 gpioiic_getscl(device_t dev)
218 {
219 	struct gpioiic_softc *sc = device_get_softc(dev);
220 	bool val;
221 
222 	gpio_pin_setflags(sc->sclpin, GPIO_PIN_INPUT);
223 	gpio_pin_is_active(sc->sclpin, &val);
224 	return (val);
225 }
226 
227 static int
228 gpioiic_getsda(device_t dev)
229 {
230 	struct gpioiic_softc *sc = device_get_softc(dev);
231 	bool val;
232 
233 	gpio_pin_setflags(sc->sdapin, GPIO_PIN_INPUT);
234 	gpio_pin_is_active(sc->sdapin, &val);
235 	return (val);
236 }
237 
238 static int
239 gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
240 {
241 	struct gpioiic_softc *sc = device_get_softc(dev);
242 
243 	/* Stop driving the bus pins. */
244 	gpio_pin_setflags(sc->sdapin, GPIO_PIN_INPUT);
245 	gpio_pin_setflags(sc->sclpin, GPIO_PIN_INPUT);
246 
247 	/* Indicate that we have no slave address (master mode). */
248 	return (IIC_ENOADDR);
249 }
250 
251 static void
252 gpioiic_cleanup(struct gpioiic_softc *sc)
253 {
254 
255 	device_delete_children(sc->dev);
256 
257 	if (sc->sclpin != NULL)
258 		gpio_pin_release(sc->sclpin);
259 
260 	if (sc->sdapin != NULL)
261 		gpio_pin_release(sc->sdapin);
262 }
263 
264 static int
265 gpioiic_probe(device_t dev)
266 {
267 	int rv;
268 
269 	/*
270 	 * By default we only bid to attach if specifically added by our parent
271 	 * (usually via hint.gpioiic.#.at=busname).  On FDT systems we bid as
272 	 * the default driver based on being configured in the FDT data.
273 	 */
274 	rv = BUS_PROBE_NOWILDCARD;
275 
276 #ifdef FDT
277 	if (ofw_bus_status_okay(dev) &&
278 	    ofw_bus_search_compatible(dev, compat_data)->ocd_data)
279                 rv = BUS_PROBE_DEFAULT;
280 #endif
281 
282 	device_set_desc(dev, "GPIO I2C");
283 
284 	return (rv);
285 }
286 
287 static int
288 gpioiic_attach(device_t dev)
289 {
290 	struct gpioiic_softc *sc = device_get_softc(dev);
291 	int err;
292 
293 	sc->dev = dev;
294 
295 	/* Acquire our gpio pins. */
296 	err = gpioiic_setup_hinted_pins(sc);
297 #ifdef FDT
298 	if (err != 0)
299 		err = gpioiic_setup_fdt_pins(sc);
300 #endif
301 	if (err != 0) {
302 		device_printf(sc->dev, "no pins configured\n");
303 		gpioiic_cleanup(sc);
304 		return (ENXIO);
305 	}
306 
307 	/*
308 	 * Say what we came up with for pin config.
309 	 * NB: in the !FDT case the controller driver might not be set up enough
310 	 * for GPIO_GET_BUS() to work.  Also, our parent is the only gpiobus
311 	 * that can provide our pins.
312 	 */
313 	device_printf(dev, "SCL pin: %s:%d, SDA pin: %s:%d\n",
314 #ifdef FDT
315 	    device_get_nameunit(GPIO_GET_BUS(sc->sclpin->dev)), sc->sclpin->pin,
316 	    device_get_nameunit(GPIO_GET_BUS(sc->sdapin->dev)), sc->sdapin->pin);
317 #else
318 	    device_get_nameunit(device_get_parent(dev)), sc->sclpin->pin,
319 	    device_get_nameunit(device_get_parent(dev)), sc->sdapin->pin);
320 #endif
321 
322 	/* Add the bitbang driver as our only child; it will add iicbus. */
323 	device_add_child(sc->dev, "iicbb", DEVICE_UNIT_ANY);
324 	return (bus_generic_attach(dev));
325 }
326 
327 static int
328 gpioiic_detach(device_t dev)
329 {
330 	struct gpioiic_softc *sc = device_get_softc(dev);
331 	int err;
332 
333 	if ((err = bus_generic_detach(dev)) != 0)
334 		return (err);
335 
336 	gpioiic_cleanup(sc);
337 
338 	return (0);
339 }
340 
341 static device_method_t gpioiic_methods[] = {
342 	/* Device interface */
343 	DEVMETHOD(device_probe,		gpioiic_probe),
344 	DEVMETHOD(device_attach,	gpioiic_attach),
345 	DEVMETHOD(device_detach,	gpioiic_detach),
346 
347 	/* iicbb interface */
348 	DEVMETHOD(iicbb_setsda,		gpioiic_setsda),
349 	DEVMETHOD(iicbb_setscl,		gpioiic_setscl),
350 	DEVMETHOD(iicbb_getsda,		gpioiic_getsda),
351 	DEVMETHOD(iicbb_getscl,		gpioiic_getscl),
352 	DEVMETHOD(iicbb_reset,		gpioiic_reset),
353 
354 #ifdef FDT
355 	/* OFW bus interface */
356 	DEVMETHOD(ofw_bus_get_node,	gpioiic_get_node),
357 #endif
358 
359 	DEVMETHOD_END
360 };
361 
362 static driver_t gpioiic_driver = {
363 	"gpioiic",
364 	gpioiic_methods,
365 	sizeof(struct gpioiic_softc),
366 };
367 
368 DRIVER_MODULE(gpioiic, gpiobus, gpioiic_driver, 0, 0);
369 DRIVER_MODULE(gpioiic, simplebus, gpioiic_driver, 0, 0);
370 DRIVER_MODULE(iicbb, gpioiic, iicbb_driver, 0, 0);
371 MODULE_DEPEND(gpioiic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
372 MODULE_DEPEND(gpioiic, gpiobus, 1, 1, 1);
373