Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102865202
D37893.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
21 KB
Referenced Files
None
Subscribers
None
D37893.diff
View Options
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -159,6 +159,7 @@
ffclock.4 \
filemon.4 \
firewire.4 \
+ ${_ftgpio.4} \
${_ftwd.4} \
full.4 \
fwe.4 \
@@ -802,6 +803,7 @@
_coretemp.4= coretemp.4
_cpuctl.4= cpuctl.4
_dpms.4= dpms.4
+_ftgpio.4= ftgpio.4
_ftwd.4= ftwd.4
_hpt27xx.4= hpt27xx.4
_hptiop.4= hptiop.4
diff --git a/share/man/man4/ftgpio.4 b/share/man/man4/ftgpio.4
new file mode 100644
--- /dev/null
+++ b/share/man/man4/ftgpio.4
@@ -0,0 +1,56 @@
+.\" Copyright (c) 2022, Stormshield
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 28, 2022
+.Dt FTGPIO 4
+.Os
+.Sh NAME
+.Nm ftgpio
+.Nd GPIO Controller on Fintek Super I/O",
+.Sh SYNOPSIS
+.Cd "device ftgpio"
+.Cd "device gpio"
+.Cd "device gpioled"
+.Sh DESCRIPTION
+The
+.Nm
+is a driver for the GPIO controller found on Fintek Super I/O chips.
+.Sh SEE ALSO
+.Xr gpio 3 ,
+.Xr gpio 4 ,
+.Xr gpioled 4 ,
+.Xr gpioctl 8
+.Xr superio 4 ,
+.Sh HISTORY
+The
+.Nm
+manual page first appeared in
+.Fx 14.0 .
+.Sh AUTHORS
+The
+.Nm
+driver was partially written by
+.An Stéphane Rochoy Aq Mt stéphane.rochoy@stormshield.eu .
diff --git a/share/man/man4/superio.4 b/share/man/man4/superio.4
--- a/share/man/man4/superio.4
+++ b/share/man/man4/superio.4
@@ -101,7 +101,15 @@
The
.Nm
driver supports a multitude of Super I/O controllers produced by Nuvoton,
-formerly known as Winbond, and ITE.
+formerly known as Winbond, and ITE. As well as some produced by Fintek, namely:
+
+.Bl -bullet -compact
+.It
+F81803
+.It
+F81865
+.El
+
.Sh SEE ALSO
.Xr superio 9
.Sh HISTORY
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -127,6 +127,7 @@
dev/enic/vnic_intr.c optional enic
dev/enic/vnic_rq.c optional enic
dev/enic/vnic_wq.c optional enic
+dev/ftgpio/ftgpio.c optional ftgpio superio
dev/hyperv/vmbus/amd64/hyperv_machdep.c optional hyperv
dev/hyperv/vmbus/amd64/vmbus_vector.S optional hyperv
dev/iavf/if_iavf_iflib.c optional iavf pci \
diff --git a/sys/dev/ftgpio/ftgpio.c b/sys/dev/ftgpio/ftgpio.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/ftgpio/ftgpio.c
@@ -0,0 +1,610 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2016-2023 Stormshield
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/bus.h>
+#include <sys/eventhandler.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/superio/superio.h>
+
+#include "gpio_if.h"
+
+#define GPIO_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \
+ device_get_nameunit(dev), NULL, MTX_DEF)
+#define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx)
+#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx)
+#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
+#define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED)
+#define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED)
+
+/* Global register set */
+#define GPIO4_ENABLE 0x28
+#define GPIO3_ENABLE 0x29
+#define FULL_UR5_UR6 0x2A
+#define GPIO1_ENABLE 0x2B
+#define GPIO2_ENABLE 0x2C
+
+/* Logical Device Numbers. */
+#define FTGPIO_LDN_GPIO 0x06
+
+#define FTGPIO_MAX_GROUP 6
+#define FTGPIO_MAX_PIN 52
+
+#define FTGPIO_IS_VALID_PIN(_p) ((_p) >= 0 && (_p) <= FTGPIO_MAX_PIN)
+#define FTGPIO_PIN_GETINDEX(_p) ((_p) & 7)
+#define FTGPIO_PIN_GETGROUP(_p) ((_p) >> 3)
+
+#define FTGPIO_GPIO_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | \
+ GPIO_PIN_INVOUT | GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)
+
+#define GET_BIT(_v, _b) (((_v) >> (_b)) & 1)
+
+#define FTGPIO_VERBOSE_PRINTF(dev, ...) \
+ do { \
+ if (__predict_false(bootverbose)) \
+ device_printf(dev, __VA_ARGS__); \
+ } while (0)
+
+/*
+ * Note that the values are important.
+ * They match actual register offsets.
+ * See p71 and p72 of F81865's datasheet.
+ */
+#define REG_OUTPUT_ENABLE 0 /* Not for GPIO0 */
+#define REG_OUTPUT_DATA 1
+#define REG_PIN_STATUS 2
+#define REG_DRIVE_ENABLE 3
+#define REG_MODE_SELECT_1 4 /* Only for GPIO0 */
+#define REG_MODE_SELECT_2 5 /* Only for GPIO0 */
+#define REG_PULSE_WIDTH_SELECT_1 6 /* Only for GPIO0 */
+#define REG_PULSE_WIDTH_SELECT_2 7 /* Only for GPIO0 */
+#define REG_INTERRUPT_ENABLE 8 /* Only for GPIO0 */
+#define REG_INTERRUPT_STATUS 9 /* Only for GPIO0 */
+
+struct ftgpio_device {
+ uint16_t devid;
+ const char *descr;
+} ftgpio_devices[] = {
+ {
+ .devid = 0x0704,
+ .descr = "GPIO Controller on Fintek Super I/O",
+ },
+};
+
+struct ftgpio_softc {
+ device_t dev;
+ device_t busdev;
+ struct mtx mtx;
+ struct gpio_pin pins[FTGPIO_MAX_PIN + 1];
+};
+
+static uint8_t
+ftgpio_group_get_ioreg(struct ftgpio_softc *sc, uint8_t reg, unsigned group)
+{
+ uint8_t ioreg;
+
+ KASSERT((group == 0 && REG_OUTPUT_DATA <= reg && reg <= REG_INTERRUPT_STATUS) || \
+ (group >= 1 && reg <= REG_DRIVE_ENABLE),
+ ("%s: invalid register %u for group %u", __func__, reg, group));
+ ioreg = (((0xf - group) << 4) + reg);
+ return (ioreg);
+}
+
+static uint8_t
+ftgpio_group_get_output(struct ftgpio_softc *sc, unsigned group)
+{
+ uint8_t ioreg, val;
+
+ ioreg = ftgpio_group_get_ioreg(sc, REG_OUTPUT_DATA, group);
+ val = superio_read(sc->dev, ioreg);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "group GPIO%u output is 0x%x (ioreg=0x%x)\n",
+ group, val, ioreg);
+ return (val);
+}
+
+static void
+ftgpio_group_set_output(struct ftgpio_softc *sc, unsigned group, uint8_t group_value)
+{
+ uint8_t ioreg;
+
+ ioreg = ftgpio_group_get_ioreg(sc, REG_OUTPUT_DATA, group);
+ superio_write(sc->dev, ioreg, group_value);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "set group GPIO%u output to 0x%x (ioreg=0x%x)\n",
+ group, group_value, ioreg);
+}
+
+static uint8_t
+ftgpio_group_get_status(struct ftgpio_softc *sc, unsigned group)
+{
+ uint8_t ioreg;
+
+ ioreg = ftgpio_group_get_ioreg(sc, REG_PIN_STATUS, group);
+ return (superio_read(sc->dev, ioreg));
+}
+
+static void
+ftgpio_pin_write(struct ftgpio_softc *sc, uint32_t pin_num, bool pin_value)
+{
+ uint32_t pin_flags;
+ uint8_t val;
+ unsigned group, index;
+
+ GPIO_ASSERT_LOCKED(sc);
+ index = FTGPIO_PIN_GETINDEX(pin_num);
+ group = FTGPIO_PIN_GETGROUP(pin_num);
+ pin_flags = sc->pins[pin_num].gp_flags;
+ if ((pin_flags & (GPIO_PIN_OUTPUT)) == 0) {
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "pin %u<GPIO%u%u> is not configured for output\n",
+ pin_num, group, index);
+ return;
+ }
+
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "set pin %u<GPIO%u%u> to %s\n",
+ pin_num, group, index, (pin_value ? "on" : "off"));
+
+ val = ftgpio_group_get_output(sc, group);
+ if (!pin_value != !(pin_flags & GPIO_PIN_INVOUT))
+ val |= (1 << index);
+ else
+ val &= ~(1 << index);
+ ftgpio_group_set_output(sc, group, val);
+}
+
+static bool
+ftgpio_pin_read(struct ftgpio_softc *sc, uint32_t pin_num)
+{
+ uint32_t pin_flags;
+ unsigned group, index;
+ uint8_t val;
+ bool pin_value;
+
+ GPIO_ASSERT_LOCKED(sc);
+ group = FTGPIO_PIN_GETGROUP(pin_num);
+ index = FTGPIO_PIN_GETINDEX(pin_num);
+ pin_flags = sc->pins[pin_num].gp_flags;
+ if ((pin_flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) == 0) {
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "pin %u<GPIO%u%u> is not configured for input or output\n",
+ pin_num, group, index);
+ return (false);
+ }
+
+ if (pin_flags & GPIO_PIN_OUTPUT)
+ val = ftgpio_group_get_output(sc, group);
+ else
+ val = ftgpio_group_get_status(sc, group);
+ pin_value = GET_BIT(val, index);
+
+ if (((pin_flags & (GPIO_PIN_OUTPUT|GPIO_PIN_INVOUT)) == (GPIO_PIN_OUTPUT|GPIO_PIN_INVOUT)) ||
+ ((pin_flags & (GPIO_PIN_INPUT |GPIO_PIN_INVIN )) == (GPIO_PIN_INPUT |GPIO_PIN_INVIN)))
+ pin_value = !pin_value;
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "pin %u<GPIO%u%u> is %s\n",
+ pin_num, group, index, (pin_value ? "on" : "off"));
+
+ return (pin_value);
+}
+
+static void
+ftgpio_pin_set_drive(struct ftgpio_softc *sc, uint32_t pin_num, bool pin_drive)
+{
+ unsigned group, index;
+ uint8_t group_drive, ioreg;
+
+ index = FTGPIO_PIN_GETINDEX(pin_num);
+ group = FTGPIO_PIN_GETGROUP(pin_num);
+ ioreg = ftgpio_group_get_ioreg(sc, REG_DRIVE_ENABLE, group);
+ group_drive = superio_read(sc->dev, ioreg);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "group GPIO%u drive is 0x%x (ioreg=0x%x)\n",
+ group, group_drive, ioreg);
+
+ if (pin_drive)
+ group_drive |= (1 << index); /* push pull */
+ else
+ group_drive &= ~(1 << index); /* open drain */
+ superio_write(sc->dev, ioreg, group_drive);
+}
+
+static bool
+ftgpio_pin_is_pushpull(struct ftgpio_softc *sc, uint32_t pin_num)
+{
+ unsigned group, index;
+ uint8_t group_drive, ioreg;
+ bool is_pushpull;
+
+ index = FTGPIO_PIN_GETINDEX(pin_num);
+ group = FTGPIO_PIN_GETGROUP(pin_num);
+
+ ioreg = ftgpio_group_get_ioreg(sc, REG_DRIVE_ENABLE, group);
+ group_drive = superio_read(sc->dev, ioreg);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "group GPIO%u drive is 0x%x (ioreg=0x%x)\n",
+ group, group_drive, ioreg);
+
+ is_pushpull = group_drive & (1 << index);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "pin %u<GPIO%u%u> drive is %s\n",
+ pin_num, group, index, (is_pushpull ? "pushpull" : "opendrain"));
+
+ return (is_pushpull);
+}
+
+static void
+ftgpio_pin_set_io(struct ftgpio_softc *sc, uint32_t pin_num, bool pin_io)
+{
+ unsigned group, index;
+ uint8_t group_io, ioreg;
+
+ index = FTGPIO_PIN_GETINDEX(pin_num);
+ group = FTGPIO_PIN_GETGROUP(pin_num);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "set pin %u<GPIO%u%u> io to %s\n",
+ pin_num, group, index, (pin_io ? "output" : "input"));
+
+ ioreg = ftgpio_group_get_ioreg(sc, REG_OUTPUT_ENABLE, group);
+ group_io = superio_read(sc->dev, ioreg);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "group GPIO%u io is 0x%x (ioreg=0x%x)\n",
+ group, group_io, ioreg);
+ if (pin_io)
+ group_io |= (1 << index); /* output */
+ else
+ group_io &= ~(1 << index); /* input */
+ superio_write(sc->dev, ioreg, group_io);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "set group GPIO%u io to 0x%x (ioreg=0x%x)\n",
+ group, group_io, ioreg);
+}
+
+static bool
+ftgpio_pin_is_output(struct ftgpio_softc *sc, uint32_t pin_num)
+{
+ unsigned group, index;
+ uint8_t group_io, ioreg;
+ bool is_output;
+
+ index = FTGPIO_PIN_GETINDEX(pin_num);
+ group = FTGPIO_PIN_GETGROUP(pin_num);
+
+ ioreg = ftgpio_group_get_ioreg(sc, REG_OUTPUT_ENABLE, group);
+ group_io = superio_read(sc->dev, ioreg);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "group GPIO%u io is 0x%x (ioreg=0x%x)\n",
+ group, group_io, ioreg);
+
+ is_output = group_io & (1 << index);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "pin %u<GPIO%u%u> io is %s\n",
+ pin_num, group, index, (is_output ? "output" : "input"));
+ return (is_output);
+}
+
+static int
+ftgpio_pin_setflags(struct ftgpio_softc *sc, uint32_t pin_num, uint32_t pin_flags)
+{
+ /* check flags consistency */
+ if ((pin_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
+ (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
+ return (EINVAL);
+
+ if ((pin_flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) ==
+ (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL))
+ return (EINVAL);
+
+ if (pin_flags & GPIO_PIN_OPENDRAIN)
+ ftgpio_pin_set_drive(sc, pin_num, 0 /* open drain */);
+ else if (pin_flags & GPIO_PIN_PUSHPULL)
+ ftgpio_pin_set_drive(sc, pin_num, 1 /* push pull */);
+
+ if (pin_flags & GPIO_PIN_INPUT)
+ ftgpio_pin_set_io(sc, pin_num, 0 /* input */);
+ else if (pin_flags & GPIO_PIN_OUTPUT)
+ ftgpio_pin_set_io(sc, pin_num, 1 /* output */);
+
+ sc->pins[pin_num].gp_flags = pin_flags;
+
+ return (0);
+}
+
+static int
+ftgpio_probe(device_t dev)
+{
+ uint16_t devid;
+ int i;
+
+ if (superio_vendor(dev) != SUPERIO_VENDOR_FINTEK)
+ return (ENXIO);
+ if (superio_get_type(dev) != SUPERIO_DEV_GPIO)
+ return (ENXIO);
+
+ /*
+ * There are several GPIO devices, we attach only to one of them
+ * and use the rest without attaching.
+ */
+ if (superio_get_ldn(dev) != FTGPIO_LDN_GPIO)
+ return (ENXIO);
+
+ devid = superio_devid(dev);
+ for (i = 0; i < nitems(ftgpio_devices); i++) {
+ if (devid == ftgpio_devices[i].devid) {
+ device_set_desc(dev, ftgpio_devices[i].descr);
+ return (BUS_PROBE_DEFAULT);
+ }
+ }
+ return (ENXIO);
+}
+
+static int
+ftgpio_attach(device_t dev)
+{
+ struct ftgpio_softc *sc;
+ int i;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ GPIO_LOCK_INIT(sc);
+ GPIO_LOCK(sc);
+
+ for (i = 0; i <= FTGPIO_MAX_PIN; i++) {
+ struct gpio_pin *pin;
+
+ pin = &sc->pins[i];
+ pin->gp_pin = i;
+ pin->gp_caps = FTGPIO_GPIO_CAPS;
+ pin->gp_flags = 0;
+
+ if (ftgpio_pin_is_output(sc, i))
+ pin->gp_flags |= GPIO_PIN_OUTPUT;
+ else
+ pin->gp_flags |= GPIO_PIN_INPUT;
+
+ if (ftgpio_pin_is_pushpull(sc, i))
+ pin->gp_flags |= GPIO_PIN_PUSHPULL;
+ else
+ pin->gp_flags |= GPIO_PIN_OPENDRAIN;
+
+ snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%u%u",
+ FTGPIO_PIN_GETGROUP(i), FTGPIO_PIN_GETINDEX(i));
+ }
+
+ /* Enable all groups */
+ superio_write(sc->dev, GPIO1_ENABLE, 0xFF);
+ superio_write(sc->dev, GPIO2_ENABLE, 0xFF);
+ superio_write(sc->dev, GPIO3_ENABLE, 0xFF);
+ superio_write(sc->dev, GPIO4_ENABLE, 0xFF);
+ superio_write(sc->dev, FULL_UR5_UR6, 0x0A);
+ FTGPIO_VERBOSE_PRINTF(sc->dev, "groups GPIO1..GPIO6 enabled\n");
+
+ GPIO_UNLOCK(sc);
+ sc->busdev = gpiobus_attach_bus(dev);
+ if (sc->busdev == NULL) {
+ GPIO_LOCK_DESTROY(sc);
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+ftgpio_detach(device_t dev)
+{
+ struct ftgpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ gpiobus_detach_bus(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static device_t
+ftgpio_gpio_get_bus(device_t dev)
+{
+ struct ftgpio_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ return (sc->busdev);
+}
+
+static int
+ftgpio_gpio_pin_max(device_t dev, int *npins)
+{
+ *npins = FTGPIO_MAX_PIN;
+ return (0);
+}
+
+static int
+ftgpio_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
+{
+ struct ftgpio_softc *sc;
+
+ if (!FTGPIO_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_LOCK(sc);
+ if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) {
+ GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+ ftgpio_pin_write(sc, pin_num, pin_value);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+ftgpio_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
+{
+ struct ftgpio_softc *sc;
+
+ if (!FTGPIO_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ if (pin_value == NULL)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_LOCK(sc);
+ *pin_value = ftgpio_pin_read(sc, pin_num);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+ftgpio_gpio_pin_toggle(device_t dev, uint32_t pin_num)
+{
+ struct ftgpio_softc *sc;
+ bool pin_value;
+
+ if (!FTGPIO_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_LOCK(sc);
+ pin_value = ftgpio_pin_read(sc, pin_num);
+ ftgpio_pin_write(sc, pin_num, !pin_value);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+ftgpio_gpio_pin_getname(device_t dev, uint32_t pin_num, char *pin_name)
+{
+ struct ftgpio_softc *sc;
+
+ if (pin_name == NULL)
+ return (EINVAL);
+
+ if (!FTGPIO_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ strlcpy(pin_name, sc->pins[pin_num].gp_name, GPIOMAXNAME);
+
+ return (0);
+}
+
+static int
+ftgpio_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *pin_caps)
+{
+ struct ftgpio_softc *sc;
+
+ if (pin_caps == NULL)
+ return (EINVAL);
+
+ if (!FTGPIO_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ *pin_caps = sc->pins[pin_num].gp_caps;
+
+ return (0);
+}
+
+static int
+ftgpio_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *pin_flags)
+{
+ struct ftgpio_softc *sc;
+
+ if (pin_flags == NULL)
+ return (EINVAL);
+
+ if (!FTGPIO_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ *pin_flags = sc->pins[pin_num].gp_flags;
+
+ return (0);
+}
+
+static int
+ftgpio_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t pin_flags)
+{
+ struct ftgpio_softc *sc;
+ int ret;
+
+ if (!FTGPIO_IS_VALID_PIN(pin_num)) {
+ FTGPIO_VERBOSE_PRINTF(dev, "invalid pin number: %u\n", pin_num);
+ return (EINVAL);
+ }
+
+ sc = device_get_softc(dev);
+
+ /* Check for unwanted flags. */
+ if ((pin_flags & sc->pins[pin_num].gp_caps) != pin_flags) {
+ FTGPIO_VERBOSE_PRINTF(dev, "invalid pin flags 0x%x, vs caps 0x%x\n",
+ pin_flags, sc->pins[pin_num].gp_caps);
+ return (EINVAL);
+ }
+
+ GPIO_LOCK(sc);
+ ret = ftgpio_pin_setflags(sc, pin_num, pin_flags);
+ GPIO_UNLOCK(sc);
+
+ return (ret);
+}
+
+static device_method_t ftgpio_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ftgpio_probe),
+ DEVMETHOD(device_attach, ftgpio_attach),
+ DEVMETHOD(device_detach, ftgpio_detach),
+
+ /* GPIO */
+ DEVMETHOD(gpio_get_bus, ftgpio_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, ftgpio_gpio_pin_max),
+ DEVMETHOD(gpio_pin_set, ftgpio_gpio_pin_set),
+ DEVMETHOD(gpio_pin_get, ftgpio_gpio_pin_get),
+ DEVMETHOD(gpio_pin_toggle, ftgpio_gpio_pin_toggle),
+ DEVMETHOD(gpio_pin_getname, ftgpio_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getcaps, ftgpio_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_getflags, ftgpio_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_setflags, ftgpio_gpio_pin_setflags),
+
+ DEVMETHOD_END
+};
+
+static driver_t ftgpio_driver = {
+ "gpio",
+ ftgpio_methods,
+ sizeof(struct ftgpio_softc)
+};
+
+DRIVER_MODULE(ftgpio, superio, ftgpio_driver, NULL, NULL);
+MODULE_DEPEND(ftgpio, gpiobus, 1, 1, 1);
+MODULE_DEPEND(ftgpio, superio, 1, 1, 1);
+MODULE_VERSION(ftgpio, 1);
diff --git a/sys/dev/superio/superio.c b/sys/dev/superio/superio.c
--- a/sys/dev/superio/superio.c
+++ b/sys/dev/superio/superio.c
@@ -283,6 +283,7 @@
};
const struct sio_device fintek_devices[] = {
+ { .ldn = 6, .type = SUPERIO_DEV_GPIO },
{ .ldn = 7, .type = SUPERIO_DEV_WDT },
{ .type = SUPERIO_DEV_NONE },
};
@@ -441,6 +442,11 @@
.descr = "Fintek F81803",
.devices = fintek_devices,
},
+ {
+ .vendor = SUPERIO_VENDOR_FINTEK, .devid = 0x0704,
+ .descr = "Fintek F81865",
+ .devices = fintek_devices,
+ },
{ 0, 0 }
};
@@ -550,8 +556,9 @@
sc->revid = revid;
KASSERT(sc->vendor == SUPERIO_VENDOR_ITE ||
- sc->vendor == SUPERIO_VENDOR_NUVOTON,
- ("Only ITE and Nuvoton SuperIO-s are supported"));
+ sc->vendor == SUPERIO_VENDOR_NUVOTON ||
+ sc->vendor == SUPERIO_VENDOR_FINTEK,
+ ("Only ITE, Nuvoton and Fintek SuperIO-s are supported"));
sc->ldn_reg = 0x07;
sc->enable_reg = 0x30;
sc->current_ldn = 0xff; /* no device should have this */
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -122,6 +122,7 @@
firewire \
firmware \
flash \
+ ${_ftgpio} \
${_ftwd} \
fusefs \
${_fxp} \
@@ -681,6 +682,7 @@
_dpms= dpms
_em= em
_et= et
+_ftgpio= ftgpio
_ftwd= ftwd
_exca= exca
_igc= igc
diff --git a/sys/modules/ftgpio/Makefile b/sys/modules/ftgpio/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/ftgpio/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${SRCTOP}/sys/dev/ftgpio
+KMOD= ftgpio
+SRCS= ftgpio.c
+SRCS+= device_if.h bus_if.h isa_if.h gpio_if.h opt_platform.h
+
+.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Nov 19, 4:21 AM (21 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14710216
Default Alt Text
D37893.diff (21 KB)
Attached To
Mode
D37893: ftgpio: Add support for Fintek F81865 Super I/O's GPIO
Attached
Detach File
Event Timeline
Log In to Comment