diff options
author | Guodong Xu <guodong.xu@linaro.org> | 2013-01-28 11:31:17 +0800 |
---|---|---|
committer | Guodong Xu <guodong.xu@linaro.org> | 2013-02-21 16:12:30 +0800 |
commit | 9e40b6373b27460f5372905dee685941ea0309be (patch) | |
tree | cf8d57a0f8310cbdb6f1d992e73b133742dfdad5 | |
parent | 3cba44e58a5ae4ca2d338695925a8166244ae324 (diff) |
regulator: hi6421 driver for each regulator
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | arch/arm/boot/dts/hi4511.dts | 102 | ||||
-rw-r--r-- | drivers/regulator/Kconfig | 6 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/hi6421-regulator.c | 478 | ||||
-rw-r--r-- | drivers/regulator/of_regulator.c | 3 |
6 files changed, 562 insertions, 31 deletions
diff --git a/.gitignore b/.gitignore index 3b8b9b33be38..42315353f3ea 100644 --- a/.gitignore +++ b/.gitignore @@ -91,3 +91,6 @@ extra_certificates signing_key.priv signing_key.x509 x509.genkey + +# ctags index +TAGS diff --git a/arch/arm/boot/dts/hi4511.dts b/arch/arm/boot/dts/hi4511.dts index f5fe4538a7b6..c3f1b98cdb48 100644 --- a/arch/arm/boot/dts/hi4511.dts +++ b/arch/arm/boot/dts/hi4511.dts @@ -831,21 +831,38 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO0"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x20 0x10 0x20>; hisilicon,hi6421-vset = <0x20 0x07>; + hisilicon,hi6421-n-voltages = <8>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, <2400000>, <2500000>, <2600000>, <2700000>, <2850000>, <3000000>; + hisilicon,hi6421-off-on-delay-us = <10000>; + hisilicon,hi6421-enable-time-us = <250>; }; + +static const u32 on_off_delay_us[NUM_OF_HI6421_REGULATOR] = { + 10000, 10000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 40000, 40000, /* LDO0 ~ 10 */ + 40000, 40000,40000, 40000,40000, 40000,40000, 40000,40000, 40000, 40000, /* LDO_11 ~ LDO20 ,LDO_AUDIO */ + 20000, 20000, 100, 20000, 20000, 20000 /* BUCK0 ~ 5*/ +}; + +static const u32 on_enable_delay_us[NUM_OF_HI6421_REGULATOR] = { + 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, /* LDO0 ~ 10 */ + 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, /* LDO_11 ~ LDO20 ,LDO_AUDIO */ + 300, 300, 250, 250, 250, 250 /* BUCK0 ~ 5*/ +}; + + ldo1: ldo@21 { compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO1"; regulator-min-microvolt = <1700000>; - regulatro-max-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x21 0x10 0x20>; hisilicon,hi6421-vset = <0x21 0x03>; @@ -857,7 +874,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO2"; regulator-min-microvolt = <1050000>; - regulatro-max-microvolt = <1400000>; + regulator-max-microvolt = <1400000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x22 0x10 0x20>; hisilicon,hi6421-vset = <0x22 0x07>; @@ -871,7 +888,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO3"; regulator-min-microvolt = <1050000>; - regulatro-max-microvolt = <1400000>; + regulator-max-microvolt = <1400000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x23 0x10 0x20>; hisilicon,hi6421-vset = <0x23 0x07>; @@ -885,7 +902,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO4"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x24 0x10 0x20>; hisilicon,hi6421-vset = <0x24 0x07>; @@ -899,7 +916,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO5"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x25 0x10 0x20>; hisilicon,hi6421-vset = <0x25 0x07>; @@ -913,7 +930,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO6"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x26 0x10 0x20>; hisilicon,hi6421-vset = <0x26 0x07>; @@ -927,7 +944,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO7"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x27 0x10 0x20>; hisilicon,hi6421-vset = <0x27 0x07>; @@ -941,7 +958,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO8"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x28 0x10 0x20>; hisilicon,hi6421-vset = <0x28 0x07>; @@ -955,7 +972,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO9"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x29 0x10 0x20>; hisilicon,hi6421-vset = <0x29 0x07>; @@ -969,7 +986,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO10"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x2a 0x10 0x20>; hisilicon,hi6421-vset = <0x2a 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -982,7 +999,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO11"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x2b 0x10 0x20>; hisilicon,hi6421-vset = <0x2b 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -995,7 +1012,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO12"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x2c 0x10 0x20>; hisilicon,hi6421-vset = <0x2c 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -1008,7 +1025,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO13"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x2d 0x10 0x20>; hisilicon,hi6421-vset = <0x2d 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -1021,7 +1038,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO14"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x2e 0x10 0x20>; hisilicon,hi6421-vset = <0x2e 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -1034,7 +1051,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO15"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x2f 0x10 0x20>; hisilicon,hi6421-vset = <0x2f 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -1047,7 +1064,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO16"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x30 0x10 0x20>; hisilicon,hi6421-vset = <0x30 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -1060,7 +1077,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO17"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x31 0x10 0x20>; hisilicon,hi6421-vset = <0x31 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -1073,7 +1090,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO18"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x32 0x10 0x20>; hisilicon,hi6421-vset = <0x32 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -1086,7 +1103,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO19"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x2a 0x10 0x20>; hisilicon,hi6421-vset = <0x2a 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -1099,7 +1116,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDO20"; regulator-min-microvolt = <1500000>; - regulatro-max-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; hisilicon,hi6421-ctrl = <0x34 0x10 0x20>; hisilicon,hi6421-vset = <0x34 0x07>; hisilicon,hi6421-vset-table = <1500000>, <1800000>, @@ -1112,7 +1129,7 @@ compatible = "hisilicon,hi6421-ldo"; regulator-name = "LDOAUDIO"; regulator-min-microvolt = <2800000>; - regulatro-max-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; hisilicon,hi6421-ctrl = <0x36 0x01 0x02>; hisilicon,hi6421-vset = <0x36 0x70>; hisilicon,hi6421-vset-table = <2800000>, <2850000>, @@ -1121,46 +1138,69 @@ <3200000>, <3300000>; }; + + +static const u32 on_off_delay_us[NUM_OF_HI6421_REGULATOR] = { + 10000, 10000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 40000, 40000, /* LDO0 ~ 10 */ + 40000, 40000,40000, 40000,40000, 40000,40000, 40000,40000, 40000, 40000, /* LDO_11 ~ LDO20 ,LDO_AUDIO */ + 20000, 20000, 100, 20000, 20000, 20000 /* BUCK0 ~ 5*/ +}; + +static const u32 on_enable_delay_us[NUM_OF_HI6421_REGULATOR] = { + 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, /* LDO0 ~ 10 */ + 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, /* LDO_11 ~ LDO20 ,LDO_AUDIO */ + 300, 300, 250, 250, 250, 250 /* BUCK0 ~ 5*/ +}; + buck0: buck@0c { compatible = "hisilicon,hi6421-buck012"; regulator-name = "BUCK0"; regulator-min-microvolt = <700000>; - regulatro-max-microvolt = <1600000>; + regulator-max-microvolt = <1600000>; regulator-boot-on; regulator-always-on; hisilicon,hi6421-ctrl = <0x0c 0x01 0x10>; hisilicon,hi6421-vset = <0x0d 0x7f>; - hisilicon,hi6421-vset-stage = <128>; + hisilicon,hi6421-n-voltages = <128>; + hisilicon,hi6421-uv-step = <7087>; + hisilicon,hi6421-off-on-delay-us = <20000>; + hisilicon,hi6421-enable-time-us = <300>; }; buck1: buck@0e { compatible = "hisilicon,hi6421-buck012"; regulator-name = "BUCK1"; regulator-min-microvolt = <700000>; - regulatro-max-microvolt = <1600000>; + regulator-max-microvolt = <1600000>; regulator-boot-on; regulator-always-on; hisilicon,hi6421-ctrl = <0x0e 0x01 0x10>; hisilicon,hi6421-vset = <0x0f 0x7f>; - hisilicon,hi6421-vset-stage = <128>; + hisilicon,hi6421-n-voltages = <128>; + hisilicon,hi6421-uv-step = <7087>; + hisilicon,hi6421-off-on-delay-us = <20000>; + hisilicon,hi6421-enable-time-us = <300>; }; buck2: buck@10 { compatible = "hisilicon,hi6421-buck012"; regulator-name = "BUCK2"; regulator-min-microvolt = <700000>; - regulatro-max-microvolt = <1600000>; + regulator-max-microvolt = <1600000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x10 0x01 0x10>; hisilicon,hi6421-vset = <0x11 0x7f>; - hisilicon,hi6421-vset-stage = <128>; + hisilicon,hi6421-n-voltages = <128>; + hisilicon,hi6421-uv-step = <7087>; + hisilicon,hi6421-off-on-delay-us = <100>; + hisilicon,hi6421-enable-time-us = <250>; }; buck3: buck@12 { compatible = "hisilicon,hi6421-buck345"; regulator-name = "BUCK3"; regulator-min-microvolt = <950000>; - regulatro-max-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x12 0x01 0x10>; hisilicon,hi6421-vset = <0x13 0x07>; @@ -1174,7 +1214,7 @@ compatible = "hisilicon,hi6421-buck345"; regulator-name = "BUCK4"; regulator-min-microvolt = <1150000>; - regulatro-max-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x14 0x01 0x10>; hisilicon,hi6421-vset = <0x15 0x07>; @@ -1188,7 +1228,7 @@ compatible = "hisilicon,hi6421-buck345"; regulator-name = "BUCK5"; regulator-min-microvolt = <1150000>; - regulatro-max-microvolt = <1900000>; + regulator-max-microvolt = <1900000>; regulator-boot-on; hisilicon,hi6421-ctrl = <0x16 0x01 0x10>; hisilicon,hi6421-vset = <0x17 0x07>; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 551a22b07538..a0c63e7eaecd 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -504,5 +504,11 @@ config REGULATOR_AS3711 This driver provides support for the voltage regulators on the AS3711 PMIC +config REGULATOR_HI6421 + tristate "HiSilicon Hi6421 PMIC" + help + This driver provides support for the voltage regulators of the + HiSilicon Hi6421 PMIC. + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index b802b0c7fb02..b58ef7afd547 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o +obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c new file mode 100644 index 000000000000..5815d4c54a5d --- /dev/null +++ b/drivers/regulator/hi6421-regulator.c @@ -0,0 +1,478 @@ +/* + * Device driver for regulators in Hi6421 IC + * + * Copyright (c) 2013 Linaro Ltd. + * Copyright (C) 2011 Hisilicon. + * + * Guodong Xu <guodong.xu@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_address.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> + +struct hi6421_regulator_register_info { + u32 ctrl_reg; + u32 enable_mask; + u32 eco_mode_mask; + u32 vset_reg; + u32 vset_mask; +} + +struct hi6421_regulator { + const char *name; + struct hi6421_regulator_register_info register_info; +/* u32 control_reg; + struct regmap *anatop; + int vol_bit_shift; + int vol_bit_width; + int min_bit_val; + int min_voltage; + int max_voltage; + */ + u32 off_on_delay; + struct regulator_desc rdesc; + int (*dt_parse)(struct hi6421_regulator *, struct platform_device *); +/* struct regulator_init_data *initdata; + */ +}; + +#if 0 +static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, + unsigned selector) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + + if (!anatop_reg->control_reg) + return -ENOTSUPP; + + return regulator_set_voltage_sel_regmap(reg, selector); +} + +static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + + if (!anatop_reg->control_reg) + return -ENOTSUPP; + + return regulator_get_voltage_sel_regmap(reg); +} +#endif + +static int hi6421_regulator_enable(struct regulator_dev *dev) +{ + int ret = 0; + struct timeval tv; + u32 diff; + struct hi6421_regulator *sreg = rdev_get_drvdata(dev); + +#ifdef HI6421_REGULATOR_DEBUG + rdev_info(dev, "will be enabled\n"); +#endif + + /* + do_gettimeofday(&tv); + diff = (tv.tv_sec - hi6421_regulator_data->lastoff_time[regulator_id].tv_sec) * USEC_PER_SEC + + tv.tv_usec - hi6421_regulator_data->lastoff_time[regulator_id].tv_usec; + if (diff < on_off_delay_us[regulator_id]) { + msleep((on_off_delay_us[regulator_id] - diff + 999 )/1000); + } + + if (regulator_id == HI6421_LDO12) { + ret = gpio_request(SD_GPIO_DCDC, "sdcard_dcdc"); + if (ret < 0) { + rdev_err(NULL, "hi6421 regulator gpio_request failed,please check!\n"); + return ret; + } + gpio_direction_output(SD_GPIO_DCDC, 1); + } + if (regulator_id <= HI6421_LDO20) { + hi6421_regulator_set_bits(hi6421_regulator_data, regulator_ctrl_to_reg[regulator_id], HI6421_LDO_ENA_MASK, HI6421_LDO_ENA); + } else if (regulator_id == HI6421_LDOAUDIO) { + hi6421_regulator_set_bits(hi6421_regulator_data, regulator_ctrl_to_reg[regulator_id], HI6421_LDOAUDIO_ENA_MASK, HI6421_LDOAUDIO_ENA); + } else { + hi6421_regulator_set_bits(hi6421_regulator_data, regulator_ctrl_to_reg[regulator_id], HI6421_BUCK_ENA_MASK, HI6421_BUCK_ENA); + } + + udelay(on_enable_delay_us[regulator_id]); + + return 0; +} + +static int hi6421_dt_parse_common(struct hi6421_regulator *sreg, struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct regulator_desc *rdesc = sreg->rdesc; + unsigned int register_info[3]; + int ret = 0; + + /* parse .register_info.ctrl_reg */ + ret = of_property_read_u32_array(np, "hisilicon,hi6421-ctrl", register_info, 3); + if (ret) { + dev_err(dev, "no hisilicon,hi6421-ctrl property set\n"); + goto dt_parse_common_end; + } + sreg->register_info.ctrl_reg = register_info[0]; + sreg->register_info.enable_mask = register_info[1]; + sreg->register_info.eco_mode_mask = register_info[2]; + + /* parse .register_info.vset_reg */ + ret = of_property_read_u32_array(np, "hisilicon,hi6421-vset", register_info, 2); + if (ret) { + dev_err(dev, "no hisilicon,hi6421-vset property set\n"); + goto dt_parse_common_end; + } + sreg->register_info.vset_reg = register_info[0]; + sreg->register_info.vset_mask = register_info[1]; + /* debug info */ + { + int i; + printk("regulator: hi6421-register_info:\n"); + for(i=0;i<5;i++){ + printk("regulator: reg_infor[%d]=%d\n", i, (u32 *)(&(sreg->register_info))[i]); + } + } + + /* parse .off-on-delay */ + ret = of_property_read_u32(np, "hisilicon,hi6421-off-on-delay-us", + &sreg->off_on_delay); + if (ret) { + dev_err(dev, "no hisilicon,hi6421-off-on-delay-us property set\n"); + goto dt_parse_common_end; + } + + /* parse .enable_time */ + ret = of_property_read_u32(np, "hisilicon,hi6421-enable-time-us", + &rdesc->enable_time); + if (ret) { + dev_err(dev, "no hisilicon,hi6421-enable-time-us property set\n"); + goto dt_parse_common_end; + } + +dt_parse_common_end: + return ret; + +} + +static int hi6421_dt_parse_ldo(struct hi6421_regulator *sreg, struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct regulator_desc *rdesc = sreg->rdesc; + int ret = 0; + + /* parse .n_voltages, and .volt_table */ + ret = of_property_read_u32(np, "hisilicon,hi6421-n-voltages", + &rdesc->n_voltages); + if (ret) { + dev_err(dev, "no hisilicon,hi6421-n-voltages property set\n"); + goto dt_parse_ldo_end; + } + + /* alloc space for .volt_table */ + rdesc->volt_table = devm_kzalloc(dev, sizeof(unsigned int) * rdesc->n_voltages, GFP_KERNEL); + if (unlikely(!rdesc->volt_table)) { + ret = -ENOMEM; + dev_err(dev, "no memory for .volt_table\n"); + goto dt_parse_ldo_end; + } + + ret = of_property_read_u32_array(np, "hisilicon,hi6421-vset-table", rdesc->volt_table, rdesc->n_voltages); + if (ret) { + dev_err(dev, "no hisilicon,hi6421-vset-table property set\n"); + goto dt_parse_ldo_end1; + } + /* debug info */ + { + int i; + printk("regulator: hi6421-vset-table:\n"); + for(i=0;i<rdesc->volt_table;i++){ + printk("regulator: hi6421 desc.volt_table[%d]=%d\n", i, rdesc->volt_table[i]); + } + } + + /* parse hi6421 regulator's dt common part */ + ret = hi6421_dt_parse_common(sreg, pdev); + if (ret) { + dev_err(dev, "failure in hi6421_dt_parse_common\n"); + goto dt_parse_ldo_end1; + } + +dt_parse_ldo_end1: + devm_kfree(dev, rdesc->volt_table); +dt_parse_ldo_end: + return ret; +} + +static int hi6421_dt_parse_buck012(struct hi6421_regulator *sreg, struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct regulator_desc *rdesc = sreg->rdesc; + int ret = 0; + + /* parse .n_voltages, and .uV_step */ + ret = of_property_read_u32(np, "hisilicon,hi6421-n-voltages", + &rdesc->n_voltages); + if (ret) { + dev_err(dev, "no hisilicon,hi6421-n-voltages property set\n"); + goto dt_parse_buck012_end; + } + ret = of_property_read_u32(np, "hisilicon,hi6421-uv-step", + &rdesc->uV_step); + if (ret) { + dev_err(dev, "no hisilicon,hi6421-uv-step property set\n"); + goto dt_parse_buck012_end; + } + + /* parse hi6421 regulator's dt common part */ + ret = hi6421_dt_parse_common(sreg, pdev); + if (ret) { + dev_err(dev, "failure in hi6421_dt_parse_common\n"); + goto dt_parse_ldo_end1; + } + +dt_parse_buck012_end: + return ret; +} + +static struct regulator_ops hi6421_rops_ldo = { +#if 0 /* ref from v3.0.8 */ + .is_enabled = hi6421_regulator_is_enabled, + .enable = hi6421_regulator_enable, + .disable = hi6421_regulator_disable, + .list_voltage = hi6421_regulator_list_voltage, + .get_voltage = hi6421_regulator_get_voltage, + .set_voltage = hi6421_regulator_set_voltage, + .get_mode = hi6421_regulator_get_mode, + .set_mode = hi6421_regulator_set_mode, + .get_optimum_mode = hi6421_regulator_get_optimum_mode, +#endif +/* + .set_voltage_sel = anatop_regmap_set_voltage_sel, + .get_voltage_sel = anatop_regmap_get_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, +*/ +}; + + + +static const struct hi6421_regulator hi6421_regulator_ldo = { +/* .base = offset, + .min_mV = min_mVolts, + .max_mV = max_mVolts, + */ + .rdesc = { +/* .name = #label, \ + .id = TWL6030_REG_##label, \ + .n_voltages = 32, \ + */ + .ops = &hi6421_rops_ldo, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .dt_parse = hi6421_dt_parse_ldo, +}; + +static const struct hi6421_regulator hi6421_regulator_buck012 = { +/* .base = offset, + .min_mV = min_mVolts, + .max_mV = max_mVolts, + */ + .rdesc = { +/* .name = #label, \ + .id = TWL6030_REG_##label, \ + .n_voltages = 32, \ + */ + .ops = &hi6421_rops_ldo, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .dt_parse = hi6421_dt_parse_buck012, +}; + +static const struct hi6421_regulator hi6421_regulator_buck345 = { +/* .base = offset, + .min_mV = min_mVolts, + .max_mV = max_mVolts, + */ + .rdesc = { +/* .name = #label, \ + .id = TWL6030_REG_##label, \ + .n_voltages = 32, \ + */ + .ops = &hi6421_rops_ldo, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .dt_parse = hi6421_dt_parse_ldo, +}; + +static struct of_device_id of_hi6421_regulator_match_tbl[] = { + { + .compatible = "hisilicon,hi6421-ldo", + .data = &hi6421_regulator_ldo, + }, + { + .compatible = "hisilicon,hi6421-buck012", + .data = &hi6421_regulator_buck012, + }, + { + .compatible = "hisilicon,hi6421-buck345", + .data = &hi6421_regulator_buck345, + }, + { /* end */ } +}; + +static int hi6421_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *hi6421_np; + struct regulator_desc *rdesc; + struct regulator_dev *rdev; + struct hi6421_regulator *sreg = NULL; + struct regulator_init_data *initdata; + struct regulator_config config = { }; + const struct of_device_id *match; + const struct hi6421_regulator *template; + unsigned int register_info[3]; + int ret = 0; + + /* to check which type of regulator this is */ + match = of_match_device(of_hi6421_regulator_match_tbl, &pdev->dev); + if (match) { + template = match->data; +/* id = template->desc.id; */ +/* initdata = of_get_regulator_init_data(dev, np); */ + printk("regulator: hi6421 match found!\n"); + } else { + printk("regulator: hi6421 ERROR!\n"); + } + + initdata = of_get_regulator_init_data(dev, np); + sreg = kmemdup(template, sizeof (*sreg), GFP_KERNEL); + if (!sreg) + return -ENOMEM; + +/* initdata is already in regulator_config */ +/* sreg->initdata = initdata; */ + + sreg->name = initdata->constraints.name; + rdesc = &sreg->rdesc; + rdesc->name = initdata->constraints.name; + + /* not needed any more. coming from template. */ +/* rdesc->ops = &hi6421_rops_ldo; + rdesc->type = REGULATOR_VOLTAGE; + rdesc->owner = THIS_MODULE; + */ + + + /* to parse device tree data for regulator specific */ + ret = sreg->dt_parse(sreg, pdev); + if (ret) { + dev_err(dev, "device tree parameter parse error!\n"); + goto hi6421_probe_end; + } + +#if 0 + anatop_np = of_get_parent(np); + if (!anatop_np) + return -ENODEV; + sreg->anatop = syscon_node_to_regmap(anatop_np); + of_node_put(anatop_np); + if (IS_ERR(sreg->anatop)) + return PTR_ERR(sreg->anatop); +#endif + + config.dev = &pdev->dev; + config.init_data = initdata; + config.driver_data = sreg; + config.of_node = pdev->dev.of_node; + +/* config.regmap = sreg->anatop; */ /* ?? */ + + /* register regulator */ + rdev = regulator_register(rdesc, &config); + if (IS_ERR(rdev)) { + dev_err(dev, "failed to register %s\n", + rdesc->name); + ret = PTR_ERR(rdev); + goto hi6421_probe_end; + } + + platform_set_drvdata(pdev, rdev); + +hi6421_probe_end: + if (sreg) + kfree(sreg); + return ret; +} + +static int hi6421_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct hi6421_regulator *sreg = rdev_get_drvdata(rdev); + + regulator_unregister(rdev); + + /* TODO: should i worry about that? devm_kzalloc */ + if (sreg->rdesc->volt_table) + devm_kfree(pdev->dev, sreg->rdesc->volt_table); + + kfree(sreg); + return 0; +} + +static struct platform_driver hi6421_regulator_driver = { + .driver = { + .name = "hi6421_regulator", + .owner = THIS_MODULE, + .of_match_table = of_hi6421_regulator_match_tbl, + }, + .probe = hi6421_regulator_probe, + .remove = hi6421_regulator_remove, +}; + +static int __init hi6421_regulator_init(void) +{ + return platform_driver_register(&hi6421_regulator_driver); +} +postcore_initcall(hi6421_regulator_init); + +static void __exit hi6421_regulator_exit(void) +{ + platform_driver_unregister(&hi6421_regulator_driver); +} +module_exit(hi6421_regulator_exit); + +MODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>"); +MODULE_DESCRIPTION("Hi6421 regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 66ca769287ab..3ba7dc6b96ee 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -32,6 +32,9 @@ static void of_get_regulation_constraints(struct device_node *np, if (max_uV) constraints->max_uV = be32_to_cpu(*max_uV); + printk("regulator: name=%s,min/max=%d/%d\n", constraints->name,\ + constraints->min_uV, constraints->max_uV); + /* Voltage change possible? */ if (constraints->min_uV != constraints->max_uV) constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE; |