xref: /freebsd-13-stable/sys/dev/iicbus/gpio/tca6416.c (revision 3bc80996974a61a4223eae4c1ccd47b6ee32a48a)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020 Alstom Group.
5  * Copyright (c) 2020 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Driver for TI TCA6416 I2C GPIO expander module.
31  *
32  * This driver only supports basic functionality
33  * (interrupt handling and polarity inversion were omitted).
34  */
35 
36 #include <sys/cdefs.h>
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/gpio.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/proc.h>
43 #include <sys/systm.h>
44 #include <sys/sysctl.h>
45 
46 #include <machine/bus.h>
47 
48 #include <dev/ofw/openfirm.h>
49 #include <dev/ofw/ofw_bus.h>
50 #include <dev/ofw/ofw_bus_subr.h>
51 
52 #include <dev/iicbus/iicbus.h>
53 #include <dev/iicbus/iiconf.h>
54 
55 #include <dev/gpio/gpiobusvar.h>
56 
57 #include "gpio_if.h"
58 
59 /* Base addresses of registers. LSB omitted. */
60 #define	IN_PORT_REG		0x00
61 #define	OUT_PORT_REG		0x02
62 #define	POLARITY_INV_REG	0x04
63 #define	CONF_REG		0x06
64 
65 #define	NUM_PINS	16
66 #define	PINS_PER_REG	8
67 #define	PIN_CAPS				\
68 	(GPIO_PIN_OUTPUT | GPIO_PIN_INPUT	\
69 	| GPIO_PIN_PUSHPULL | GPIO_PIN_INVIN)
70 
71 #ifdef DEBUG
72 #define	dbg_dev_printf(dev, fmt, args...)	\
73 	device_printf(dev, fmt, ##args)
74 #else
75 #define	dbg_dev_printf(dev, fmt, args...)
76 #endif
77 
78 #define	TCA6416_BIT_FROM_PIN(pin)	(pin % PINS_PER_REG)
79 #define	TCA6416_REG_ADDR(pin, baseaddr)	(baseaddr | (pin / PINS_PER_REG))
80 
81 struct tca6416_softc {
82 	device_t	dev;
83 	device_t	busdev;
84 	struct mtx	mtx;
85 	uint32_t	addr;
86 };
87 
88 static int tca6416_read(device_t, uint8_t, uint8_t*);
89 static int tca6416_write(device_t, uint8_t, uint8_t);
90 static int tca6416_probe(device_t);
91 static int tca6416_attach(device_t);
92 static int tca6416_detach(device_t);
93 static device_t tca6416_get_bus(device_t);
94 static int tca6416_pin_max(device_t, int*);
95 static int tca6416_pin_getcaps(device_t, uint32_t, uint32_t*);
96 static int tca6416_pin_getflags(device_t, uint32_t, uint32_t*);
97 static int tca6416_pin_setflags(device_t, uint32_t, uint32_t);
98 static int tca6416_pin_getname(device_t, uint32_t, char*);
99 static int tca6416_pin_get(device_t, uint32_t, unsigned int*);
100 static int tca6416_pin_set(device_t, uint32_t, unsigned int);
101 static int tca6416_pin_toggle(device_t, uint32_t);
102 #ifdef DEBUG
103 static void tca6416_regdump_setup(device_t dev);
104 static int tca6416_regdump_sysctl(SYSCTL_HANDLER_ARGS);
105 #endif
106 
107 static device_method_t tca6416_methods[] = {
108 	DEVMETHOD(device_probe,		tca6416_probe),
109 	DEVMETHOD(device_attach,	tca6416_attach),
110 	DEVMETHOD(device_detach,	tca6416_detach),
111 
112 	/* GPIO methods */
113 	DEVMETHOD(gpio_get_bus,		tca6416_get_bus),
114 	DEVMETHOD(gpio_pin_max,		tca6416_pin_max),
115 	DEVMETHOD(gpio_pin_getcaps,	tca6416_pin_getcaps),
116 	DEVMETHOD(gpio_pin_getflags,	tca6416_pin_getflags),
117 	DEVMETHOD(gpio_pin_setflags,	tca6416_pin_setflags),
118 	DEVMETHOD(gpio_pin_getname,	tca6416_pin_getname),
119 	DEVMETHOD(gpio_pin_get,		tca6416_pin_get),
120 	DEVMETHOD(gpio_pin_set,		tca6416_pin_set),
121 	DEVMETHOD(gpio_pin_toggle,	tca6416_pin_toggle),
122 
123 	DEVMETHOD_END
124 };
125 
126 static driver_t tca6416_driver = {
127 	"gpio",
128 	tca6416_methods,
129 	sizeof(struct tca6416_softc)
130 };
131 
132 static devclass_t tca6416_devclass;
133 
134 DRIVER_MODULE(tca6416, iicbus, tca6416_driver, tca6416_devclass, 0, 0);
135 MODULE_VERSION(tca6416, 1);
136 
137 static struct ofw_compat_data compat_data[] = {
138 	{"ti,tca6416",	1},
139 	{"ti,tca9539",	1},
140 	{0,0}
141 };
142 
143 static int
tca6416_read(device_t dev,uint8_t reg,uint8_t * data)144 tca6416_read(device_t dev, uint8_t reg, uint8_t *data)
145 {
146 	struct iic_msg msgs[2];
147 	struct tca6416_softc *sc;
148 	int error;
149 
150 	sc = device_get_softc(dev);
151 	if (data == NULL)
152 		return (EINVAL);
153 
154 	msgs[0].slave = sc->addr;
155 	msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;
156 	msgs[0].len = 1;
157 	msgs[0].buf = &reg;
158 
159 	msgs[1].slave = sc->addr;
160 	msgs[1].flags = IIC_M_RD;
161 	msgs[1].len = 1;
162 	msgs[1].buf = data;
163 
164 	error = iicbus_transfer_excl(dev, msgs, 2, IIC_WAIT);
165 	return (iic2errno(error));
166 }
167 
168 static int
tca6416_write(device_t dev,uint8_t reg,uint8_t val)169 tca6416_write(device_t dev, uint8_t reg, uint8_t val)
170 {
171 	struct iic_msg msg;
172 	struct tca6416_softc *sc;
173 	int error;
174 	uint8_t buffer[2] = {reg, val};
175 
176 	sc = device_get_softc(dev);
177 
178 	msg.slave = sc->addr;
179 	msg.flags = IIC_M_WR;
180 	msg.len = 2;
181 	msg.buf = buffer;
182 
183 	error = iicbus_transfer_excl(dev, &msg, 1, IIC_WAIT);
184 	return (iic2errno(error));
185 }
186 
187 static int
tca6416_probe(device_t dev)188 tca6416_probe(device_t dev)
189 {
190 
191 	if (!ofw_bus_status_okay(dev))
192 		return (ENXIO);
193 
194 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
195 		return (ENXIO);
196 
197 	device_set_desc(dev, "TCA6416 I/O expander");
198 	return (BUS_PROBE_DEFAULT);
199 }
200 
201 static int
tca6416_attach(device_t dev)202 tca6416_attach(device_t dev)
203 {
204 	struct tca6416_softc *sc;
205 
206 	sc = device_get_softc(dev);
207 	sc->dev = dev;
208 	sc->addr = iicbus_get_addr(dev);
209 
210 	mtx_init(&sc->mtx, "tca6416 gpio", "gpio", MTX_DEF);
211 
212 	sc->busdev = gpiobus_attach_bus(dev);
213 	if (sc->busdev == NULL) {
214 		device_printf(dev, "Could not create busdev child\n");
215 		return (ENXIO);
216 	}
217 
218 #ifdef DEBUG
219 	tca6416_regdump_setup(dev);
220 #endif
221 
222 	return (0);
223 }
224 
225 static int
tca6416_detach(device_t dev)226 tca6416_detach(device_t dev)
227 {
228 	struct tca6416_softc *sc;
229 
230 	sc = device_get_softc(dev);
231 
232 	if (sc->busdev != NULL)
233 		gpiobus_detach_bus(sc->busdev);
234 
235 	mtx_destroy(&sc->mtx);
236 
237 	return (0);
238 }
239 
240 static device_t
tca6416_get_bus(device_t dev)241 tca6416_get_bus(device_t dev)
242 {
243 	struct tca6416_softc *sc;
244 
245 	sc = device_get_softc(dev);
246 
247 	return (sc->busdev);
248 }
249 
250 static int
tca6416_pin_max(device_t dev __unused,int * maxpin)251 tca6416_pin_max(device_t dev __unused, int *maxpin)
252 {
253 
254 	if (maxpin == NULL)
255 		return (EINVAL);
256 
257 	*maxpin = NUM_PINS - 1;
258 	return (0);
259 }
260 
261 static int
tca6416_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)262 tca6416_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
263 {
264 
265 	if (pin >= NUM_PINS || caps == NULL)
266 		return (EINVAL);
267 
268 	*caps = PIN_CAPS;
269 	return (0);
270 }
271 
272 static int
tca6416_pin_getflags(device_t dev,uint32_t pin,uint32_t * pflags)273 tca6416_pin_getflags(device_t dev, uint32_t pin, uint32_t *pflags)
274 {
275 	int error;
276 	uint8_t reg_addr, reg_bit, val;
277 
278 	if (pin >= NUM_PINS || pflags == NULL)
279 		return (EINVAL);
280 
281 	reg_addr = TCA6416_REG_ADDR(pin, CONF_REG);
282 	reg_bit = TCA6416_BIT_FROM_PIN(pin);
283 
284 	error = tca6416_read(dev, reg_addr, &val);
285 	if (error != 0)
286 		return (error);
287 
288 	*pflags = (val & (1 << reg_bit))
289 	    ? GPIO_PIN_INPUT : GPIO_PIN_OUTPUT;
290 
291 	reg_addr = TCA6416_REG_ADDR(pin, POLARITY_INV_REG);
292 
293 	error = tca6416_read(dev, reg_addr, &val);
294 	if (error != 0)
295 		return (error);
296 
297 	if (val & (1 << reg_bit))
298 		*pflags |= GPIO_PIN_INVIN;
299 
300 	return (0);
301 }
302 
303 static int
tca6416_pin_setflags(device_t dev,uint32_t pin,uint32_t flags)304 tca6416_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
305 {
306 	uint8_t reg_addr, inv_reg_addr, reg_bit, val, inv_val;
307 	struct tca6416_softc *sc;
308 	int error;
309 
310 	sc = device_get_softc(dev);
311 
312 	if (pin >= NUM_PINS)
313 		return (EINVAL);
314 
315 	reg_addr = TCA6416_REG_ADDR(pin, CONF_REG);
316 	inv_reg_addr = TCA6416_REG_ADDR(pin, POLARITY_INV_REG);
317 	reg_bit = TCA6416_BIT_FROM_PIN(pin);
318 
319 	mtx_lock(&sc->mtx);
320 
321 	error = tca6416_read(dev, reg_addr, &val);
322 	if (error != 0)
323 		goto fail;
324 	error = tca6416_read(dev, inv_reg_addr, &inv_val);
325 	if (error != 0)
326 		goto fail;
327 
328 	if (flags & GPIO_PIN_INPUT)
329 		val |= (1 << reg_bit);
330 	else if (flags & GPIO_PIN_OUTPUT)
331 		val &= ~(1 << reg_bit);
332 
333 	if (flags & GPIO_PIN_INVIN)
334 		inv_val |= (1 << reg_bit);
335 	else
336 		inv_val &= ~(1 << reg_bit);
337 
338 	error = tca6416_write(dev, reg_addr, val);
339 	if (error != 0)
340 		goto fail;
341 	error = tca6416_write(dev, inv_reg_addr, val);
342 
343 fail:
344 	mtx_unlock(&sc->mtx);
345 	return (error);
346 }
347 
348 static int
tca6416_pin_getname(device_t dev,uint32_t pin,char * name)349 tca6416_pin_getname(device_t dev, uint32_t pin, char *name)
350 {
351 
352 	if (pin >= NUM_PINS || name == NULL)
353 		return (EINVAL);
354 
355 	snprintf(name, GPIOMAXNAME, "gpio_P%d%d", pin / PINS_PER_REG,
356 	    pin % PINS_PER_REG);
357 
358 	return (0);
359 }
360 
361 static int
tca6416_pin_get(device_t dev,uint32_t pin,unsigned int * pval)362 tca6416_pin_get(device_t dev, uint32_t pin, unsigned int *pval)
363 {
364 	uint8_t reg_bit, reg_addr, reg_pvalue;
365 	int error;
366 
367 	if (pin >= NUM_PINS || pval == NULL)
368 		return (EINVAL);
369 
370 	reg_bit = TCA6416_BIT_FROM_PIN(pin);
371 	reg_addr = TCA6416_REG_ADDR(pin, IN_PORT_REG);
372 
373 	dbg_dev_printf(dev, "Reading pin %u pvalue.", pin);
374 
375 	error = tca6416_read(dev, reg_addr, &reg_pvalue);
376 	if (error != 0)
377 		return (error);
378 
379 	*pval = reg_pvalue & (1 << reg_bit) ? 1 : 0;
380 
381 	return (0);
382 }
383 
384 static int
tca6416_pin_set(device_t dev,uint32_t pin,unsigned int val)385 tca6416_pin_set(device_t dev, uint32_t pin, unsigned int val)
386 {
387 	struct tca6416_softc *sc;
388 	uint8_t reg_addr, reg_bit, reg_value;
389 	int error;
390 
391 	sc = device_get_softc(dev);
392 
393 	if (pin >= NUM_PINS)
394 		return (EINVAL);
395 
396 	reg_addr = TCA6416_REG_ADDR(pin , OUT_PORT_REG);
397 	reg_bit = TCA6416_BIT_FROM_PIN(pin);
398 
399 	dbg_dev_printf(dev, "Setting pin: %u to %u\n", pin, val);
400 
401 	mtx_lock(&sc->mtx);
402 
403 	error = tca6416_read(dev, reg_addr, &reg_value);
404 	if (error != 0) {
405 		dbg_dev_printf(dev, "Failed to read from register.\n");
406 		mtx_unlock(&sc->mtx);
407 		return (error);
408 	}
409 
410 	if (val != 0)
411 		reg_value |= (1 << reg_bit);
412 	else
413 		reg_value &= ~(1 << reg_bit);
414 
415 
416 	error = tca6416_write(dev, reg_addr, reg_value);
417 	if (error != 0) {
418 		dbg_dev_printf(dev, "Could not write to register.\n");
419 		mtx_unlock(&sc->mtx);
420 		return (error);
421 	}
422 
423 	mtx_unlock(&sc->mtx);
424 
425 	return (0);
426 }
427 
428 static int
tca6416_pin_toggle(device_t dev,uint32_t pin)429 tca6416_pin_toggle(device_t dev, uint32_t pin)
430 {
431 	struct tca6416_softc *sc;
432 	int error;
433 	uint8_t reg_addr, reg_bit, reg_value;
434 
435 	sc = device_get_softc(dev);
436 
437 	if (pin >= NUM_PINS)
438 		return (EINVAL);
439 
440 	reg_addr = TCA6416_REG_ADDR(pin, OUT_PORT_REG);
441 	reg_bit = TCA6416_BIT_FROM_PIN(pin);
442 
443 	dbg_dev_printf(dev, "Toggling pin: %d\n", pin);
444 
445 	mtx_lock(&sc->mtx);
446 
447 	error = tca6416_read(dev, reg_addr, &reg_value);
448 	if (error != 0) {
449 		mtx_unlock(&sc->mtx);
450 		dbg_dev_printf(dev, "Cannot read from register.\n");
451 		return (error);
452 	}
453 
454 	reg_value ^= (1 << reg_bit);
455 
456 	error = tca6416_write(dev, reg_addr, reg_value);
457 	if (error != 0)
458 		dbg_dev_printf(dev, "Cannot write to register.\n");
459 
460 	mtx_unlock(&sc->mtx);
461 
462 	return (error);
463 }
464 
465 #ifdef DEBUG
466 static void
tca6416_regdump_setup(device_t dev)467 tca6416_regdump_setup(device_t dev)
468 {
469 	struct sysctl_ctx_list *ctx;
470 	struct sysctl_oid *node;
471 
472 	ctx = device_get_sysctl_ctx(dev);
473 	node = device_get_sysctl_tree(dev);
474 
475 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "in_reg_1",
476 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, IN_PORT_REG,
477 	    tca6416_regdump_sysctl, "A", "Input port 1");
478 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "in_reg_2",
479 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
480 	    IN_PORT_REG | 1, tca6416_regdump_sysctl, "A", "Input port 2");
481 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "out_reg_1",
482 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, OUT_PORT_REG,
483 	    tca6416_regdump_sysctl, "A", "Output port 1");
484 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "out_reg_2",
485 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, OUT_PORT_REG
486 	    | 1, tca6416_regdump_sysctl, "A", "Output port 2");
487 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "pol_inv_1",
488 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
489 	    POLARITY_INV_REG, tca6416_regdump_sysctl, "A", "Polarity inv 1");
490 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "pol_inv_2",
491 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
492 	    POLARITY_INV_REG | 1, tca6416_regdump_sysctl, "A",
493 	    "Polarity inv 2");
494 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "conf_reg_1",
495 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
496 	    CONF_REG, tca6416_regdump_sysctl, "A", "Configuration 1");
497 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "conf_reg_2",
498 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
499 	    CONF_REG | 1, tca6416_regdump_sysctl, "A", "Configuration 2");
500 }
501 
502 static int
tca6416_regdump_sysctl(SYSCTL_HANDLER_ARGS)503 tca6416_regdump_sysctl(SYSCTL_HANDLER_ARGS)
504 {
505 	device_t dev;
506 	char buf[5];
507 	struct tca6416_softc *sc;
508 	int len, error;
509 	uint8_t reg, regval;
510 
511 	dev = (device_t)arg1;
512 	reg = (uint8_t)arg2;
513 	sc = device_get_softc(dev);
514 
515 
516 	error = tca6416_read(dev, reg, &regval);
517 	if (error != 0) {
518 		return (error);
519 	}
520 
521 	len = snprintf(buf, 5, "0x%02x", regval);
522 
523 	error = sysctl_handle_string(oidp, buf, len, req);
524 
525 	return (error);
526 }
527 #endif
528