git: b8a083ea32f5 - main - gpio: Merge TCA6416 & TCA6408 drivers into TCA64XX
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 19 Sep 2022 07:27:03 UTC
The branch main has been updated by kd: URL: https://cgit.FreeBSD.org/src/commit/?id=b8a083ea32f5a58e76280e8787d336a65a24fda2 commit b8a083ea32f5a58e76280e8787d336a65a24fda2 Author: Jakub Kołodziej <jkol@semihalf.com> AuthorDate: 2022-09-16 11:33:40 +0000 Commit: Kornel Dulęba <kd@FreeBSD.org> CommitDate: 2022-09-19 07:18:08 +0000 gpio: Merge TCA6416 & TCA6408 drivers into TCA64XX This merges TCA6416, TCA6408 drivers and adds PCA9555 support. They handle 8 pin and 16 pin ICs with basic INPUT/OUTPUT functionality. The register map is fairly similar so there is no point in having two separate drivers. Reviewed by: kd Obtained from: Semihalf Differential Revision: https://reviews.freebsd.org/D36559 --- sys/arm64/conf/std.marvell | 1 + sys/arm64/conf/std.nxp | 2 +- sys/conf/files | 3 +- sys/dev/iicbus/gpio/tca6408.c | 375 ----------------------- sys/dev/iicbus/gpio/tca6416.c | 524 -------------------------------- sys/dev/iicbus/gpio/tca64xx.c | 642 +++++++++++++++++++++++++++++++++++++++ sys/modules/i2c/Makefile | 2 +- sys/modules/i2c/tca6416/Makefile | 7 - sys/modules/i2c/tca64xx/Makefile | 5 + 9 files changed, 651 insertions(+), 910 deletions(-) diff --git a/sys/arm64/conf/std.marvell b/sys/arm64/conf/std.marvell index 50a00b6d02a3..d3b000a9e0e7 100644 --- a/sys/arm64/conf/std.marvell +++ b/sys/arm64/conf/std.marvell @@ -12,6 +12,7 @@ device mvebu_pinctrl # Marvell Pinmux Controller # I2C device a37x0_iic # Armada 37x0 I2C controller +device tca64xx # I2C gpio expander device twsi # Allwinner/Marvell I2C controller # Interrupt controllers diff --git a/sys/arm64/conf/std.nxp b/sys/arm64/conf/std.nxp index 6225a43b6ed4..1148b26fe32b 100644 --- a/sys/arm64/conf/std.nxp +++ b/sys/arm64/conf/std.nxp @@ -8,7 +8,7 @@ options SOC_NXP_LS # I2C device pca954x # NPX I2C bus multiplexer / switches device pcf8563 # NXP Real-time clock/calendar -device tca6408 # NXP I2C gpio expander +device tca64xx # NXP I2C gpio expander device pcf85063 # NXP Real-time clock # Serial (COM) ports diff --git a/sys/conf/files b/sys/conf/files index 7633d45c5187..4397dcba280a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1878,8 +1878,7 @@ dev/iicbus/rtc/rx8803.c optional rx8803 iicbus fdt dev/iicbus/s35390a.c optional s35390a dev/iicbus/sy8106a.c optional sy8106a fdt dev/iicbus/syr827.c optional syr827 fdt -dev/iicbus/gpio/tca6408.c optional tca6408 fdt gpio -dev/iicbus/gpio/tca6416.c optional tca6416 fdt +dev/iicbus/gpio/tca64xx.c optional tca64xx fdt gpio dev/iicbus/pmic/fan53555.c optional fan53555 fdt dev/igc/if_igc.c optional igc iflib pci dev/igc/igc_api.c optional igc iflib pci diff --git a/sys/dev/iicbus/gpio/tca6408.c b/sys/dev/iicbus/gpio/tca6408.c deleted file mode 100644 index e72cd276fdda..000000000000 --- a/sys/dev/iicbus/gpio/tca6408.c +++ /dev/null @@ -1,375 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2021 Alstom Group. - * Copyright (c) 2021 Semihalf. - * - * 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> -__FBSDID("$FreeBSD$"); - -#include "opt_platform.h" - -#include <sys/param.h> -#include <sys/bus.h> -#include <sys/gpio.h> -#include <sys/kernel.h> -#include <sys/module.h> - -#include <dev/ofw/ofw_bus.h> - -#include <dev/iicbus/iicbus.h> -#include <dev/iicbus/iiconf.h> - -#include <dev/gpio/gpiobusvar.h> - -#define BIT(x) (1UL << (x)) - -#define TCA6408_READ_REG 0x0 -#define TCA6408_WRITE_REG 0x1 -#define TCA6408_POLARITY_REG 0x2 -#define TCA6408_CONFIG_REG 0x3 - -#define PINS_NUM 8 - -#define PIN_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT \ - | GPIO_PIN_INVIN) - -struct tca6408_softc { - device_t dev; - device_t bus_dev; - struct mtx mtx; -}; - -static int tca6408_read1(device_t dev, uint8_t offset, uint8_t *data); -static int tca6408_write1(device_t dev, uint8_t offset, uint8_t data); -static int tca6408_probe(device_t dev); -static int tca6408_attach(device_t dev); -static int tca6408_detach(device_t dev); -static device_t tca6408_get_bus(device_t dev); -static int tca6408_pin_max(device_t dev, int *pin); -static int tca6408_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags); -static int tca6408_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); -static int tca6408_pin_getname(device_t dev, uint32_t pin, char *name); -static int tca6408_pin_get(device_t dev, uint32_t pin, unsigned int *val); -static int tca6408_pin_set(device_t dev, uint32_t pin, unsigned int val); -static int tca6408_pin_toggle(device_t dev, uint32_t pin); -static int tca6408_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); - -static device_method_t tca6408_methods[] = { - DEVMETHOD(device_probe, tca6408_probe), - DEVMETHOD(device_attach, tca6408_attach), - DEVMETHOD(device_detach, tca6408_detach), - - DEVMETHOD(gpio_get_bus, tca6408_get_bus), - DEVMETHOD(gpio_pin_max, tca6408_pin_max), - DEVMETHOD(gpio_pin_getflags, tca6408_pin_getflags), - DEVMETHOD(gpio_pin_setflags, tca6408_pin_setflags), - DEVMETHOD(gpio_pin_getname, tca6408_pin_getname), - DEVMETHOD(gpio_pin_get, tca6408_pin_get), - DEVMETHOD(gpio_pin_set, tca6408_pin_set), - DEVMETHOD(gpio_pin_toggle, tca6408_pin_toggle), - DEVMETHOD(gpio_pin_getcaps, tca6408_pin_getcaps), - - DEVMETHOD_END -}; - -static driver_t tca6408_driver = { - "gpio", - tca6408_methods, - sizeof(struct tca6408_softc) -}; - -static struct ofw_compat_data tca6408_compat_data[] = { - { "ti,tca6408", 1 }, - { NULL, 0} -}; - -DRIVER_MODULE(tca6408, iicbus, tca6408_driver, 0, 0); -IICBUS_FDT_PNP_INFO(tca6408_compat_data); - -static int -tca6408_read1(device_t dev, uint8_t offset, uint8_t *data) -{ - int error; - - error = iicdev_readfrom(dev, offset, (void *) data, 1, IIC_WAIT); - if (error != 0) - device_printf(dev, "Failed to read from device\n"); - - return (error); -} - -static int -tca6408_write1(device_t dev, uint8_t offset, uint8_t data) -{ - int error; - - error = iicdev_writeto(dev, offset, (void *) &data, 1, IIC_WAIT); - if (error != 0) - device_printf(dev, "Failed to write to device\n"); - - return (error); -} - -static int -tca6408_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_search_compatible(dev, tca6408_compat_data)->ocd_data) - return (ENXIO); - - device_set_desc(dev, "TCA6408 GPIO expander"); - - return (BUS_PROBE_DEFAULT); -} - -static int -tca6408_attach(device_t dev) -{ - struct tca6408_softc *sc; - - sc = device_get_softc(dev); - sc->dev = dev; - - mtx_init(&sc->mtx, "tca6408 gpio", "gpio", MTX_DEF); - - sc->bus_dev = gpiobus_attach_bus(dev); - if (sc->bus_dev == NULL) { - device_printf(dev, "Could not create busdev child\n"); - return (ENXIO); - } - - OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); - - return (0); -} - -static int -tca6408_detach(device_t dev) -{ - struct tca6408_softc *sc; - - sc = device_get_softc(dev); - - if (sc->bus_dev != NULL) - gpiobus_detach_bus(sc->bus_dev); - - mtx_destroy(&sc->mtx); - - return (0); -} - -static device_t -tca6408_get_bus(device_t dev) -{ - struct tca6408_softc *sc; - - sc = device_get_softc(dev); - - return (sc->bus_dev); -} - -static int -tca6408_pin_max(device_t dev, int *pin) -{ - - if (pin == NULL) - return (EINVAL); - - *pin = PINS_NUM - 1; - - return (0); -} - -static int -tca6408_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) -{ - uint8_t buffer; - int error; - - if (pin >= PINS_NUM || flags == NULL) - return (EINVAL); - - error = tca6408_read1(dev, TCA6408_CONFIG_REG, &buffer); - if (error != 0) - return (error); - - *flags = (buffer & BIT(pin)) ? GPIO_PIN_INPUT : GPIO_PIN_OUTPUT; - - error = tca6408_read1(dev, TCA6408_POLARITY_REG, &buffer); - if (error != 0) - return (error); - - if (buffer & BIT(pin)) - *flags |= ((*flags & GPIO_PIN_INPUT) - ? GPIO_PIN_INVIN : GPIO_PIN_INVOUT); - - return (0); -} - -static int -tca6408_pin_setflags(device_t dev, uint32_t pin, unsigned int flags) -{ - uint8_t config_buf, inv_buf; - struct tca6408_softc *sc; - int error; - - if (pin >= PINS_NUM) - return (EINVAL); - - sc = device_get_softc(dev); - mtx_lock(&sc->mtx); - - error = tca6408_read1(dev, TCA6408_CONFIG_REG, &config_buf); - if (error != 0) - goto fail; - - error = tca6408_read1(dev, TCA6408_POLARITY_REG, &inv_buf); - if (error != 0) - goto fail; - - if (flags & GPIO_PIN_INPUT) - config_buf |= BIT(pin); - else if (flags & GPIO_PIN_OUTPUT) - config_buf &= ~BIT(pin); - - if (flags & GPIO_PIN_INVIN) - inv_buf |= BIT(pin); - else if (flags & GPIO_PIN_INVOUT) - inv_buf &= ~BIT(pin); - - error = tca6408_write1(dev, TCA6408_CONFIG_REG, config_buf); - if (error != 0) - goto fail; - - error = tca6408_write1(dev, TCA6408_POLARITY_REG, inv_buf); - -fail: - mtx_unlock(&sc->mtx); - - return (error); -} - -static int -tca6408_pin_getname(device_t dev, uint32_t pin, char *name) -{ - - if (pin >= PINS_NUM) - return (EINVAL); - - snprintf(name, GPIOMAXNAME, "tca6408_gpio_pin%d\n", pin); - - return (0); -} - -static int -tca6408_pin_get(device_t dev, uint32_t pin, unsigned int *val) -{ - uint8_t buffer; - int error; - - if (pin >= PINS_NUM || val == NULL) - return (EINVAL); - - error = tca6408_read1(dev, TCA6408_READ_REG, &buffer); - if (error != 0) - return (error); - - *val = buffer & BIT(pin); - - return (0); -} - -static int -tca6408_pin_set(device_t dev, uint32_t pin, uint32_t val) -{ - struct tca6408_softc *sc; - uint8_t buffer; - int error; - - if (pin >= PINS_NUM) - return (EINVAL); - - sc = device_get_softc(dev); - mtx_lock(&sc->mtx); - - error = tca6408_read1(dev, TCA6408_WRITE_REG, &buffer); - if (error != 0) - goto fail; - - if (val != 0) - buffer |= BIT(pin); - else - buffer &= ~BIT(pin); - - error = tca6408_write1(dev, TCA6408_WRITE_REG, buffer); - -fail: - mtx_unlock(&sc->mtx); - - return (error); -} - -static int -tca6408_pin_toggle(device_t dev, uint32_t pin) -{ - struct tca6408_softc *sc; - uint8_t buffer; - int error; - - if (pin >= PINS_NUM) - return (EINVAL); - - sc = device_get_softc(dev); - mtx_lock(&sc->mtx); - - error = tca6408_read1(dev, TCA6408_WRITE_REG, &buffer); - if (error) - goto fail; - - buffer ^= BIT(pin); - error = tca6408_write1(dev, TCA6408_WRITE_REG, buffer); - -fail: - mtx_unlock(&sc->mtx); - - return (error); -} - -static int -tca6408_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) -{ - - if (pin >= PINS_NUM) - return (EINVAL); - - *caps = PIN_CAPS; - - return (0); -} - diff --git a/sys/dev/iicbus/gpio/tca6416.c b/sys/dev/iicbus/gpio/tca6416.c deleted file mode 100644 index 467e20bc167c..000000000000 --- a/sys/dev/iicbus/gpio/tca6416.c +++ /dev/null @@ -1,524 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2020 Alstom Group. - * Copyright (c) 2020 Semihalf. - * - * 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. - */ - -/* - * Driver for TI TCA6416 I2C GPIO expander module. - * - * This driver only supports basic functionality - * (interrupt handling and polarity inversion were omitted). - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/bus.h> -#include <sys/gpio.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/proc.h> -#include <sys/systm.h> -#include <sys/sysctl.h> - -#include <machine/bus.h> - -#include <dev/ofw/openfirm.h> -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> - -#include <dev/iicbus/iicbus.h> -#include <dev/iicbus/iiconf.h> - -#include <dev/gpio/gpiobusvar.h> - -#include "gpio_if.h" - -/* Base addresses of registers. LSB omitted. */ -#define IN_PORT_REG 0x00 -#define OUT_PORT_REG 0x02 -#define POLARITY_INV_REG 0x04 -#define CONF_REG 0x06 - -#define NUM_PINS 16 -#define PINS_PER_REG 8 -#define PIN_CAPS \ - (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT \ - | GPIO_PIN_PUSHPULL | GPIO_PIN_INVIN) - -#ifdef DEBUG -#define dbg_dev_printf(dev, fmt, args...) \ - device_printf(dev, fmt, ##args) -#else -#define dbg_dev_printf(dev, fmt, args...) -#endif - -#define TCA6416_BIT_FROM_PIN(pin) (pin % PINS_PER_REG) -#define TCA6416_REG_ADDR(pin, baseaddr) (baseaddr | (pin / PINS_PER_REG)) - -struct tca6416_softc { - device_t dev; - device_t busdev; - struct mtx mtx; - uint32_t addr; -}; - -static int tca6416_read(device_t, uint8_t, uint8_t*); -static int tca6416_write(device_t, uint8_t, uint8_t); -static int tca6416_probe(device_t); -static int tca6416_attach(device_t); -static int tca6416_detach(device_t); -static device_t tca6416_get_bus(device_t); -static int tca6416_pin_max(device_t, int*); -static int tca6416_pin_getcaps(device_t, uint32_t, uint32_t*); -static int tca6416_pin_getflags(device_t, uint32_t, uint32_t*); -static int tca6416_pin_setflags(device_t, uint32_t, uint32_t); -static int tca6416_pin_getname(device_t, uint32_t, char*); -static int tca6416_pin_get(device_t, uint32_t, unsigned int*); -static int tca6416_pin_set(device_t, uint32_t, unsigned int); -static int tca6416_pin_toggle(device_t, uint32_t); -#ifdef DEBUG -static void tca6416_regdump_setup(device_t dev); -static int tca6416_regdump_sysctl(SYSCTL_HANDLER_ARGS); -#endif - -static device_method_t tca6416_methods[] = { - DEVMETHOD(device_probe, tca6416_probe), - DEVMETHOD(device_attach, tca6416_attach), - DEVMETHOD(device_detach, tca6416_detach), - - /* GPIO methods */ - DEVMETHOD(gpio_get_bus, tca6416_get_bus), - DEVMETHOD(gpio_pin_max, tca6416_pin_max), - DEVMETHOD(gpio_pin_getcaps, tca6416_pin_getcaps), - DEVMETHOD(gpio_pin_getflags, tca6416_pin_getflags), - DEVMETHOD(gpio_pin_setflags, tca6416_pin_setflags), - DEVMETHOD(gpio_pin_getname, tca6416_pin_getname), - DEVMETHOD(gpio_pin_get, tca6416_pin_get), - DEVMETHOD(gpio_pin_set, tca6416_pin_set), - DEVMETHOD(gpio_pin_toggle, tca6416_pin_toggle), - - DEVMETHOD_END -}; - -static driver_t tca6416_driver = { - "gpio", - tca6416_methods, - sizeof(struct tca6416_softc) -}; - -DRIVER_MODULE(tca6416, iicbus, tca6416_driver, 0, 0); -MODULE_VERSION(tca6416, 1); - -static struct ofw_compat_data compat_data[] = { - {"ti,tca6416", 1}, - {"ti,tca9539", 1}, - {0,0} -}; - -static int -tca6416_read(device_t dev, uint8_t reg, uint8_t *data) -{ - struct iic_msg msgs[2]; - struct tca6416_softc *sc; - int error; - - sc = device_get_softc(dev); - if (data == NULL) - return (EINVAL); - - msgs[0].slave = sc->addr; - msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP; - msgs[0].len = 1; - msgs[0].buf = ® - - msgs[1].slave = sc->addr; - msgs[1].flags = IIC_M_RD; - msgs[1].len = 1; - msgs[1].buf = data; - - error = iicbus_transfer_excl(dev, msgs, 2, IIC_WAIT); - return (iic2errno(error)); -} - -static int -tca6416_write(device_t dev, uint8_t reg, uint8_t val) -{ - struct iic_msg msg; - struct tca6416_softc *sc; - int error; - uint8_t buffer[2] = {reg, val}; - - sc = device_get_softc(dev); - - msg.slave = sc->addr; - msg.flags = IIC_M_WR; - msg.len = 2; - msg.buf = buffer; - - error = iicbus_transfer_excl(dev, &msg, 1, IIC_WAIT); - return (iic2errno(error)); -} - -static int -tca6416_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) - return (ENXIO); - - device_set_desc(dev, "TCA6416 I/O expander"); - return (BUS_PROBE_DEFAULT); -} - -static int -tca6416_attach(device_t dev) -{ - struct tca6416_softc *sc; - - sc = device_get_softc(dev); - sc->dev = dev; - sc->addr = iicbus_get_addr(dev); - - mtx_init(&sc->mtx, "tca6416 gpio", "gpio", MTX_DEF); - - sc->busdev = gpiobus_attach_bus(dev); - if (sc->busdev == NULL) { - device_printf(dev, "Could not create busdev child\n"); - return (ENXIO); - } - -#ifdef DEBUG - tca6416_regdump_setup(dev); -#endif - - return (0); -} - -static int -tca6416_detach(device_t dev) -{ - struct tca6416_softc *sc; - - sc = device_get_softc(dev); - - if (sc->busdev != NULL) - gpiobus_detach_bus(sc->busdev); - - mtx_destroy(&sc->mtx); - - return (0); -} - -static device_t -tca6416_get_bus(device_t dev) -{ - struct tca6416_softc *sc; - - sc = device_get_softc(dev); - - return (sc->busdev); -} - -static int -tca6416_pin_max(device_t dev __unused, int *maxpin) -{ - - if (maxpin == NULL) - return (EINVAL); - - *maxpin = NUM_PINS - 1; - return (0); -} - -static int -tca6416_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) -{ - - if (pin >= NUM_PINS || caps == NULL) - return (EINVAL); - - *caps = PIN_CAPS; - return (0); -} - -static int -tca6416_pin_getflags(device_t dev, uint32_t pin, uint32_t *pflags) -{ - int error; - uint8_t reg_addr, reg_bit, val; - - if (pin >= NUM_PINS || pflags == NULL) - return (EINVAL); - - reg_addr = TCA6416_REG_ADDR(pin, CONF_REG); - reg_bit = TCA6416_BIT_FROM_PIN(pin); - - error = tca6416_read(dev, reg_addr, &val); - if (error != 0) - return (error); - - *pflags = (val & (1 << reg_bit)) - ? GPIO_PIN_INPUT : GPIO_PIN_OUTPUT; - - reg_addr = TCA6416_REG_ADDR(pin, POLARITY_INV_REG); - - error = tca6416_read(dev, reg_addr, &val); - if (error != 0) - return (error); - - if (val & (1 << reg_bit)) - *pflags |= GPIO_PIN_INVIN; - - return (0); -} - -static int -tca6416_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) -{ - uint8_t reg_addr, inv_reg_addr, reg_bit, val, inv_val; - struct tca6416_softc *sc; - int error; - - sc = device_get_softc(dev); - - if (pin >= NUM_PINS) - return (EINVAL); - - reg_addr = TCA6416_REG_ADDR(pin, CONF_REG); - inv_reg_addr = TCA6416_REG_ADDR(pin, POLARITY_INV_REG); - reg_bit = TCA6416_BIT_FROM_PIN(pin); - - mtx_lock(&sc->mtx); - - error = tca6416_read(dev, reg_addr, &val); - if (error != 0) - goto fail; - error = tca6416_read(dev, inv_reg_addr, &inv_val); - if (error != 0) - goto fail; - - if (flags & GPIO_PIN_INPUT) - val |= (1 << reg_bit); - else if (flags & GPIO_PIN_OUTPUT) - val &= ~(1 << reg_bit); - - if (flags & GPIO_PIN_INVIN) - inv_val |= (1 << reg_bit); - else - inv_val &= ~(1 << reg_bit); - - error = tca6416_write(dev, reg_addr, val); - if (error != 0) - goto fail; - error = tca6416_write(dev, inv_reg_addr, val); - -fail: - mtx_unlock(&sc->mtx); - return (error); -} - -static int -tca6416_pin_getname(device_t dev, uint32_t pin, char *name) -{ - - if (pin >= NUM_PINS || name == NULL) - return (EINVAL); - - snprintf(name, GPIOMAXNAME, "gpio_P%d%d", pin / PINS_PER_REG, - pin % PINS_PER_REG); - - return (0); -} - -static int -tca6416_pin_get(device_t dev, uint32_t pin, unsigned int *pval) -{ - uint8_t reg_bit, reg_addr, reg_pvalue; - int error; - - if (pin >= NUM_PINS || pval == NULL) - return (EINVAL); - - reg_bit = TCA6416_BIT_FROM_PIN(pin); - reg_addr = TCA6416_REG_ADDR(pin, IN_PORT_REG); - - dbg_dev_printf(dev, "Reading pin %u pvalue.", pin); - - error = tca6416_read(dev, reg_addr, ®_pvalue); - if (error != 0) - return (error); - - *pval = reg_pvalue & (1 << reg_bit) ? 1 : 0; - - return (0); -} - -static int -tca6416_pin_set(device_t dev, uint32_t pin, unsigned int val) -{ - struct tca6416_softc *sc; - uint8_t reg_addr, reg_bit, reg_value; - int error; - - sc = device_get_softc(dev); - - if (pin >= NUM_PINS) - return (EINVAL); - - reg_addr = TCA6416_REG_ADDR(pin , OUT_PORT_REG); - reg_bit = TCA6416_BIT_FROM_PIN(pin); - - dbg_dev_printf(dev, "Setting pin: %u to %u\n", pin, val); - - mtx_lock(&sc->mtx); - - error = tca6416_read(dev, reg_addr, ®_value); - if (error != 0) { - dbg_dev_printf(dev, "Failed to read from register.\n"); - mtx_unlock(&sc->mtx); - return (error); - } - - if (val != 0) - reg_value |= (1 << reg_bit); - else - reg_value &= ~(1 << reg_bit); - - - error = tca6416_write(dev, reg_addr, reg_value); - if (error != 0) { - dbg_dev_printf(dev, "Could not write to register.\n"); - mtx_unlock(&sc->mtx); - return (error); - } - - mtx_unlock(&sc->mtx); - - return (0); -} - -static int -tca6416_pin_toggle(device_t dev, uint32_t pin) -{ - struct tca6416_softc *sc; - int error; - uint8_t reg_addr, reg_bit, reg_value; - - sc = device_get_softc(dev); - - if (pin >= NUM_PINS) - return (EINVAL); - - reg_addr = TCA6416_REG_ADDR(pin, OUT_PORT_REG); - reg_bit = TCA6416_BIT_FROM_PIN(pin); - - dbg_dev_printf(dev, "Toggling pin: %d\n", pin); - - mtx_lock(&sc->mtx); - - error = tca6416_read(dev, reg_addr, ®_value); - if (error != 0) { - mtx_unlock(&sc->mtx); - dbg_dev_printf(dev, "Cannot read from register.\n"); - return (error); - } - - reg_value ^= (1 << reg_bit); - - error = tca6416_write(dev, reg_addr, reg_value); - if (error != 0) - dbg_dev_printf(dev, "Cannot write to register.\n"); - - mtx_unlock(&sc->mtx); - - return (error); -} - -#ifdef DEBUG -static void -tca6416_regdump_setup(device_t dev) -{ - struct sysctl_ctx_list *ctx; - struct sysctl_oid *node; - - ctx = device_get_sysctl_ctx(dev); - node = device_get_sysctl_tree(dev); - - SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "in_reg_1", - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, IN_PORT_REG, - tca6416_regdump_sysctl, "A", "Input port 1"); - SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "in_reg_2", - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, - IN_PORT_REG | 1, tca6416_regdump_sysctl, "A", "Input port 2"); - SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "out_reg_1", - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, OUT_PORT_REG, - tca6416_regdump_sysctl, "A", "Output port 1"); - SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "out_reg_2", - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, OUT_PORT_REG - | 1, tca6416_regdump_sysctl, "A", "Output port 2"); - SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "pol_inv_1", - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, - POLARITY_INV_REG, tca6416_regdump_sysctl, "A", "Polarity inv 1"); - SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "pol_inv_2", - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, - POLARITY_INV_REG | 1, tca6416_regdump_sysctl, "A", - "Polarity inv 2"); - SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "conf_reg_1", - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, - CONF_REG, tca6416_regdump_sysctl, "A", "Configuration 1"); - SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "conf_reg_2", - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, - CONF_REG | 1, tca6416_regdump_sysctl, "A", "Configuration 2"); -} - -static int -tca6416_regdump_sysctl(SYSCTL_HANDLER_ARGS) -{ - device_t dev; - char buf[5]; - int len, error; - uint8_t reg, regval; - - dev = (device_t)arg1; - reg = (uint8_t)arg2; - - error = tca6416_read(dev, reg, ®val); - if (error != 0) { - return (error); - } - - len = snprintf(buf, 5, "0x%02x", regval); - - error = sysctl_handle_string(oidp, buf, len, req); - - return (error); -} -#endif diff --git a/sys/dev/iicbus/gpio/tca64xx.c b/sys/dev/iicbus/gpio/tca64xx.c new file mode 100644 index 000000000000..62cfd9d8fd59 --- /dev/null +++ b/sys/dev/iicbus/gpio/tca64xx.c *** 679 LINES SKIPPED ***