Page MenuHomeFreeBSD

D30787.diff
No OneTemporary

D30787.diff

Index: sys/arm64/rockchip/rk805.c
===================================================================
--- sys/arm64/rockchip/rk805.c
+++ sys/arm64/rockchip/rk805.c
@@ -32,13 +32,17 @@
#include <sys/bus.h>
#include <sys/clock.h>
#include <sys/eventhandler.h>
+#include <sys/gpio.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/reboot.h>
#include <sys/mutex.h>
#include <sys/rman.h>
+#include <sys/sx.h>
#include <machine/bus.h>
+#include <dev/gpio/gpiobusvar.h>
+
#include <dev/iicbus/iiconf.h>
#include <dev/iicbus/iicbus.h>
@@ -48,6 +52,8 @@
#include <dev/extres/clk/clk.h>
#include <dev/extres/regulator/regulator.h>
+#include <dev/fdt/fdt_pinctrl.h>
+
#include <arm64/rockchip/rk805reg.h>
#include "clock_if.h"
@@ -697,6 +703,317 @@
return (0);
}
+/* -------------------------------------------------------------------------- */
+/* GPIO, pinctrl and OFW bus. */
+
+#define RK805_NPINS 2
+
+static struct rk805_pinconf {
+ int npins;
+ const char *names[RK805_NPINS];
+} rk805_pinconf = {
+ RK805_NPINS,
+ {
+ "gpio0",
+ "gpio1",
+ }
+};
+
+struct rk805_gpio_softc {
+ struct sx lock;
+ device_t dev;
+ device_t base_dev;
+ device_t bus_dev;
+ struct rk805_pinconf *pinconf;
+};
+
+static device_t
+rk805_gpio_get_bus(device_t dev)
+{
+ struct rk805_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (sc->bus_dev);
+}
+
+static int
+rk805_gpio_pin_max(device_t dev, int *maxpin)
+{
+ struct rk805_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ *maxpin = sc->pinconf->npins - 1;
+ return (0);
+}
+
+static int
+rk805_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+ struct rk805_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->pinconf->npins)
+ return (EINVAL);
+
+ *caps = GPIO_PIN_OUTPUT;
+ return (0);
+}
+
+static int
+rk805_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+ struct rk805_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->pinconf->npins)
+ return (EINVAL);
+
+ *flags = GPIO_PIN_OUTPUT;
+ return (0);
+}
+
+static int
+rk805_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+ struct rk805_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->pinconf->npins)
+ return (EINVAL);
+
+ snprintf(name, GPIOMAXNAME, "%s", sc->pinconf->names[pin]);
+ return (0);
+}
+
+static int
+rk805_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+ struct rk805_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin > sc->pinconf->npins)
+ return (EINVAL);
+
+ if ((flags & ~GPIO_PIN_OUTPUT) != 0)
+ return (EINVAL);
+ return (0);
+}
+
+static int
+rk805_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
+{
+ struct rk805_gpio_softc *sc;
+ uint8_t val;
+ int ret;
+
+ sc = device_get_softc(dev);
+ if (pin > sc->pinconf->npins)
+ return (EINVAL);
+
+ sx_xlock(&sc->lock);
+ ret = rk805_read(sc->base_dev, RK805_OUT, &val, 1);
+ if (ret == 0) {
+ if (value)
+ val |= (1 << pin);
+ else
+ val &= ~(1 << pin);
+ ret = rk805_write(sc->base_dev, RK805_OUT, &val, 1);
+ }
+ sx_unlock(&sc->lock);
+ return (ret);
+}
+
+static int
+rk805_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
+{
+ struct rk805_gpio_softc *sc;
+ uint8_t val;
+ int ret;
+
+ sc = device_get_softc(dev);
+ if (pin > sc->pinconf->npins)
+ return (EINVAL);
+
+ sx_xlock(&sc->lock);
+ ret = rk805_read(sc->base_dev, RK805_OUT, &val, 1);
+ sx_unlock(&sc->lock);
+ if (ret == 0)
+ *value = (val & (1 << pin)) != 0;
+ return (ret);
+}
+
+static int
+rk805_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ struct rk805_gpio_softc *sc;
+ uint8_t val;
+ int ret;
+
+ sc = device_get_softc(dev);
+ if (pin > sc->pinconf->npins)
+ return (EINVAL);
+
+ sx_xlock(&sc->lock);
+ ret = rk805_read(sc->base_dev, RK805_OUT, &val, 1);
+ if (ret == 0) {
+ val ^= (1 << pin);
+ ret = rk805_write(sc->base_dev, RK805_OUT, &val, 1);
+ }
+ sx_unlock(&sc->lock);
+ return (ret);
+}
+
+static int
+rk805_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells,
+ pcell_t *gpios, uint32_t *pin, uint32_t *flags)
+{
+ if (gcells != 2)
+ return (EINVAL);
+
+ *pin = gpios[0];
+ *flags = gpios[1];
+ return (0);
+}
+
+static int
+rk805_find_pinnum_by_name(struct rk805_gpio_softc *sc, const char *pinname)
+{
+ int i;
+
+ for (i = 0; i < sc->pinconf->npins; i++) {
+ if (strcmp(pinname, sc->pinconf->names[i]) == 0)
+ return (i);
+ }
+ return (-1);
+}
+
+static int
+rk805_fdt_configure_pins(device_t dev, phandle_t cfgxref)
+{
+ struct rk805_gpio_softc *sc;
+ phandle_t node;
+ const char **pinlist = NULL;
+ char *pin_function = NULL;
+ int pins_nb, pin_num, i, ret;
+
+ sc = device_get_softc(dev);
+ node = OF_node_from_xref(cfgxref);
+ ret = 0;
+
+ /*
+ * Only one function, "gpio", is supported.
+ * So, just validate the configuration.
+ */
+ pins_nb = ofw_bus_string_list_to_array(node, "pins", &pinlist);
+ if (pins_nb <= 0)
+ return (ENOENT);
+ for (i = 0; i < pins_nb; i++) {
+ pin_num = rk805_find_pinnum_by_name(sc, pinlist[i]);
+ if (pin_num == -1) {
+ ret = ENOENT;
+ goto out;
+ }
+ }
+
+ if (OF_getprop_alloc(node, "function", (void **)&pin_function) != -1) {
+ ret = ENOENT;
+ goto out;
+ }
+ if (strcmp(pin_function, "gpio") != 0) {
+ ret = ENOENT;
+ goto out;
+ }
+
+ out:
+ OF_prop_free(pinlist);
+ OF_prop_free(pin_function);
+ return (ret);
+}
+
+static phandle_t
+rk805_gpio_get_node(device_t bus, device_t dev)
+{
+ /* Forward up to get the rk805's node. */
+ return (ofw_bus_get_node(bus));
+}
+
+static int
+rk805_gpio_probe(device_t dev)
+{
+ device_set_desc(dev, "RK805 general digital output");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rk805_gpio_attach(device_t dev)
+{
+ struct rk805_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->base_dev = device_get_parent(dev);
+ sx_init(&sc->lock, "rk805 gpio");
+ sc->pinconf = &rk805_pinconf;
+ sc->bus_dev = gpiobus_attach_bus(dev);
+ if (sc->bus_dev != NULL) {
+ /* Register as a pinctrl device */
+ fdt_pinctrl_register(dev, "pins");
+ fdt_pinctrl_configure_tree(dev);
+ return (0);
+ } else {
+ device_printf(dev, "Failed to enable GPIO function\n");
+ return (ENXIO);
+ }
+}
+
+static int
+rk805_gpio_detach(device_t dev)
+{
+ struct rk805_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (gpiobus_detach_bus(sc->bus_dev));
+}
+
+static device_method_t rk805_gpio_methods[] = {
+ DEVMETHOD(device_probe, rk805_gpio_probe),
+ DEVMETHOD(device_attach, rk805_gpio_attach),
+ DEVMETHOD(device_detach, rk805_gpio_detach),
+
+ /* GPIO interface */
+ DEVMETHOD(gpio_get_bus, rk805_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, rk805_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getname, rk805_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getflags, rk805_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_getcaps, rk805_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_setflags, rk805_gpio_pin_setflags),
+ DEVMETHOD(gpio_pin_get, rk805_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, rk805_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, rk805_gpio_pin_toggle),
+ DEVMETHOD(gpio_map_gpios, rk805_gpio_map_gpios),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, rk805_gpio_get_node),
+
+ /* fdt_pinctrl interface */
+ DEVMETHOD(fdt_pinctrl_configure,rk805_fdt_configure_pins),
+
+ DEVMETHOD_END
+};
+
+static driver_t rk805_gpio_driver = {
+ "gpio",
+ rk805_gpio_methods,
+ sizeof(struct rk805_gpio_softc),
+};
+
+static devclass_t rk805_gpio_devclass;
+
+DRIVER_MODULE(rk805_gpio, rk805_pmu, rk805_gpio_driver, rk805_gpio_devclass,
+ NULL, NULL);
+MODULE_DEPEND(rk805_gpio, rk805, 1, 1, 1);
+MODULE_VERSION(rk805_gpio, 1);
+
/* -------------------------------------------------------------------------- */
static int
@@ -944,6 +1261,17 @@
SHUTDOWN_PRI_LAST - 2);
}
+ if (sc->type == RK805 &&
+ OF_hasprop(ofw_bus_get_node(dev), "gpio-controller")) {
+ device_t gpio_dev;
+
+ gpio_dev = device_add_child(dev, "gpio", -1);
+ if (gpio_dev != NULL)
+ (void)bus_generic_attach(dev);
+ else
+ device_printf(dev, "failed to add gpio child\n");
+ }
+
return (0);
}
@@ -974,11 +1302,21 @@
return (ERANGE);
}
+static phandle_t
+rk805_get_node(device_t bus, device_t dev)
+{
+ /* Associate the child gpio device with our node. */
+ return (ofw_bus_get_node(bus));
+}
+
static device_method_t rk805_methods[] = {
DEVMETHOD(device_probe, rk805_probe),
DEVMETHOD(device_attach, rk805_attach),
DEVMETHOD(device_detach, rk805_detach),
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, rk805_get_node),
+
/* regdev interface */
DEVMETHOD(regdev_map, rk805_map),
Index: sys/arm64/rockchip/rk805reg.h
===================================================================
--- sys/arm64/rockchip/rk805reg.h
+++ sys/arm64/rockchip/rk805reg.h
@@ -97,6 +97,10 @@
#define RK805_DEV_CTRL_OFF (1 << 0)
#define RK805_DEV_CTRL_SLP (1 << 1)
+#define RK805_OUT 0x52
+#define RK805_OUT_1 (1 << 0)
+#define RK805_OUT_2 (1 << 1)
+
enum rk805_regulator {
RK805_DCDC1 = 0,
RK805_DCDC2,

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 21, 10:02 AM (9 h, 28 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30074523
Default Alt Text
D30787.diff (8 KB)

Event Timeline