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 = ®
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, ®_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, ®_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, ®_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, ®val);
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