From 560e4370f9d00915475f0566939dfa7a8c453ab4 Mon Sep 17 00:00:00 2001 From: patrick Date: Mon, 13 Aug 2018 15:14:27 +0000 Subject: [PATCH] Support GPIO-based voltage regulators. ok kettenis@ --- sys/dev/ofw/ofw_regulator.c | 120 +++++++++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 2 deletions(-) diff --git a/sys/dev/ofw/ofw_regulator.c b/sys/dev/ofw/ofw_regulator.c index 4c2c7152721..cd916e88139 100644 --- a/sys/dev/ofw/ofw_regulator.c +++ b/sys/dev/ofw/ofw_regulator.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofw_regulator.c,v 1.5 2018/08/02 09:45:17 kettenis Exp $ */ +/* $OpenBSD: ofw_regulator.c,v 1.6 2018/08/13 15:14:27 patrick Exp $ */ /* * Copyright (c) 2016 Mark Kettenis * @@ -27,6 +27,9 @@ LIST_HEAD(, regulator_device) regulator_devices = LIST_HEAD_INITIALIZER(regulator_devices); +uint32_t regulator_gpio_get_voltage(int); +int regulator_gpio_set_voltage(int, uint32_t); + void regulator_register(struct regulator_device *rd) { @@ -149,6 +152,9 @@ regulator_get_voltage(uint32_t phandle) if (OF_is_compatible(node, "regulator-fixed")) return OF_getpropint(node, "regulator-min-voltage", 0); + if (OF_is_compatible(node, "regulator-gpio")) + return regulator_gpio_get_voltage(node); + return 0; } @@ -157,7 +163,7 @@ regulator_set_voltage(uint32_t phandle, uint32_t voltage) { struct regulator_device *rd; uint32_t old, delta; - int error; + int error, node; LIST_FOREACH(rd, ®ulator_devices, rd_list) { if (rd->rd_phandle == phandle) @@ -178,5 +184,115 @@ regulator_set_voltage(uint32_t phandle, uint32_t voltage) return error; } + node = OF_getnodebyphandle(phandle); + if (node == 0) + return ENODEV; + + if (OF_is_compatible(node, "regulator-gpio")) + return regulator_gpio_set_voltage(node, voltage); + return ENODEV; } + +uint32_t +regulator_gpio_get_voltage(int node) +{ + uint32_t *gpio, *gpios, *states; + uint32_t idx, voltage; + size_t glen, slen; + int i; + + pinctrl_byname(node, "default"); + + if ((glen = OF_getproplen(node, "gpios")) <= 0) + return EINVAL; + if ((slen = OF_getproplen(node, "states")) <= 0) + return EINVAL; + + if (slen % (2 * sizeof(uint32_t)) != 0) + return EINVAL; + + gpios = malloc(glen, M_TEMP, M_WAITOK); + states = malloc(slen, M_TEMP, M_WAITOK); + + OF_getpropintarray(node, "gpios", gpios, glen); + OF_getpropintarray(node, "states", states, slen); + + idx = 0; + gpio = gpios; + while (gpio && gpio < gpios + (glen / sizeof(uint32_t))) { + idx |= (1 << i); + gpio = gpio_controller_next_pin(gpio); + i++; + } + + voltage = 0; + for (i = 0; i < slen / (2 * sizeof(uint32_t)); i++) { + if (states[2 * i + 1] == idx) { + voltage = states[2 * i]; + break; + } + } + if (i >= slen / (2 * sizeof(uint32_t))) + return 0; + + free(gpios, M_TEMP, glen); + free(states, M_TEMP, slen); + + return voltage; +} + +int +regulator_gpio_set_voltage(int node, uint32_t voltage) +{ + uint32_t *gpio, *gpios, *states; + size_t glen, slen; + uint32_t min, max; + uint32_t idx; + int i; + + pinctrl_byname(node, "default"); + + /* Check limits. */ + min = OF_getpropint(node, "regulator-min-microvolt", 0); + max = OF_getpropint(node, "regulator-max-microvolt", 0); + if (voltage < min || voltage > max) + return EINVAL; + + if ((glen = OF_getproplen(node, "gpios")) <= 0) + return EINVAL; + if ((slen = OF_getproplen(node, "states")) <= 0) + return EINVAL; + + if (slen % (2 * sizeof(uint32_t)) != 0) + return EINVAL; + + gpios = malloc(glen, M_TEMP, M_WAITOK); + states = malloc(slen, M_TEMP, M_WAITOK); + + OF_getpropintarray(node, "gpios", gpios, glen); + OF_getpropintarray(node, "states", states, slen); + + idx = 0; + for (i = 0; i < slen / (2 * sizeof(uint32_t)); i++) { + if (states[2 * i] < min || states[2 * i] > max) + continue; + if (states[2 * i] == voltage) + idx = states[2 * i + 1]; + } + if (i >= slen / (2 * sizeof(uint32_t))) + return EINVAL; + + i = 0; + gpio = gpios; + while (gpio && gpio < gpios + (glen / sizeof(uint32_t))) { + gpio_controller_set_pin(gpio, !!(idx & (1 << i))); + gpio = gpio_controller_next_pin(gpio); + i++; + } + + free(gpios, M_TEMP, glen); + free(states, M_TEMP, slen); + + return 0; +} -- 2.20.1