Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148824256
D30787.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D30787.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D30787: rk805: add support for controlling two output pins via gpio interface
Attached
Detach File
Event Timeline
Log In to Comment