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_attach_bus(dev);
402 if (sc->busdev == NULL) {
403 GPIO_LOCK_DESTROY(sc);
404 return (ENXIO);
405 }
406
407 return (0);
408 }
409
410 static int
ftgpio_detach(device_t dev)411 ftgpio_detach(device_t dev)
412 {
413 struct ftgpio_softc *sc;
414
415 sc = device_get_softc(dev);
416 gpiobus_detach_bus(dev);
417 GPIO_ASSERT_UNLOCKED(sc);
418 GPIO_LOCK_DESTROY(sc);
419
420 return (0);
421 }
422
423 static device_t
ftgpio_gpio_get_bus(device_t dev)424 ftgpio_gpio_get_bus(device_t dev)
425 {
426 struct ftgpio_softc *sc;
427
428 sc = device_get_softc(dev);
429
430 return (sc->busdev);
431 }
432
433 static int
ftgpio_gpio_pin_max(device_t dev,int * npins)434 ftgpio_gpio_pin_max(device_t dev, int *npins)
435 {
436 *npins = FTGPIO_MAX_PIN;
437 return (0);
438 }
439
440 static int
ftgpio_gpio_pin_set(device_t dev,uint32_t pin_num,uint32_t pin_value)441 ftgpio_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
442 {
443 struct ftgpio_softc *sc;
444
445 if (!FTGPIO_IS_VALID_PIN(pin_num))
446 return (EINVAL);
447
448 sc = device_get_softc(dev);
449 GPIO_LOCK(sc);
450 if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) {
451 GPIO_UNLOCK(sc);
452 return (EINVAL);
453 }
454 ftgpio_pin_write(sc, pin_num, pin_value);
455 GPIO_UNLOCK(sc);
456
457 return (0);
458 }
459
460 static int
ftgpio_gpio_pin_get(device_t dev,uint32_t pin_num,uint32_t * pin_value)461 ftgpio_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
462 {
463 struct ftgpio_softc *sc;
464
465 if (!FTGPIO_IS_VALID_PIN(pin_num))
466 return (EINVAL);
467
468 if (pin_value == NULL)
469 return (EINVAL);
470
471 sc = device_get_softc(dev);
472 GPIO_LOCK(sc);
473 *pin_value = ftgpio_pin_read(sc, pin_num);
474 GPIO_UNLOCK(sc);
475
476 return (0);
477 }
478
479 static int
ftgpio_gpio_pin_toggle(device_t dev,uint32_t pin_num)480 ftgpio_gpio_pin_toggle(device_t dev, uint32_t pin_num)
481 {
482 struct ftgpio_softc *sc;
483 bool pin_value;
484
485 if (!FTGPIO_IS_VALID_PIN(pin_num))
486 return (EINVAL);
487
488 sc = device_get_softc(dev);
489 GPIO_LOCK(sc);
490 pin_value = ftgpio_pin_read(sc, pin_num);
491 ftgpio_pin_write(sc, pin_num, !pin_value);
492 GPIO_UNLOCK(sc);
493
494 return (0);
495 }
496
497 static int
ftgpio_gpio_pin_getname(device_t dev,uint32_t pin_num,char * pin_name)498 ftgpio_gpio_pin_getname(device_t dev, uint32_t pin_num, char *pin_name)
499 {
500 struct ftgpio_softc *sc;
501
502 if (pin_name == NULL)
503 return (EINVAL);
504
505 if (!FTGPIO_IS_VALID_PIN(pin_num))
506 return (EINVAL);
507
508 sc = device_get_softc(dev);
509 strlcpy(pin_name, sc->pins[pin_num].gp_name, GPIOMAXNAME);
510
511 return (0);
512 }
513
514 static int
ftgpio_gpio_pin_getcaps(device_t dev,uint32_t pin_num,uint32_t * pin_caps)515 ftgpio_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *pin_caps)
516 {
517 struct ftgpio_softc *sc;
518
519 if (pin_caps == NULL)
520 return (EINVAL);
521
522 if (!FTGPIO_IS_VALID_PIN(pin_num))
523 return (EINVAL);
524
525 sc = device_get_softc(dev);
526 *pin_caps = sc->pins[pin_num].gp_caps;
527
528 return (0);
529 }
530
531 static int
ftgpio_gpio_pin_getflags(device_t dev,uint32_t pin_num,uint32_t * pin_flags)532 ftgpio_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *pin_flags)
533 {
534 struct ftgpio_softc *sc;
535
536 if (pin_flags == NULL)
537 return (EINVAL);
538
539 if (!FTGPIO_IS_VALID_PIN(pin_num))
540 return (EINVAL);
541
542 sc = device_get_softc(dev);
543 *pin_flags = sc->pins[pin_num].gp_flags;
544
545 return (0);
546 }
547
548 static int
ftgpio_gpio_pin_setflags(device_t dev,uint32_t pin_num,uint32_t pin_flags)549 ftgpio_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t pin_flags)
550 {
551 struct ftgpio_softc *sc;
552 int ret;
553
554 if (!FTGPIO_IS_VALID_PIN(pin_num)) {
555 FTGPIO_VERBOSE_PRINTF(dev, "invalid pin number: %u\n", pin_num);
556 return (EINVAL);
557 }
558
559 sc = device_get_softc(dev);
560
561 /* Check for unwanted flags. */
562 if ((pin_flags & sc->pins[pin_num].gp_caps) != pin_flags) {
563 FTGPIO_VERBOSE_PRINTF(dev, "invalid pin flags 0x%x, vs caps 0x%x\n",
564 pin_flags, sc->pins[pin_num].gp_caps);
565 return (EINVAL);
566 }
567
568 GPIO_LOCK(sc);
569 ret = ftgpio_pin_setflags(sc, pin_num, pin_flags);
570 GPIO_UNLOCK(sc);
571
572 return (ret);
573 }
574
575 static device_method_t ftgpio_methods[] = {
576 /* Device interface */
577 DEVMETHOD(device_probe, ftgpio_probe),
578 DEVMETHOD(device_attach, ftgpio_attach),
579 DEVMETHOD(device_detach, ftgpio_detach),
580
581 /* GPIO */
582 DEVMETHOD(gpio_get_bus, ftgpio_gpio_get_bus),
583 DEVMETHOD(gpio_pin_max, ftgpio_gpio_pin_max),
584 DEVMETHOD(gpio_pin_set, ftgpio_gpio_pin_set),
585 DEVMETHOD(gpio_pin_get, ftgpio_gpio_pin_get),
586 DEVMETHOD(gpio_pin_toggle, ftgpio_gpio_pin_toggle),
587 DEVMETHOD(gpio_pin_getname, ftgpio_gpio_pin_getname),
588 DEVMETHOD(gpio_pin_getcaps, ftgpio_gpio_pin_getcaps),
589 DEVMETHOD(gpio_pin_getflags, ftgpio_gpio_pin_getflags),
590 DEVMETHOD(gpio_pin_setflags, ftgpio_gpio_pin_setflags),
591
592 DEVMETHOD_END
593 };
594
595 static driver_t ftgpio_driver = {
596 "gpio",
597 ftgpio_methods,
598 sizeof(struct ftgpio_softc)
599 };
600
601 DRIVER_MODULE(ftgpio, superio, ftgpio_driver, NULL, NULL);
602 MODULE_DEPEND(ftgpio, gpiobus, 1, 1, 1);
603 MODULE_DEPEND(ftgpio, superio, 1, 1, 1);
604 MODULE_VERSION(ftgpio, 1);
605