Signed-off-by: Haojian Zhuang <haojian.zhu...@marvell.com> --- drivers/of/Kconfig | 4 + drivers/of/Makefile | 1 + drivers/of/of_regulator.c | 166 ++++++++++++++++++++++++++++++++++++++++++ include/linux/of_regulator.h | 34 +++++++++ 4 files changed, 205 insertions(+), 0 deletions(-) create mode 100644 drivers/of/of_regulator.c create mode 100644 include/linux/of_regulator.h
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index d06a637..edb6601 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -75,4 +75,8 @@ config OF_PCI help OpenFirmware PCI bus accessors +config OF_REGULATOR + def_tristate REGULATOR + depends on REGULATOR + endmenu # OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile index f7861ed..83ca06f 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_NET) += of_net.o obj-$(CONFIG_OF_SPI) += of_spi.o obj-$(CONFIG_OF_MDIO) += of_mdio.o obj-$(CONFIG_OF_PCI) += of_pci.o +obj-$(CONFIG_OF_REGULATOR) += of_regulator.o diff --git a/drivers/of/of_regulator.c b/drivers/of/of_regulator.c new file mode 100644 index 0000000..d523302 --- /dev/null +++ b/drivers/of/of_regulator.c @@ -0,0 +1,166 @@ +/* + * OF helpers for the Regulator API + * + * Copyright (c) 2011 Haojian Zhuang <haojian.zhu...@marvell.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/regulator/machine.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/suspend.h> + +static int of_regulator_init_constraints(struct device_node *of_dev, + struct regulation_constraints *constraints) +{ + const __be32 *p; + const char *cp; + const char *ops[] = {"voltage", "current", "mode", "status", + "drms"}; + int i, size, len = 0, tmp = 0; + + memset(constraints, 0, sizeof(struct regulation_constraints)); + + p = of_get_property(of_dev, "voltages", &size); + if (p && size / sizeof(int) == 2) { + constraints->min_uV = be32_to_cpu(*p++); + constraints->max_uV = be32_to_cpu(*p); + } + p = of_get_property(of_dev, "currents", &size); + if (p && size / sizeof(int) == 2) { + constraints->min_uA = be32_to_cpu(*p++); + constraints->max_uA = be32_to_cpu(*p); + } + p = of_get_property(of_dev, "modes-mask", NULL); + if (p) + constraints->valid_modes_mask = be32_to_cpu(*p); + cp = of_get_property(of_dev, "ops-mask", &size); + tmp = 0; + if (cp && size > 0) { + i = 0; + do { + len = strlen(ops[i]); + if (!strncmp(cp, ops[i], len)) { + constraints->valid_ops_mask |= 1 << i; + /* need to handle '\0' */ + cp += len + 1; + size = size - len - 1; + i = 0; + } else + i++; + } while (i < ARRAY_SIZE(ops)); + if (size > 0) + printk(KERN_WARNING "Invalid string:%s\n", cp); + } + p = of_get_property(of_dev, "input-uV", NULL); + if (p) + constraints->input_uV = be32_to_cpu(*p); + p = of_get_property(of_dev, "state-pm-disk", &size); + if (p && size / sizeof(int) == 3) { + constraints->state_disk.uV = be32_to_cpu(*p++); + constraints->state_disk.mode = be32_to_cpu(*p++); + tmp = be32_to_cpu(*p); + constraints->state_disk.enabled = (tmp) ? 1 : 0; + constraints->state_disk.disabled = (tmp) ? 0 : 1; + } + p = of_get_property(of_dev, "state-pm-mem", &size); + if (p && size / sizeof(int) == 3) { + constraints->state_mem.uV = be32_to_cpu(*p++); + constraints->state_mem.mode = be32_to_cpu(*p++); + tmp = be32_to_cpu(*p); + constraints->state_mem.enabled = (tmp) ? 1 : 0; + constraints->state_mem.disabled = (tmp) ? 0 : 1; + } + p = of_get_property(of_dev, "state-pm-standby", &size); + if (p && size / sizeof(int) == 3) { + constraints->state_standby.uV = be32_to_cpu(*p++); + constraints->state_standby.mode = be32_to_cpu(*p++); + tmp = be32_to_cpu(*p); + constraints->state_standby.enabled = (tmp) ? 1 : 0; + constraints->state_standby.disabled = (tmp) ? 0 : 1; + } + cp = of_get_property(of_dev, "initial-state", &size); + if (cp) { + if (!strncmp(cp, "pm-suspend-on", size)) + constraints->initial_state = PM_SUSPEND_ON; + if (!strncmp(cp, "pm-suspend-mem", size)) + constraints->initial_state = PM_SUSPEND_MEM; + if (!strncmp(cp, "pm-suspend-standby", size)) + constraints->initial_state = PM_SUSPEND_STANDBY; + } + p = of_get_property(of_dev, "initial_mode", NULL); + if (p) + constraints->initial_mode = be32_to_cpu(*p); + p = of_get_property(of_dev, "always-on", NULL); + if (p) + constraints->always_on = 1; + p = of_get_property(of_dev, "boot-on", NULL); + if (p) + constraints->boot_on = 1; + p = of_get_property(of_dev, "apply-uV", NULL); + if (p) + constraints->apply_uV = 1; + return 0; +} + +int of_regulator_init_data(struct device_node *of_dev, + struct regulator_init_data *data) +{ + struct regulator_consumer_supply *supply; + const char *p, *str; + int ret, i, size, calc_size, len, count = 0; + + if (of_dev == NULL || data == NULL) + return -EINVAL; + + p = of_get_property(of_dev, "device_type", &size); + if (p == NULL || strncmp(p, "regulator", size)) + return -EINVAL; + + ret = of_regulator_init_constraints(of_dev, &data->constraints); + if (ret) + return ret; + p = of_get_property(of_dev, "supply-name", &size); + str = p; + calc_size = size; + while (str && calc_size > 0) { + len = strlen(str); + if (len == 0) + break; + calc_size = calc_size - len - 1; + str += len + 1; + count++; + } + if (count == 0) + return -EINVAL; + + supply = kzalloc(sizeof(struct regulator_consumer_supply) * count, + GFP_KERNEL); + if (supply == NULL) + return -EINVAL; + str = p; + calc_size = size; + i = 0; + while (str && calc_size > 0 && i < count) { + len = strlen(str); + if (len == 0) + break; + supply[i++].supply = str; + calc_size = calc_size - len - 1; + str += len + 1; + } + data->consumer_supplies = supply; + data->num_consumer_supplies = count; + return 0; +} + +void of_regulator_deinit_data(struct regulator_init_data *data) +{ + if (data && data->consumer_supplies) + kfree(data->consumer_supplies); +} diff --git a/include/linux/of_regulator.h b/include/linux/of_regulator.h new file mode 100644 index 0000000..0155bd8 --- /dev/null +++ b/include/linux/of_regulator.h @@ -0,0 +1,34 @@ +/* + * Generic Regulator API implementation + * + * Copyright (c) 2011 Haojian Zhuang <haojian.zhu...@marvell.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __LINUX_OF_REGULATOR_H +#define __LINUX_OF_REGULATOR_H + +#if defined(CONFIG_OF_REGULATOR) || defined(CONFIG_OF_REGULATOR_MODULE) +#include <linux/regulator/machine.h> + +extern int of_regulator_init_data(struct device_node *of_node, + struct regulator_init_data *data); +extern void of_regulator_deinit_data(struct regulator_init_data *data); + +#else +static inline int of_regulator_init_data(struct device_node *of_node, + struct regulator_init_data *data) +{ + return 0; +} + +static inline void of_regulator_deinit_data(struct regulator_init_data *data) +{ +} +#endif /* CONFIG_OF_REGULATOR */ + +#endif /* __LINUX_OF_REGULATOR_H */ -- 1.5.6.5 _______________________________________________ devicetree-discuss mailing list devicetree-discuss@lists.ozlabs.org https://lists.ozlabs.org/listinfo/devicetree-discuss