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