Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/i2c Add GPIO support.



details:   https://anonhg.NetBSD.org/src/rev/35cb7650e2f2
branches:  trunk
changeset: 372201:35cb7650e2f2
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sun Oct 30 11:51:19 2022 +0000

description:
Add GPIO support.

PR# kern/57030

diffstat:

 sys/dev/i2c/axppmic.c |  158 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 156 insertions(+), 2 deletions(-)

diffs (221 lines):

diff -r 633df62a7e5d -r 35cb7650e2f2 sys/dev/i2c/axppmic.c
--- a/sys/dev/i2c/axppmic.c     Sun Oct 30 10:26:48 2022 +0000
+++ b/sys/dev/i2c/axppmic.c     Sun Oct 30 11:51:19 2022 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: axppmic.c,v 1.36 2021/08/07 16:19:11 thorpej Exp $ */
+/* $NetBSD: axppmic.c,v 1.37 2022/10/30 11:51:19 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014-2018 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: axppmic.c,v 1.36 2021/08/07 16:19:11 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: axppmic.c,v 1.37 2022/10/30 11:51:19 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -79,6 +79,13 @@
 #define        AXP_ADC_RAW(_hi, _lo)   \
        (((u_int)(_hi) << 4) | ((_lo) & 0xf))
 
+#define        AXP_GPIO_CTRL_REG(pin)  (0x90 + (pin) * 2)
+#define         AXP_GPIO_CTRL_FUNC_MASK        __BITS(2,0)
+#define         AXP_GPIO_CTRL_FUNC_LOW         0
+#define         AXP_GPIO_CTRL_FUNC_HIGH        1
+#define         AXP_GPIO_CTRL_FUNC_INPUT       2
+#define        AXP_GPIO_SIGNAL_REG     0x94
+
 #define        AXP_FUEL_GAUGE_CTRL_REG 0xb8
 #define         AXP_FUEL_GAUGE_CTRL_EN __BIT(7)
 
@@ -327,6 +334,8 @@
 
 struct axppmic_config {
        const char *name;
+       const char *gpio_compat;
+       u_int gpio_npins;
        const struct axppmic_ctrl *controls;
        u_int ncontrols;
        u_int irq_regs;
@@ -386,6 +395,13 @@
        u_int           sc_shut_thres;
 };
 
+struct axppmic_gpio_pin {
+       struct axppmic_softc *pin_sc;
+       u_int pin_nr;
+       int pin_flags;
+       bool pin_actlo;
+};
+
 struct axpreg_softc {
        device_t        sc_dev;
        i2c_tag_t       sc_i2c;
@@ -402,6 +418,8 @@
 
 static const struct axppmic_config axp803_config = {
        .name = "AXP803",
+       .gpio_compat = "x-powers,axp803-gpio",
+       .gpio_npins = 2,
        .controls = axp803_ctrls,
        .ncontrols = __arraycount(axp803_ctrls),
        .irq_regs = 6,
@@ -447,6 +465,8 @@
 
 static const struct axppmic_config axp813_config = {
        .name = "AXP813",
+       .gpio_compat = "x-powers,axp813-gpio",
+       .gpio_npins = 2,
        .controls = axp813_ctrls,
        .ncontrols = __arraycount(axp813_ctrls),
        .irq_regs = 6,
@@ -583,6 +603,132 @@
        .poweroff = axppmic_power_poweroff,
 };
 
+static int
+axppmic_gpio_ctl(struct axppmic_softc *sc, uint8_t pin, uint8_t func)
+{
+       uint8_t val;
+       int error;
+
+       KASSERT(pin < sc->sc_conf->gpio_npins);
+       KASSERT((func & ~AXP_GPIO_CTRL_FUNC_MASK) == 0);
+
+       iic_acquire_bus(sc->sc_i2c, 0);
+       error = axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_GPIO_CTRL_REG(pin),
+           &val, 0);
+       if (error == 0) {
+               val &= ~AXP_GPIO_CTRL_FUNC_MASK;
+               val |= func;
+               error = axppmic_write(sc->sc_i2c, sc->sc_addr,
+                   AXP_GPIO_CTRL_REG(pin), val, 0);
+       }
+       iic_release_bus(sc->sc_i2c, 0);
+
+       return error;
+}
+
+static void *
+axppmic_gpio_acquire(device_t dev, const void *data, size_t len, int flags)
+{
+       struct axppmic_softc *sc = device_private(dev);
+       struct axppmic_gpio_pin *gpin;
+       const u_int *gpio = data;
+       int error;
+
+       if (len != 12) {
+               return NULL;
+       }
+
+       const uint8_t pin = be32toh(gpio[1]) & 0xff;
+       const bool actlo = be32toh(gpio[2]) & 1;
+
+       if (pin >= sc->sc_conf->gpio_npins) {
+               return NULL;
+       }
+
+       if ((flags & GPIO_PIN_INPUT) != 0) {
+               error = axppmic_gpio_ctl(sc, pin, AXP_GPIO_CTRL_FUNC_INPUT);
+               if (error != 0) {
+                       return NULL;
+               }
+       }
+
+       gpin = kmem_zalloc(sizeof(*gpin), KM_SLEEP);
+       gpin->pin_sc = sc;
+       gpin->pin_nr = pin;
+       gpin->pin_flags = flags;
+       gpin->pin_actlo = actlo;
+
+       return gpin;
+}
+
+static void
+axppmic_gpio_release(device_t dev, void *priv)
+{
+       struct axppmic_softc *sc = device_private(dev);
+       struct axppmic_gpio_pin *gpin = priv;
+
+       axppmic_gpio_ctl(sc, gpin->pin_nr, AXP_GPIO_CTRL_FUNC_INPUT);
+
+       kmem_free(gpin, sizeof(*gpin));
+}
+
+static int
+axppmic_gpio_read(device_t dev, void *priv, bool raw)
+{
+       struct axppmic_softc *sc = device_private(dev);
+       struct axppmic_gpio_pin *gpin = priv;
+       uint8_t data;
+       int error, val;
+
+       KASSERT(sc == gpin->pin_sc);
+
+       const uint8_t data_mask = __BIT(gpin->pin_nr);
+
+       iic_acquire_bus(sc->sc_i2c, 0);
+       error = axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_GPIO_SIGNAL_REG,
+           &data, 0);
+       iic_release_bus(sc->sc_i2c, 0);
+
+       if (error != 0) {
+               device_printf(dev, "WARNING: failed to read pin %d: %d\n",
+                   gpin->pin_nr, error);
+               val = 0;
+       } else {
+               val = __SHIFTOUT(data, data_mask);
+       }
+       if (!raw && gpin->pin_actlo) {
+               val = !val;
+       }
+
+       return val;
+}
+
+static void
+axppmic_gpio_write(device_t dev, void *priv, int val, bool raw)
+{
+       struct axppmic_softc *sc = device_private(dev);
+       struct axppmic_gpio_pin *gpin = priv;
+       int error;
+
+       if (!raw && gpin->pin_actlo) {
+               val = !val;
+       }
+
+       error = axppmic_gpio_ctl(sc, gpin->pin_nr,
+           val == 0 ? AXP_GPIO_CTRL_FUNC_LOW : AXP_GPIO_CTRL_FUNC_HIGH);
+       if (error != 0) {
+               device_printf(dev, "WARNING: failed to write pin %d: %d\n",
+                   gpin->pin_nr, error);
+       }
+}
+
+static struct fdtbus_gpio_controller_func axppmic_gpio_funcs = {
+       .acquire = axppmic_gpio_acquire,
+       .release = axppmic_gpio_release,
+       .read = axppmic_gpio_read,
+       .write = axppmic_gpio_write,
+};
+
 static void
 axppmic_task_shut(void *priv)
 {
@@ -1041,6 +1187,14 @@
        fdtbus_register_power_controller(sc->sc_dev, sc->sc_phandle,
            &axppmic_power_funcs);
 
+       if (c->gpio_compat != NULL) {
+               phandle = of_find_bycompat(sc->sc_phandle, c->gpio_compat);
+               if (phandle > 0) {
+                       fdtbus_register_gpio_controller(self, phandle,
+                           &axppmic_gpio_funcs);
+               }
+       }
+
        phandle = of_find_firstchild_byname(sc->sc_phandle, "regulators");
        if (phandle > 0) {
                aaa.reg_i2c = sc->sc_i2c;



Home | Main Index | Thread Index | Old Index