Page MenuHomeFreeBSD

D6135.diff
No OneTemporary

D6135.diff

Index: head/sys/arm/allwinner/axp209.c
===================================================================
--- head/sys/arm/allwinner/axp209.c
+++ head/sys/arm/allwinner/axp209.c
@@ -1,5 +1,6 @@
/*-
- * Copyright (c) 2015 Emmanuel Vadot <manu@bidouilliste.com>
+ * Copyright (c) 2015-2016 Emmanuel Vadot <manu@freebsd.org>
+ * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,6 +39,7 @@
#include <sys/time.h>
#include <sys/bus.h>
#include <sys/proc.h>
+#include <sys/gpio.h>
#include <sys/reboot.h>
#include <sys/resource.h>
#include <sys/rman.h>
@@ -46,40 +48,45 @@
#include <dev/iicbus/iicbus.h>
#include <dev/iicbus/iiconf.h>
+#include <dev/gpio/gpiobusvar.h>
+
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
-#include "iicbus_if.h"
-
-/* Power State Register */
-#define AXP209_PSR 0x00
-#define AXP209_PSR_ACIN 0x80
-#define AXP209_PSR_ACIN_SHIFT 7
-#define AXP209_PSR_VBUS 0x20
-#define AXP209_PSR_VBUS_SHIFT 5
-
-/* Shutdown and battery control */
-#define AXP209_SHUTBAT 0x32
-#define AXP209_SHUTBAT_SHUTDOWN 0x80
-
-/* Temperature monitor */
-#define AXP209_TEMPMON 0x5e
-#define AXP209_TEMPMON_H(a) ((a) << 4)
-#define AXP209_TEMPMON_L(a) ((a) & 0xf)
-#define AXP209_TEMPMON_MIN 1447 /* -144.7C */
+#include <arm/allwinner/axp209reg.h>
-#define AXP209_0C_TO_K 2731
+#include "iicbus_if.h"
+#include "gpio_if.h"
struct axp209_softc {
+ device_t dev;
uint32_t addr;
- struct intr_config_hook enum_hook;
+ struct resource * res[1];
+ void * intrcookie;
+ struct intr_config_hook intr_hook;
+ device_t gpiodev;
+ struct mtx mtx;
+};
+
+/* GPIO3 is different, don't expose it for now */
+static const struct {
+ const char *name;
+ uint8_t ctrl_reg;
+} axp209_pins[] = {
+ { "GPIO0", AXP209_GPIO0_CTRL },
+ { "GPIO1", AXP209_GPIO1_CTRL },
+ { "GPIO2", AXP209_GPIO2_CTRL },
};
-enum axp209_sensor {
- AXP209_TEMP
+static struct resource_spec axp_res_spec[] = {
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { -1, 0, 0 }
};
+#define AXP_LOCK(sc) mtx_lock(&(sc)->mtx)
+#define AXP_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
+
static int
axp209_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size)
{
@@ -125,16 +132,75 @@
uint8_t data[2];
int val, error;
- if (sensor != AXP209_TEMP)
+ switch (sensor) {
+ case AXP209_TEMP:
+ error = axp209_read(dev, AXP209_TEMPMON, data, 2);
+ if (error != 0)
+ return (error);
+
+ /* Temperature is between -144.7C and 264.8C, step +0.1C */
+ val = (AXP209_SENSOR_H(data[0]) | AXP209_SENSOR_L(data[1])) -
+ AXP209_TEMPMON_MIN + AXP209_0C_TO_K;
+ break;
+ case AXP209_ACVOLT:
+ error = axp209_read(dev, AXP209_ACIN_VOLTAGE, data, 2);
+ if (error != 0)
+ return (error);
+
+ val = (AXP209_SENSOR_H(data[0]) | AXP209_SENSOR_L(data[1])) *
+ AXP209_VOLT_STEP;
+ break;
+ case AXP209_ACCURRENT:
+ error = axp209_read(dev, AXP209_ACIN_CURRENT, data, 2);
+ if (error != 0)
+ return (error);
+
+ val = (AXP209_SENSOR_H(data[0]) | AXP209_SENSOR_L(data[1])) *
+ AXP209_ACCURRENT_STEP;
+ break;
+ case AXP209_VBUSVOLT:
+ error = axp209_read(dev, AXP209_VBUS_VOLTAGE, data, 2);
+ if (error != 0)
+ return (error);
+
+ val = (AXP209_SENSOR_H(data[0]) | AXP209_SENSOR_L(data[1])) *
+ AXP209_VOLT_STEP;
+ break;
+ case AXP209_VBUSCURRENT:
+ error = axp209_read(dev, AXP209_VBUS_CURRENT, data, 2);
+ if (error != 0)
+ return (error);
+
+ val = (AXP209_SENSOR_H(data[0]) | AXP209_SENSOR_L(data[1])) *
+ AXP209_VBUSCURRENT_STEP;
+ break;
+ case AXP209_BATVOLT:
+ error = axp209_read(dev, AXP209_BAT_VOLTAGE, data, 2);
+ if (error != 0)
+ return (error);
+
+ val = (AXP209_SENSOR_H(data[0]) | AXP209_SENSOR_L(data[1])) *
+ AXP209_BATVOLT_STEP;
+ break;
+ case AXP209_BATCHARGECURRENT:
+ error = axp209_read(dev, AXP209_BAT_CHARGE_CURRENT, data, 2);
+ if (error != 0)
+ return (error);
+
+ val = (AXP209_SENSOR_H(data[0]) | AXP209_SENSOR_L(data[1])) *
+ AXP209_BATCURRENT_STEP;
+ break;
+ case AXP209_BATDISCHARGECURRENT:
+ error = axp209_read(dev, AXP209_BAT_DISCHARGE_CURRENT, data, 2);
+ if (error != 0)
+ return (error);
+
+ val = (AXP209_SENSOR_BAT_H(data[0]) |
+ AXP209_SENSOR_BAT_L(data[1])) * AXP209_BATCURRENT_STEP;
+ break;
+ default:
return (ENOENT);
-
- error = axp209_read(dev, AXP209_TEMPMON, data, 2);
- if (error != 0)
- return (error);
-
- /* Temperature is between -144.7C and 264.8C, step +0.1C */
- val = (AXP209_TEMPMON_H(data[0]) | AXP209_TEMPMON_L(data[1])) -
- AXP209_TEMPMON_MIN + AXP209_0C_TO_K;
+ }
return sysctl_handle_opaque(oidp, &val, sizeof(val), req);
}
@@ -154,32 +220,317 @@
axp209_write(dev, AXP209_SHUTBAT, AXP209_SHUTBAT_SHUTDOWN);
}
+static void
+axp_intr(void *arg)
+{
+ struct axp209_softc *sc;
+ uint8_t reg;
+
+ sc = arg;
+
+ axp209_read(sc->dev, AXP209_IRQ1_STATUS, &reg, 1);
+ if (reg) {
+ if (reg & AXP209_IRQ1_AC_OVERVOLT)
+ devctl_notify("PMU", "AC", "overvoltage", NULL);
+ if (reg & AXP209_IRQ1_VBUS_OVERVOLT)
+ devctl_notify("PMU", "USB", "overvoltage", NULL);
+ if (reg & AXP209_IRQ1_VBUS_LOW)
+ devctl_notify("PMU", "USB", "undervoltage", NULL);
+ if (reg & AXP209_IRQ1_AC_CONN)
+ devctl_notify("PMU", "AC", "plugged", NULL);
+ if (reg & AXP209_IRQ1_AC_DISCONN)
+ devctl_notify("PMU", "AC", "unplugged", NULL);
+ if (reg & AXP209_IRQ1_VBUS_CONN)
+ devctl_notify("PMU", "USB", "plugged", NULL);
+ if (reg & AXP209_IRQ1_VBUS_DISCONN)
+ devctl_notify("PMU", "USB", "unplugged", NULL);
+ axp209_write(sc->dev, AXP209_IRQ1_STATUS, AXP209_IRQ_ACK);
+ }
+
+ axp209_read(sc->dev, AXP209_IRQ2_STATUS, &reg, 1);
+ if (reg) {
+ if (reg & AXP209_IRQ2_BATT_CHARGED)
+ devctl_notify("PMU", "Battery", "charged", NULL);
+ if (reg & AXP209_IRQ2_BATT_CHARGING)
+ devctl_notify("PMU", "Battery", "charging", NULL);
+ if (reg & AXP209_IRQ2_BATT_CONN)
+ devctl_notify("PMU", "Battery", "connected", NULL);
+ if (reg & AXP209_IRQ2_BATT_DISCONN)
+ devctl_notify("PMU", "Battery", "disconnected", NULL);
+ if (reg & AXP209_IRQ2_BATT_TEMP_LOW)
+ devctl_notify("PMU", "Battery", "low temp", NULL);
+ if (reg & AXP209_IRQ2_BATT_TEMP_OVER)
+ devctl_notify("PMU", "Battery", "high temp", NULL);
+ axp209_write(sc->dev, AXP209_IRQ2_STATUS, AXP209_IRQ_ACK);
+ }
+
+ axp209_read(sc->dev, AXP209_IRQ3_STATUS, &reg, 1);
+ if (reg) {
+ if (reg & AXP209_IRQ3_PEK_SHORT)
+ shutdown_nice(RB_POWEROFF);
+ axp209_write(sc->dev, AXP209_IRQ3_STATUS, AXP209_IRQ_ACK);
+ }
+
+ axp209_read(sc->dev, AXP209_IRQ4_STATUS, &reg, 1);
+ if (reg) {
+ axp209_write(sc->dev, AXP209_IRQ4_STATUS, AXP209_IRQ_ACK);
+ }
+
+ axp209_read(sc->dev, AXP209_IRQ5_STATUS, &reg, 1);
+ if (reg) {
+ axp209_write(sc->dev, AXP209_IRQ5_STATUS, AXP209_IRQ_ACK);
+ }
+}
+
+static device_t
+axp209_gpio_get_bus(device_t dev)
+{
+ struct axp209_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ return (sc->gpiodev);
+}
+
static int
-axp209_probe(device_t dev)
+axp209_gpio_pin_max(device_t dev, int *maxpin)
{
+ *maxpin = nitems(axp209_pins) - 1;
- if (!ofw_bus_status_okay(dev))
- return (ENXIO);
+ return (0);
+}
- if (!ofw_bus_is_compatible(dev, "x-powers,axp209"))
- return (ENXIO);
+static int
+axp209_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+ if (pin >= nitems(axp209_pins))
+ return (EINVAL);
- device_set_desc(dev, "X-Power AXP209 Power Management Unit");
+ snprintf(name, GPIOMAXNAME, "%s", axp209_pins[pin].name);
- return (BUS_PROBE_DEFAULT);
+ return (0);
}
static int
-axp209_attach(device_t dev)
+axp209_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+ if (pin >= nitems(axp209_pins))
+ return (EINVAL);
+
+ *caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+
+ return (0);
+}
+
+static int
+axp209_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
{
struct axp209_softc *sc;
+ uint8_t data, func;
+ int error;
+
+ if (pin >= nitems(axp209_pins))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+
+ AXP_LOCK(sc);
+ error = axp209_read(dev, axp209_pins[pin].ctrl_reg, &data, 1);
+ if (error == 0) {
+ func = data & AXP209_GPIO_FUNC_MASK;
+ if (func == AXP209_GPIO_FUNC_INPUT)
+ *flags = GPIO_PIN_INPUT;
+ else if (func == AXP209_GPIO_FUNC_DRVLO ||
+ func == AXP209_GPIO_FUNC_DRVHI)
+ *flags = GPIO_PIN_OUTPUT;
+ else
+ *flags = 0;
+ }
+ AXP_UNLOCK(sc);
+
+ return (error);
+}
+
+static int
+axp209_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+ struct axp209_softc *sc;
+ uint8_t data;
+ int error;
+
+ if (pin >= nitems(axp209_pins))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+
+ AXP_LOCK(sc);
+ error = axp209_read(dev, axp209_pins[pin].ctrl_reg, &data, 1);
+ if (error == 0) {
+ data &= ~AXP209_GPIO_FUNC_MASK;
+ if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) != 0) {
+ if ((flags & GPIO_PIN_OUTPUT) == 0)
+ data |= AXP209_GPIO_FUNC_INPUT;
+ }
+ error = axp209_write(dev, axp209_pins[pin].ctrl_reg, data);
+ }
+ AXP_UNLOCK(sc);
+
+ return (error);
+}
+
+static int
+axp209_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
+{
+ struct axp209_softc *sc;
+ uint8_t data, func;
+ int error;
+
+ if (pin >= nitems(axp209_pins))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+
+ AXP_LOCK(sc);
+ error = axp209_read(dev, axp209_pins[pin].ctrl_reg, &data, 1);
+ if (error == 0) {
+ func = data & AXP209_GPIO_FUNC_MASK;
+ switch (func) {
+ case AXP209_GPIO_FUNC_DRVLO:
+ *val = 0;
+ break;
+ case AXP209_GPIO_FUNC_DRVHI:
+ *val = 1;
+ break;
+ case AXP209_GPIO_FUNC_INPUT:
+ error = axp209_read(dev, AXP209_GPIO_STATUS, &data, 1);
+ if (error == 0)
+ *val = (data & AXP209_GPIO_DATA(pin)) ? 1 : 0;
+ break;
+ default:
+ error = EIO;
+ break;
+ }
+ }
+ AXP_UNLOCK(sc);
+
+ return (error);
+}
+
+static int
+axp209_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
+{
+ struct axp209_softc *sc;
+ uint8_t data, func;
+ int error;
+
+ if (pin >= nitems(axp209_pins))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+
+ AXP_LOCK(sc);
+ error = axp209_read(dev, axp209_pins[pin].ctrl_reg, &data, 1);
+ if (error == 0) {
+ func = data & AXP209_GPIO_FUNC_MASK;
+ switch (func) {
+ case AXP209_GPIO_FUNC_DRVLO:
+ case AXP209_GPIO_FUNC_DRVHI:
+ /* GPIO2 can't be set to 1 */
+ if (pin == 2 && val == 1) {
+ error = EINVAL;
+ break;
+ }
+ data &= ~AXP209_GPIO_FUNC_MASK;
+ data |= val;
+ break;
+ default:
+ error = EIO;
+ break;
+ }
+ }
+ if (error == 0)
+ error = axp209_write(dev, axp209_pins[pin].ctrl_reg, data);
+ AXP_UNLOCK(sc);
+
+ return (error);
+}
+
+
+static int
+axp209_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ struct axp209_softc *sc;
+ uint8_t data, func;
+ int error;
+
+ if (pin >= nitems(axp209_pins))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+
+ AXP_LOCK(sc);
+ error = axp209_read(dev, axp209_pins[pin].ctrl_reg, &data, 1);
+ if (error == 0) {
+ func = data & AXP209_GPIO_FUNC_MASK;
+ switch (func) {
+ case AXP209_GPIO_FUNC_DRVLO:
+ /* Pin 2 can't be set to 1*/
+ if (pin == 2) {
+ error = EINVAL;
+ break;
+ }
+ data &= ~AXP209_GPIO_FUNC_MASK;
+ data |= AXP209_GPIO_FUNC_DRVHI;
+ break;
+ case AXP209_GPIO_FUNC_DRVHI:
+ data &= ~AXP209_GPIO_FUNC_MASK;
+ data |= AXP209_GPIO_FUNC_DRVLO;
+ break;
+ default:
+ error = EIO;
+ break;
+ }
+ }
+ if (error == 0)
+ error = axp209_write(dev, axp209_pins[pin].ctrl_reg, data);
+ AXP_UNLOCK(sc);
+
+ return (error);
+}
+
+static int
+axp209_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent,
+ int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
+{
+ if (gpios[0] >= nitems(axp209_pins))
+ return (EINVAL);
+
+ *pin = gpios[0];
+ *flags = gpios[1];
+
+ return (0);
+}
+
+static phandle_t
+axp209_get_node(device_t dev, device_t bus)
+{
+ return (ofw_bus_get_node(dev));
+}
+
+static void
+axp209_start(void *pdev)
+{
+ device_t dev;
+ struct axp209_softc *sc;
const char *pwr_name[] = {"Battery", "AC", "USB", "AC and USB"};
uint8_t data;
uint8_t pwr_src;
- sc = device_get_softc(dev);
+ dev = pdev;
+ sc = device_get_softc(dev);
sc->addr = iicbus_get_addr(dev);
+ sc->dev = dev;
if (bootverbose) {
/*
@@ -195,22 +546,154 @@
pwr_name[pwr_src]);
}
+ /* Only enable interrupts that we are interested in */
+ axp209_write(dev, AXP209_IRQ1_ENABLE,
+ AXP209_IRQ1_AC_OVERVOLT |
+ AXP209_IRQ1_AC_DISCONN |
+ AXP209_IRQ1_AC_CONN |
+ AXP209_IRQ1_VBUS_OVERVOLT |
+ AXP209_IRQ1_VBUS_DISCONN |
+ AXP209_IRQ1_VBUS_CONN);
+ axp209_write(dev, AXP209_IRQ2_ENABLE,
+ AXP209_IRQ2_BATT_CONN |
+ AXP209_IRQ2_BATT_DISCONN |
+ AXP209_IRQ2_BATT_CHARGE_ACCT_ON |
+ AXP209_IRQ2_BATT_CHARGE_ACCT_OFF |
+ AXP209_IRQ2_BATT_CHARGING |
+ AXP209_IRQ2_BATT_CHARGED |
+ AXP209_IRQ2_BATT_TEMP_OVER |
+ AXP209_IRQ2_BATT_TEMP_LOW);
+ axp209_write(dev, AXP209_IRQ3_ENABLE,
+ AXP209_IRQ3_PEK_SHORT | AXP209_IRQ3_PEK_LONG);
+ axp209_write(dev, AXP209_IRQ4_ENABLE, AXP209_IRQ4_APS_LOW_2);
+ axp209_write(dev, AXP209_IRQ5_ENABLE, 0x0);
+
EVENTHANDLER_REGISTER(shutdown_final, axp209_shutdown, dev,
SHUTDOWN_PRI_LAST);
+ /* Enable ADC sensors */
+ if (axp209_write(dev, AXP209_ADC_ENABLE1,
+ AXP209_ADC1_BATVOLT | AXP209_ADC1_BATCURRENT |
+ AXP209_ADC1_ACVOLT | AXP209_ADC1_ACCURRENT |
+ AXP209_ADC1_VBUSVOLT | AXP209_ADC1_VBUSCURRENT) != -1) {
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "acvolt",
+ CTLTYPE_INT | CTLFLAG_RD,
+ dev, AXP209_ACVOLT, axp209_sysctl, "I",
+ "AC Voltage (microVolt)");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "accurrent",
+ CTLTYPE_INT | CTLFLAG_RD,
+ dev, AXP209_ACCURRENT, axp209_sysctl, "I",
+ "AC Current (microAmpere)");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "vbusvolt",
+ CTLTYPE_INT | CTLFLAG_RD,
+ dev, AXP209_VBUSVOLT, axp209_sysctl, "I",
+ "VBUS Voltage (microVolt)");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "vbuscurrent",
+ CTLTYPE_INT | CTLFLAG_RD,
+ dev, AXP209_VBUSCURRENT, axp209_sysctl, "I",
+ "VBUS Current (microAmpere)");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "batvolt",
+ CTLTYPE_INT | CTLFLAG_RD,
+ dev, AXP209_BATVOLT, axp209_sysctl, "I",
+ "Battery Voltage (microVolt)");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "batchargecurrent",
+ CTLTYPE_INT | CTLFLAG_RD,
+ dev, AXP209_BATCHARGECURRENT, axp209_sysctl, "I",
+ "Battery Charging Current (microAmpere)");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "batdischargecurrent",
+ CTLTYPE_INT | CTLFLAG_RD,
+ dev, AXP209_BATDISCHARGECURRENT, axp209_sysctl, "I",
+ "Battery Discharging Current (microAmpere)");
+ } else {
+ device_printf(dev, "Couldn't enable ADC sensors\n");
+ }
+
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "temp",
CTLTYPE_INT | CTLFLAG_RD,
dev, AXP209_TEMP, axp209_sysctl, "IK", "Internal temperature");
+ if ((bus_setup_intr(dev, sc->res[0], INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, axp_intr, sc, &sc->intrcookie)))
+ device_printf(dev, "unable to register interrupt handler\n");
+
+ config_intrhook_disestablish(&sc->intr_hook);
+}
+
+static int
+axp209_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "x-powers,axp209"))
+ return (ENXIO);
+
+ device_set_desc(dev, "X-Powers AXP209 Power Management Unit");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+axp209_attach(device_t dev)
+{
+ struct axp209_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ if (bus_alloc_resources(dev, axp_res_spec, sc->res) != 0) {
+ device_printf(dev, "can't allocate device resources\n");
+ return (ENXIO);
+ }
+
+ sc->intr_hook.ich_func = axp209_start;
+ sc->intr_hook.ich_arg = dev;
+
+ if (config_intrhook_establish(&sc->intr_hook) != 0)
+ return (ENOMEM);
+
+ sc->gpiodev = gpiobus_attach_bus(dev);
+
return (0);
}
static device_method_t axp209_methods[] = {
DEVMETHOD(device_probe, axp209_probe),
DEVMETHOD(device_attach, axp209_attach),
- {0, 0},
+
+ /* GPIO interface */
+ DEVMETHOD(gpio_get_bus, axp209_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, axp209_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getname, axp209_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getcaps, axp209_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_getflags, axp209_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_setflags, axp209_gpio_pin_setflags),
+ DEVMETHOD(gpio_pin_get, axp209_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, axp209_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, axp209_gpio_pin_toggle),
+ DEVMETHOD(gpio_map_gpios, axp209_gpio_map_gpios),
+
+ /* OFW bus interface */
+ DEVMETHOD(ofw_bus_get_node, axp209_get_node),
+
+ DEVMETHOD_END
};
static driver_t axp209_driver = {
@@ -220,7 +703,14 @@
};
static devclass_t axp209_devclass;
+extern devclass_t ofwgpiobus_devclass, gpioc_devclass;
+extern driver_t ofw_gpiobus_driver, gpioc_driver;
-DRIVER_MODULE(axp209, iicbus, axp209_driver, axp209_devclass, 0, 0);
+EARLY_DRIVER_MODULE(axp209, iicbus, axp209_driver, axp209_devclass,
+ 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
+EARLY_DRIVER_MODULE(ofw_gpiobus, axp209_pmu, ofw_gpiobus_driver,
+ ofwgpiobus_devclass, 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
+EARLY_DRIVER_MODULE(gpioc, axp209_pmu, gpioc_driver, gpioc_devclass,
+ 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
MODULE_VERSION(axp209, 1);
MODULE_DEPEND(axp209, iicbus, 1, 1, 1);
Index: head/sys/arm/allwinner/axp209reg.h
===================================================================
--- head/sys/arm/allwinner/axp209reg.h
+++ head/sys/arm/allwinner/axp209reg.h
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu@freeebsd.org>
+ * 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 ``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 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$
+ */
+
+#ifndef _AXP209REG_H_
+#define _AXP209REG_H_
+
+/* Power State Register */
+#define AXP209_PSR 0x00
+#define AXP209_PSR_ACIN 0x80
+#define AXP209_PSR_ACIN_SHIFT 7
+#define AXP209_PSR_VBUS 0x20
+#define AXP209_PSR_VBUS_SHIFT 5
+
+/* Shutdown and battery control */
+#define AXP209_SHUTBAT 0x32
+#define AXP209_SHUTBAT_SHUTDOWN 0x80
+
+/* Voltage/Current Monitor */
+#define AXP209_ACIN_VOLTAGE 0x56
+#define AXP209_ACIN_CURRENT 0x58
+#define AXP209_VBUS_VOLTAGE 0x5A
+#define AXP209_VBUS_CURRENT 0x5C
+#define AXP209_BAT_VOLTAGE 0x78
+#define AXP209_BAT_CHARGE_CURRENT 0x7A
+#define AXP209_BAT_DISCHARGE_CURRENT 0x7C
+
+#define AXP209_VOLT_STEP 1700
+#define AXP209_BATVOLT_STEP 1100
+#define AXP209_ACCURRENT_STEP 625
+#define AXP209_VBUSCURRENT_STEP 375
+#define AXP209_BATCURRENT_STEP 500
+
+/* Temperature monitor */
+#define AXP209_TEMPMON 0x5e
+#define AXP209_TEMPMON_MIN 1447 /* -144.7C */
+
+/* Sensors conversion macros */
+#define AXP209_SENSOR_H(a) ((a) << 4)
+#define AXP209_SENSOR_L(a) ((a) & 0xf)
+#define AXP209_SENSOR_BAT_H(a) ((a) << 5)
+#define AXP209_SENSOR_BAT_L(a) ((a) & 0x1f)
+
+#define AXP209_0C_TO_K 2732
+
+/* ADC Sensors */
+#define AXP209_ADC_ENABLE1 0x82
+#define AXP209_ADC_ENABLE2 0x83
+
+#define AXP209_ADC1_BATVOLT (1 << 7)
+#define AXP209_ADC1_BATCURRENT (1 << 6)
+#define AXP209_ADC1_ACVOLT (1 << 5)
+#define AXP209_ADC1_ACCURRENT (1 << 4)
+#define AXP209_ADC1_VBUSVOLT (1 << 3)
+#define AXP209_ADC1_VBUSCURRENT (1 << 2)
+
+/* Interrupt related registers */
+#define AXP209_IRQ1_ENABLE 0x40
+#define AXP209_IRQ1_STATUS 0x48
+#define AXP209_IRQ1_AC_OVERVOLT (1 << 7)
+#define AXP209_IRQ1_AC_CONN (1 << 6)
+#define AXP209_IRQ1_AC_DISCONN (1 << 5)
+#define AXP209_IRQ1_VBUS_OVERVOLT (1 << 4)
+#define AXP209_IRQ1_VBUS_CONN (1 << 3)
+#define AXP209_IRQ1_VBUS_DISCONN (1 << 2)
+#define AXP209_IRQ1_VBUS_LOW (1 << 1)
+
+#define AXP209_IRQ2_ENABLE 0x41
+#define AXP209_IRQ2_STATUS 0x49
+#define AXP209_IRQ2_BATT_CONN (1 << 7)
+#define AXP209_IRQ2_BATT_DISCONN (1 << 6)
+#define AXP209_IRQ2_BATT_CHARGE_ACCT_ON (1 << 5)
+#define AXP209_IRQ2_BATT_CHARGE_ACCT_OFF (1 << 4)
+#define AXP209_IRQ2_BATT_CHARGING (1 << 3)
+#define AXP209_IRQ2_BATT_CHARGED (1 << 2)
+#define AXP209_IRQ2_BATT_TEMP_OVER (1 << 1)
+#define AXP209_IRQ2_BATT_TEMP_LOW (1 << 0)
+
+#define AXP209_IRQ3_ENABLE 0x42
+#define AXP209_IRQ3_STATUS 0x4A
+#define AXP209_IRQ3_TEMP_OVER (1 << 7)
+#define AXP209_IRQ3_CHARGE_CURRENT_LOW (1 << 6)
+#define AXP209_IRQ3_DCDC2_LOW (1 << 4)
+#define AXP209_IRQ3_DCDC3_LOW (1 << 3)
+#define AXP209_IRQ3_LDO3_LOW (1 << 2)
+#define AXP209_IRQ3_PEK_SHORT (1 << 1)
+#define AXP209_IRQ3_PEK_LONG (1 << 0)
+
+#define AXP209_IRQ4_ENABLE 0x43
+#define AXP209_IRQ4_STATUS 0x4B
+#define AXP209_IRQ4_NOE_START (1 << 7)
+#define AXP209_IRQ4_NOE_SHUT (1 << 6)
+#define AXP209_IRQ4_VBUS_VALID (1 << 5)
+#define AXP209_IRQ4_VBUS_INVALID (1 << 4)
+#define AXP209_IRQ4_VBUS_SESSION (1 << 3)
+#define AXP209_IRQ4_VBUS_SESSION_END (1 << 2)
+#define AXP209_IRQ4_APS_LOW_1 (1 << 1)
+#define AXP209_IRQ4_APS_LOW_2 (1 << 0)
+
+#define AXP209_IRQ5_ENABLE 0x44
+#define AXP209_IRQ5_STATUS 0x4C
+#define AXP209_IRQ5_TIMER_EXPIRE (1 << 7)
+#define AXP209_IRQ5_PEK_RISE_EDGE (1 << 6)
+#define AXP209_IRQ5_PEK_FALL_EDGE (1 << 5)
+#define AXP209_IRQ5_GPIO3 (1 << 3)
+#define AXP209_IRQ5_GPIO2 (1 << 2)
+#define AXP209_IRQ5_GPIO1 (1 << 1)
+#define AXP209_IRQ5_GPIO0 (1 << 0)
+
+#define AXP209_IRQ_ACK 0xff
+
+/* GPIOs registers */
+#define AXP209_GPIO_FUNC_MASK 0x7
+
+#define AXP209_GPIO_FUNC_DRVLO 0x0
+#define AXP209_GPIO_FUNC_DRVHI 0x1
+#define AXP209_GPIO_FUNC_INPUT 0x2
+
+#define AXP209_GPIO0_CTRL 0x90
+#define AXP209_GPIO1_CTRL 0x92
+#define AXP209_GPIO2_CTRL 0x93
+#define AXP209_GPIO_STATUS 0x94
+
+#define AXP209_GPIO_DATA(x) (1 << (x + 4))
+
+enum axp209_sensor {
+ AXP209_TEMP,
+ AXP209_ACVOLT,
+ AXP209_ACCURRENT,
+ AXP209_VBUSVOLT,
+ AXP209_VBUSCURRENT,
+ AXP209_BATVOLT,
+ AXP209_BATCHARGECURRENT,
+ AXP209_BATDISCHARGECURRENT,
+};
+
+#endif /* _AXP209REG_H_ */
Index: head/sys/boot/fdt/dts/arm/bananapi.dts
===================================================================
--- head/sys/boot/fdt/dts/arm/bananapi.dts
+++ head/sys/boot/fdt/dts/arm/bananapi.dts
@@ -28,6 +28,7 @@
#include "sun7i-a20-bananapi.dts"
#include "sun7i-a20-hdmi.dtsi"
+#include "xpowers-axp209.dtsi"
/ {
soc@01c00000 {
Index: head/sys/boot/fdt/dts/arm/cubieboard.dts
===================================================================
--- head/sys/boot/fdt/dts/arm/cubieboard.dts
+++ head/sys/boot/fdt/dts/arm/cubieboard.dts
@@ -27,3 +27,4 @@
*/
#include "sun4i-a10-cubieboard.dts"
+#include "xpowers-axp209.dtsi"
Index: head/sys/boot/fdt/dts/arm/cubieboard2.dts
===================================================================
--- head/sys/boot/fdt/dts/arm/cubieboard2.dts
+++ head/sys/boot/fdt/dts/arm/cubieboard2.dts
@@ -29,6 +29,7 @@
#include "sun7i-a20-cubieboard2.dts"
#include "sun7i-a20-hdmi.dtsi"
+#include "xpowers-axp209.dtsi"
/ {
soc@01c00000 {
Index: head/sys/boot/fdt/dts/arm/olimex-a20-som-evb.dts
===================================================================
--- head/sys/boot/fdt/dts/arm/olimex-a20-som-evb.dts
+++ head/sys/boot/fdt/dts/arm/olimex-a20-som-evb.dts
@@ -28,6 +28,7 @@
#include "sun7i-a20-olimex-som-evb.dts"
#include "sun7i-a20-hdmi.dtsi"
+#include "xpowers-axp209.dtsi"
/ {
soc@01c00000 {
Index: head/sys/boot/fdt/dts/arm/olinuxino-lime.dts
===================================================================
--- head/sys/boot/fdt/dts/arm/olinuxino-lime.dts
+++ head/sys/boot/fdt/dts/arm/olinuxino-lime.dts
@@ -27,3 +27,4 @@
*/
#include "sun4i-a10-olinuxino-lime.dts"
+#include "xpowers-axp209.dtsi"
Index: head/sys/boot/fdt/dts/arm/xpowers-axp209.dtsi
===================================================================
--- head/sys/boot/fdt/dts/arm/xpowers-axp209.dtsi
+++ head/sys/boot/fdt/dts/arm/xpowers-axp209.dtsi
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2016 Emmanuel Vadot <manu@freebsd.org>
+ * 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$
+ */
+
+
+&axp209 {
+ gpio-controller;
+ #gpio-cells = <1>;
+};
Index: head/sys/dev/iicbus/twsi/a10_twsi.c
===================================================================
--- head/sys/dev/iicbus/twsi/a10_twsi.c
+++ head/sys/dev/iicbus/twsi/a10_twsi.c
@@ -153,6 +153,8 @@
static devclass_t a10_twsi_devclass;
-DRIVER_MODULE(a10_twsi, simplebus, a10_twsi_driver, a10_twsi_devclass, 0, 0);
-DRIVER_MODULE(iicbus, a10_twsi, iicbus_driver, iicbus_devclass, 0, 0);
+EARLY_DRIVER_MODULE(a10_twsi, simplebus, a10_twsi_driver, a10_twsi_devclass,
+ 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+EARLY_DRIVER_MODULE(iicbus, a10_twsi, iicbus_driver, iicbus_devclass,
+ 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
MODULE_DEPEND(a10_twsi, iicbus, 1, 1, 1);

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 15, 3:28 AM (19 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27630168
Default Alt Text
D6135.diff (27 KB)

Event Timeline