1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2016-2023 Stormshield
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
30 #include <sys/param.h>
31 #include <sys/systm.h>
32
33 #include <sys/bus.h>
34 #include <sys/eventhandler.h>
35 #include <sys/gpio.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/module.h>
39 #include <sys/mutex.h>
40
41 #include <machine/bus.h>
42
43 #include <dev/gpio/gpiobusvar.h>
44 #include <dev/superio/superio.h>
45
46 #include "gpio_if.h"
47
48 #define GPIO_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \
49 device_get_nameunit(dev), NULL, MTX_DEF)
50 #define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx)
51 #define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx)
52 #define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
53 #define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED)
54 #define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED)
55
56 /* Global register set */
57 #define GPIO4_ENABLE 0x28
58 #define GPIO3_ENABLE 0x29
59 #define FULL_UR5_UR6 0x2A
60 #define GPIO1_ENABLE 0x2B
61 #define GPIO2_ENABLE 0x2C
62
63 /* Logical Device Numbers. */
64 #define FTGPIO_LDN_GPIO 0x06
65
66 #define FTGPIO_MAX_GROUP 6
67 #define FTGPIO_MAX_PIN 52
68
69 #define FTGPIO_IS_VALID_PIN(_p) ((_p) >= 0 && (_p) <= FTGPIO_MAX_PIN)
70 #define FTGPIO_PIN_GETINDEX(_p) ((_p) & 7)
71 #define FTGPIO_PIN_GETGROUP(_p) ((_p) >> 3)
72
73 #define FTGPIO_GPIO_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | \
74 GPIO_PIN_INVOUT | GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)
75
76 #define GET_BIT(_v, _b) (((_v) >> (_b)) & 1)
77
78 #define FTGPIO_VERBOSE_PRINTF(dev, ...) \
79 do { \
80 if (__predict_false(bootverbose)) \
81 device_printf(dev, __VA_ARGS__); \
82 } while (0)
83
84 /*
85 * Note that the values are important.
86 * They match actual register offsets.
87 * See p71 and p72 of F81865's datasheet.
88 */
89 #define REG_OUTPUT_ENABLE 0 /* Not for GPIO0 */
90 #define REG_OUTPUT_DATA 1
91 #define REG_PIN_STATUS 2
92 #define REG_DRIVE_ENABLE 3
93 #define REG_MODE_SELECT_1 4 /* Only for GPIO0 */
94 #define REG_MODE_SELECT_2 5 /* Only for GPIO0 */
95 #define REG_PULSE_WIDTH_SELECT_1 6 /* Only for GPIO0 */
96 #define REG_PULSE_WIDTH_SELECT_2 7 /* Only for GPIO0 */
97 #define REG_INTERRUPT_ENABLE 8 /* Only for GPIO0 */
98 #define REG_INTERRUPT_STATUS 9 /* Only for GPIO0 */
99
100 struct ftgpio_device {
101 uint16_t devid;
102 const char *descr;
103 } ftgpio_devices[] = {
104 {
105 .devid = 0x0704,
106 .descr = "Fintek F81865",
107 },
108 };
109
110 struct ftgpio_softc {
111 device_t dev;
112 device_t busdev;
113 struct mtx mtx;
114 struct gpio_pin pins[FTGPIO_MAX_PIN + 1];
115 };
116
117 static uint8_t
ftgpio_group_get_ioreg(struct ftgpio_softc * sc,uint8_t reg,unsigned group)118 ftgpio_group_get_ioreg(struct ftgpio_softc *sc, uint8_t reg, unsigned group)
119 {
120 uint8_t ioreg;
121
122 KASSERT((group == 0 && REG_OUTPUT_DATA <= reg && reg <= REG_INTERRUPT_STATUS) || \
123 (group >= 1 && reg <= REG_DRIVE_ENABLE),
124 ("%s: invalid register %u for group %u", __func__, reg, group));
125 ioreg = (((0xf - group) << 4) + reg);
126 return (ioreg);
127 }
128
129 static uint8_t
ftgpio_group_get_output(struct ftgpio_softc * sc,unsigned group)130 ftgpio_group_get_output(struct ftgpio_softc *sc, unsigned group)
131 {
132 uint8_t ioreg, val;
133
134 ioreg = ftgpio_group_get_ioreg(sc, REG_OUTPUT_DATA, group);
135 val = superio_read(sc->dev, ioreg);
136 FTGPIO_VERBOSE_PRINTF(sc->dev, "group GPIO%u output is 0x%x (ioreg=0x%x)\n",
137 group, val, ioreg);
138 return (val);
139 }
140
141 static void
ftgpio_group_set_output(struct ftgpio_softc * sc,unsigned group,uint8_t group_value)142 ftgpio_group_set_output(struct ftgpio_softc *sc, unsigned group, uint8_t group_value)
143 {
144 uint8_t ioreg;
145
146 ioreg = ftgpio_group_get_ioreg(sc, REG_OUTPUT_DATA, group);
147 superio_write(sc->dev, ioreg, group_value);
148 FTGPIO_VERBOSE_PRINTF(sc->dev, "set group GPIO%u output to 0x%x (ioreg=0x%x)\n",
149 group, group_value, ioreg);
150 }
151
152 static uint8_t
ftgpio_group_get_status(struct ftgpio_softc * sc,unsigned group)153 ftgpio_group_get_status(struct ftgpio_softc *sc, unsigned group)
154 {
155 uint8_t ioreg;
156
157 ioreg = ftgpio_group_get_ioreg(sc, REG_PIN_STATUS, group);
158 return (superio_read(sc->dev, ioreg));
159 }
160
161 static void
ftgpio_pin_write(struct ftgpio_softc * sc,uint32_t pin_num,bool pin_value)162 ftgpio_pin_write(struct ftgpio_softc *sc, uint32_t pin_num, bool pin_value)
163 {
164 uint32_t pin_flags;
165 uint8_t val;
166 unsigned group, index;
167
168 GPIO_ASSERT_LOCKED(sc);
169 index = FTGPIO_PIN_GETINDEX(pin_num);
170 group = FTGPIO_PIN_GETGROUP(pin_num);
171 pin_flags = sc->pins[pin_num].gp_flags;
172 if ((pin_flags & (GPIO_PIN_OUTPUT)) == 0) {
173 FTGPIO_VERBOSE_PRINTF(sc->dev, "pin %u<GPIO%u%u> is not configured for output\n",
174 pin_num, group, index);
175 return;
176 }
177
178 FTGPIO_VERBOSE_PRINTF(sc->dev, "set pin %u<GPIO%u%u> to %s\n",
179 pin_num, group, index, (pin_value ? "on" : "off"));
180
181 val = ftgpio_group_get_output(sc, group);
182 if (!pin_value != !(pin_flags & GPIO_PIN_INVOUT))
183 val |= (1 << index);
184 else
185 val &= ~(1 << index);
186 ftgpio_group_set_output(sc, group, val);
187 }
188
189 static bool
ftgpio_pin_read(struct ftgpio_softc * sc,uint32_t pin_num)190 ftgpio_pin_read(struct ftgpio_softc *sc, uint32_t pin_num)
191 {
192 uint32_t pin_flags;
193 unsigned group, index;
194 uint8_t val;
195 bool pin_value;
196
197 GPIO_ASSERT_LOCKED(sc);
198 group = FTGPIO_PIN_GETGROUP(pin_num);
199 index = FTGPIO_PIN_GETINDEX(pin_num);
200 pin_flags = sc->pins[pin_num].gp_flags;
201 if ((pin_flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) == 0) {
202 FTGPIO_VERBOSE_PRINTF(sc->dev, "pin %u<GPIO%u%u> is not configured for input or output\n",
203 pin_num, group, index);
204 return (false);
205 }
206
207 if (pin_flags & GPIO_PIN_OUTPUT)
208 val = ftgpio_group_get_output(sc, group);
209 else
210 val = ftgpio_group_get_status(sc, group);
211 pin_value = GET_BIT(val, index);
212
213 if (((pin_flags & (GPIO_PIN_OUTPUT|GPIO_PIN_INVOUT)) == (GPIO_PIN_OUTPUT|GPIO_PIN_INVOUT)) ||
214 ((pin_flags & (GPIO_PIN_INPUT |GPIO_PIN_INVIN )) == (GPIO_PIN_INPUT |GPIO_PIN_INVIN)))
215 pin_value = !pin_value;
216 FTGPIO_VERBOSE_PRINTF(sc->dev, "pin %u<GPIO%u%u> is %s\n",
217 pin_num, group, index, (pin_value ? "on" : "off"));
218
219 return (pin_value);
220 }
221
222 static void
ftgpio_pin_set_drive(struct ftgpio_softc * sc,uint32_t pin_num,bool pin_drive)223 ftgpio_pin_set_drive(struct ftgpio_softc *sc, uint32_t pin_num, bool pin_drive)
224 {
225 unsigned group, index;
226 uint8_t group_drive, ioreg;
227
228 index = FTGPIO_PIN_GETINDEX(pin_num);
229 group = FTGPIO_PIN_GETGROUP(pin_num);
230 ioreg = ftgpio_group_get_ioreg(sc, REG_DRIVE_ENABLE, group);
231 group_drive = superio_read(sc->dev, ioreg);
232 FTGPIO_VERBOSE_PRINTF(sc->dev, "group GPIO%u drive is 0x%x (ioreg=0x%x)\n",
233 group, group_drive, ioreg);
234
235 if (pin_drive)
236 group_drive |= (1 << index); /* push pull */
237 else
238 group_drive &= ~(1 << index); /* open drain */
239 superio_write(sc->dev, ioreg, group_drive);
240 }
241
242 static bool
ftgpio_pin_is_pushpull(struct ftgpio_softc * sc,uint32_t pin_num)243 ftgpio_pin_is_pushpull(struct ftgpio_softc *sc, uint32_t pin_num)
244 {
245 unsigned group, index;
246 uint8_t group_drive, ioreg;
247 bool is_pushpull;
248
249 index = FTGPIO_PIN_GETINDEX(pin_num);
250 group = FTGPIO_PIN_GETGROUP(pin_num);
251
252 ioreg = ftgpio_group_get_ioreg(sc, REG_DRIVE_ENABLE, group);
253 group_drive = superio_read(sc->dev, ioreg);
254 FTGPIO_VERBOSE_PRINTF(sc->dev, "group GPIO%u drive is 0x%x (ioreg=0x%x)\n",
255 group, group_drive, ioreg);
256
257 is_pushpull = group_drive & (1 << index);
258 FTGPIO_VERBOSE_PRINTF(sc->dev, "pin %u<GPIO%u%u> drive is %s\n",
259 pin_num, group, index, (is_pushpull ? "pushpull" : "opendrain"));
260
261 return (is_pushpull);
262 }
263
264 static void
ftgpio_pin_set_io(struct ftgpio_softc * sc,uint32_t pin_num,bool pin_io)265 ftgpio_pin_set_io(struct ftgpio_softc *sc, uint32_t pin_num, bool pin_io)
266 {
267 unsigned group, index;
268 uint8_t group_io, ioreg;
269
270 index = FTGPIO_PIN_GETINDEX(pin_num);
271 group = FTGPIO_PIN_GETGROUP(pin_num);
272 FTGPIO_VERBOSE_PRINTF(sc->dev, "set pin %u<GPIO%u%u> io to %s\n",
273 pin_num, group, index, (pin_io ? "output" : "input"));
274
275 ioreg = ftgpio_group_get_ioreg(sc, REG_OUTPUT_ENABLE, group);
276 group_io = superio_read(sc->dev, ioreg);
277 FTGPIO_VERBOSE_PRINTF(sc->dev, "group GPIO%u io is 0x%x (ioreg=0x%x)\n",
278 group, group_io, ioreg);
279 if (pin_io)
280 group_io |= (1 << index); /* output */
281 else
282 group_io &= ~(1 << index); /* input */
283 superio_write(sc->dev, ioreg, group_io);
284 FTGPIO_VERBOSE_PRINTF(sc->dev, "set group GPIO%u io to 0x%x (ioreg=0x%x)\n",
285 group, group_io, ioreg);
286 }
287
288 static bool
ftgpio_pin_is_output(struct ftgpio_softc * sc,uint32_t pin_num)289 ftgpio_pin_is_output(struct ftgpio_softc *sc, uint32_t pin_num)
290 {
291 unsigned group, index;
292 bool is_output;
293
294 index = FTGPIO_PIN_GETINDEX(pin_num);
295 group = FTGPIO_PIN_GETGROUP(pin_num);
296
297 is_output = ftgpio_group_get_status(sc, group) & (1 << index);
298 FTGPIO_VERBOSE_PRINTF(sc->dev, "pin %u<GPIO%u%u> io is %s\n",
299 pin_num, group, index, (is_output ? "output" : "input"));
300 return (is_output);
301 }
302
303 static int
ftgpio_pin_setflags(struct ftgpio_softc * sc,uint32_t pin_num,uint32_t pin_flags)304 ftgpio_pin_setflags(struct ftgpio_softc *sc, uint32_t pin_num, uint32_t pin_flags)
305 {
306 /* check flags consistency */
307 if ((pin_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
308 (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
309 return (EINVAL);
310
311 if ((pin_flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) ==
312 (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL))
313 return (EINVAL);
314
315 if (pin_flags & GPIO_PIN_OPENDRAIN)
316 ftgpio_pin_set_drive(sc, pin_num, 0 /* open drain */);
317 else if (pin_flags & GPIO_PIN_PUSHPULL)
318 ftgpio_pin_set_drive(sc, pin_num, 1 /* push pull */);
319
320 if (pin_flags & GPIO_PIN_INPUT)
321 ftgpio_pin_set_io(sc, pin_num, 0 /* input */);
322 else if (pin_flags & GPIO_PIN_OUTPUT)
323 ftgpio_pin_set_io(sc, pin_num, 1 /* output */);
324
325 sc->pins[pin_num].gp_flags = pin_flags;
326
327 return (0);
328 }
329
330 static int
ftgpio_probe(device_t dev)331 ftgpio_probe(device_t dev)
332 {
333 uint16_t devid;
334 int i;
335
336 if (superio_vendor(dev) != SUPERIO_VENDOR_FINTEK)
337 return (ENXIO);
338 if (superio_get_type(dev) != SUPERIO_DEV_GPIO)
339 return (ENXIO);
340
341 /*
342 * There are several GPIO devices, we attach only to one of them
343 * and use the rest without attaching.
344 */
345 if (superio_get_ldn(dev) != FTGPIO_LDN_GPIO)
346 return (ENXIO);
347
348 devid = superio_devid(dev);
349 for (i = 0; i < nitems(ftgpio_devices); i++) {
350 if (devid == ftgpio_devices[i].devid) {
351 device_set_desc(dev, ftgpio_devices[i].descr);
352 return (BUS_PROBE_DEFAULT);
353 }
354 }
355 return (ENXIO);
356 }
357
358 static int
ftgpio_attach(device_t dev)359 ftgpio_attach(device_t dev)
360 {
361 struct ftgpio_softc *sc;
362 int i;
363
364 sc = device_get_softc(dev);
365 sc->dev = dev;
366
367 GPIO_LOCK_INIT(sc);
368 GPIO_LOCK(sc);
369
370 for (i = 0; i <= FTGPIO_MAX_PIN; i++) {
371 struct gpio_pin *pin;
372
373 pin = &sc->pins[i];
374 pin->gp_pin = i;
375 pin->gp_caps = FTGPIO_GPIO_CAPS;
376 pin->gp_flags = 0;
377
378 if (ftgpio_pin_is_output(sc, i))
379 pin->gp_flags |= GPIO_PIN_OUTPUT;
380 else
381 pin->gp_flags |= GPIO_PIN_INPUT;
382
383 if (ftgpio_pin_is_pushpull(sc, i))
384 pin->gp_flags |= GPIO_PIN_PUSHPULL;
385 else
386 pin->gp_flags |= GPIO_PIN_OPENDRAIN;
387
388 snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%u%u",
389 FTGPIO_PIN_GETGROUP(i), FTGPIO_PIN_GETINDEX(i));
390 }
391
392 /* Enable all groups */
393 superio_write(sc->dev, GPIO1_ENABLE, 0xFF);
394 superio_write(sc->dev, GPIO2_ENABLE, 0xFF);
395 superio_write(sc->dev, GPIO3_ENABLE, 0xFF);
396 superio_write(sc->dev, GPIO4_ENABLE, 0xFF);
397 superio_write(sc->dev, FULL_UR5_UR6, 0x0A);
398 FTGPIO_VERBOSE_PRINTF(sc->dev, "groups GPIO1..GPIO6 enabled\n");
399
400 GPIO_UNLOCK(sc);
401 sc->busdev = gpiobus_add_bus(dev);
402 if (sc->busdev == NULL) {
403 GPIO_LOCK_DESTROY(sc);
404 return (ENXIO);
405 }
406
407 bus_attach_children(dev);
408 return (0);
409 }
410
411 static int
ftgpio_detach(device_t dev)412 ftgpio_detach(device_t dev)
413 {
414 struct ftgpio_softc *sc;
415
416 sc = device_get_softc(dev);
417 gpiobus_detach_bus(dev);
418 GPIO_ASSERT_UNLOCKED(sc);
419 GPIO_LOCK_DESTROY(sc);
420
421 return (0);
422 }
423
424 static device_t
ftgpio_gpio_get_bus(device_t dev)425 ftgpio_gpio_get_bus(device_t dev)
426 {
427 struct ftgpio_softc *sc;
428
429 sc = device_get_softc(dev);
430
431 return (sc->busdev);
432 }
433
434 static int
ftgpio_gpio_pin_max(device_t dev,int * npins)435 ftgpio_gpio_pin_max(device_t dev, int *npins)
436 {
437 *npins = FTGPIO_MAX_PIN;
438 return (0);
439 }
440
441 static int
ftgpio_gpio_pin_set(device_t dev,uint32_t pin_num,uint32_t pin_value)442 ftgpio_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
443 {
444 struct ftgpio_softc *sc;
445
446 if (!FTGPIO_IS_VALID_PIN(pin_num))
447 return (EINVAL);
448
449 sc = device_get_softc(dev);
450 GPIO_LOCK(sc);
451 if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) {
452 GPIO_UNLOCK(sc);
453 return (EINVAL);
454 }
455 ftgpio_pin_write(sc, pin_num, pin_value);
456 GPIO_UNLOCK(sc);
457
458 return (0);
459 }
460
461 static int
ftgpio_gpio_pin_get(device_t dev,uint32_t pin_num,uint32_t * pin_value)462 ftgpio_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
463 {
464 struct ftgpio_softc *sc;
465
466 if (!FTGPIO_IS_VALID_PIN(pin_num))
467 return (EINVAL);
468
469 if (pin_value == NULL)
470 return (EINVAL);
471
472 sc = device_get_softc(dev);
473 GPIO_LOCK(sc);
474 *pin_value = ftgpio_pin_read(sc, pin_num);
475 GPIO_UNLOCK(sc);
476
477 return (0);
478 }
479
480 static int
ftgpio_gpio_pin_toggle(device_t dev,uint32_t pin_num)481 ftgpio_gpio_pin_toggle(device_t dev, uint32_t pin_num)
482 {
483 struct ftgpio_softc *sc;
484 bool pin_value;
485
486 if (!FTGPIO_IS_VALID_PIN(pin_num))
487 return (EINVAL);
488
489 sc = device_get_softc(dev);
490 GPIO_LOCK(sc);
491 pin_value = ftgpio_pin_read(sc, pin_num);
492 ftgpio_pin_write(sc, pin_num, !pin_value);
493 GPIO_UNLOCK(sc);
494
495 return (0);
496 }
497
498 static int
ftgpio_gpio_pin_getname(device_t dev,uint32_t pin_num,char * pin_name)499 ftgpio_gpio_pin_getname(device_t dev, uint32_t pin_num, char *pin_name)
500 {
501 struct ftgpio_softc *sc;
502
503 if (pin_name == NULL)
504 return (EINVAL);
505
506 if (!FTGPIO_IS_VALID_PIN(pin_num))
507 return (EINVAL);
508
509 sc = device_get_softc(dev);
510 strlcpy(pin_name, sc->pins[pin_num].gp_name, GPIOMAXNAME);
511
512 return (0);
513 }
514
515 static int
ftgpio_gpio_pin_getcaps(device_t dev,uint32_t pin_num,uint32_t * pin_caps)516 ftgpio_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *pin_caps)
517 {
518 struct ftgpio_softc *sc;
519
520 if (pin_caps == NULL)
521 return (EINVAL);
522
523 if (!FTGPIO_IS_VALID_PIN(pin_num))
524 return (EINVAL);
525
526 sc = device_get_softc(dev);
527 *pin_caps = sc->pins[pin_num].gp_caps;
528
529 return (0);
530 }
531
532 static int
ftgpio_gpio_pin_getflags(device_t dev,uint32_t pin_num,uint32_t * pin_flags)533 ftgpio_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *pin_flags)
534 {
535 struct ftgpio_softc *sc;
536
537 if (pin_flags == NULL)
538 return (EINVAL);
539
540 if (!FTGPIO_IS_VALID_PIN(pin_num))
541 return (EINVAL);
542
543 sc = device_get_softc(dev);
544 *pin_flags = sc->pins[pin_num].gp_flags;
545
546 return (0);
547 }
548
549 static int
ftgpio_gpio_pin_setflags(device_t dev,uint32_t pin_num,uint32_t pin_flags)550 ftgpio_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t pin_flags)
551 {
552 struct ftgpio_softc *sc;
553 int ret;
554
555 if (!FTGPIO_IS_VALID_PIN(pin_num)) {
556 FTGPIO_VERBOSE_PRINTF(dev, "invalid pin number: %u\n", pin_num);
557 return (EINVAL);
558 }
559
560 sc = device_get_softc(dev);
561
562 /* Check for unwanted flags. */
563 if ((pin_flags & sc->pins[pin_num].gp_caps) != pin_flags) {
564 FTGPIO_VERBOSE_PRINTF(dev, "invalid pin flags 0x%x, vs caps 0x%x\n",
565 pin_flags, sc->pins[pin_num].gp_caps);
566 return (EINVAL);
567 }
568
569 GPIO_LOCK(sc);
570 ret = ftgpio_pin_setflags(sc, pin_num, pin_flags);
571 GPIO_UNLOCK(sc);
572
573 return (ret);
574 }
575
576 static device_method_t ftgpio_methods[] = {
577 /* Device interface */
578 DEVMETHOD(device_probe, ftgpio_probe),
579 DEVMETHOD(device_attach, ftgpio_attach),
580 DEVMETHOD(device_detach, ftgpio_detach),
581
582 /* GPIO */
583 DEVMETHOD(gpio_get_bus, ftgpio_gpio_get_bus),
584 DEVMETHOD(gpio_pin_max, ftgpio_gpio_pin_max),
585 DEVMETHOD(gpio_pin_set, ftgpio_gpio_pin_set),
586 DEVMETHOD(gpio_pin_get, ftgpio_gpio_pin_get),
587 DEVMETHOD(gpio_pin_toggle, ftgpio_gpio_pin_toggle),
588 DEVMETHOD(gpio_pin_getname, ftgpio_gpio_pin_getname),
589 DEVMETHOD(gpio_pin_getcaps, ftgpio_gpio_pin_getcaps),
590 DEVMETHOD(gpio_pin_getflags, ftgpio_gpio_pin_getflags),
591 DEVMETHOD(gpio_pin_setflags, ftgpio_gpio_pin_setflags),
592
593 DEVMETHOD_END
594 };
595
596 static driver_t ftgpio_driver = {
597 "gpio",
598 ftgpio_methods,
599 sizeof(struct ftgpio_softc)
600 };
601
602 DRIVER_MODULE(ftgpio, superio, ftgpio_driver, NULL, NULL);
603 MODULE_DEPEND(ftgpio, gpiobus, 1, 1, 1);
604 MODULE_DEPEND(ftgpio, superio, 1, 1, 1);
605 MODULE_VERSION(ftgpio, 1);
606