Hello Jan, can you please try this patch:
https://lists.rtems.org/pipermail/devel/2020-April/059419.html I've still seen quite some linker errors in if_em.c. But as far as I can tell they doesn't seem to be related. Are they? Best regards Christian On 17/04/2020 08:17, Christian Mauderer wrote: > Hello Jan, > > On 16/04/2020 22:27, jan.som...@dlr.de wrote: >> I have a question: >> I just rebased my working tree for the i386 target to the current >> 5-freebsd-12 branch. >> The compilation now fails in regulator related files. >> It seems that I am missing the FDT define and that comments out some >> includes. >> Could you tell me what FDT means in this context and do you know where I can >> activate it? > > FDT is a flattened device tree. That's something that isn't used on > i386. So most likely quite some more BSPs will have that problem. > > It's some code that I took over quite unchanged from FreeBSD. I would > have expected that it is used in FreeBSD for a lot of different cases > and therefore didn't expect a problem like that. I'll have a look at it. > > Best regards > > Christian > >> >> Cheers, >> >> Jan >> >>> -----Ursprüngliche Nachricht----- >>> Von: devel [mailto:devel-boun...@rtems.org] Im Auftrag von Christian >>> Mauderer >>> Gesendet: Dienstag, 14. April 2020 16:51 >>> An: devel@rtems.org >>> Betreff: [PATCH rtems-libbsd v2 06/14] regulator: Import from FreeBSD. >>> >>> Update #3869. >>> --- >>> freebsd/sys/dev/extres/regulator/regulator.c | 1321 >>> ++++++++++++++++++++ >>> freebsd/sys/dev/extres/regulator/regulator.h | 156 +++ >>> freebsd/sys/dev/extres/regulator/regulator_bus.c | 89 ++ >>> freebsd/sys/dev/extres/regulator/regulator_fixed.c | 502 ++++++++ >>> freebsd/sys/dev/extres/regulator/regulator_fixed.h | 44 + >>> freebsd/sys/dev/gpio/gpioregulator.c | 350 ++++++ >>> 6 files changed, 2462 insertions(+) >>> create mode 100644 freebsd/sys/dev/extres/regulator/regulator.c >>> create mode 100644 freebsd/sys/dev/extres/regulator/regulator.h >>> create mode 100644 freebsd/sys/dev/extres/regulator/regulator_bus.c >>> create mode 100644 freebsd/sys/dev/extres/regulator/regulator_fixed.c >>> create mode 100644 freebsd/sys/dev/extres/regulator/regulator_fixed.h >>> create mode 100644 freebsd/sys/dev/gpio/gpioregulator.c >>> >>> diff --git a/freebsd/sys/dev/extres/regulator/regulator.c >>> b/freebsd/sys/dev/extres/regulator/regulator.c >>> new file mode 100644 >>> index 00000000..4ad6e94a >>> --- /dev/null >>> +++ b/freebsd/sys/dev/extres/regulator/regulator.c >>> @@ -0,0 +1,1321 @@ >>> +#include <machine/rtems-bsd-kernel-space.h> >>> + >>> +/*- >>> + * Copyright 2016 Michal Meloun <m...@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. >>> + */ >>> + >>> +#include <sys/cdefs.h> >>> +__FBSDID("$FreeBSD$"); >>> + >>> +#include <rtems/bsd/local/opt_platform.h> >>> +#include <sys/param.h> >>> +#include <sys/conf.h> >>> +#include <sys/bus.h> >>> +#include <sys/kernel.h> >>> +#include <sys/queue.h> >>> +#include <sys/kobj.h> >>> +#include <sys/malloc.h> >>> +#include <sys/mutex.h> >>> +#include <sys/limits.h> >>> +#include <sys/lock.h> >>> +#include <sys/sysctl.h> >>> +#include <sys/systm.h> >>> +#include <sys/sx.h> >>> + >>> +#ifdef FDT >>> +#include <dev/fdt/fdt_common.h> >>> +#include <dev/ofw/ofw_bus.h> >>> +#include <dev/ofw/ofw_bus_subr.h> >>> +#endif >>> +#include <dev/extres/regulator/regulator.h> >>> + >>> +#include <rtems/bsd/local/regdev_if.h> >>> + >>> +SYSCTL_NODE(_hw, OID_AUTO, regulator, CTLFLAG_RD, NULL, >>> "Regulators"); >>> + >>> +MALLOC_DEFINE(M_REGULATOR, "regulator", "Regulator framework"); >>> + >>> +#define DIV_ROUND_UP(n,d) howmany(n, d) >>> + >>> +/* Forward declarations. */ >>> +struct regulator; >>> +struct regnode; >>> + >>> +typedef TAILQ_HEAD(regnode_list, regnode) regnode_list_t; >>> +typedef TAILQ_HEAD(regulator_list, regulator) regulator_list_t; >>> + >>> +/* Default regulator methods. */ >>> +static int regnode_method_init(struct regnode *regnode); >>> +static int regnode_method_enable(struct regnode *regnode, bool enable, >>> + int *udelay); >>> +static int regnode_method_status(struct regnode *regnode, int *status); >>> +static int regnode_method_set_voltage(struct regnode *regnode, int >>> min_uvolt, >>> + int max_uvolt, int *udelay); >>> +static int regnode_method_get_voltage(struct regnode *regnode, int >>> *uvolt); >>> +static void regulator_constraint(void *dummy); >>> +static void regulator_shutdown(void *dummy); >>> + >>> +/* >>> + * Regulator controller methods. >>> + */ >>> +static regnode_method_t regnode_methods[] = { >>> + REGNODEMETHOD(regnode_init, >>> regnode_method_init), >>> + REGNODEMETHOD(regnode_enable, >>> regnode_method_enable), >>> + REGNODEMETHOD(regnode_status, >>> regnode_method_status), >>> + REGNODEMETHOD(regnode_set_voltage, >>> regnode_method_set_voltage), >>> + REGNODEMETHOD(regnode_get_voltage, >>> regnode_method_get_voltage), >>> + REGNODEMETHOD(regnode_check_voltage, >>> regnode_method_check_voltage), >>> + >>> + REGNODEMETHOD_END >>> +}; >>> +DEFINE_CLASS_0(regnode, regnode_class, regnode_methods, 0); >>> + >>> +/* >>> + * Regulator node - basic element for modelling SOC and bard power supply >>> + * chains. Its contains producer data. >>> + */ >>> +struct regnode { >>> + KOBJ_FIELDS; >>> + >>> + TAILQ_ENTRY(regnode) reglist_link; /* Global list entry */ >>> + regulator_list_t consumers_list; /* Consumers list */ >>> + >>> + /* Cache for already resolved names */ >>> + struct regnode *parent; /* Resolved parent */ >>> + >>> + /* Details of this device. */ >>> + const char *name; /* Globally unique >>> name */ >>> + const char *parent_name; /* Parent name */ >>> + >>> + device_t pdev; /* Producer device_t */ >>> + void *softc; /* Producer softc */ >>> + intptr_t id; /* Per producer unique id */ >>> +#ifdef FDT >>> + phandle_t ofw_node; /* OFW node of regulator */ >>> +#endif >>> + int flags; /* REGULATOR_FLAGS_ */ >>> + struct sx lock; /* Lock for this regulator */ >>> + int ref_cnt; /* Reference counter */ >>> + int enable_cnt; /* Enabled counter */ >>> + >>> + struct regnode_std_param std_param; /* Standard >>> parameters */ >>> + >>> + struct sysctl_ctx_list sysctl_ctx; >>> +}; >>> + >>> +/* >>> + * Per consumer data, information about how a consumer is using a >>> regulator >>> + * node. >>> + * A pointer to this structure is used as a handle in the consumer >>> interface. >>> + */ >>> +struct regulator { >>> + device_t cdev; /* Consumer device */ >>> + struct regnode *regnode; >>> + TAILQ_ENTRY(regulator) link; /* Consumers list >>> entry */ >>> + >>> + int enable_cnt; >>> + int min_uvolt; /* Requested uvolt range */ >>> + int max_uvolt; >>> +}; >>> + >>> +/* >>> + * Regulator names must be system wide unique. >>> + */ >>> +static regnode_list_t regnode_list = >>> TAILQ_HEAD_INITIALIZER(regnode_list); >>> + >>> +static struct sx regnode_topo_lock; >>> +SX_SYSINIT(regulator_topology, ®node_topo_lock, "Regulator topology >>> lock"); >>> + >>> +#define REG_TOPO_SLOCK() sx_slock(®node_topo_lock) >>> +#define REG_TOPO_XLOCK() sx_xlock(®node_topo_lock) >>> +#define REG_TOPO_UNLOCK() sx_unlock(®node_topo_lock) >>> +#define REG_TOPO_ASSERT() sx_assert(®node_topo_lock, >>> SA_LOCKED) >>> +#define REG_TOPO_XASSERT() sx_assert(®node_topo_lock, >>> SA_XLOCKED) >>> + >>> +#define REGNODE_SLOCK(_sc) sx_slock(&((_sc)->lock)) >>> +#define REGNODE_XLOCK(_sc) sx_xlock(&((_sc)->lock)) >>> +#define REGNODE_UNLOCK(_sc) sx_unlock(&((_sc)->lock)) >>> + >>> +SYSINIT(regulator_constraint, SI_SUB_LAST, SI_ORDER_ANY, >>> regulator_constraint, >>> + NULL); >>> +SYSINIT(regulator_shutdown, SI_SUB_LAST, SI_ORDER_ANY, >>> regulator_shutdown, >>> + NULL); >>> + >>> +static void >>> +regulator_constraint(void *dummy) >>> +{ >>> + struct regnode *entry; >>> + int rv; >>> + >>> + REG_TOPO_SLOCK(); >>> + TAILQ_FOREACH(entry, ®node_list, reglist_link) { >>> + rv = regnode_set_constraint(entry); >>> + if (rv != 0 && bootverbose) >>> + printf("regulator: setting constraint on %s failed >>> (%d)\n", >>> + entry->name, rv); >>> + } >>> + REG_TOPO_UNLOCK(); >>> +} >>> + >>> +/* >>> + * Disable unused regulator >>> + * We run this function at SI_SUB_LAST which mean that every driver that >>> needs >>> + * regulator should have already enable them. >>> + * All the remaining regulators should be those left enabled by the >>> bootloader >>> + * or enable by default by the PMIC. >>> + */ >>> +static void >>> +regulator_shutdown(void *dummy) >>> +{ >>> + struct regnode *entry; >>> + int status, ret; >>> + int disable = 1; >>> + >>> + TUNABLE_INT_FETCH("hw.regulator.disable_unused", &disable); >>> + if (!disable) >>> + return; >>> + REG_TOPO_SLOCK(); >>> + >>> + if (bootverbose) >>> + printf("regulator: shutting down unused regulators\n"); >>> + TAILQ_FOREACH(entry, ®node_list, reglist_link) { >>> + if (!entry->std_param.always_on) { >>> + ret = regnode_status(entry, &status); >>> + if (ret == 0 && status == >>> REGULATOR_STATUS_ENABLED) { >>> + if (bootverbose) >>> + printf("regulator: shutting down %s... >>> ", >>> + entry->name); >>> + ret = regnode_stop(entry, 0); >>> + if (bootverbose) { >>> + /* >>> + * Call out busy in particular, here, >>> + * because it's not unexpected to fail >>> + * shutdown if the regulator is simply >>> + * in-use. >>> + */ >>> + if (ret == EBUSY) >>> + printf("busy\n"); >>> + else if (ret != 0) >>> + printf("error (%d)\n", ret); >>> + else >>> + printf("ok\n"); >>> + } >>> + } >>> + } >>> + } >>> + REG_TOPO_UNLOCK(); >>> +} >>> + >>> +/* >>> + * sysctl handler >>> + */ >>> +static int >>> +regnode_uvolt_sysctl(SYSCTL_HANDLER_ARGS) >>> +{ >>> + struct regnode *regnode = arg1; >>> + int rv, uvolt; >>> + >>> + if (regnode->std_param.min_uvolt == regnode- >>>> std_param.max_uvolt) { >>> + uvolt = regnode->std_param.min_uvolt; >>> + } else { >>> + REG_TOPO_SLOCK(); >>> + if ((rv = regnode_get_voltage(regnode, &uvolt)) != 0) { >>> + REG_TOPO_UNLOCK(); >>> + return (rv); >>> + } >>> + REG_TOPO_UNLOCK(); >>> + } >>> + >>> + return sysctl_handle_int(oidp, &uvolt, sizeof(uvolt), req); >>> +} >>> + >>> +/* >>> ---------------------------------------------------------------------------- >>> + * >>> + * Default regulator methods for base class. >>> + * >>> + */ >>> +static int >>> +regnode_method_init(struct regnode *regnode) >>> +{ >>> + >>> + return (0); >>> +} >>> + >>> +static int >>> +regnode_method_enable(struct regnode *regnode, bool enable, int >>> *udelay) >>> +{ >>> + >>> + if (!enable) >>> + return (ENXIO); >>> + >>> + *udelay = 0; >>> + return (0); >>> +} >>> + >>> +static int >>> +regnode_method_status(struct regnode *regnode, int *status) >>> +{ >>> + *status = REGULATOR_STATUS_ENABLED; >>> + return (0); >>> +} >>> + >>> +static int >>> +regnode_method_set_voltage(struct regnode *regnode, int min_uvolt, int >>> max_uvolt, >>> + int *udelay) >>> +{ >>> + >>> + if ((min_uvolt > regnode->std_param.max_uvolt) || >>> + (max_uvolt < regnode->std_param.min_uvolt)) >>> + return (ERANGE); >>> + *udelay = 0; >>> + return (0); >>> +} >>> + >>> +static int >>> +regnode_method_get_voltage(struct regnode *regnode, int *uvolt) >>> +{ >>> + >>> + return (regnode->std_param.min_uvolt + >>> + (regnode->std_param.max_uvolt - regnode- >>>> std_param.min_uvolt) / 2); >>> +} >>> + >>> +int >>> +regnode_method_check_voltage(struct regnode *regnode, int uvolt) >>> +{ >>> + >>> + if ((uvolt > regnode->std_param.max_uvolt) || >>> + (uvolt < regnode->std_param.min_uvolt)) >>> + return (ERANGE); >>> + return (0); >>> +} >>> + >>> +/* >>> ---------------------------------------------------------------------------- >>> + * >>> + * Internal functions. >>> + * >>> + */ >>> + >>> +static struct regnode * >>> +regnode_find_by_name(const char *name) >>> +{ >>> + struct regnode *entry; >>> + >>> + REG_TOPO_ASSERT(); >>> + >>> + TAILQ_FOREACH(entry, ®node_list, reglist_link) { >>> + if (strcmp(entry->name, name) == 0) >>> + return (entry); >>> + } >>> + return (NULL); >>> +} >>> + >>> +static struct regnode * >>> +regnode_find_by_id(device_t dev, intptr_t id) >>> +{ >>> + struct regnode *entry; >>> + >>> + REG_TOPO_ASSERT(); >>> + >>> + TAILQ_FOREACH(entry, ®node_list, reglist_link) { >>> + if ((entry->pdev == dev) && (entry->id == id)) >>> + return (entry); >>> + } >>> + >>> + return (NULL); >>> +} >>> + >>> +/* >>> + * Create and initialize regulator object, but do not register it. >>> + */ >>> +struct regnode * >>> +regnode_create(device_t pdev, regnode_class_t regnode_class, >>> + struct regnode_init_def *def) >>> +{ >>> + struct regnode *regnode; >>> + struct sysctl_oid *regnode_oid; >>> + >>> + KASSERT(def->name != NULL, ("regulator name is NULL")); >>> + KASSERT(def->name[0] != '\0', ("regulator name is empty")); >>> + >>> + REG_TOPO_SLOCK(); >>> + if (regnode_find_by_name(def->name) != NULL) >>> + panic("Duplicated regulator registration: %s\n", def->name); >>> + REG_TOPO_UNLOCK(); >>> + >>> + /* Create object and initialize it. */ >>> + regnode = malloc(sizeof(struct regnode), M_REGULATOR, >>> + M_WAITOK | M_ZERO); >>> + kobj_init((kobj_t)regnode, (kobj_class_t)regnode_class); >>> + sx_init(®node->lock, "Regulator node lock"); >>> + >>> + /* Allocate softc if required. */ >>> + if (regnode_class->size > 0) { >>> + regnode->softc = malloc(regnode_class->size, >>> M_REGULATOR, >>> + M_WAITOK | M_ZERO); >>> + } >>> + >>> + >>> + /* Copy all strings unless they're flagged as static. */ >>> + if (def->flags & REGULATOR_FLAGS_STATIC) { >>> + regnode->name = def->name; >>> + regnode->parent_name = def->parent_name; >>> + } else { >>> + regnode->name = strdup(def->name, M_REGULATOR); >>> + if (def->parent_name != NULL) >>> + regnode->parent_name = strdup(def- >>>> parent_name, >>> + M_REGULATOR); >>> + } >>> + >>> + /* Rest of init. */ >>> + TAILQ_INIT(®node->consumers_list); >>> + regnode->id = def->id; >>> + regnode->pdev = pdev; >>> + regnode->flags = def->flags; >>> + regnode->parent = NULL; >>> + regnode->std_param = def->std_param; >>> +#ifdef FDT >>> + regnode->ofw_node = def->ofw_node; >>> +#endif >>> + >>> + sysctl_ctx_init(®node->sysctl_ctx); >>> + regnode_oid = SYSCTL_ADD_NODE(®node->sysctl_ctx, >>> + SYSCTL_STATIC_CHILDREN(_hw_regulator), >>> + OID_AUTO, regnode->name, >>> + CTLFLAG_RD, 0, "A regulator node"); >>> + >>> + SYSCTL_ADD_INT(®node->sysctl_ctx, >>> + SYSCTL_CHILDREN(regnode_oid), >>> + OID_AUTO, "min_uvolt", >>> + CTLFLAG_RD, ®node->std_param.min_uvolt, 0, >>> + "Minimal voltage (in uV)"); >>> + SYSCTL_ADD_INT(®node->sysctl_ctx, >>> + SYSCTL_CHILDREN(regnode_oid), >>> + OID_AUTO, "max_uvolt", >>> + CTLFLAG_RD, ®node->std_param.max_uvolt, 0, >>> + "Maximal voltage (in uV)"); >>> + SYSCTL_ADD_INT(®node->sysctl_ctx, >>> + SYSCTL_CHILDREN(regnode_oid), >>> + OID_AUTO, "min_uamp", >>> + CTLFLAG_RD, ®node->std_param.min_uamp, 0, >>> + "Minimal amperage (in uA)"); >>> + SYSCTL_ADD_INT(®node->sysctl_ctx, >>> + SYSCTL_CHILDREN(regnode_oid), >>> + OID_AUTO, "max_uamp", >>> + CTLFLAG_RD, ®node->std_param.max_uamp, 0, >>> + "Maximal amperage (in uA)"); >>> + SYSCTL_ADD_INT(®node->sysctl_ctx, >>> + SYSCTL_CHILDREN(regnode_oid), >>> + OID_AUTO, "ramp_delay", >>> + CTLFLAG_RD, ®node->std_param.ramp_delay, 0, >>> + "Ramp delay (in uV/us)"); >>> + SYSCTL_ADD_INT(®node->sysctl_ctx, >>> + SYSCTL_CHILDREN(regnode_oid), >>> + OID_AUTO, "enable_delay", >>> + CTLFLAG_RD, ®node->std_param.enable_delay, 0, >>> + "Enable delay (in us)"); >>> + SYSCTL_ADD_INT(®node->sysctl_ctx, >>> + SYSCTL_CHILDREN(regnode_oid), >>> + OID_AUTO, "enable_cnt", >>> + CTLFLAG_RD, ®node->enable_cnt, 0, >>> + "The regulator enable counter"); >>> + SYSCTL_ADD_U8(®node->sysctl_ctx, >>> + SYSCTL_CHILDREN(regnode_oid), >>> + OID_AUTO, "boot_on", >>> + CTLFLAG_RD, (uint8_t *) ®node->std_param.boot_on, 0, >>> + "Is enabled on boot"); >>> + SYSCTL_ADD_U8(®node->sysctl_ctx, >>> + SYSCTL_CHILDREN(regnode_oid), >>> + OID_AUTO, "always_on", >>> + CTLFLAG_RD, (uint8_t *)®node->std_param.always_on, 0, >>> + "Is always enabled"); >>> + >>> + SYSCTL_ADD_PROC(®node->sysctl_ctx, >>> + SYSCTL_CHILDREN(regnode_oid), >>> + OID_AUTO, "uvolt", >>> + CTLTYPE_INT | CTLFLAG_RD, >>> + regnode, 0, regnode_uvolt_sysctl, >>> + "I", >>> + "Current voltage (in uV)"); >>> + >>> + return (regnode); >>> +} >>> + >>> +/* Register regulator object. */ >>> +struct regnode * >>> +regnode_register(struct regnode *regnode) >>> +{ >>> + int rv; >>> + >>> +#ifdef FDT >>> + if (regnode->ofw_node <= 0) >>> + regnode->ofw_node = ofw_bus_get_node(regnode->pdev); >>> + if (regnode->ofw_node <= 0) >>> + return (NULL); >>> +#endif >>> + >>> + rv = REGNODE_INIT(regnode); >>> + if (rv != 0) { >>> + printf("REGNODE_INIT failed: %d\n", rv); >>> + return (NULL); >>> + } >>> + >>> + REG_TOPO_XLOCK(); >>> + TAILQ_INSERT_TAIL(®node_list, regnode, reglist_link); >>> + REG_TOPO_UNLOCK(); >>> +#ifdef FDT >>> + OF_device_register_xref(OF_xref_from_node(regnode- >>>> ofw_node), >>> + regnode->pdev); >>> +#endif >>> + return (regnode); >>> +} >>> + >>> +static int >>> +regnode_resolve_parent(struct regnode *regnode) >>> +{ >>> + >>> + /* All ready resolved or no parent? */ >>> + if ((regnode->parent != NULL) || >>> + (regnode->parent_name == NULL)) >>> + return (0); >>> + >>> + regnode->parent = regnode_find_by_name(regnode- >>>> parent_name); >>> + if (regnode->parent == NULL) >>> + return (ENODEV); >>> + return (0); >>> +} >>> + >>> +static void >>> +regnode_delay(int usec) >>> +{ >>> + int ticks; >>> + >>> + if (usec == 0) >>> + return; >>> + ticks = (usec * hz + 999999) / 1000000; >>> + >>> + if (cold || ticks < 2) >>> + DELAY(usec); >>> + else >>> + pause("REGULATOR", ticks); >>> +} >>> + >>> +/* >>> -------------------------------------------------------------------------- >>> + * >>> + * Regulator providers interface >>> + * >>> + */ >>> + >>> +const char * >>> +regnode_get_name(struct regnode *regnode) >>> +{ >>> + >>> + return (regnode->name); >>> +} >>> + >>> +const char * >>> +regnode_get_parent_name(struct regnode *regnode) >>> +{ >>> + >>> + return (regnode->parent_name); >>> +} >>> + >>> +int >>> +regnode_get_flags(struct regnode *regnode) >>> +{ >>> + >>> + return (regnode->flags); >>> +} >>> + >>> +void * >>> +regnode_get_softc(struct regnode *regnode) >>> +{ >>> + >>> + return (regnode->softc); >>> +} >>> + >>> +device_t >>> +regnode_get_device(struct regnode *regnode) >>> +{ >>> + >>> + return (regnode->pdev); >>> +} >>> + >>> +struct regnode_std_param *regnode_get_stdparam(struct regnode >>> *regnode) >>> +{ >>> + >>> + return (®node->std_param); >>> +} >>> + >>> +void regnode_topo_unlock(void) >>> +{ >>> + >>> + REG_TOPO_UNLOCK(); >>> +} >>> + >>> +void regnode_topo_xlock(void) >>> +{ >>> + >>> + REG_TOPO_XLOCK(); >>> +} >>> + >>> +void regnode_topo_slock(void) >>> +{ >>> + >>> + REG_TOPO_SLOCK(); >>> +} >>> + >>> + >>> +/* >>> -------------------------------------------------------------------------- >>> + * >>> + * Real consumers executive >>> + * >>> + */ >>> +struct regnode * >>> +regnode_get_parent(struct regnode *regnode) >>> +{ >>> + int rv; >>> + >>> + REG_TOPO_ASSERT(); >>> + >>> + rv = regnode_resolve_parent(regnode); >>> + if (rv != 0) >>> + return (NULL); >>> + >>> + return (regnode->parent); >>> +} >>> + >>> +/* >>> + * Enable regulator. >>> + */ >>> +int >>> +regnode_enable(struct regnode *regnode) >>> +{ >>> + int udelay; >>> + int rv; >>> + >>> + REG_TOPO_ASSERT(); >>> + >>> + /* Enable regulator for each node in chain, starting from source. */ >>> + rv = regnode_resolve_parent(regnode); >>> + if (rv != 0) >>> + return (rv); >>> + if (regnode->parent != NULL) { >>> + rv = regnode_enable(regnode->parent); >>> + if (rv != 0) >>> + return (rv); >>> + } >>> + >>> + /* Handle this node. */ >>> + REGNODE_XLOCK(regnode); >>> + if (regnode->enable_cnt == 0) { >>> + rv = REGNODE_ENABLE(regnode, true, &udelay); >>> + if (rv != 0) { >>> + REGNODE_UNLOCK(regnode); >>> + return (rv); >>> + } >>> + regnode_delay(udelay); >>> + } >>> + regnode->enable_cnt++; >>> + REGNODE_UNLOCK(regnode); >>> + return (0); >>> +} >>> + >>> +/* >>> + * Disable regulator. >>> + */ >>> +int >>> +regnode_disable(struct regnode *regnode) >>> +{ >>> + int udelay; >>> + int rv; >>> + >>> + REG_TOPO_ASSERT(); >>> + rv = 0; >>> + >>> + REGNODE_XLOCK(regnode); >>> + /* Disable regulator for each node in chain, starting from consumer. >>> */ >>> + if (regnode->enable_cnt == 1 && >>> + (regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0 && >>> + !regnode->std_param.always_on) { >>> + rv = REGNODE_ENABLE(regnode, false, &udelay); >>> + if (rv != 0) { >>> + REGNODE_UNLOCK(regnode); >>> + return (rv); >>> + } >>> + regnode_delay(udelay); >>> + } >>> + regnode->enable_cnt--; >>> + REGNODE_UNLOCK(regnode); >>> + >>> + rv = regnode_resolve_parent(regnode); >>> + if (rv != 0) >>> + return (rv); >>> + if (regnode->parent != NULL) >>> + rv = regnode_disable(regnode->parent); >>> + return (rv); >>> +} >>> + >>> +/* >>> + * Stop regulator. >>> + */ >>> +int >>> +regnode_stop(struct regnode *regnode, int depth) >>> +{ >>> + int udelay; >>> + int rv; >>> + >>> + REG_TOPO_ASSERT(); >>> + rv = 0; >>> + >>> + REGNODE_XLOCK(regnode); >>> + /* The first node must not be enabled. */ >>> + if ((regnode->enable_cnt != 0) && (depth == 0)) { >>> + REGNODE_UNLOCK(regnode); >>> + return (EBUSY); >>> + } >>> + /* Disable regulator for each node in chain, starting from consumer >>> */ >>> + if ((regnode->enable_cnt == 0) && >>> + ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) { >>> + rv = REGNODE_STOP(regnode, &udelay); >>> + if (rv != 0) { >>> + REGNODE_UNLOCK(regnode); >>> + return (rv); >>> + } >>> + regnode_delay(udelay); >>> + } >>> + REGNODE_UNLOCK(regnode); >>> + >>> + rv = regnode_resolve_parent(regnode); >>> + if (rv != 0) >>> + return (rv); >>> + if (regnode->parent != NULL && regnode->parent->enable_cnt == 0) >>> + rv = regnode_stop(regnode->parent, depth + 1); >>> + return (rv); >>> +} >>> + >>> +/* >>> + * Get regulator status. (REGULATOR_STATUS_*) >>> + */ >>> +int >>> +regnode_status(struct regnode *regnode, int *status) >>> +{ >>> + int rv; >>> + >>> + REG_TOPO_ASSERT(); >>> + >>> + REGNODE_XLOCK(regnode); >>> + rv = REGNODE_STATUS(regnode, status); >>> + REGNODE_UNLOCK(regnode); >>> + return (rv); >>> +} >>> + >>> +/* >>> + * Get actual regulator voltage. >>> + */ >>> +int >>> +regnode_get_voltage(struct regnode *regnode, int *uvolt) >>> +{ >>> + int rv; >>> + >>> + REG_TOPO_ASSERT(); >>> + >>> + REGNODE_XLOCK(regnode); >>> + rv = REGNODE_GET_VOLTAGE(regnode, uvolt); >>> + REGNODE_UNLOCK(regnode); >>> + >>> + /* Pass call into parent, if regulator is in bypass mode. */ >>> + if (rv == ENOENT) { >>> + rv = regnode_resolve_parent(regnode); >>> + if (rv != 0) >>> + return (rv); >>> + if (regnode->parent != NULL) >>> + rv = regnode_get_voltage(regnode->parent, uvolt); >>> + >>> + } >>> + return (rv); >>> +} >>> + >>> +/* >>> + * Set regulator voltage. >>> + */ >>> +int >>> +regnode_set_voltage(struct regnode *regnode, int min_uvolt, int >>> max_uvolt) >>> +{ >>> + int udelay; >>> + int rv; >>> + >>> + REG_TOPO_ASSERT(); >>> + >>> + REGNODE_XLOCK(regnode); >>> + >>> + rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, >>> &udelay); >>> + if (rv == 0) >>> + regnode_delay(udelay); >>> + REGNODE_UNLOCK(regnode); >>> + return (rv); >>> +} >>> + >>> +/* >>> + * Consumer variant of regnode_set_voltage(). >>> + */ >>> +static int >>> +regnode_set_voltage_checked(struct regnode *regnode, struct regulator >>> *reg, >>> + int min_uvolt, int max_uvolt) >>> +{ >>> + int udelay; >>> + int all_max_uvolt; >>> + int all_min_uvolt; >>> + struct regulator *tmp; >>> + int rv; >>> + >>> + REG_TOPO_ASSERT(); >>> + >>> + REGNODE_XLOCK(regnode); >>> + /* Return error if requested range is outside of regulator range. */ >>> + if ((min_uvolt > regnode->std_param.max_uvolt) || >>> + (max_uvolt < regnode->std_param.min_uvolt)) { >>> + REGNODE_UNLOCK(regnode); >>> + return (ERANGE); >>> + } >>> + >>> + /* Get actual voltage range for all consumers. */ >>> + all_min_uvolt = regnode->std_param.min_uvolt; >>> + all_max_uvolt = regnode->std_param.max_uvolt; >>> + TAILQ_FOREACH(tmp, ®node->consumers_list, link) { >>> + /* Don't take requestor in account. */ >>> + if (tmp == reg) >>> + continue; >>> + if (all_min_uvolt < tmp->min_uvolt) >>> + all_min_uvolt = tmp->min_uvolt; >>> + if (all_max_uvolt > tmp->max_uvolt) >>> + all_max_uvolt = tmp->max_uvolt; >>> + } >>> + >>> + /* Test if request fits to actual contract. */ >>> + if ((min_uvolt > all_max_uvolt) || >>> + (max_uvolt < all_min_uvolt)) { >>> + REGNODE_UNLOCK(regnode); >>> + return (ERANGE); >>> + } >>> + >>> + /* Adjust new range.*/ >>> + if (min_uvolt < all_min_uvolt) >>> + min_uvolt = all_min_uvolt; >>> + if (max_uvolt > all_max_uvolt) >>> + max_uvolt = all_max_uvolt; >>> + >>> + rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, >>> &udelay); >>> + regnode_delay(udelay); >>> + REGNODE_UNLOCK(regnode); >>> + return (rv); >>> +} >>> + >>> +int >>> +regnode_set_constraint(struct regnode *regnode) >>> +{ >>> + int status, rv, uvolt; >>> + >>> + if (regnode->std_param.boot_on != true && >>> + regnode->std_param.always_on != true) >>> + return (0); >>> + >>> + rv = regnode_status(regnode, &status); >>> + if (rv != 0) { >>> + if (bootverbose) >>> + printf("Cannot get regulator status for %s\n", >>> + regnode_get_name(regnode)); >>> + return (rv); >>> + } >>> + >>> + if (status == REGULATOR_STATUS_ENABLED) >>> + return (0); >>> + >>> + rv = regnode_get_voltage(regnode, &uvolt); >>> + if (rv != 0) { >>> + if (bootverbose) >>> + printf("Cannot get regulator voltage for %s\n", >>> + regnode_get_name(regnode)); >>> + return (rv); >>> + } >>> + >>> + if (uvolt < regnode->std_param.min_uvolt || >>> + uvolt > regnode->std_param.max_uvolt) { >>> + if (bootverbose) >>> + printf("Regulator %s current voltage %d is not in the" >>> + " acceptable range : %d<->%d\n", >>> + regnode_get_name(regnode), >>> + uvolt, regnode->std_param.min_uvolt, >>> + regnode->std_param.max_uvolt); >>> + return (ERANGE); >>> + } >>> + >>> + rv = regnode_enable(regnode); >>> + if (rv != 0) { >>> + if (bootverbose) >>> + printf("Cannot enable regulator %s\n", >>> + regnode_get_name(regnode)); >>> + return (rv); >>> + } >>> + >>> + return (0); >>> +} >>> + >>> +#ifdef FDT >>> +phandle_t >>> +regnode_get_ofw_node(struct regnode *regnode) >>> +{ >>> + >>> + return (regnode->ofw_node); >>> +} >>> +#endif >>> + >>> +/* >>> -------------------------------------------------------------------------- >>> + * >>> + * Regulator consumers interface. >>> + * >>> + */ >>> +/* Helper function for regulator_get*() */ >>> +static regulator_t >>> +regulator_create(struct regnode *regnode, device_t cdev) >>> +{ >>> + struct regulator *reg; >>> + >>> + REG_TOPO_ASSERT(); >>> + >>> + reg = malloc(sizeof(struct regulator), M_REGULATOR, >>> + M_WAITOK | M_ZERO); >>> + reg->cdev = cdev; >>> + reg->regnode = regnode; >>> + reg->enable_cnt = 0; >>> + >>> + REGNODE_XLOCK(regnode); >>> + regnode->ref_cnt++; >>> + TAILQ_INSERT_TAIL(®node->consumers_list, reg, link); >>> + reg ->min_uvolt = regnode->std_param.min_uvolt; >>> + reg ->max_uvolt = regnode->std_param.max_uvolt; >>> + REGNODE_UNLOCK(regnode); >>> + >>> + return (reg); >>> +} >>> + >>> +int >>> +regulator_enable(regulator_t reg) >>> +{ >>> + int rv; >>> + struct regnode *regnode; >>> + >>> + regnode = reg->regnode; >>> + KASSERT(regnode->ref_cnt > 0, >>> + ("Attempt to access unreferenced regulator: %s\n", regnode- >>>> name)); >>> + REG_TOPO_SLOCK(); >>> + rv = regnode_enable(regnode); >>> + if (rv == 0) >>> + reg->enable_cnt++; >>> + REG_TOPO_UNLOCK(); >>> + return (rv); >>> +} >>> + >>> +int >>> +regulator_disable(regulator_t reg) >>> +{ >>> + int rv; >>> + struct regnode *regnode; >>> + >>> + regnode = reg->regnode; >>> + KASSERT(regnode->ref_cnt > 0, >>> + ("Attempt to access unreferenced regulator: %s\n", regnode- >>>> name)); >>> + KASSERT(reg->enable_cnt > 0, >>> + ("Attempt to disable already disabled regulator: %s\n", >>> + regnode->name)); >>> + REG_TOPO_SLOCK(); >>> + rv = regnode_disable(regnode); >>> + if (rv == 0) >>> + reg->enable_cnt--; >>> + REG_TOPO_UNLOCK(); >>> + return (rv); >>> +} >>> + >>> +int >>> +regulator_stop(regulator_t reg) >>> +{ >>> + int rv; >>> + struct regnode *regnode; >>> + >>> + regnode = reg->regnode; >>> + KASSERT(regnode->ref_cnt > 0, >>> + ("Attempt to access unreferenced regulator: %s\n", regnode- >>>> name)); >>> + KASSERT(reg->enable_cnt == 0, >>> + ("Attempt to stop already enabled regulator: %s\n", regnode- >>>> name)); >>> + >>> + REG_TOPO_SLOCK(); >>> + rv = regnode_stop(regnode, 0); >>> + REG_TOPO_UNLOCK(); >>> + return (rv); >>> +} >>> + >>> +int >>> +regulator_status(regulator_t reg, int *status) >>> +{ >>> + int rv; >>> + struct regnode *regnode; >>> + >>> + regnode = reg->regnode; >>> + KASSERT(regnode->ref_cnt > 0, >>> + ("Attempt to access unreferenced regulator: %s\n", regnode- >>>> name)); >>> + >>> + REG_TOPO_SLOCK(); >>> + rv = regnode_status(regnode, status); >>> + REG_TOPO_UNLOCK(); >>> + return (rv); >>> +} >>> + >>> +int >>> +regulator_get_voltage(regulator_t reg, int *uvolt) >>> +{ >>> + int rv; >>> + struct regnode *regnode; >>> + >>> + regnode = reg->regnode; >>> + KASSERT(regnode->ref_cnt > 0, >>> + ("Attempt to access unreferenced regulator: %s\n", regnode- >>>> name)); >>> + >>> + REG_TOPO_SLOCK(); >>> + rv = regnode_get_voltage(regnode, uvolt); >>> + REG_TOPO_UNLOCK(); >>> + return (rv); >>> +} >>> + >>> +int >>> +regulator_set_voltage(regulator_t reg, int min_uvolt, int max_uvolt) >>> +{ >>> + struct regnode *regnode; >>> + int rv; >>> + >>> + regnode = reg->regnode; >>> + KASSERT(regnode->ref_cnt > 0, >>> + ("Attempt to access unreferenced regulator: %s\n", regnode- >>>> name)); >>> + >>> + REG_TOPO_SLOCK(); >>> + >>> + rv = regnode_set_voltage_checked(regnode, reg, min_uvolt, >>> max_uvolt); >>> + if (rv == 0) { >>> + reg->min_uvolt = min_uvolt; >>> + reg->max_uvolt = max_uvolt; >>> + } >>> + REG_TOPO_UNLOCK(); >>> + return (rv); >>> +} >>> + >>> +int >>> +regulator_check_voltage(regulator_t reg, int uvolt) >>> +{ >>> + int rv; >>> + struct regnode *regnode; >>> + >>> + regnode = reg->regnode; >>> + KASSERT(regnode->ref_cnt > 0, >>> + ("Attempt to access unreferenced regulator: %s\n", regnode- >>>> name)); >>> + >>> + REG_TOPO_SLOCK(); >>> + rv = REGNODE_CHECK_VOLTAGE(regnode, uvolt); >>> + REG_TOPO_UNLOCK(); >>> + return (rv); >>> +} >>> + >>> +const char * >>> +regulator_get_name(regulator_t reg) >>> +{ >>> + struct regnode *regnode; >>> + >>> + regnode = reg->regnode; >>> + KASSERT(regnode->ref_cnt > 0, >>> + ("Attempt to access unreferenced regulator: %s\n", regnode- >>>> name)); >>> + return (regnode->name); >>> +} >>> + >>> +int >>> +regulator_get_by_name(device_t cdev, const char *name, regulator_t >>> *reg) >>> +{ >>> + struct regnode *regnode; >>> + >>> + REG_TOPO_SLOCK(); >>> + regnode = regnode_find_by_name(name); >>> + if (regnode == NULL) { >>> + REG_TOPO_UNLOCK(); >>> + return (ENODEV); >>> + } >>> + *reg = regulator_create(regnode, cdev); >>> + REG_TOPO_UNLOCK(); >>> + return (0); >>> +} >>> + >>> +int >>> +regulator_get_by_id(device_t cdev, device_t pdev, intptr_t id, regulator_t >>> *reg) >>> +{ >>> + struct regnode *regnode; >>> + >>> + REG_TOPO_SLOCK(); >>> + >>> + regnode = regnode_find_by_id(pdev, id); >>> + if (regnode == NULL) { >>> + REG_TOPO_UNLOCK(); >>> + return (ENODEV); >>> + } >>> + *reg = regulator_create(regnode, cdev); >>> + REG_TOPO_UNLOCK(); >>> + >>> + return (0); >>> +} >>> + >>> +int >>> +regulator_release(regulator_t reg) >>> +{ >>> + struct regnode *regnode; >>> + >>> + regnode = reg->regnode; >>> + KASSERT(regnode->ref_cnt > 0, >>> + ("Attempt to access unreferenced regulator: %s\n", regnode- >>>> name)); >>> + REG_TOPO_SLOCK(); >>> + while (reg->enable_cnt > 0) { >>> + regnode_disable(regnode); >>> + reg->enable_cnt--; >>> + } >>> + REGNODE_XLOCK(regnode); >>> + TAILQ_REMOVE(®node->consumers_list, reg, link); >>> + regnode->ref_cnt--; >>> + REGNODE_UNLOCK(regnode); >>> + REG_TOPO_UNLOCK(); >>> + >>> + free(reg, M_REGULATOR); >>> + return (0); >>> +} >>> + >>> +#ifdef FDT >>> +/* Default DT mapper. */ >>> +int >>> +regdev_default_ofw_map(device_t dev, phandle_t xref, int ncells, >>> + pcell_t *cells, intptr_t *id) >>> +{ >>> + if (ncells == 0) >>> + *id = 1; >>> + else if (ncells == 1) >>> + *id = cells[0]; >>> + else >>> + return (ERANGE); >>> + >>> + return (0); >>> +} >>> + >>> +int >>> +regulator_parse_ofw_stdparam(device_t pdev, phandle_t node, >>> + struct regnode_init_def *def) >>> +{ >>> + phandle_t supply_xref; >>> + struct regnode_std_param *par; >>> + int rv; >>> + >>> + par = &def->std_param; >>> + rv = OF_getprop_alloc(node, "regulator-name", >>> + (void **)&def->name); >>> + if (rv <= 0) { >>> + device_printf(pdev, "%s: Missing regulator name\n", >>> + __func__); >>> + return (ENXIO); >>> + } >>> + >>> + rv = OF_getencprop(node, "regulator-min-microvolt", &par- >>>> min_uvolt, >>> + sizeof(par->min_uvolt)); >>> + if (rv <= 0) >>> + par->min_uvolt = 0; >>> + >>> + rv = OF_getencprop(node, "regulator-max-microvolt", &par- >>>> max_uvolt, >>> + sizeof(par->max_uvolt)); >>> + if (rv <= 0) >>> + par->max_uvolt = 0; >>> + >>> + rv = OF_getencprop(node, "regulator-min-microamp", &par- >>>> min_uamp, >>> + sizeof(par->min_uamp)); >>> + if (rv <= 0) >>> + par->min_uamp = 0; >>> + >>> + rv = OF_getencprop(node, "regulator-max-microamp", &par- >>>> max_uamp, >>> + sizeof(par->max_uamp)); >>> + if (rv <= 0) >>> + par->max_uamp = 0; >>> + >>> + rv = OF_getencprop(node, "regulator-ramp-delay", &par- >>>> ramp_delay, >>> + sizeof(par->ramp_delay)); >>> + if (rv <= 0) >>> + par->ramp_delay = 0; >>> + >>> + rv = OF_getencprop(node, "regulator-enable-ramp-delay", >>> + &par->enable_delay, sizeof(par->enable_delay)); >>> + if (rv <= 0) >>> + par->enable_delay = 0; >>> + >>> + if (OF_hasprop(node, "regulator-boot-on")) >>> + par->boot_on = true; >>> + >>> + if (OF_hasprop(node, "regulator-always-on")) >>> + par->always_on = true; >>> + >>> + if (OF_hasprop(node, "enable-active-high")) >>> + par->enable_active_high = 1; >>> + >>> + rv = OF_getencprop(node, "vin-supply", &supply_xref, >>> + sizeof(supply_xref)); >>> + if (rv >= 0) { >>> + rv = OF_getprop_alloc(supply_xref, "regulator-name", >>> + (void **)&def->parent_name); >>> + if (rv <= 0) >>> + def->parent_name = NULL; >>> + } >>> + return (0); >>> +} >>> + >>> +int >>> +regulator_get_by_ofw_property(device_t cdev, phandle_t cnode, char >>> *name, >>> + regulator_t *reg) >>> +{ >>> + phandle_t *cells; >>> + device_t regdev; >>> + int ncells, rv; >>> + intptr_t id; >>> + >>> + *reg = NULL; >>> + >>> + if (cnode <= 0) >>> + cnode = ofw_bus_get_node(cdev); >>> + if (cnode <= 0) { >>> + device_printf(cdev, "%s called on not ofw based device\n", >>> + __func__); >>> + return (ENXIO); >>> + } >>> + >>> + cells = NULL; >>> + ncells = OF_getencprop_alloc_multi(cnode, name, sizeof(*cells), >>> + (void **)&cells); >>> + if (ncells <= 0) >>> + return (ENOENT); >>> + >>> + /* Translate xref to device */ >>> + regdev = OF_device_from_xref(cells[0]); >>> + if (regdev == NULL) { >>> + OF_prop_free(cells); >>> + return (ENODEV); >>> + } >>> + >>> + /* Map regulator to number */ >>> + rv = REGDEV_MAP(regdev, cells[0], ncells - 1, cells + 1, &id); >>> + OF_prop_free(cells); >>> + if (rv != 0) >>> + return (rv); >>> + return (regulator_get_by_id(cdev, regdev, id, reg)); >>> +} >>> +#endif >>> + >>> +/* >>> -------------------------------------------------------------------------- >>> + * >>> + * Regulator utility functions. >>> + * >>> + */ >>> + >>> +/* Convert raw selector value to real voltage */ >>> +int >>> +regulator_range_sel8_to_volt(struct regulator_range *ranges, int nranges, >>> + uint8_t sel, int *volt) >>> +{ >>> + struct regulator_range *range; >>> + int i; >>> + >>> + if (nranges == 0) >>> + panic("Voltage regulator have zero ranges\n"); >>> + >>> + for (i = 0; i < nranges ; i++) { >>> + range = ranges + i; >>> + >>> + if (!(sel >= range->min_sel && >>> + sel <= range->max_sel)) >>> + continue; >>> + >>> + sel -= range->min_sel; >>> + >>> + *volt = range->min_uvolt + sel * range->step_uvolt; >>> + return (0); >>> + } >>> + >>> + return (ERANGE); >>> +} >>> + >>> +int >>> +regulator_range_volt_to_sel8(struct regulator_range *ranges, int nranges, >>> + int min_uvolt, int max_uvolt, uint8_t *out_sel) >>> +{ >>> + struct regulator_range *range; >>> + uint8_t sel; >>> + int uvolt; >>> + int rv, i; >>> + >>> + if (nranges == 0) >>> + panic("Voltage regulator have zero ranges\n"); >>> + >>> + for (i = 0; i < nranges; i++) { >>> + range = ranges + i; >>> + uvolt = range->min_uvolt + >>> + (range->max_sel - range->min_sel) * range->step_uvolt; >>> + >>> + if ((min_uvolt > uvolt) || >>> + (max_uvolt < range->min_uvolt)) >>> + continue; >>> + >>> + if (min_uvolt <= range->min_uvolt) >>> + min_uvolt = range->min_uvolt; >>> + >>> + /* if step == 0 -> fixed voltage range. */ >>> + if (range->step_uvolt == 0) >>> + sel = 0; >>> + else >>> + sel = DIV_ROUND_UP(min_uvolt - range->min_uvolt, >>> + range->step_uvolt); >>> + >>> + >>> + sel += range->min_sel; >>> + >>> + break; >>> + } >>> + >>> + if (i >= nranges) >>> + return (ERANGE); >>> + >>> + /* Verify new settings. */ >>> + rv = regulator_range_sel8_to_volt(ranges, nranges, sel, &uvolt); >>> + if (rv != 0) >>> + return (rv); >>> + if ((uvolt < min_uvolt) || (uvolt > max_uvolt)) >>> + return (ERANGE); >>> + >>> + *out_sel = sel; >>> + return (0); >>> +} >>> diff --git a/freebsd/sys/dev/extres/regulator/regulator.h >>> b/freebsd/sys/dev/extres/regulator/regulator.h >>> new file mode 100644 >>> index 00000000..3905aa36 >>> --- /dev/null >>> +++ b/freebsd/sys/dev/extres/regulator/regulator.h >>> @@ -0,0 +1,156 @@ >>> +/*- >>> + * Copyright 2016 Michal Meloun <m...@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$ >>> + */ >>> + >>> +#ifndef _DEV_EXTRES_REGULATOR_H_ >>> +#define _DEV_EXTRES_REGULATOR_H_ >>> +#include <rtems/bsd/local/opt_platform.h> >>> + >>> +#include <sys/kobj.h> >>> +#include <sys/sysctl.h> >>> +#ifdef FDT >>> +#include <dev/ofw/ofw_bus.h> >>> +#endif >>> +#include <rtems/bsd/local/regnode_if.h> >>> + >>> +SYSCTL_DECL(_hw_regulator); >>> + >>> +#define REGULATOR_FLAGS_STATIC 0x00000001 /* Static strings */ >>> +#define REGULATOR_FLAGS_NOT_DISABLE 0x00000002 /* Cannot be >>> disabled */ >>> + >>> +#define REGULATOR_STATUS_ENABLED 0x00000001 >>> +#define REGULATOR_STATUS_OVERCURRENT 0x00000002 >>> + >>> +typedef struct regulator *regulator_t; >>> + >>> +/* Standard regulator parameters. */ >>> +struct regnode_std_param { >>> + int min_uvolt; /* In uV */ >>> + int max_uvolt; /* In uV */ >>> + int min_uamp; /* In uA */ >>> + int max_uamp; /* In uA */ >>> + int ramp_delay; /* In uV/usec */ >>> + int enable_delay; /* In usec */ >>> + bool boot_on; /* Is enabled on boot */ >>> + bool always_on; /* Must be enabled */ >>> + int enable_active_high; >>> +}; >>> + >>> +/* Initialization parameters. */ >>> +struct regnode_init_def { >>> + char *name; /* Regulator name */ >>> + char *parent_name; /* Name of parent >>> regulator */ >>> + struct regnode_std_param std_param; /* Standard >>> parameters */ >>> + intptr_t id; /* Regulator ID */ >>> + int flags; /* Flags */ >>> +#ifdef FDT >>> + phandle_t ofw_node; /* OFW node of regulator */ >>> +#endif >>> +}; >>> + >>> +struct regulator_range { >>> + int min_uvolt; >>> + int step_uvolt; >>> + uint8_t min_sel; >>> + uint8_t max_sel; >>> +}; >>> + >>> +#define REG_RANGE_INIT(_min_sel, _max_sel, _min_uvolt, >>> _step_uvolt) { \ >>> + .min_sel = _min_sel, \ >>> + .max_sel = _max_sel, \ >>> + .min_uvolt = _min_uvolt, \ >>> + .step_uvolt = _step_uvolt, \ >>> +} >>> + >>> +/* >>> + * Shorthands for constructing method tables. >>> + */ >>> +#define REGNODEMETHOD KOBJMETHOD >>> +#define REGNODEMETHOD_END KOBJMETHOD_END >>> +#define regnode_method_t kobj_method_t >>> +#define regnode_class_t kobj_class_t >>> +DECLARE_CLASS(regnode_class); >>> + >>> +/* Providers interface. */ >>> +struct regnode *regnode_create(device_t pdev, regnode_class_t >>> regnode_class, >>> + struct regnode_init_def *def); >>> +struct regnode *regnode_register(struct regnode *regnode); >>> +const char *regnode_get_name(struct regnode *regnode); >>> +const char *regnode_get_parent_name(struct regnode *regnode); >>> +struct regnode *regnode_get_parent(struct regnode *regnode); >>> +int regnode_get_flags(struct regnode *regnode); >>> +void *regnode_get_softc(struct regnode *regnode); >>> +device_t regnode_get_device(struct regnode *regnode); >>> +struct regnode_std_param *regnode_get_stdparam(struct regnode >>> *regnode); >>> +void regnode_topo_unlock(void); >>> +void regnode_topo_xlock(void); >>> +void regnode_topo_slock(void); >>> + >>> +int regnode_enable(struct regnode *regnode); >>> +int regnode_disable(struct regnode *regnode); >>> +int regnode_stop(struct regnode *regnode, int depth); >>> +int regnode_status(struct regnode *regnode, int *status); >>> +int regnode_get_voltage(struct regnode *regnode, int *uvolt); >>> +int regnode_set_voltage(struct regnode *regnode, int min_uvolt, int >>> max_uvolt); >>> +int regnode_set_constraint(struct regnode *regnode); >>> + >>> +/* Standard method that aren't default */ >>> +int regnode_method_check_voltage(struct regnode *regnode, int uvolt); >>> + >>> +#ifdef FDT >>> +phandle_t regnode_get_ofw_node(struct regnode *regnode); >>> +#endif >>> + >>> +/* Consumers interface. */ >>> +int regulator_get_by_name(device_t cdev, const char *name, >>> + regulator_t *regulator); >>> +int regulator_get_by_id(device_t cdev, device_t pdev, intptr_t id, >>> + regulator_t *regulator); >>> +int regulator_release(regulator_t regulator); >>> +const char *regulator_get_name(regulator_t regulator); >>> +int regulator_enable(regulator_t reg); >>> +int regulator_disable(regulator_t reg); >>> +int regulator_stop(regulator_t reg); >>> +int regulator_status(regulator_t reg, int *status); >>> +int regulator_get_voltage(regulator_t reg, int *uvolt); >>> +int regulator_set_voltage(regulator_t reg, int min_uvolt, int max_uvolt); >>> +int regulator_check_voltage(regulator_t reg, int uvolt); >>> + >>> +#ifdef FDT >>> +int regulator_get_by_ofw_property(device_t dev, phandle_t node, char >>> *name, >>> + regulator_t *reg); >>> +int regulator_parse_ofw_stdparam(device_t dev, phandle_t node, >>> + struct regnode_init_def *def); >>> +#endif >>> + >>> +/* Utility functions */ >>> +int regulator_range_volt_to_sel8(struct regulator_range *ranges, int >>> nranges, >>> + int min_uvolt, int max_uvolt, uint8_t *out_sel); >>> +int regulator_range_sel8_to_volt(struct regulator_range *ranges, int >>> nranges, >>> + uint8_t sel, int *volt); >>> + >>> +#endif /* _DEV_EXTRES_REGULATOR_H_ */ >>> diff --git a/freebsd/sys/dev/extres/regulator/regulator_bus.c >>> b/freebsd/sys/dev/extres/regulator/regulator_bus.c >>> new file mode 100644 >>> index 00000000..b79c2633 >>> --- /dev/null >>> +++ b/freebsd/sys/dev/extres/regulator/regulator_bus.c >>> @@ -0,0 +1,89 @@ >>> +#include <machine/rtems-bsd-kernel-space.h> >>> + >>> +/*- >>> + * Copyright 2016 Michal Meloun <m...@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. >>> + */ >>> + >>> +#include <sys/cdefs.h> >>> +__FBSDID("$FreeBSD$"); >>> + >>> +#include <sys/param.h> >>> +#include <sys/systm.h> >>> +#include <sys/kernel.h> >>> +#include <sys/module.h> >>> +#include <sys/bus.h> >>> + >>> +#include <dev/fdt/simplebus.h> >>> + >>> +#include <dev/ofw/openfirm.h> >>> +#include <dev/ofw/ofw_bus_subr.h> >>> + >>> +struct ofw_regulator_bus_softc { >>> + struct simplebus_softc simplebus_sc; >>> +}; >>> + >>> +static int >>> +ofw_regulator_bus_probe(device_t dev) >>> +{ >>> + const char *name; >>> + >>> + name = ofw_bus_get_name(dev); >>> + if (name == NULL || strcmp(name, "regulators") != 0) >>> + return (ENXIO); >>> + device_set_desc(dev, "OFW regulators bus"); >>> + >>> + return (0); >>> +} >>> + >>> +static int >>> +ofw_regulator_bus_attach(device_t dev) >>> +{ >>> + phandle_t node, child; >>> + >>> + node = ofw_bus_get_node(dev); >>> + simplebus_init(dev, node); >>> + >>> + for (child = OF_child(node); child > 0; child = OF_peer(child)) { >>> + simplebus_add_device(dev, child, 0, NULL, -1, NULL); >>> + } >>> + >>> + return (bus_generic_attach(dev)); >>> +} >>> + >>> +static device_method_t ofw_regulator_bus_methods[] = { >>> + /* Device interface */ >>> + DEVMETHOD(device_probe, ofw_regulator_bus_probe), >>> + DEVMETHOD(device_attach, ofw_regulator_bus_attach), >>> + >>> + DEVMETHOD_END >>> +}; >>> + >>> +DEFINE_CLASS_1(ofw_regulator_bus, ofw_regulator_bus_driver, >>> + ofw_regulator_bus_methods, sizeof(struct ofw_regulator_bus_softc), >>> + simplebus_driver); >>> +static devclass_t ofw_regulator_bus_devclass; >>> +EARLY_DRIVER_MODULE(ofw_regulator_bus, simplebus, >>> ofw_regulator_bus_driver, >>> + ofw_regulator_bus_devclass, 0, 0, BUS_PASS_BUS + >>> BUS_PASS_ORDER_MIDDLE); >>> +MODULE_VERSION(ofw_regulator_bus, 1); >>> diff --git a/freebsd/sys/dev/extres/regulator/regulator_fixed.c >>> b/freebsd/sys/dev/extres/regulator/regulator_fixed.c >>> new file mode 100644 >>> index 00000000..0bc6d96e >>> --- /dev/null >>> +++ b/freebsd/sys/dev/extres/regulator/regulator_fixed.c >>> @@ -0,0 +1,502 @@ >>> +#include <machine/rtems-bsd-kernel-space.h> >>> + >>> +/*- >>> + * Copyright 2016 Michal Meloun <m...@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. >>> + */ >>> + >>> +#include <sys/cdefs.h> >>> +__FBSDID("$FreeBSD$"); >>> + >>> +#include <rtems/bsd/local/opt_platform.h> >>> +#include <sys/param.h> >>> +#include <sys/conf.h> >>> +#include <sys/gpio.h> >>> +#include <sys/kernel.h> >>> +#include <sys/kobj.h> >>> +#include <sys/systm.h> >>> +#include <sys/module.h> >>> +#include <sys/mutex.h> >>> + >>> +#ifdef FDT >>> +#include <dev/fdt/fdt_common.h> >>> +#include <dev/ofw/ofw_bus.h> >>> +#include <dev/ofw/ofw_bus_subr.h> >>> +#endif >>> +#include <dev/gpio/gpiobusvar.h> >>> +#include <dev/extres/regulator/regulator_fixed.h> >>> + >>> +#include <rtems/bsd/local/regdev_if.h> >>> + >>> +MALLOC_DEFINE(M_FIXEDREGULATOR, "fixedregulator", "Fixed >>> regulator"); >>> + >>> +/* GPIO list for shared pins. */ >>> +typedef TAILQ_HEAD(gpio_list, gpio_entry) gpio_list_t; >>> +struct gpio_entry { >>> + TAILQ_ENTRY(gpio_entry) link; >>> + struct gpiobus_pin gpio_pin; >>> + int use_cnt; >>> + int enable_cnt; >>> + bool always_on; >>> +}; >>> +static gpio_list_t gpio_list = TAILQ_HEAD_INITIALIZER(gpio_list); >>> +static struct mtx gpio_list_mtx; >>> +MTX_SYSINIT(gpio_list_lock, &gpio_list_mtx, "Regulator GPIO lock", >>> MTX_DEF); >>> + >>> +struct regnode_fixed_sc { >>> + struct regnode_std_param *param; >>> + bool gpio_open_drain; >>> + struct gpio_entry *gpio_entry; >>> +}; >>> + >>> +static int regnode_fixed_init(struct regnode *regnode); >>> +static int regnode_fixed_enable(struct regnode *regnode, bool enable, >>> + int *udelay); >>> +static int regnode_fixed_status(struct regnode *regnode, int *status); >>> +static int regnode_fixed_stop(struct regnode *regnode, int *udelay); >>> + >>> +static regnode_method_t regnode_fixed_methods[] = { >>> + /* Regulator interface */ >>> + REGNODEMETHOD(regnode_init, regnode_fixed_init), >>> + REGNODEMETHOD(regnode_enable, >>> regnode_fixed_enable), >>> + REGNODEMETHOD(regnode_status, >>> regnode_fixed_status), >>> + REGNODEMETHOD(regnode_stop, regnode_fixed_stop), >>> + REGNODEMETHOD(regnode_check_voltage, >>> regnode_method_check_voltage), >>> + REGNODEMETHOD_END >>> +}; >>> +DEFINE_CLASS_1(regnode_fixed, regnode_fixed_class, >>> regnode_fixed_methods, >>> + sizeof(struct regnode_fixed_sc), regnode_class); >>> + >>> +/* >>> + * GPIO list functions. >>> + * Two or more regulators can share single GPIO pins, so we must track all >>> + * GPIOs in gpio_list. >>> + * The GPIO pin is registerd and reseved for first consumer, all others >>> share >>> + * gpio_entry with it. >>> + */ >>> +static struct gpio_entry * >>> +regnode_get_gpio_entry(struct gpiobus_pin *gpio_pin) >>> +{ >>> + struct gpio_entry *entry, *tmp; >>> + device_t busdev; >>> + int rv; >>> + >>> + busdev = GPIO_GET_BUS(gpio_pin->dev); >>> + if (busdev == NULL) >>> + return (NULL); >>> + entry = malloc(sizeof(struct gpio_entry), M_FIXEDREGULATOR, >>> + M_WAITOK | M_ZERO); >>> + >>> + mtx_lock(&gpio_list_mtx); >>> + >>> + TAILQ_FOREACH(tmp, &gpio_list, link) { >>> + if (tmp->gpio_pin.dev == gpio_pin->dev && >>> + tmp->gpio_pin.pin == gpio_pin->pin) { >>> + tmp->use_cnt++; >>> + mtx_unlock(&gpio_list_mtx); >>> + free(entry, M_FIXEDREGULATOR); >>> + return (tmp); >>> + } >>> + } >>> + >>> + /* Reserve pin. */ >>> + /* XXX Can we call gpiobus_acquire_pin() with gpio_list_mtx held? */ >>> + rv = gpiobus_acquire_pin(busdev, gpio_pin->pin); >>> + if (rv != 0) { >>> + mtx_unlock(&gpio_list_mtx); >>> + free(entry, M_FIXEDREGULATOR); >>> + return (NULL); >>> + } >>> + /* Everything is OK, build new entry and insert it to list. */ >>> + entry->gpio_pin = *gpio_pin; >>> + entry->use_cnt = 1; >>> + TAILQ_INSERT_TAIL(&gpio_list, entry, link); >>> + >>> + mtx_unlock(&gpio_list_mtx); >>> + return (entry); >>> +} >>> + >>> + >>> +/* >>> + * Regulator class implementation. >>> + */ >>> +static int >>> +regnode_fixed_init(struct regnode *regnode) >>> +{ >>> + device_t dev; >>> + struct regnode_fixed_sc *sc; >>> + struct gpiobus_pin *pin; >>> + uint32_t flags; >>> + int rv; >>> + >>> + sc = regnode_get_softc(regnode); >>> + dev = regnode_get_device(regnode); >>> + sc->param = regnode_get_stdparam(regnode); >>> + if (sc->gpio_entry == NULL) >>> + return (0); >>> + pin = &sc->gpio_entry->gpio_pin; >>> + >>> + flags = GPIO_PIN_OUTPUT; >>> + if (sc->gpio_open_drain) >>> + flags |= GPIO_PIN_OPENDRAIN; >>> + if (sc->param->boot_on || sc->param->always_on) { >>> + rv = GPIO_PIN_SET(pin->dev, pin->pin, sc->param- >>>> enable_active_high); >>> + if (rv != 0) { >>> + device_printf(dev, "Cannot set GPIO pin: %d\n", >>> + pin->pin); >>> + return (rv); >>> + } >>> + } >>> + >>> + rv = GPIO_PIN_SETFLAGS(pin->dev, pin->pin, flags); >>> + if (rv != 0) { >>> + device_printf(dev, "Cannot configure GPIO pin: %d\n", pin- >>>> pin); >>> + return (rv); >>> + } >>> + >>> + return (0); >>> +} >>> + >>> +/* >>> + * Enable/disable regulator. >>> + * Take shared GPIO pins in account >>> + */ >>> +static int >>> +regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay) >>> +{ >>> + device_t dev; >>> + struct regnode_fixed_sc *sc; >>> + struct gpiobus_pin *pin; >>> + int rv; >>> + >>> + sc = regnode_get_softc(regnode); >>> + dev = regnode_get_device(regnode); >>> + >>> + *udelay = 0; >>> + if (sc->gpio_entry == NULL) >>> + return (0); >>> + pin = &sc->gpio_entry->gpio_pin; >>> + if (enable) { >>> + sc->gpio_entry->enable_cnt++; >>> + if (sc->gpio_entry->enable_cnt > 1) >>> + return (0); >>> + } else { >>> + KASSERT(sc->gpio_entry->enable_cnt > 0, >>> + ("Invalid enable count")); >>> + sc->gpio_entry->enable_cnt--; >>> + if (sc->gpio_entry->enable_cnt >= 1) >>> + return (0); >>> + } >>> + if (sc->gpio_entry->always_on && !enable) >>> + return (0); >>> + if (!sc->param->enable_active_high) >>> + enable = !enable; >>> + rv = GPIO_PIN_SET(pin->dev, pin->pin, enable); >>> + if (rv != 0) { >>> + device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin); >>> + return (rv); >>> + } >>> + *udelay = sc->param->enable_delay; >>> + return (0); >>> +} >>> + >>> +/* >>> + * Stop (physicaly shutdown) regulator. >>> + * Take shared GPIO pins in account >>> + */ >>> +static int >>> +regnode_fixed_stop(struct regnode *regnode, int *udelay) >>> +{ >>> + device_t dev; >>> + struct regnode_fixed_sc *sc; >>> + struct gpiobus_pin *pin; >>> + int rv; >>> + >>> + sc = regnode_get_softc(regnode); >>> + dev = regnode_get_device(regnode); >>> + >>> + *udelay = 0; >>> + if (sc->gpio_entry == NULL) >>> + return (0); >>> + if (sc->gpio_entry->always_on) >>> + return (0); >>> + pin = &sc->gpio_entry->gpio_pin; >>> + if (sc->gpio_entry->enable_cnt > 0) { >>> + /* Other regulator(s) are enabled. */ >>> + /* XXXX Any diagnostic message? Or error? */ >>> + return (0); >>> + } >>> + rv = GPIO_PIN_SET(pin->dev, pin->pin, >>> + sc->param->enable_active_high ? false: true); >>> + if (rv != 0) { >>> + device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin); >>> + return (rv); >>> + } >>> + *udelay = sc->param->enable_delay; >>> + return (0); >>> +} >>> + >>> +static int >>> +regnode_fixed_status(struct regnode *regnode, int *status) >>> +{ >>> + struct regnode_fixed_sc *sc; >>> + struct gpiobus_pin *pin; >>> + uint32_t val; >>> + int rv; >>> + >>> + sc = regnode_get_softc(regnode); >>> + >>> + *status = 0; >>> + if (sc->gpio_entry == NULL) { >>> + *status = REGULATOR_STATUS_ENABLED; >>> + return (0); >>> + } >>> + pin = &sc->gpio_entry->gpio_pin; >>> + >>> + rv = GPIO_PIN_GET(pin->dev, pin->pin, &val); >>> + if (rv == 0) { >>> + if (!sc->param->enable_active_high ^ (val != 0)) >>> + *status = REGULATOR_STATUS_ENABLED; >>> + } >>> + return (rv); >>> +} >>> + >>> +int >>> +regnode_fixed_register(device_t dev, struct regnode_fixed_init_def >>> *init_def) >>> +{ >>> + struct regnode *regnode; >>> + struct regnode_fixed_sc *sc; >>> + >>> + regnode = regnode_create(dev, ®node_fixed_class, >>> + &init_def->reg_init_def); >>> + if (regnode == NULL) { >>> + device_printf(dev, "Cannot create regulator.\n"); >>> + return(ENXIO); >>> + } >>> + sc = regnode_get_softc(regnode); >>> + sc->gpio_open_drain = init_def->gpio_open_drain; >>> + if (init_def->gpio_pin != NULL) { >>> + sc->gpio_entry = regnode_get_gpio_entry(init_def- >>>> gpio_pin); >>> + if (sc->gpio_entry == NULL) >>> + return(ENXIO); >>> + } >>> + regnode = regnode_register(regnode); >>> + if (regnode == NULL) { >>> + device_printf(dev, "Cannot register regulator.\n"); >>> + return(ENXIO); >>> + } >>> + >>> + if (sc->gpio_entry != NULL) >>> + sc->gpio_entry->always_on |= sc->param->always_on; >>> + >>> + return (0); >>> +} >>> + >>> +/* >>> + * OFW Driver implementation. >>> + */ >>> +#ifdef FDT >>> + >>> +struct regfix_softc >>> +{ >>> + device_t dev; >>> + bool attach_done; >>> + struct regnode_fixed_init_def init_def; >>> + phandle_t gpio_prodxref; >>> + pcell_t *gpio_cells; >>> + int gpio_ncells; >>> + struct gpiobus_pin gpio_pin; >>> +}; >>> + >>> +static struct ofw_compat_data compat_data[] = { >>> + {"regulator-fixed", 1}, >>> + {NULL, 0}, >>> +}; >>> + >>> +static int >>> +regfix_get_gpio(struct regfix_softc * sc) >>> +{ >>> + device_t busdev; >>> + phandle_t node; >>> + >>> + int rv; >>> + >>> + if (sc->gpio_prodxref == 0) >>> + return (0); >>> + >>> + node = ofw_bus_get_node(sc->dev); >>> + >>> + /* Test if controller exist. */ >>> + sc->gpio_pin.dev = OF_device_from_xref(sc->gpio_prodxref); >>> + if (sc->gpio_pin.dev == NULL) >>> + return (ENODEV); >>> + >>> + /* Test if GPIO bus already exist. */ >>> + busdev = GPIO_GET_BUS(sc->gpio_pin.dev); >>> + if (busdev == NULL) >>> + return (ENODEV); >>> + >>> + rv = gpio_map_gpios(sc->gpio_pin.dev, node, >>> + OF_node_from_xref(sc->gpio_prodxref), sc->gpio_ncells, >>> + sc->gpio_cells, &(sc->gpio_pin.pin), &(sc->gpio_pin.flags)); >>> + if (rv != 0) { >>> + device_printf(sc->dev, "Cannot map the gpio property.\n"); >>> + return (ENXIO); >>> + } >>> + sc->init_def.gpio_pin = &sc->gpio_pin; >>> + return (0); >>> +} >>> + >>> +static int >>> +regfix_parse_fdt(struct regfix_softc * sc) >>> +{ >>> + phandle_t node; >>> + int rv; >>> + struct regnode_init_def *init_def; >>> + >>> + node = ofw_bus_get_node(sc->dev); >>> + init_def = &sc->init_def.reg_init_def; >>> + >>> + rv = regulator_parse_ofw_stdparam(sc->dev, node, init_def); >>> + if (rv != 0) { >>> + device_printf(sc->dev, "Cannot parse standard >>> parameters.\n"); >>> + return(rv); >>> + } >>> + >>> + /* Fixed regulator uses 'startup-delay-us' property for enable_delay >>> */ >>> + rv = OF_getencprop(node, "startup-delay-us", >>> + &init_def->std_param.enable_delay, >>> + sizeof(init_def->std_param.enable_delay)); >>> + if (rv <= 0) >>> + init_def->std_param.enable_delay = 0; >>> + /* GPIO pin */ >>> + if (OF_hasprop(node, "gpio-open-drain")) >>> + sc->init_def.gpio_open_drain = true; >>> + >>> + if (!OF_hasprop(node, "gpio")) >>> + return (0); >>> + rv = ofw_bus_parse_xref_list_alloc(node, "gpio", "#gpio-cells", 0, >>> + &sc->gpio_prodxref, &sc->gpio_ncells, &sc->gpio_cells); >>> + if (rv != 0) { >>> + sc->gpio_prodxref = 0; >>> + device_printf(sc->dev, "Malformed gpio property\n"); >>> + return (ENXIO); >>> + } >>> + return (0); >>> +} >>> + >>> +static void >>> +regfix_new_pass(device_t dev) >>> +{ >>> + struct regfix_softc * sc; >>> + int rv; >>> + >>> + sc = device_get_softc(dev); >>> + bus_generic_new_pass(dev); >>> + >>> + if (sc->attach_done) >>> + return; >>> + >>> + /* Try to get and configure GPIO. */ >>> + rv = regfix_get_gpio(sc); >>> + if (rv != 0) >>> + return; >>> + >>> + /* Register regulator. */ >>> + regnode_fixed_register(sc->dev, &sc->init_def); >>> + sc->attach_done = true; >>> +} >>> + >>> +static int >>> +regfix_probe(device_t dev) >>> +{ >>> + >>> + if (!ofw_bus_status_okay(dev)) >>> + return (ENXIO); >>> + >>> + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) >>> + return (ENXIO); >>> + >>> + device_set_desc(dev, "Fixed Regulator"); >>> + return (BUS_PROBE_DEFAULT); >>> +} >>> + >>> +static int >>> +regfix_detach(device_t dev) >>> +{ >>> + >>> + /* This device is always present. */ >>> + return (EBUSY); >>> +} >>> + >>> +static int >>> +regfix_attach(device_t dev) >>> +{ >>> + struct regfix_softc * sc; >>> + int rv; >>> + >>> + sc = device_get_softc(dev); >>> + sc->dev = dev; >>> + >>> + /* Parse FDT data. */ >>> + rv = regfix_parse_fdt(sc); >>> + if (rv != 0) >>> + return(ENXIO); >>> + >>> + /* Fill reset of init. */ >>> + sc->init_def.reg_init_def.id = 1; >>> + sc->init_def.reg_init_def.flags = REGULATOR_FLAGS_STATIC; >>> + >>> + /* Try to get and configure GPIO. */ >>> + rv = regfix_get_gpio(sc); >>> + if (rv != 0) >>> + return (bus_generic_attach(dev)); >>> + >>> + /* Register regulator. */ >>> + regnode_fixed_register(sc->dev, &sc->init_def); >>> + sc->attach_done = true; >>> + >>> + return (bus_generic_attach(dev)); >>> +} >>> + >>> +static device_method_t regfix_methods[] = { >>> + /* Device interface */ >>> + DEVMETHOD(device_probe, regfix_probe), >>> + DEVMETHOD(device_attach, regfix_attach), >>> + DEVMETHOD(device_detach, regfix_detach), >>> + /* Bus interface */ >>> + DEVMETHOD(bus_new_pass, regfix_new_pass), >>> + /* Regdev interface */ >>> + DEVMETHOD(regdev_map, regdev_default_ofw_map), >>> + >>> + DEVMETHOD_END >>> +}; >>> + >>> +static devclass_t regfix_devclass; >>> +DEFINE_CLASS_0(regfix, regfix_driver, regfix_methods, >>> + sizeof(struct regfix_softc)); >>> +EARLY_DRIVER_MODULE(regfix, simplebus, regfix_driver, >>> + regfix_devclass, 0, 0, BUS_PASS_BUS); >>> + >>> +#endif /* FDT */ >>> diff --git a/freebsd/sys/dev/extres/regulator/regulator_fixed.h >>> b/freebsd/sys/dev/extres/regulator/regulator_fixed.h >>> new file mode 100644 >>> index 00000000..5cc07516 >>> --- /dev/null >>> +++ b/freebsd/sys/dev/extres/regulator/regulator_fixed.h >>> @@ -0,0 +1,44 @@ >>> +/*- >>> + * Copyright 2016 Michal Meloun <m...@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$ >>> + */ >>> + >>> +#ifndef _DEV_EXTRES_REGULATOR_FIXED_H_ >>> +#define _DEV_EXTRES_REGULATOR_FIXED_H_ >>> + >>> +#include <dev/gpio/gpiobusvar.h> >>> +#include <dev/extres/regulator/regulator.h> >>> + >>> +struct regnode_fixed_init_def { >>> + struct regnode_init_def reg_init_def; >>> + bool gpio_open_drain; >>> + struct gpiobus_pin *gpio_pin; >>> +}; >>> + >>> +int regnode_fixed_register(device_t dev, >>> + struct regnode_fixed_init_def *init_def); >>> + >>> +#endif /*_DEV_EXTRES_REGULATOR_FIXED_H_*/ >>> diff --git a/freebsd/sys/dev/gpio/gpioregulator.c >>> b/freebsd/sys/dev/gpio/gpioregulator.c >>> new file mode 100644 >>> index 00000000..6d05e52e >>> --- /dev/null >>> +++ b/freebsd/sys/dev/gpio/gpioregulator.c >>> @@ -0,0 +1,350 @@ >>> +#include <machine/rtems-bsd-kernel-space.h> >>> + >>> +/*- >>> + * Copyright (c) 2016 Jared McNeill <jmcne...@invisible.ca> >>> + * 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$ >>> + */ >>> + >>> +/* >>> + * GPIO controlled regulators >>> + */ >>> + >>> +#include <sys/cdefs.h> >>> +__FBSDID("$FreeBSD$"); >>> + >>> +#include <sys/param.h> >>> +#include <sys/systm.h> >>> +#include <sys/bus.h> >>> +#include <sys/rman.h> >>> +#include <sys/kernel.h> >>> +#include <sys/module.h> >>> +#include <sys/gpio.h> >>> + >>> +#include <dev/ofw/ofw_bus.h> >>> +#include <dev/ofw/ofw_bus_subr.h> >>> + >>> +#include <dev/gpio/gpiobusvar.h> >>> + >>> +#include <dev/extres/regulator/regulator.h> >>> + >>> +#include <rtems/bsd/local/regdev_if.h> >>> + >>> +struct gpioregulator_state { >>> + int val; >>> + uint32_t mask; >>> +}; >>> + >>> +struct gpioregulator_init_def { >>> + struct regnode_init_def reg_init_def; >>> + struct gpiobus_pin *enable_pin; >>> + int enable_pin_valid; >>> + int startup_delay_us; >>> + int nstates; >>> + struct gpioregulator_state *states; >>> + int npins; >>> + struct gpiobus_pin **pins; >>> +}; >>> + >>> +struct gpioregulator_reg_sc { >>> + struct regnode *regnode; >>> + device_t base_dev; >>> + struct regnode_std_param *param; >>> + struct gpioregulator_init_def *def; >>> +}; >>> + >>> +struct gpioregulator_softc { >>> + device_t dev; >>> + struct gpioregulator_reg_sc *reg_sc; >>> + struct gpioregulator_init_def init_def; >>> +}; >>> + >>> +static int >>> +gpioregulator_regnode_init(struct regnode *regnode) >>> +{ >>> + struct gpioregulator_reg_sc *sc; >>> + int error, n; >>> + >>> + sc = regnode_get_softc(regnode); >>> + >>> + if (sc->def->enable_pin_valid == 1) { >>> + error = gpio_pin_setflags(sc->def->enable_pin, >>> GPIO_PIN_OUTPUT); >>> + if (error != 0) >>> + return (error); >>> + } >>> + >>> + for (n = 0; n < sc->def->npins; n++) { >>> + error = gpio_pin_setflags(sc->def->pins[n], >>> GPIO_PIN_OUTPUT); >>> + if (error != 0) >>> + return (error); >>> + } >>> + >>> + return (0); >>> +} >>> + >>> +static int >>> +gpioregulator_regnode_enable(struct regnode *regnode, bool enable, int >>> *udelay) >>> +{ >>> + struct gpioregulator_reg_sc *sc; >>> + bool active; >>> + int error; >>> + >>> + sc = regnode_get_softc(regnode); >>> + >>> + if (sc->def->enable_pin_valid == 1) { >>> + active = enable; >>> + if (!sc->param->enable_active_high) >>> + active = !active; >>> + error = gpio_pin_set_active(sc->def->enable_pin, active); >>> + if (error != 0) >>> + return (error); >>> + } >>> + >>> + *udelay = sc->def->startup_delay_us; >>> + >>> + return (0); >>> +} >>> + >>> +static int >>> +gpioregulator_regnode_set_voltage(struct regnode *regnode, int >>> min_uvolt, >>> + int max_uvolt, int *udelay) >>> +{ >>> + struct gpioregulator_reg_sc *sc; >>> + const struct gpioregulator_state *state; >>> + int error, n; >>> + >>> + sc = regnode_get_softc(regnode); >>> + state = NULL; >>> + >>> + for (n = 0; n < sc->def->nstates; n++) { >>> + if (sc->def->states[n].val >= min_uvolt && >>> + sc->def->states[n].val <= max_uvolt) { >>> + state = &sc->def->states[n]; >>> + break; >>> + } >>> + } >>> + if (state == NULL) >>> + return (EINVAL); >>> + >>> + for (n = 0; n < sc->def->npins; n++) { >>> + error = gpio_pin_set_active(sc->def->pins[n], >>> + (state->mask >> n) & 1); >>> + if (error != 0) >>> + return (error); >>> + } >>> + >>> + *udelay = sc->def->startup_delay_us; >>> + >>> + return (0); >>> +} >>> + >>> +static int >>> +gpioregulator_regnode_get_voltage(struct regnode *regnode, int *uvolt) >>> +{ >>> + struct gpioregulator_reg_sc *sc; >>> + uint32_t mask; >>> + int error, n; >>> + bool active; >>> + >>> + sc = regnode_get_softc(regnode); >>> + mask = 0; >>> + >>> + for (n = 0; n < sc->def->npins; n++) { >>> + error = gpio_pin_is_active(sc->def->pins[n], &active); >>> + if (error != 0) >>> + return (error); >>> + mask |= (active << n); >>> + } >>> + >>> + for (n = 0; n < sc->def->nstates; n++) { >>> + if (sc->def->states[n].mask == mask) { >>> + *uvolt = sc->def->states[n].val; >>> + return (0); >>> + } >>> + } >>> + >>> + return (EIO); >>> +} >>> + >>> +static regnode_method_t gpioregulator_regnode_methods[] = { >>> + /* Regulator interface */ >>> + REGNODEMETHOD(regnode_init, gpioregulator_regnode_init), >>> + REGNODEMETHOD(regnode_enable, >>> gpioregulator_regnode_enable), >>> + REGNODEMETHOD(regnode_set_voltage, >>> gpioregulator_regnode_set_voltage), >>> + REGNODEMETHOD(regnode_get_voltage, >>> gpioregulator_regnode_get_voltage), >>> + REGNODEMETHOD_END >>> +}; >>> +DEFINE_CLASS_1(gpioregulator_regnode, gpioregulator_regnode_class, >>> + gpioregulator_regnode_methods, sizeof(struct gpioregulator_reg_sc), >>> + regnode_class); >>> + >>> +static int >>> +gpioregulator_parse_fdt(struct gpioregulator_softc *sc) >>> +{ >>> + uint32_t *pstates, mask; >>> + phandle_t node; >>> + ssize_t len; >>> + int error, n; >>> + >>> + node = ofw_bus_get_node(sc->dev); >>> + pstates = NULL; >>> + mask = 0; >>> + >>> + error = regulator_parse_ofw_stdparam(sc->dev, node, >>> + &sc->init_def.reg_init_def); >>> + if (error != 0) >>> + return (error); >>> + >>> + /* "states" property (required) */ >>> + len = OF_getencprop_alloc_multi(node, "states", sizeof(*pstates), >>> + (void **)&pstates); >>> + if (len < 2) { >>> + device_printf(sc->dev, "invalid 'states' property\n"); >>> + error = EINVAL; >>> + goto done; >>> + } >>> + sc->init_def.nstates = len / 2; >>> + sc->init_def.states = malloc(sc->init_def.nstates * >>> + sizeof(*sc->init_def.states), M_DEVBUF, M_WAITOK); >>> + for (n = 0; n < sc->init_def.nstates; n++) { >>> + sc->init_def.states[n].val = pstates[n * 2 + 0]; >>> + sc->init_def.states[n].mask = pstates[n * 2 + 1]; >>> + mask |= sc->init_def.states[n].mask; >>> + } >>> + >>> + /* "startup-delay-us" property (optional) */ >>> + len = OF_getencprop(node, "startup-delay-us", >>> + &sc->init_def.startup_delay_us, >>> + sizeof(sc->init_def.startup_delay_us)); >>> + if (len <= 0) >>> + sc->init_def.startup_delay_us = 0; >>> + >>> + /* "enable-gpio" property (optional) */ >>> + error = gpio_pin_get_by_ofw_property(sc->dev, node, "enable- >>> gpio", >>> + &sc->init_def.enable_pin); >>> + if (error == 0) >>> + sc->init_def.enable_pin_valid = 1; >>> + >>> + /* "gpios" property */ >>> + sc->init_def.npins = 32 - __builtin_clz(mask); >>> + sc->init_def.pins = malloc(sc->init_def.npins * >>> + sizeof(sc->init_def.pins), M_DEVBUF, M_WAITOK); >>> + for (n = 0; n < sc->init_def.npins; n++) { >>> + error = gpio_pin_get_by_ofw_idx(sc->dev, node, n, >>> + &sc->init_def.pins[n]); >>> + if (error != 0) { >>> + device_printf(sc->dev, "cannot get pin %d\n", n); >>> + goto done; >>> + } >>> + } >>> + >>> +done: >>> + if (error != 0) { >>> + for (n = 0; n < sc->init_def.npins; n++) { >>> + if (sc->init_def.pins[n] != NULL) >>> + gpio_pin_release(sc->init_def.pins[n]); >>> + } >>> + >>> + free(sc->init_def.states, M_DEVBUF); >>> + free(sc->init_def.pins, M_DEVBUF); >>> + >>> + } >>> + OF_prop_free(pstates); >>> + >>> + return (error); >>> +} >>> + >>> +static int >>> +gpioregulator_probe(device_t dev) >>> +{ >>> + >>> + if (!ofw_bus_is_compatible(dev, "regulator-gpio")) >>> + return (ENXIO); >>> + >>> + device_set_desc(dev, "GPIO controlled regulator"); >>> + return (BUS_PROBE_GENERIC); >>> +} >>> + >>> +static int >>> +gpioregulator_attach(device_t dev) >>> +{ >>> + struct gpioregulator_softc *sc; >>> + struct regnode *regnode; >>> + phandle_t node; >>> + int error; >>> + >>> + sc = device_get_softc(dev); >>> + sc->dev = dev; >>> + node = ofw_bus_get_node(dev); >>> + >>> + error = gpioregulator_parse_fdt(sc); >>> + if (error != 0) { >>> + device_printf(dev, "cannot parse parameters\n"); >>> + return (ENXIO); >>> + } >>> + sc->init_def.reg_init_def.id = 1; >>> + sc->init_def.reg_init_def.ofw_node = node; >>> + >>> + regnode = regnode_create(dev, &gpioregulator_regnode_class, >>> + &sc->init_def.reg_init_def); >>> + if (regnode == NULL) { >>> + device_printf(dev, "cannot create regulator\n"); >>> + return (ENXIO); >>> + } >>> + >>> + sc->reg_sc = regnode_get_softc(regnode); >>> + sc->reg_sc->regnode = regnode; >>> + sc->reg_sc->base_dev = dev; >>> + sc->reg_sc->param = regnode_get_stdparam(regnode); >>> + sc->reg_sc->def = &sc->init_def; >>> + >>> + regnode_register(regnode); >>> + >>> + return (0); >>> +} >>> + >>> + >>> +static device_method_t gpioregulator_methods[] = { >>> + /* Device interface */ >>> + DEVMETHOD(device_probe, gpioregulator_probe), >>> + DEVMETHOD(device_attach, gpioregulator_attach), >>> + >>> + /* Regdev interface */ >>> + DEVMETHOD(regdev_map, regdev_default_ofw_map), >>> + >>> + DEVMETHOD_END >>> +}; >>> + >>> +static driver_t gpioregulator_driver = { >>> + "gpioregulator", >>> + gpioregulator_methods, >>> + sizeof(struct gpioregulator_softc), >>> +}; >>> + >>> +static devclass_t gpioregulator_devclass; >>> + >>> +EARLY_DRIVER_MODULE(gpioregulator, simplebus, gpioregulator_driver, >>> + gpioregulator_devclass, 0, 0, BUS_PASS_INTERRUPT + >>> BUS_PASS_ORDER_LAST); >>> +MODULE_VERSION(gpioregulator, 1); >>> -- >>> 2.16.4 >>> >>> _______________________________________________ >>> devel mailing list >>> devel@rtems.org >>> http://lists.rtems.org/mailman/listinfo/devel > -- -------------------------------------------- embedded brains GmbH Herr Christian Mauderer Dornierstr. 4 D-82178 Puchheim Germany email: christian.maude...@embedded-brains.de Phone: +49-89-18 94 741 - 18 Fax: +49-89-18 94 741 - 08 PGP: Public key available on request. Diese Nachricht ist keine geschäftliche Mitteilung im Sinne des EHUG. _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel