diff options
Diffstat (limited to 'drivers/regulator')
69 files changed, 5726 insertions, 1222 deletions
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 1c5ab0172ea2..c79ab843333e 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -30,8 +30,6 @@ struct pm8607_regulator_info { unsigned int *vol_table; unsigned int *vol_suspend; - int update_reg; - int update_bit; int slope_double; }; @@ -222,29 +220,6 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) return ret; } -static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - uint8_t val; - int ret; - - val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1)); - - ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg, - rdev->desc->vsel_mask, val); - if (ret) - return ret; - switch (info->desc.id) { - case PM8607_ID_BUCK1: - case PM8607_ID_BUCK3: - ret = pm860x_set_bits(info->i2c, info->update_reg, - 1 << info->update_bit, - 1 << info->update_bit); - break; - } - return ret; -} - static int pm8606_preg_enable(struct regulator_dev *rdev) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); @@ -276,7 +251,7 @@ static int pm8606_preg_is_enabled(struct regulator_dev *rdev) static struct regulator_ops pm8607_regulator_ops = { .list_voltage = pm8607_list_voltage, - .set_voltage_sel = pm8607_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -313,11 +288,11 @@ static struct regulator_ops pm8606_preg_ops = { .n_voltages = ARRAY_SIZE(vreg##_table), \ .vsel_reg = PM8607_##vreg, \ .vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \ + .apply_reg = PM8607_##ureg, \ + .apply_bit = (ubit), \ .enable_reg = PM8607_##ereg, \ .enable_mask = 1 << (ebit), \ }, \ - .update_reg = PM8607_##ureg, \ - .update_bit = (ubit), \ .slope_double = (0), \ .vol_table = (unsigned int *)&vreg##_table, \ .vol_suspend = (unsigned int *)&vreg##_suspend_table, \ @@ -343,9 +318,9 @@ static struct regulator_ops pm8606_preg_ops = { } static struct pm8607_regulator_info pm8607_regulator_info[] = { - PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0), - PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1), - PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2), + PM8607_DVC(BUCK1, GO, BIT(0), SUPPLIES_EN11, 0), + PM8607_DVC(BUCK2, GO, BIT(1), SUPPLIES_EN11, 1), + PM8607_DVC(BUCK3, GO, BIT(2), SUPPLIES_EN11, 2), PM8607_LDO(1, LDO1, 0, SUPPLIES_EN11, 3), PM8607_LDO(2, LDO2, 0, SUPPLIES_EN11, 4), @@ -372,7 +347,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev, struct regulator_config *config) { struct device_node *nproot, *np; - nproot = pdev->dev.parent->of_node; + nproot = of_node_get(pdev->dev.parent->of_node); if (!nproot) return -ENODEV; nproot = of_find_node_by_name(nproot, "regulators"); @@ -388,13 +363,14 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev, break; } } + of_node_put(nproot); return 0; } #else #define pm8607_regulator_dt_init(x, y, z) (-1) #endif -static int __devinit pm8607_regulator_probe(struct platform_device *pdev) +static int pm8607_regulator_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm8607_regulator_info *info = NULL; @@ -454,7 +430,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit pm8607_regulator_remove(struct platform_device *pdev) +static int pm8607_regulator_remove(struct platform_device *pdev) { struct pm8607_regulator_info *info = platform_get_drvdata(pdev); @@ -481,7 +457,7 @@ static struct platform_driver pm8607_regulator_driver = { .owner = THIS_MODULE, }, .probe = pm8607_regulator_probe, - .remove = __devexit_p(pm8607_regulator_remove), + .remove = pm8607_regulator_remove, .id_table = pm8607_regulator_driver_ids, }; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 67d47b59a66d..a5d97eaee99e 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -91,6 +91,7 @@ config REGULATOR_AAT2870 config REGULATOR_ARIZONA tristate "Wolfson Arizona class devices" depends on MFD_ARIZONA + depends on SND_SOC help Support for the regulators found on Wolfson Arizona class devices. @@ -109,6 +110,16 @@ config REGULATOR_DA9052 This driver supports the voltage regulators of DA9052-BC and DA9053-AA/Bx PMIC. +config REGULATOR_DA9055 + tristate "Dialog Semiconductor DA9055 regulators" + depends on MFD_DA9055 + help + Say y here to support the BUCKs and LDOs regulators found on + Dialog Semiconductor DA9055 PMIC. + + This driver can also be built as a module. If so, the module + will be called da9055-regulator. + config REGULATOR_FAN53555 tristate "Fairchild FAN53555 Regulator" depends on I2C @@ -204,6 +215,16 @@ config REGULATOR_MAX8952 via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS modes ranging from 0.77V to 1.40V by 0.01V steps. +config REGULATOR_MAX8973 + tristate "Maxim MAX8973 voltage regulator " + depends on I2C + select REGMAP_I2C + help + The MAXIM MAX8973 high-efficiency. three phase, DC-DC step-down + switching regulator delievers up to 9A of output current. Each + phase operates at a 2MHz fixed frequency with a 120 deg shift + from the adjacent phase, allowing the use of small magnetic component. + config REGULATOR_MAX8997 tristate "Maxim 8997/8966 regulator" depends on MFD_MAX8997 @@ -257,6 +278,15 @@ config REGULATOR_LP872X help This driver supports LP8720/LP8725 PMIC +config REGULATOR_LP8755 + tristate "TI LP8755 High Performance PMU driver" + depends on I2C + select REGMAP_I2C + help + This driver supports LP8755 High Performance PMU driver. This + chip contains six step-down DC/DC converters which can support + 9 mode multiphase configuration. + config REGULATOR_LP8788 bool "TI LP8788 Power Regulators" depends on MFD_LP8788 @@ -335,6 +365,17 @@ config REGULATOR_PALMAS on the muxing. This is handled automatically in the driver by reading the mux info from OTP. +config REGULATOR_TPS51632 + tristate "TI TPS51632 Power Regulator" + depends on I2C + select REGMAP_I2C + help + This driver supports TPS51632 voltage regulator chip. + The TPS51632 is 3-2-1 Phase D-Cap+ Step Down Driverless Controller + with Serial VID control and DVFS. + The voltage output can be configure through I2C interface or PWM + interface. + config REGULATOR_TPS6105X tristate "TI TPS6105X Power regulators" depends on TPS6105X @@ -415,6 +456,15 @@ config REGULATOR_TPS65912 help This driver supports TPS65912 voltage regulator chip. +config REGULATOR_TPS80031 + tristate "TI TPS80031/TPS80032 power regualtor driver" + depends on MFD_TPS80031 + help + TPS80031/ TPS80032 Fully Integrated Power Management with Power + Path and Battery Charger. It has 5 configurable step-down + converters, 11 general purpose LDOs, VBUS generator and digital + output to control regulators. + config REGULATOR_TWL4030 bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" depends on TWL4030_CORE @@ -422,6 +472,13 @@ config REGULATOR_TWL4030 This driver supports the voltage regulators provided by this family of companion chips. +config REGULATOR_VEXPRESS + tristate "Versatile Express regulators" + depends on VEXPRESS_CONFIG + help + This driver provides support for voltage regulators available + on the ARM Ltd's Versatile Express platform. + config REGULATOR_WM831X tristate "Wolfson Microelectronics WM831x PMIC regulators" depends on MFD_WM831X @@ -450,5 +507,12 @@ config REGULATOR_WM8994 This driver provides support for the voltage regulators on the WM8994 CODEC. +config REGULATOR_AS3711 + tristate "AS3711 PMIC" + depends on MFD_AS3711 + help + This driver provides support for the voltage regulators on the + AS3711 PMIC + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index e431eed8a878..6e8250382def 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -16,8 +16,10 @@ obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o +obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o +obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o @@ -28,12 +30,14 @@ obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o +obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o +obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o @@ -41,6 +45,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o +obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o @@ -56,7 +61,9 @@ obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o +obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o +obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 167c93f21981..8b5876356db9 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -187,7 +187,7 @@ static int aat2870_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit aat2870_regulator_remove(struct platform_device *pdev) +static int aat2870_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -201,7 +201,7 @@ static struct platform_driver aat2870_regulator_driver = { .owner = THIS_MODULE, }, .probe = aat2870_regulator_probe, - .remove = __devexit_p(aat2870_regulator_remove), + .remove = aat2870_regulator_remove, }; static int __init aat2870_regulator_init(void) diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index df4ad8927f0c..111ec69a3e94 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -494,7 +494,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = { * for all the different regulators. */ -static int __devinit ab3100_regulators_probe(struct platform_device *pdev) +static int ab3100_regulators_probe(struct platform_device *pdev) { struct ab3100_platform_data *plfdata = pdev->dev.platform_data; struct regulator_config config = { }; @@ -571,7 +571,7 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev) return 0; } -static int __devexit ab3100_regulators_remove(struct platform_device *pdev) +static int ab3100_regulators_remove(struct platform_device *pdev) { int i; @@ -589,7 +589,7 @@ static struct platform_driver ab3100_regulators_driver = { .owner = THIS_MODULE, }, .probe = ab3100_regulators_probe, - .remove = __devexit_p(ab3100_regulators_remove), + .remove = ab3100_regulators_remove, }; static __init int ab3100_regulators_init(void) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index e3d1d063025a..09014f38a948 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -641,7 +641,7 @@ static struct ab8500_reg_init ab8500_reg_init[] = { REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), }; -static __devinit int +static int ab8500_regulator_init_registers(struct platform_device *pdev, int id, int value) { int err; @@ -676,7 +676,7 @@ ab8500_regulator_init_registers(struct platform_device *pdev, int id, int value) return 0; } -static __devinit int ab8500_regulator_register(struct platform_device *pdev, +static int ab8500_regulator_register(struct platform_device *pdev, struct regulator_init_data *init_data, int id, struct device_node *np) @@ -735,7 +735,7 @@ static struct of_regulator_match ab8500_regulator_matches[] = { { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8500_LDO_ANA, }, }; -static __devinit int +static int ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np) { int err, i; @@ -751,7 +751,7 @@ ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np) return 0; } -static __devinit int ab8500_regulator_probe(struct platform_device *pdev) +static int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); struct ab8500_platform_data *pdata; @@ -817,7 +817,7 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) return 0; } -static __devexit int ab8500_regulator_remove(struct platform_device *pdev) +static int ab8500_regulator_remove(struct platform_device *pdev) { int i; @@ -836,7 +836,7 @@ static __devexit int ab8500_regulator_remove(struct platform_device *pdev) static struct platform_driver ab8500_regulator_driver = { .probe = ab8500_regulator_probe, - .remove = __devexit_p(ab8500_regulator_remove), + .remove = ab8500_regulator_remove, .driver = { .name = "ab8500-regulator", .owner = THIS_MODULE, diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index f123f7e3b752..6b981b5faa70 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -211,7 +211,7 @@ static const struct i2c_device_id ad5398_id[] = { }; MODULE_DEVICE_TABLE(i2c, ad5398_id); -static int __devinit ad5398_probe(struct i2c_client *client, +static int ad5398_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct regulator_init_data *init_data = client->dev.platform_data; @@ -256,7 +256,7 @@ err: return ret; } -static int __devexit ad5398_remove(struct i2c_client *client) +static int ad5398_remove(struct i2c_client *client) { struct ad5398_chip_info *chip = i2c_get_clientdata(client); @@ -266,7 +266,7 @@ static int __devexit ad5398_remove(struct i2c_client *client) static struct i2c_driver ad5398_driver = { .probe = ad5398_probe, - .remove = __devexit_p(ad5398_remove), + .remove = ad5398_remove, .driver = { .name = "ad5398", }, diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 1af97686f444..0d4a8ccbb536 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -31,12 +31,18 @@ #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> +#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */ +#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */ + struct anatop_regulator { const char *name; u32 control_reg; struct regmap *anatop; int vol_bit_shift; int vol_bit_width; + u32 delay_reg; + int delay_bit_shift; + int delay_bit_width; int min_bit_val; int min_voltage; int max_voltage; @@ -48,46 +54,58 @@ static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, unsigned selector) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); - u32 val, mask; if (!anatop_reg->control_reg) return -ENOTSUPP; - val = anatop_reg->min_bit_val + selector; - dev_dbg(®->dev, "%s: calculated val %d\n", __func__, val); - mask = ((1 << anatop_reg->vol_bit_width) - 1) << - anatop_reg->vol_bit_shift; - val <<= anatop_reg->vol_bit_shift; - regmap_update_bits(anatop_reg->anatop, anatop_reg->control_reg, - mask, val); + return regulator_set_voltage_sel_regmap(reg, selector); +} - return 0; +static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg, + unsigned int old_sel, + unsigned int new_sel) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + u32 val; + int ret = 0; + + /* check whether need to care about LDO ramp up speed */ + if (anatop_reg->delay_bit_width && new_sel > old_sel) { + /* + * the delay for LDO ramp up time is + * based on the register setting, we need + * to calculate how many steps LDO need to + * ramp up, and how much delay needed. (us) + */ + regmap_read(anatop_reg->anatop, anatop_reg->delay_reg, &val); + val = (val >> anatop_reg->delay_bit_shift) & + ((1 << anatop_reg->delay_bit_width) - 1); + ret = (new_sel - old_sel) * (LDO_RAMP_UP_UNIT_IN_CYCLES << + val) / LDO_RAMP_UP_FREQ_IN_MHZ + 1; + } + + return ret; } static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); - u32 val, mask; if (!anatop_reg->control_reg) return -ENOTSUPP; - regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val); - mask = ((1 << anatop_reg->vol_bit_width) - 1) << - anatop_reg->vol_bit_shift; - val = (val & mask) >> anatop_reg->vol_bit_shift; - - return val - anatop_reg->min_bit_val; + return regulator_get_voltage_sel_regmap(reg); } static struct regulator_ops anatop_rops = { .set_voltage_sel = anatop_regmap_set_voltage_sel, + .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel, .get_voltage_sel = anatop_regmap_get_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, }; -static int __devinit anatop_regulator_probe(struct platform_device *pdev) +static int anatop_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; @@ -158,15 +176,28 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev) goto anatop_probe_end; } - rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) - / 25000 + 1; + /* read LDO ramp up setting, only for core reg */ + of_property_read_u32(np, "anatop-delay-reg-offset", + &sreg->delay_reg); + of_property_read_u32(np, "anatop-delay-bit-width", + &sreg->delay_bit_width); + of_property_read_u32(np, "anatop-delay-bit-shift", + &sreg->delay_bit_shift); + + rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1 + + sreg->min_bit_val; rdesc->min_uV = sreg->min_voltage; rdesc->uV_step = 25000; + rdesc->linear_min_sel = sreg->min_bit_val; + rdesc->vsel_reg = sreg->control_reg; + rdesc->vsel_mask = ((1 << sreg->vol_bit_width) - 1) << + sreg->vol_bit_shift; 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); @@ -186,7 +217,7 @@ anatop_probe_end: return ret; } -static int __devexit anatop_regulator_remove(struct platform_device *pdev) +static int anatop_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); struct anatop_regulator *sreg = rdev_get_drvdata(rdev); @@ -198,7 +229,7 @@ static int __devexit anatop_regulator_remove(struct platform_device *pdev) return 0; } -static struct of_device_id __devinitdata of_anatop_regulator_match_tbl[] = { +static struct of_device_id of_anatop_regulator_match_tbl[] = { { .compatible = "fsl,anatop-regulator", }, { /* end */ } }; @@ -210,7 +241,7 @@ static struct platform_driver anatop_regulator_driver = { .of_match_table = of_anatop_regulator_match_tbl, }, .probe = anatop_regulator_probe, - .remove = __devexit_p(anatop_regulator_remove), + .remove = anatop_regulator_remove, }; static int __init anatop_regulator_init(void) diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index d184aa35abcb..ed7beec53af8 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -34,6 +34,108 @@ struct arizona_ldo1 { struct regulator_init_data init_data; }; +static int arizona_ldo1_hc_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + if (selector == rdev->desc->n_voltages - 1) + return 1800000; + else + return rdev->desc->min_uV + (rdev->desc->uV_step * selector); +} + +static int arizona_ldo1_hc_map_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int sel; + + sel = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step); + if (sel >= rdev->desc->n_voltages) + sel = rdev->desc->n_voltages - 1; + + return sel; +} + +static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev, + unsigned sel) +{ + struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev); + struct regmap *regmap = ldo->arizona->regmap; + unsigned int val; + int ret; + + if (sel == rdev->desc->n_voltages - 1) + val = ARIZONA_LDO1_HI_PWR; + else + val = 0; + + ret = regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_2, + ARIZONA_LDO1_HI_PWR, val); + if (ret != 0) + return ret; + + ret = regmap_update_bits(regmap, ARIZONA_DYNAMIC_FREQUENCY_SCALING_1, + ARIZONA_SUBSYS_MAX_FREQ, val); + if (ret != 0) + return ret; + + if (val) + return 0; + + val = sel << ARIZONA_LDO1_VSEL_SHIFT; + + return regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_1, + ARIZONA_LDO1_VSEL_MASK, val); +} + +static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev) +{ + struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev); + struct regmap *regmap = ldo->arizona->regmap; + unsigned int val; + int ret; + + ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_2, &val); + if (ret != 0) + return ret; + + if (val & ARIZONA_LDO1_HI_PWR) + return rdev->desc->n_voltages - 1; + + ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_1, &val); + if (ret != 0) + return ret; + + return (val & ARIZONA_LDO1_VSEL_MASK) >> ARIZONA_LDO1_VSEL_SHIFT; +} + +static struct regulator_ops arizona_ldo1_hc_ops = { + .list_voltage = arizona_ldo1_hc_list_voltage, + .map_voltage = arizona_ldo1_hc_map_voltage, + .get_voltage_sel = arizona_ldo1_hc_get_voltage_sel, + .set_voltage_sel = arizona_ldo1_hc_set_voltage_sel, + .get_bypass = regulator_get_bypass_regmap, + .set_bypass = regulator_set_bypass_regmap, +}; + +static const struct regulator_desc arizona_ldo1_hc = { + .name = "LDO1", + .supply_name = "LDOVDD", + .type = REGULATOR_VOLTAGE, + .ops = &arizona_ldo1_hc_ops, + + .bypass_reg = ARIZONA_LDO1_CONTROL_1, + .bypass_mask = ARIZONA_LDO1_BYPASS, + .min_uV = 900000, + .uV_step = 50000, + .n_voltages = 8, + .enable_time = 500, + + .owner = THIS_MODULE, +}; + static struct regulator_ops arizona_ldo1_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -55,11 +157,22 @@ static const struct regulator_desc arizona_ldo1 = { .bypass_mask = ARIZONA_LDO1_BYPASS, .min_uV = 900000, .uV_step = 50000, - .n_voltages = 6, + .n_voltages = 7, + .enable_time = 500, .owner = THIS_MODULE, }; +static const struct regulator_init_data arizona_ldo1_dvfs = { + .constraints = { + .min_uV = 1200000, + .max_uV = 1800000, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = 1, +}; + static const struct regulator_init_data arizona_ldo1_default = { .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS, @@ -67,9 +180,10 @@ static const struct regulator_init_data arizona_ldo1_default = { .num_consumer_supplies = 1, }; -static __devinit int arizona_ldo1_probe(struct platform_device *pdev) +static int arizona_ldo1_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); + const struct regulator_desc *desc; struct regulator_config config = { }; struct arizona_ldo1 *ldo1; int ret; @@ -87,7 +201,17 @@ static __devinit int arizona_ldo1_probe(struct platform_device *pdev) * default init_data for it. This will be overridden with * platform data if provided. */ - ldo1->init_data = arizona_ldo1_default; + switch (arizona->type) { + case WM5102: + desc = &arizona_ldo1_hc; + ldo1->init_data = arizona_ldo1_dvfs; + break; + default: + desc = &arizona_ldo1; + ldo1->init_data = arizona_ldo1_default; + break; + } + ldo1->init_data.consumer_supplies = &ldo1->supply; ldo1->supply.supply = "DCVDD"; ldo1->supply.dev_name = dev_name(arizona->dev); @@ -102,7 +226,7 @@ static __devinit int arizona_ldo1_probe(struct platform_device *pdev) else config.init_data = &ldo1->init_data; - ldo1->regulator = regulator_register(&arizona_ldo1, &config); + ldo1->regulator = regulator_register(desc, &config); if (IS_ERR(ldo1->regulator)) { ret = PTR_ERR(ldo1->regulator); dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n", @@ -115,7 +239,7 @@ static __devinit int arizona_ldo1_probe(struct platform_device *pdev) return 0; } -static __devexit int arizona_ldo1_remove(struct platform_device *pdev) +static int arizona_ldo1_remove(struct platform_device *pdev) { struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev); @@ -126,7 +250,7 @@ static __devexit int arizona_ldo1_remove(struct platform_device *pdev) static struct platform_driver arizona_ldo1_driver = { .probe = arizona_ldo1_probe, - .remove = __devexit_p(arizona_ldo1_remove), + .remove = arizona_ldo1_remove, .driver = { .name = "arizona-ldo1", .owner = THIS_MODULE, diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index d9b1f82cc5bd..e87536bf0bed 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -21,6 +21,8 @@ #include <linux/regulator/machine.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/workqueue.h> +#include <sound/soc.h> #include <linux/mfd/arizona/core.h> #include <linux/mfd/arizona/pdata.h> @@ -34,6 +36,8 @@ struct arizona_micsupp { struct regulator_consumer_supply supply; struct regulator_init_data init_data; + + struct work_struct check_cp_work; }; static int arizona_micsupp_list_voltage(struct regulator_dev *rdev, @@ -72,9 +76,73 @@ static int arizona_micsupp_map_voltage(struct regulator_dev *rdev, return selector; } +static void arizona_micsupp_check_cp(struct work_struct *work) +{ + struct arizona_micsupp *micsupp = + container_of(work, struct arizona_micsupp, check_cp_work); + struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm; + struct arizona *arizona = micsupp->arizona; + struct regmap *regmap = arizona->regmap; + unsigned int reg; + int ret; + + ret = regmap_read(regmap, ARIZONA_MIC_CHARGE_PUMP_1, ®); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read CP state: %d\n", ret); + return; + } + + if (dapm) { + if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) == + ARIZONA_CPMIC_ENA) + snd_soc_dapm_force_enable_pin(dapm, "MICSUPP"); + else + snd_soc_dapm_disable_pin(dapm, "MICSUPP"); + + snd_soc_dapm_sync(dapm); + } +} + +static int arizona_micsupp_enable(struct regulator_dev *rdev) +{ + struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev); + int ret; + + ret = regulator_enable_regmap(rdev); + + if (ret == 0) + schedule_work(&micsupp->check_cp_work); + + return ret; +} + +static int arizona_micsupp_disable(struct regulator_dev *rdev) +{ + struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev); + int ret; + + ret = regulator_disable_regmap(rdev); + if (ret == 0) + schedule_work(&micsupp->check_cp_work); + + return ret; +} + +static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena) +{ + struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev); + int ret; + + ret = regulator_set_bypass_regmap(rdev, ena); + if (ret == 0) + schedule_work(&micsupp->check_cp_work); + + return ret; +} + static struct regulator_ops arizona_micsupp_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, + .enable = arizona_micsupp_enable, + .disable = arizona_micsupp_disable, .is_enabled = regulator_is_enabled_regmap, .list_voltage = arizona_micsupp_list_voltage, @@ -84,7 +152,7 @@ static struct regulator_ops arizona_micsupp_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_bypass = regulator_get_bypass_regmap, - .set_bypass = regulator_set_bypass_regmap, + .set_bypass = arizona_micsupp_set_bypass, }; static const struct regulator_desc arizona_micsupp = { @@ -101,13 +169,16 @@ static const struct regulator_desc arizona_micsupp = { .bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1, .bypass_mask = ARIZONA_CPMIC_BYPASS, + .enable_time = 3000, + .owner = THIS_MODULE, }; static const struct regulator_init_data arizona_micsupp_default = { .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS | - REGULATOR_CHANGE_VOLTAGE, + REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_BYPASS, .min_uV = 1700000, .max_uV = 3300000, }, @@ -115,7 +186,7 @@ static const struct regulator_init_data arizona_micsupp_default = { .num_consumer_supplies = 1, }; -static __devinit int arizona_micsupp_probe(struct platform_device *pdev) +static int arizona_micsupp_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; @@ -129,6 +200,7 @@ static __devinit int arizona_micsupp_probe(struct platform_device *pdev) } micsupp->arizona = arizona; + INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp); /* * Since the chip usually supplies itself we provide some @@ -166,7 +238,7 @@ static __devinit int arizona_micsupp_probe(struct platform_device *pdev) return 0; } -static __devexit int arizona_micsupp_remove(struct platform_device *pdev) +static int arizona_micsupp_remove(struct platform_device *pdev) { struct arizona_micsupp *micsupp = platform_get_drvdata(pdev); @@ -177,7 +249,7 @@ static __devexit int arizona_micsupp_remove(struct platform_device *pdev) static struct platform_driver arizona_micsupp_driver = { .probe = arizona_micsupp_probe, - .remove = __devexit_p(arizona_micsupp_remove), + .remove = arizona_micsupp_remove, .driver = { .name = "arizona-micsupp", .owner = THIS_MODULE, diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c new file mode 100644 index 000000000000..f0ba8c4eefa9 --- /dev/null +++ b/drivers/regulator/as3711-regulator.c @@ -0,0 +1,369 @@ +/* + * AS3711 PMIC regulator driver, using DCDC Step Down and LDO supplies + * + * Copyright (C) 2012 Renesas Electronics Corporation + * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the version 2 of the GNU General Public License as + * published by the Free Software Foundation + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/mfd/as3711.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/slab.h> + +struct as3711_regulator_info { + struct regulator_desc desc; + unsigned int max_uV; +}; + +struct as3711_regulator { + struct as3711_regulator_info *reg_info; + struct regulator_dev *rdev; +}; + +static int as3711_list_voltage_sd(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + if (!selector) + return 0; + if (selector < 0x41) + return 600000 + selector * 12500; + if (selector < 0x71) + return 1400000 + (selector - 0x40) * 25000; + return 2600000 + (selector - 0x70) * 50000; +} + +static int as3711_list_voltage_aldo(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + if (selector < 0x10) + return 1200000 + selector * 50000; + return 1800000 + (selector - 0x10) * 100000; +} + +static int as3711_list_voltage_dldo(struct regulator_dev *rdev, + unsigned int selector) +{ + if (selector >= rdev->desc->n_voltages || + (selector > 0x10 && selector < 0x20)) + return -EINVAL; + + if (selector < 0x11) + return 900000 + selector * 50000; + return 1750000 + (selector - 0x20) * 50000; +} + +static int as3711_bound_check(struct regulator_dev *rdev, + int *min_uV, int *max_uV) +{ + struct as3711_regulator *reg = rdev_get_drvdata(rdev); + struct as3711_regulator_info *info = reg->reg_info; + + dev_dbg(&rdev->dev, "%s(), %d, %d, %d\n", __func__, + *min_uV, rdev->desc->min_uV, info->max_uV); + + if (*max_uV < *min_uV || + *min_uV > info->max_uV || rdev->desc->min_uV > *max_uV) + return -EINVAL; + + if (rdev->desc->n_voltages == 1) + return 0; + + if (*max_uV > info->max_uV) + *max_uV = info->max_uV; + + if (*min_uV < rdev->desc->min_uV) + *min_uV = rdev->desc->min_uV; + + return *min_uV; +} + +static int as3711_sel_check(int min, int max, int bottom, int step) +{ + int sel, voltage; + + /* Round up min, when dividing: keeps us within the range */ + sel = DIV_ROUND_UP(min - bottom, step); + voltage = sel * step + bottom; + pr_debug("%s(): select %d..%d in %d+N*%d: %d\n", __func__, + min, max, bottom, step, sel); + if (voltage > max) + return -EINVAL; + + return sel; +} + +static int as3711_map_voltage_sd(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret; + + ret = as3711_bound_check(rdev, &min_uV, &max_uV); + if (ret <= 0) + return ret; + + if (min_uV <= 1400000) + return as3711_sel_check(min_uV, max_uV, 600000, 12500); + + if (min_uV <= 2600000) + return as3711_sel_check(min_uV, max_uV, 1400000, 25000) + 0x40; + + return as3711_sel_check(min_uV, max_uV, 2600000, 50000) + 0x70; +} + +/* + * The regulator API supports 4 modes of operataion: FAST, NORMAL, IDLE and + * STANDBY. We map them in the following way to AS3711 SD1-4 DCDC modes: + * FAST: sdX_fast=1 + * NORMAL: low_noise=1 + * IDLE: low_noise=0 + */ + +static int as3711_set_mode_sd(struct regulator_dev *rdev, unsigned int mode) +{ + unsigned int fast_bit = rdev->desc->enable_mask, + low_noise_bit = fast_bit << 4; + u8 val; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = fast_bit | low_noise_bit; + break; + case REGULATOR_MODE_NORMAL: + val = low_noise_bit; + break; + case REGULATOR_MODE_IDLE: + val = 0; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(rdev->regmap, AS3711_SD_CONTROL_1, + low_noise_bit | fast_bit, val); +} + +static unsigned int as3711_get_mode_sd(struct regulator_dev *rdev) +{ + unsigned int fast_bit = rdev->desc->enable_mask, + low_noise_bit = fast_bit << 4, mask = fast_bit | low_noise_bit; + unsigned int val; + int ret = regmap_read(rdev->regmap, AS3711_SD_CONTROL_1, &val); + + if (ret < 0) + return ret; + + if ((val & mask) == mask) + return REGULATOR_MODE_FAST; + + if ((val & mask) == low_noise_bit) + return REGULATOR_MODE_NORMAL; + + if (!(val & mask)) + return REGULATOR_MODE_IDLE; + + return -EINVAL; +} + +static int as3711_map_voltage_aldo(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret; + + ret = as3711_bound_check(rdev, &min_uV, &max_uV); + if (ret <= 0) + return ret; + + if (min_uV <= 1800000) + return as3711_sel_check(min_uV, max_uV, 1200000, 50000); + + return as3711_sel_check(min_uV, max_uV, 1800000, 100000) + 0x10; +} + +static int as3711_map_voltage_dldo(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret; + + ret = as3711_bound_check(rdev, &min_uV, &max_uV); + if (ret <= 0) + return ret; + + if (min_uV <= 1700000) + return as3711_sel_check(min_uV, max_uV, 900000, 50000); + + return as3711_sel_check(min_uV, max_uV, 1750000, 50000) + 0x20; +} + +static struct regulator_ops as3711_sd_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = as3711_list_voltage_sd, + .map_voltage = as3711_map_voltage_sd, + .get_mode = as3711_get_mode_sd, + .set_mode = as3711_set_mode_sd, +}; + +static struct regulator_ops as3711_aldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = as3711_list_voltage_aldo, + .map_voltage = as3711_map_voltage_aldo, +}; + +static struct regulator_ops as3711_dldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = as3711_list_voltage_dldo, + .map_voltage = as3711_map_voltage_dldo, +}; + +#define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx) \ + [AS3711_REGULATOR_ ## _id] = { \ + .desc = { \ + .name = "as3711-regulator-" # _id, \ + .id = AS3711_REGULATOR_ ## _id, \ + .n_voltages = (_vmask + 1), \ + .ops = &as3711_ ## _sfx ## _ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = AS3711_ ## _id ## _VOLTAGE, \ + .vsel_mask = _vmask << _vshift, \ + .enable_reg = AS3711_ ## _en_reg, \ + .enable_mask = BIT(_en_bit), \ + .min_uV = _min_uV, \ + }, \ + .max_uV = _max_uV, \ +} + +static struct as3711_regulator_info as3711_reg_info[] = { + AS3711_REG(SD_1, SD_CONTROL, 0, 0x7f, 0, 612500, 3350000, sd), + AS3711_REG(SD_2, SD_CONTROL, 1, 0x7f, 0, 612500, 3350000, sd), + AS3711_REG(SD_3, SD_CONTROL, 2, 0x7f, 0, 612500, 3350000, sd), + AS3711_REG(SD_4, SD_CONTROL, 3, 0x7f, 0, 612500, 3350000, sd), + AS3711_REG(LDO_1, LDO_1_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo), + AS3711_REG(LDO_2, LDO_2_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo), + AS3711_REG(LDO_3, LDO_3_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(LDO_4, LDO_4_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(LDO_5, LDO_5_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(LDO_6, LDO_6_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(LDO_7, LDO_7_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + AS3711_REG(LDO_8, LDO_8_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), + /* StepUp output voltage depends on supplying regulator */ +}; + +#define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info) + +static int as3711_regulator_probe(struct platform_device *pdev) +{ + struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev); + struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent); + struct regulator_init_data *reg_data; + struct regulator_config config = {.dev = &pdev->dev,}; + struct as3711_regulator *reg = NULL; + struct as3711_regulator *regs; + struct regulator_dev *rdev; + struct as3711_regulator_info *ri; + int ret; + int id; + + if (!pdata) + dev_dbg(&pdev->dev, "No platform data...\n"); + + regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM * + sizeof(struct as3711_regulator), GFP_KERNEL); + if (!regs) { + dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); + return -ENOMEM; + } + + for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) { + reg_data = pdata ? pdata->init_data[id] : NULL; + + /* No need to register if there is no regulator data */ + if (!reg_data) + continue; + + reg = ®s[id]; + reg->reg_info = ri; + + config.init_data = reg_data; + config.driver_data = reg; + config.regmap = as3711->regmap; + + rdev = regulator_register(&ri->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to register regulator %s\n", + ri->desc.name); + ret = PTR_ERR(rdev); + goto eregreg; + } + reg->rdev = rdev; + } + platform_set_drvdata(pdev, regs); + return 0; + +eregreg: + while (--id >= 0) + regulator_unregister(regs[id].rdev); + + return ret; +} + +static int as3711_regulator_remove(struct platform_device *pdev) +{ + struct as3711_regulator *regs = platform_get_drvdata(pdev); + int id; + + for (id = 0; id < AS3711_REGULATOR_NUM; ++id) + regulator_unregister(regs[id].rdev); + return 0; +} + +static struct platform_driver as3711_regulator_driver = { + .driver = { + .name = "as3711-regulator", + .owner = THIS_MODULE, + }, + .probe = as3711_regulator_probe, + .remove = as3711_regulator_remove, +}; + +static int __init as3711_regulator_init(void) +{ + return platform_driver_register(&as3711_regulator_driver); +} +subsys_initcall(as3711_regulator_init); + +static void __exit as3711_regulator_exit(void) +{ + platform_driver_unregister(&as3711_regulator_driver); +} +module_exit(as3711_regulator_exit); + +MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); +MODULE_DESCRIPTION("AS3711 regulator driver"); +MODULE_ALIAS("platform:as3711-regulator"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 5c4829cba6a6..e3661c20cf38 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -199,8 +199,11 @@ static int regulator_check_consumers(struct regulator_dev *rdev, *min_uV = regulator->min_uV; } - if (*min_uV > *max_uV) + if (*min_uV > *max_uV) { + rdev_err(rdev, "Restricting voltage, %u-%uuV\n", + *min_uV, *max_uV); return -EINVAL; + } return 0; } @@ -880,7 +883,9 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* final: [min_uV..max_uV] valid iff constraints valid */ if (max_uV < min_uV) { - rdev_err(rdev, "unsupportable voltage constraints\n"); + rdev_err(rdev, + "unsupportable voltage constraints %u-%uuV\n", + min_uV, max_uV); return -EINVAL; } @@ -1381,22 +1386,14 @@ struct regulator *regulator_get_exclusive(struct device *dev, const char *id) } EXPORT_SYMBOL_GPL(regulator_get_exclusive); -/** - * regulator_put - "free" the regulator source - * @regulator: regulator source - * - * Note: drivers must ensure that all regulator_enable calls made on this - * regulator source are balanced by regulator_disable calls prior to calling - * this function. - */ -void regulator_put(struct regulator *regulator) +/* Locks held by regulator_put() */ +static void _regulator_put(struct regulator *regulator) { struct regulator_dev *rdev; if (regulator == NULL || IS_ERR(regulator)) return; - mutex_lock(®ulator_list_mutex); rdev = regulator->rdev; debugfs_remove_recursive(regulator->debugfs); @@ -1412,6 +1409,20 @@ void regulator_put(struct regulator *regulator) rdev->exclusive = 0; module_put(rdev->owner); +} + +/** + * regulator_put - "free" the regulator source + * @regulator: regulator source + * + * Note: drivers must ensure that all regulator_enable calls made on this + * regulator source are balanced by regulator_disable calls prior to calling + * this function. + */ +void regulator_put(struct regulator *regulator) +{ + mutex_lock(®ulator_list_mutex); + _regulator_put(regulator); mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_put); @@ -1861,6 +1872,34 @@ int regulator_is_enabled(struct regulator *regulator) EXPORT_SYMBOL_GPL(regulator_is_enabled); /** + * regulator_can_change_voltage - check if regulator can change voltage + * @regulator: regulator source + * + * Returns positive if the regulator driver backing the source/client + * can change its voltage, false otherwise. Usefull for detecting fixed + * or dummy regulators and disabling voltage change logic in the client + * driver. + */ +int regulator_can_change_voltage(struct regulator *regulator) +{ + struct regulator_dev *rdev = regulator->rdev; + + if (rdev->constraints && + (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { + if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1) + return 1; + + if (rdev->desc->continuous_voltage_range && + rdev->constraints->min_uV && rdev->constraints->max_uV && + rdev->constraints->min_uV != rdev->constraints->max_uV) + return 1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(regulator_can_change_voltage); + +/** * regulator_count_voltages - count regulator_list_voltage() selectors * @regulator: regulator source * @@ -1891,6 +1930,10 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev, { if (selector >= rdev->desc->n_voltages) return -EINVAL; + if (selector < rdev->desc->linear_min_sel) + return 0; + + selector -= rdev->desc->linear_min_sel; return rdev->desc->min_uV + (rdev->desc->uV_step * selector); } @@ -1974,11 +2017,16 @@ int regulator_is_supported_voltage(struct regulator *regulator, if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { ret = regulator_get_voltage(regulator); if (ret >= 0) - return (min_uV >= ret && ret <= max_uV); + return (min_uV <= ret && ret <= max_uV); else return ret; } + /* Any voltage within constrains range is fine? */ + if (rdev->desc->continuous_voltage_range) + return min_uV >= rdev->constraints->min_uV && + max_uV <= rdev->constraints->max_uV; + ret = regulator_count_voltages(regulator); if (ret < 0) return ret; @@ -2032,10 +2080,20 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap); */ int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel) { + int ret; + sel <<= ffs(rdev->desc->vsel_mask) - 1; - return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, rdev->desc->vsel_mask, sel); + if (ret) + return ret; + + if (rdev->desc->apply_bit) + ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg, + rdev->desc->apply_bit, + rdev->desc->apply_bit); + return ret; } EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap); @@ -2114,6 +2172,8 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev, if (ret < 0) return ret; + ret += rdev->desc->linear_min_sel; + /* Map back into a voltage to verify we're still in bounds */ voltage = rdev->desc->ops->list_voltage(rdev, ret); if (voltage < min_uV || voltage > max_uV) @@ -2179,8 +2239,11 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, best_val = rdev->desc->ops->list_voltage(rdev, ret); if (min_uV <= best_val && max_uV >= best_val) { selector = ret; - ret = rdev->desc->ops->set_voltage_sel(rdev, - ret); + if (old_selector == selector) + ret = 0; + else + ret = rdev->desc->ops->set_voltage_sel( + rdev, ret); } else { ret = -EINVAL; } @@ -2191,7 +2254,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, /* Call set_voltage_time_sel if successfully obtained old_selector */ if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 && - rdev->desc->ops->set_voltage_time_sel) { + old_selector != selector && rdev->desc->ops->set_voltage_time_sel) { delay = rdev->desc->ops->set_voltage_time_sel(rdev, old_selector, selector); @@ -2244,6 +2307,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { struct regulator_dev *rdev = regulator->rdev; int ret = 0; + int old_min_uV, old_max_uV; mutex_lock(&rdev->mutex); @@ -2265,18 +2329,29 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) ret = regulator_check_voltage(rdev, &min_uV, &max_uV); if (ret < 0) goto out; + + /* restore original values in case of error */ + old_min_uV = regulator->min_uV; + old_max_uV = regulator->max_uV; regulator->min_uV = min_uV; regulator->max_uV = max_uV; ret = regulator_check_consumers(rdev, &min_uV, &max_uV); if (ret < 0) - goto out; + goto out2; ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); - + if (ret < 0) + goto out2; + out: mutex_unlock(&rdev->mutex); return ret; +out2: + regulator->min_uV = old_min_uV; + regulator->max_uV = old_max_uV; + mutex_unlock(&rdev->mutex); + return ret; } EXPORT_SYMBOL_GPL(regulator_set_voltage); @@ -2755,7 +2830,7 @@ EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap); * regulator_allow_bypass - allow the regulator to go into bypass mode * * @regulator: Regulator to configure - * @allow: enable or disable bypass mode + * @enable: enable or disable bypass mode * * Allow the regulator to go into bypass mode if all other consumers * for the regulator also enable bypass mode and the machine @@ -2982,9 +3057,13 @@ int regulator_bulk_enable(int num_consumers, return 0; err: - pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret); - while (--i >= 0) - regulator_disable(consumers[i].consumer); + for (i = 0; i < num_consumers; i++) { + if (consumers[i].ret < 0) + pr_err("Failed to enable %s: %d\n", consumers[i].supply, + consumers[i].ret); + else + regulator_disable(consumers[i].consumer); + } return ret; } @@ -3158,7 +3237,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) if (status < 0) return status; } - if (ops->is_enabled) { + if (rdev->ena_gpio || ops->is_enabled) { status = device_create_file(dev, &dev_attr_state); if (status < 0) return status; @@ -3271,7 +3350,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) * @config: runtime configuration for regulator * * Called by regulator drivers to register a regulator. - * Returns 0 on success. + * Returns a valid pointer to struct regulator_dev on success + * or an ERR_PTR() on error. */ struct regulator_dev * regulator_register(const struct regulator_desc *regulator_desc, @@ -3365,7 +3445,7 @@ regulator_register(const struct regulator_desc *regulator_desc, if (ret != 0) { rdev_err(rdev, "Failed to request enable GPIO%d: %d\n", config->ena_gpio, ret); - goto clean; + goto wash; } rdev->ena_gpio = config->ena_gpio; @@ -3445,10 +3525,11 @@ unset_supplies: scrub: if (rdev->supply) - regulator_put(rdev->supply); + _regulator_put(rdev->supply); if (rdev->ena_gpio) gpio_free(rdev->ena_gpio); kfree(rdev->constraints); +wash: device_unregister(&rdev->dev); /* device core frees rdev */ rdev = ERR_PTR(ret); diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 36c5b92fe0af..2afa5730f324 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -460,7 +460,7 @@ static inline struct da903x_regulator_info *find_regulator_info(int id) return NULL; } -static int __devinit da903x_regulator_probe(struct platform_device *pdev) +static int da903x_regulator_probe(struct platform_device *pdev) { struct da903x_regulator_info *ri = NULL; struct regulator_dev *rdev; @@ -499,7 +499,7 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit da903x_regulator_remove(struct platform_device *pdev) +static int da903x_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -513,7 +513,7 @@ static struct platform_driver da903x_regulator_driver = { .owner = THIS_MODULE, }, .probe = da903x_regulator_probe, - .remove = __devexit_p(da903x_regulator_remove), + .remove = da903x_regulator_remove, }; static int __init da903x_regulator_init(void) diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 27355b1199e5..96b569abb46c 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -70,7 +70,6 @@ struct da9052_regulator_info { int step_uV; int min_uV; int max_uV; - unsigned char activate_bit; }; struct da9052_regulator { @@ -129,17 +128,17 @@ static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA, else if (offset == 0) row = 1; - if (min_uA > da9052_current_limits[row][DA9052_MAX_UA] || - max_uA < da9052_current_limits[row][DA9052_MIN_UA]) - return -EINVAL; - for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) { - if (da9052_current_limits[row][i] <= max_uA) { + if ((min_uA <= da9052_current_limits[row][i]) && + (da9052_current_limits[row][i] <= max_uA)) { reg_val = i; break; } } + if (i < 0) + return -EINVAL; + /* Determine the even or odd position of the buck current limit * register field */ @@ -210,36 +209,6 @@ static int da9052_map_voltage(struct regulator_dev *rdev, return sel; } -static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, - unsigned int selector) -{ - struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; - int id = rdev_get_id(rdev); - int ret; - - ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg, - rdev->desc->vsel_mask, selector); - if (ret < 0) - return ret; - - /* Some LDOs and DCDCs are DVC controlled which requires enabling of - * the activate bit to implment the changes on the output. - */ - switch (id) { - case DA9052_ID_BUCK1: - case DA9052_ID_BUCK2: - case DA9052_ID_BUCK3: - case DA9052_ID_LDO2: - case DA9052_ID_LDO3: - ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, - info->activate_bit, info->activate_bit); - break; - } - - return ret; -} - static struct regulator_ops da9052_dcdc_ops = { .get_current_limit = da9052_dcdc_get_current_limit, .set_current_limit = da9052_dcdc_set_current_limit, @@ -247,7 +216,7 @@ static struct regulator_ops da9052_dcdc_ops = { .list_voltage = da9052_list_voltage, .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = da9052_regulator_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -257,7 +226,7 @@ static struct regulator_ops da9052_ldo_ops = { .list_voltage = da9052_list_voltage, .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = da9052_regulator_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -274,13 +243,14 @@ static struct regulator_ops da9052_ldo_ops = { .owner = THIS_MODULE,\ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .vsel_mask = (1 << (sbits)) - 1,\ + .apply_reg = DA9052_SUPPLY_REG, \ + .apply_bit = (abits), \ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ - .activate_bit = (abits),\ } #define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \ @@ -294,13 +264,14 @@ static struct regulator_ops da9052_ldo_ops = { .owner = THIS_MODULE,\ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .vsel_mask = (1 << (sbits)) - 1,\ + .apply_reg = DA9052_SUPPLY_REG, \ + .apply_bit = (abits), \ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ - .activate_bit = (abits),\ } static struct da9052_regulator_info da9052_regulator_info[] = { @@ -365,7 +336,7 @@ static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, return NULL; } -static int __devinit da9052_regulator_probe(struct platform_device *pdev) +static int da9052_regulator_probe(struct platform_device *pdev) { struct regulator_config config = { }; struct da9052_regulator *regulator; @@ -395,9 +366,9 @@ static int __devinit da9052_regulator_probe(struct platform_device *pdev) config.init_data = pdata->regulators[pdev->id]; } else { #ifdef CONFIG_OF - struct device_node *nproot = da9052->dev->of_node; - struct device_node *np; + struct device_node *nproot, *np; + nproot = of_node_get(da9052->dev->of_node); if (!nproot) return -ENODEV; @@ -414,6 +385,7 @@ static int __devinit da9052_regulator_probe(struct platform_device *pdev) break; } } + of_node_put(nproot); #endif } @@ -430,7 +402,7 @@ static int __devinit da9052_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit da9052_regulator_remove(struct platform_device *pdev) +static int da9052_regulator_remove(struct platform_device *pdev) { struct da9052_regulator *regulator = platform_get_drvdata(pdev); @@ -440,7 +412,7 @@ static int __devexit da9052_regulator_remove(struct platform_device *pdev) static struct platform_driver da9052_regulator_driver = { .probe = da9052_regulator_probe, - .remove = __devexit_p(da9052_regulator_remove), + .remove = da9052_regulator_remove, .driver = { .name = "da9052-regulator", .owner = THIS_MODULE, diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c new file mode 100644 index 000000000000..30221099d09c --- /dev/null +++ b/drivers/regulator/da9055-regulator.c @@ -0,0 +1,638 @@ +/* +* Regulator driver for DA9055 PMIC +* +* Copyright(c) 2012 Dialog Semiconductor Ltd. +* +* Author: David Dajun Chen <dchen@diasemi.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/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#include <linux/mfd/da9055/core.h> +#include <linux/mfd/da9055/reg.h> +#include <linux/mfd/da9055/pdata.h> + +#define DA9055_MIN_UA 0 +#define DA9055_MAX_UA 3 + +#define DA9055_LDO_MODE_SYNC 0 +#define DA9055_LDO_MODE_SLEEP 1 + +#define DA9055_BUCK_MODE_SLEEP 1 +#define DA9055_BUCK_MODE_SYNC 2 +#define DA9055_BUCK_MODE_AUTO 3 + +/* DA9055 REGULATOR IDs */ +#define DA9055_ID_BUCK1 0 +#define DA9055_ID_BUCK2 1 +#define DA9055_ID_LDO1 2 +#define DA9055_ID_LDO2 3 +#define DA9055_ID_LDO3 4 +#define DA9055_ID_LDO4 5 +#define DA9055_ID_LDO5 6 +#define DA9055_ID_LDO6 7 + +/* DA9055 BUCK current limit */ +static const int da9055_current_limits[] = { 500000, 600000, 700000, 800000 }; + +struct da9055_conf_reg { + int reg; + int sel_mask; + int en_mask; +}; + +struct da9055_volt_reg { + int reg_a; + int reg_b; + int sl_shift; + int v_mask; +}; + +struct da9055_mode_reg { + int reg; + int mask; + int shift; +}; + +struct da9055_regulator_info { + struct regulator_desc reg_desc; + struct da9055_conf_reg conf; + struct da9055_volt_reg volt; + struct da9055_mode_reg mode; +}; + +struct da9055_regulator { + struct da9055 *da9055; + struct da9055_regulator_info *info; + struct regulator_dev *rdev; + enum gpio_select reg_rselect; +}; + +static unsigned int da9055_buck_get_mode(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int ret, mode = 0; + + ret = da9055_reg_read(regulator->da9055, info->mode.reg); + if (ret < 0) + return ret; + + switch ((ret & info->mode.mask) >> info->mode.shift) { + case DA9055_BUCK_MODE_SYNC: + mode = REGULATOR_MODE_FAST; + break; + case DA9055_BUCK_MODE_AUTO: + mode = REGULATOR_MODE_NORMAL; + break; + case DA9055_BUCK_MODE_SLEEP: + mode = REGULATOR_MODE_STANDBY; + break; + } + + return mode; +} + +static int da9055_buck_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int val = 0; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = DA9055_BUCK_MODE_SYNC << info->mode.shift; + break; + case REGULATOR_MODE_NORMAL: + val = DA9055_BUCK_MODE_AUTO << info->mode.shift; + break; + case REGULATOR_MODE_STANDBY: + val = DA9055_BUCK_MODE_SLEEP << info->mode.shift; + break; + } + + return da9055_reg_update(regulator->da9055, info->mode.reg, + info->mode.mask, val); +} + +static unsigned int da9055_ldo_get_mode(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int ret; + + ret = da9055_reg_read(regulator->da9055, info->volt.reg_b); + if (ret < 0) + return ret; + + if (ret >> info->volt.sl_shift) + return REGULATOR_MODE_STANDBY; + else + return REGULATOR_MODE_NORMAL; +} + +static int da9055_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + struct da9055_volt_reg volt = info->volt; + int val = 0; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + case REGULATOR_MODE_FAST: + val = DA9055_LDO_MODE_SYNC; + break; + case REGULATOR_MODE_STANDBY: + val = DA9055_LDO_MODE_SLEEP; + break; + } + + return da9055_reg_update(regulator->da9055, volt.reg_b, + 1 << volt.sl_shift, + val << volt.sl_shift); +} + +static int da9055_buck_get_current_limit(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int ret; + + ret = da9055_reg_read(regulator->da9055, DA9055_REG_BUCK_LIM); + if (ret < 0) + return ret; + + ret &= info->mode.mask; + return da9055_current_limits[ret >> info->mode.shift]; +} + +static int da9055_buck_set_current_limit(struct regulator_dev *rdev, int min_uA, + int max_uA) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int i; + + for (i = ARRAY_SIZE(da9055_current_limits) - 1; i >= 0; i--) { + if ((min_uA <= da9055_current_limits[i]) && + (da9055_current_limits[i] <= max_uA)) + return da9055_reg_update(regulator->da9055, + DA9055_REG_BUCK_LIM, + info->mode.mask, + i << info->mode.shift); + } + + return -EINVAL; +} + +static int da9055_regulator_get_voltage_sel(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + struct da9055_volt_reg volt = info->volt; + int ret, sel; + + /* + * There are two voltage register set A & B for voltage ramping but + * either one of then can be active therefore we first determine + * the active register set. + */ + ret = da9055_reg_read(regulator->da9055, info->conf.reg); + if (ret < 0) + return ret; + + ret &= info->conf.sel_mask; + + /* Get the voltage for the active register set A/B */ + if (ret == DA9055_REGUALTOR_SET_A) + ret = da9055_reg_read(regulator->da9055, volt.reg_a); + else + ret = da9055_reg_read(regulator->da9055, volt.reg_b); + + if (ret < 0) + return ret; + + sel = (ret & volt.v_mask); + return sel; +} + +static int da9055_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int ret; + + /* + * Regulator register set A/B is not selected through GPIO therefore + * we use default register set A for voltage ramping. + */ + if (regulator->reg_rselect == NO_GPIO) { + /* Select register set A */ + ret = da9055_reg_update(regulator->da9055, info->conf.reg, + info->conf.sel_mask, DA9055_SEL_REG_A); + if (ret < 0) + return ret; + + /* Set the voltage */ + return da9055_reg_update(regulator->da9055, info->volt.reg_a, + info->volt.v_mask, selector); + } + + /* + * Here regulator register set A/B is selected through GPIO. + * Therefore we first determine the selected register set A/B and + * then set the desired voltage for that register set A/B. + */ + ret = da9055_reg_read(regulator->da9055, info->conf.reg); + if (ret < 0) + return ret; + + ret &= info->conf.sel_mask; + + /* Set the voltage */ + if (ret == DA9055_REGUALTOR_SET_A) + return da9055_reg_update(regulator->da9055, info->volt.reg_a, + info->volt.v_mask, selector); + else + return da9055_reg_update(regulator->da9055, info->volt.reg_b, + info->volt.v_mask, selector); +} + +static int da9055_regulator_set_suspend_voltage(struct regulator_dev *rdev, + int uV) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + int ret; + + /* Select register set B for suspend voltage ramping. */ + if (regulator->reg_rselect == NO_GPIO) { + ret = da9055_reg_update(regulator->da9055, info->conf.reg, + info->conf.sel_mask, DA9055_SEL_REG_B); + if (ret < 0) + return ret; + } + + ret = regulator_map_voltage_linear(rdev, uV, uV); + if (ret < 0) + return ret; + + return da9055_reg_update(regulator->da9055, info->volt.reg_b, + info->volt.v_mask, ret); +} + +static int da9055_suspend_enable(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + + /* Select register set B for voltage ramping. */ + if (regulator->reg_rselect == NO_GPIO) + return da9055_reg_update(regulator->da9055, info->conf.reg, + info->conf.sel_mask, DA9055_SEL_REG_B); + else + return 0; +} + +static int da9055_suspend_disable(struct regulator_dev *rdev) +{ + struct da9055_regulator *regulator = rdev_get_drvdata(rdev); + struct da9055_regulator_info *info = regulator->info; + + /* Diselect register set B. */ + if (regulator->reg_rselect == NO_GPIO) + return da9055_reg_update(regulator->da9055, info->conf.reg, + info->conf.sel_mask, DA9055_SEL_REG_A); + else + return 0; +} + +static struct regulator_ops da9055_buck_ops = { + .get_mode = da9055_buck_get_mode, + .set_mode = da9055_buck_set_mode, + + .get_current_limit = da9055_buck_get_current_limit, + .set_current_limit = da9055_buck_set_current_limit, + + .get_voltage_sel = da9055_regulator_get_voltage_sel, + .set_voltage_sel = da9055_regulator_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + + .set_suspend_voltage = da9055_regulator_set_suspend_voltage, + .set_suspend_enable = da9055_suspend_enable, + .set_suspend_disable = da9055_suspend_disable, + .set_suspend_mode = da9055_buck_set_mode, +}; + +static struct regulator_ops da9055_ldo_ops = { + .get_mode = da9055_ldo_get_mode, + .set_mode = da9055_ldo_set_mode, + + .get_voltage_sel = da9055_regulator_get_voltage_sel, + .set_voltage_sel = da9055_regulator_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + + .set_suspend_voltage = da9055_regulator_set_suspend_voltage, + .set_suspend_enable = da9055_suspend_enable, + .set_suspend_disable = da9055_suspend_disable, + .set_suspend_mode = da9055_ldo_set_mode, + +}; + +#define DA9055_LDO(_id, step, min, max, vbits, voffset) \ +{\ + .reg_desc = {\ + .name = #_id,\ + .ops = &da9055_ldo_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = DA9055_ID_##_id,\ + .n_voltages = (max - min) / step + 1 + (voffset), \ + .enable_reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \ + .enable_mask = 1, \ + .min_uV = (min) * 1000,\ + .uV_step = (step) * 1000,\ + .linear_min_sel = (voffset),\ + .owner = THIS_MODULE,\ + },\ + .conf = {\ + .reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \ + .sel_mask = (1 << 4),\ + .en_mask = 1,\ + },\ + .volt = {\ + .reg_a = DA9055_REG_VBCORE_A + DA9055_ID_##_id, \ + .reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \ + .sl_shift = 7,\ + .v_mask = (1 << (vbits)) - 1,\ + },\ +} + +#define DA9055_BUCK(_id, step, min, max, vbits, voffset, mbits, sbits) \ +{\ + .reg_desc = {\ + .name = #_id,\ + .ops = &da9055_buck_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = DA9055_ID_##_id,\ + .n_voltages = (max - min) / step + 1 + (voffset), \ + .enable_reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \ + .enable_mask = 1,\ + .min_uV = (min) * 1000,\ + .uV_step = (step) * 1000,\ + .linear_min_sel = (voffset),\ + .owner = THIS_MODULE,\ + },\ + .conf = {\ + .reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \ + .sel_mask = (1 << 4),\ + .en_mask = 1,\ + },\ + .volt = {\ + .reg_a = DA9055_REG_VBCORE_A + DA9055_ID_##_id, \ + .reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \ + .sl_shift = 7,\ + .v_mask = (1 << (vbits)) - 1,\ + },\ + .mode = {\ + .reg = DA9055_REG_BCORE_MODE,\ + .mask = (mbits),\ + .shift = (sbits),\ + },\ +} + +static struct da9055_regulator_info da9055_regulator_info[] = { + DA9055_BUCK(BUCK1, 25, 725, 2075, 6, 9, 0xc, 2), + DA9055_BUCK(BUCK2, 25, 925, 2500, 6, 0, 3, 0), + DA9055_LDO(LDO1, 50, 900, 3300, 6, 2), + DA9055_LDO(LDO2, 50, 900, 3300, 6, 3), + DA9055_LDO(LDO3, 50, 900, 3300, 6, 2), + DA9055_LDO(LDO4, 50, 900, 3300, 6, 2), + DA9055_LDO(LDO5, 50, 900, 2750, 6, 2), + DA9055_LDO(LDO6, 20, 900, 3300, 7, 0), +}; + +/* + * Configures regulator to be controlled either through GPIO 1 or 2. + * GPIO can control regulator state and/or select the regulator register + * set A/B for voltage ramping. + */ +static int da9055_gpio_init(struct da9055_regulator *regulator, + struct regulator_config *config, + struct da9055_pdata *pdata, int id) +{ + struct da9055_regulator_info *info = regulator->info; + int ret = 0; + + if (pdata->gpio_ren && pdata->gpio_ren[id]) { + char name[18]; + int gpio_mux = pdata->gpio_ren[id]; + + config->ena_gpio = pdata->ena_gpio[id]; + config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + config->ena_gpio_invert = 1; + + /* + * GPI pin is muxed with regulator to control the + * regulator state. + */ + sprintf(name, "DA9055 GPI %d", gpio_mux); + ret = devm_gpio_request_one(config->dev, gpio_mux, GPIOF_DIR_IN, + name); + if (ret < 0) + goto err; + + /* + * Let the regulator know that its state is controlled + * through GPI. + */ + ret = da9055_reg_update(regulator->da9055, info->conf.reg, + DA9055_E_GPI_MASK, + pdata->reg_ren[id] + << DA9055_E_GPI_SHIFT); + if (ret < 0) + goto err; + } + + if (pdata->gpio_rsel && pdata->gpio_rsel[id]) { + char name[18]; + int gpio_mux = pdata->gpio_rsel[id]; + + regulator->reg_rselect = pdata->reg_rsel[id]; + + /* + * GPI pin is muxed with regulator to select the + * regulator register set A/B for voltage ramping. + */ + sprintf(name, "DA9055 GPI %d", gpio_mux); + ret = devm_gpio_request_one(config->dev, gpio_mux, GPIOF_DIR_IN, + name); + if (ret < 0) + goto err; + + /* + * Let the regulator know that its register set A/B + * will be selected through GPI for voltage ramping. + */ + ret = da9055_reg_update(regulator->da9055, info->conf.reg, + DA9055_V_GPI_MASK, + pdata->reg_rsel[id] + << DA9055_V_GPI_SHIFT); + } + +err: + return ret; +} + +static irqreturn_t da9055_ldo5_6_oc_irq(int irq, void *data) +{ + struct da9055_regulator *regulator = data; + + regulator_notifier_call_chain(regulator->rdev, + REGULATOR_EVENT_OVER_CURRENT, NULL); + + return IRQ_HANDLED; +} + +static inline struct da9055_regulator_info *find_regulator_info(int id) +{ + struct da9055_regulator_info *info; + int i; + + for (i = 0; i < ARRAY_SIZE(da9055_regulator_info); i++) { + info = &da9055_regulator_info[i]; + if (info->reg_desc.id == id) + return info; + } + + return NULL; +} + +static int da9055_regulator_probe(struct platform_device *pdev) +{ + struct regulator_config config = { }; + struct da9055_regulator *regulator; + struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent); + struct da9055_pdata *pdata = da9055->dev->platform_data; + int ret, irq; + + if (pdata == NULL || pdata->regulators[pdev->id] == NULL) + return -ENODEV; + + regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9055_regulator), + GFP_KERNEL); + if (!regulator) + return -ENOMEM; + + regulator->info = find_regulator_info(pdev->id); + if (regulator->info == NULL) { + dev_err(&pdev->dev, "invalid regulator ID specified\n"); + return -EINVAL; + } + + regulator->da9055 = da9055; + config.dev = &pdev->dev; + config.driver_data = regulator; + config.regmap = da9055->regmap; + + if (pdata && pdata->regulators) + config.init_data = pdata->regulators[pdev->id]; + + ret = da9055_gpio_init(regulator, &config, pdata, pdev->id); + if (ret < 0) + return ret; + + regulator->rdev = regulator_register(®ulator->info->reg_desc, + &config); + if (IS_ERR(regulator->rdev)) { + dev_err(&pdev->dev, "Failed to register regulator %s\n", + regulator->info->reg_desc.name); + ret = PTR_ERR(regulator->rdev); + return ret; + } + + /* Only LDO 5 and 6 has got the over current interrupt */ + if (pdev->id == DA9055_ID_LDO5 || pdev->id == DA9055_ID_LDO6) { + irq = platform_get_irq_byname(pdev, "REGULATOR"); + irq = regmap_irq_get_virq(da9055->irq_data, irq); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + da9055_ldo5_6_oc_irq, + IRQF_TRIGGER_HIGH | + IRQF_ONESHOT | + IRQF_PROBE_SHARED, + pdev->name, regulator); + if (ret != 0) { + if (ret != -EBUSY) { + dev_err(&pdev->dev, + "Failed to request Regulator IRQ %d: %d\n", + irq, ret); + goto err_regulator; + } + } + } + + platform_set_drvdata(pdev, regulator); + + return 0; + +err_regulator: + regulator_unregister(regulator->rdev); + return ret; +} + +static int da9055_regulator_remove(struct platform_device *pdev) +{ + struct da9055_regulator *regulator = platform_get_drvdata(pdev); + + regulator_unregister(regulator->rdev); + + return 0; +} + +static struct platform_driver da9055_regulator_driver = { + .probe = da9055_regulator_probe, + .remove = da9055_regulator_remove, + .driver = { + .name = "da9055-regulator", + .owner = THIS_MODULE, + }, +}; + +static int __init da9055_regulator_init(void) +{ + return platform_driver_register(&da9055_regulator_driver); +} +subsys_initcall(da9055_regulator_init); + +static void __exit da9055_regulator_exit(void) +{ + platform_driver_unregister(&da9055_regulator_driver); +} +module_exit(da9055_regulator_exit); + +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9055 PMIC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-regulator"); diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 359f8d18fc3f..a53c11a529d5 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -412,7 +412,7 @@ dbx500_regulator_info[DB8500_NUM_REGULATORS] = { }, }; -static __devinit int db8500_regulator_register(struct platform_device *pdev, +static int db8500_regulator_register(struct platform_device *pdev, struct regulator_init_data *init_data, int id, struct device_node *np) @@ -474,7 +474,7 @@ static struct of_regulator_match db8500_regulator_matches[] = { { .name = "db8500_esram34_ret", .driver_data = (void *) DB8500_REGULATOR_SWITCH_ESRAM34RET, }, }; -static __devinit int +static int db8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np) { @@ -491,7 +491,7 @@ db8500_regulator_of_probe(struct platform_device *pdev, return 0; } -static int __devinit db8500_regulator_probe(struct platform_device *pdev) +static int db8500_regulator_probe(struct platform_device *pdev) { struct regulator_init_data *db8500_init_data = dev_get_platdata(&pdev->dev); @@ -528,7 +528,7 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev) return 0; } -static int __exit db8500_regulator_remove(struct platform_device *pdev) +static int db8500_regulator_remove(struct platform_device *pdev) { int i; @@ -553,7 +553,7 @@ static struct platform_driver db8500_regulator_driver = { .owner = THIS_MODULE, }, .probe = db8500_regulator_probe, - .remove = __exit_p(db8500_regulator_remove), + .remove = db8500_regulator_remove, }; static int __init db8500_regulator_init(void) diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index f2e5ecdc5864..89bd2faaef8c 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -14,6 +14,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/module.h> #include "dbx500-prcmu.h" @@ -173,7 +174,7 @@ int __attribute__((weak)) dbx500_regulator_testcase( return 0; } -int __devinit +int ux500_regulator_debug_init(struct platform_device *pdev, struct dbx500_regulator_info *regulator_info, int num_regulators) @@ -230,7 +231,7 @@ exit_no_debugfs: return -ENOMEM; } -int __devexit ux500_regulator_debug_exit(void) +int ux500_regulator_debug_exit(void) { debugfs_remove_recursive(rdebug.dir); kfree(rdebug.state_after_suspend); diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index 03a1d7c11ef2..df9f42524abb 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c @@ -37,7 +37,7 @@ static struct regulator_desc dummy_desc = { .ops = &dummy_ops, }; -static int __devinit dummy_regulator_probe(struct platform_device *pdev) +static int dummy_regulator_probe(struct platform_device *pdev) { struct regulator_config config = { }; int ret; diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 339f4d732e97..9165b0c40ed3 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -230,7 +230,7 @@ static struct regmap_config fan53555_regmap_config = { .val_bits = 8, }; -static int __devinit fan53555_regulator_probe(struct i2c_client *client, +static int fan53555_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct fan53555_device_info *di; @@ -293,7 +293,7 @@ static int __devinit fan53555_regulator_probe(struct i2c_client *client, } -static int __devexit fan53555_regulator_remove(struct i2c_client *client) +static int fan53555_regulator_remove(struct i2c_client *client) { struct fan53555_device_info *di = i2c_get_clientdata(client); @@ -311,7 +311,7 @@ static struct i2c_driver fan53555_regulator_driver = { .name = "fan53555-regulator", }, .probe = fan53555_regulator_probe, - .remove = __devexit_p(fan53555_regulator_remove), + .remove = fan53555_regulator_remove, .id_table = fan53555_id, }; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 185468c4d38f..e5c03b534fae 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -134,7 +134,7 @@ static struct regulator_ops fixed_voltage_ops = { .list_voltage = fixed_voltage_list_voltage, }; -static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) +static int reg_fixed_voltage_probe(struct platform_device *pdev) { struct fixed_voltage_config *config; struct fixed_voltage_data *drvdata; @@ -234,7 +234,7 @@ err: return ret; } -static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev) +static int reg_fixed_voltage_remove(struct platform_device *pdev) { struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); @@ -246,7 +246,7 @@ static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev) } #if defined(CONFIG_OF) -static const struct of_device_id fixed_of_match[] __devinitconst = { +static const struct of_device_id fixed_of_match[] = { { .compatible = "regulator-fixed", }, {}, }; @@ -255,7 +255,7 @@ MODULE_DEVICE_TABLE(of, fixed_of_match); static struct platform_driver regulator_fixed_voltage_driver = { .probe = reg_fixed_voltage_probe, - .remove = __devexit_p(reg_fixed_voltage_remove), + .remove = reg_fixed_voltage_remove, .driver = { .name = "reg-fixed-voltage", .owner = THIS_MODULE, diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 8b5944f2d7d1..9d39eb4aafa3 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -28,9 +28,12 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/regulator/gpio-regulator.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h> struct gpio_regulator_data { struct regulator_desc desc; @@ -79,7 +82,7 @@ static int gpio_regulator_set_voltage(struct regulator_dev *dev, for (ptr = 0; ptr < data->nr_gpios; ptr++) { state = (target & (1 << ptr)) >> ptr; - gpio_set_value(data->gpios[ptr].gpio, state); + gpio_set_value_cansleep(data->gpios[ptr].gpio, state); } data->state = target; @@ -116,7 +119,7 @@ static int gpio_regulator_set_current_limit(struct regulator_dev *dev, for (ptr = 0; ptr < data->nr_gpios; ptr++) { state = (target & (1 << ptr)) >> ptr; - gpio_set_value(data->gpios[ptr].gpio, state); + gpio_set_value_cansleep(data->gpios[ptr].gpio, state); } data->state = target; @@ -129,18 +132,105 @@ static struct regulator_ops gpio_regulator_voltage_ops = { .list_voltage = gpio_regulator_list_voltage, }; +static struct gpio_regulator_config * +of_get_gpio_regulator_config(struct device *dev, struct device_node *np) +{ + struct gpio_regulator_config *config; + struct property *prop; + const char *regtype; + int proplen, gpio, i; + + config = devm_kzalloc(dev, + sizeof(struct gpio_regulator_config), + GFP_KERNEL); + if (!config) + return ERR_PTR(-ENOMEM); + + config->init_data = of_get_regulator_init_data(dev, np); + if (!config->init_data) + return ERR_PTR(-EINVAL); + + config->supply_name = config->init_data->constraints.name; + + if (of_property_read_bool(np, "enable-active-high")) + config->enable_high = true; + + if (of_property_read_bool(np, "enable-at-boot")) + config->enabled_at_boot = true; + + of_property_read_u32(np, "startup-delay-us", &config->startup_delay); + + config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); + + /* Fetch GPIOs. */ + config->nr_gpios = of_gpio_count(np); + + config->gpios = devm_kzalloc(dev, + sizeof(struct gpio) * config->nr_gpios, + GFP_KERNEL); + if (!config->gpios) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < config->nr_gpios; i++) { + gpio = of_get_named_gpio(np, "gpios", i); + if (gpio < 0) + break; + config->gpios[i].gpio = gpio; + } + + /* Fetch states. */ + prop = of_find_property(np, "states", NULL); + if (!prop) { + dev_err(dev, "No 'states' property found\n"); + return ERR_PTR(-EINVAL); + } + + proplen = prop->length / sizeof(int); + + config->states = devm_kzalloc(dev, + sizeof(struct gpio_regulator_state) + * (proplen / 2), + GFP_KERNEL); + if (!config->states) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < proplen / 2; i++) { + config->states[i].value = + be32_to_cpup((int *)prop->value + (i * 2)); + config->states[i].gpios = + be32_to_cpup((int *)prop->value + (i * 2 + 1)); + } + config->nr_states = i; + + of_property_read_string(np, "regulator-type", ®type); + + if (!strncmp("voltage", regtype, 7)) + config->type = REGULATOR_VOLTAGE; + else if (!strncmp("current", regtype, 7)) + config->type = REGULATOR_CURRENT; + + return config; +} + static struct regulator_ops gpio_regulator_current_ops = { .get_current_limit = gpio_regulator_get_value, .set_current_limit = gpio_regulator_set_current_limit, }; -static int __devinit gpio_regulator_probe(struct platform_device *pdev) +static int gpio_regulator_probe(struct platform_device *pdev) { struct gpio_regulator_config *config = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; struct gpio_regulator_data *drvdata; struct regulator_config cfg = { }; int ptr, ret, state; + if (np) { + config = of_get_gpio_regulator_config(&pdev->dev, np); + if (IS_ERR(config)) + return PTR_ERR(config); + } + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), GFP_KERNEL); if (drvdata == NULL) { @@ -215,6 +305,7 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) cfg.dev = &pdev->dev; cfg.init_data = config->init_data; cfg.driver_data = drvdata; + cfg.of_node = np; if (config->enable_gpio >= 0) cfg.ena_gpio = config->enable_gpio; @@ -254,7 +345,7 @@ err: return ret; } -static int __devexit gpio_regulator_remove(struct platform_device *pdev) +static int gpio_regulator_remove(struct platform_device *pdev) { struct gpio_regulator_data *drvdata = platform_get_drvdata(pdev); @@ -270,12 +361,20 @@ static int __devexit gpio_regulator_remove(struct platform_device *pdev) return 0; } +#if defined(CONFIG_OF) +static const struct of_device_id regulator_gpio_of_match[] = { + { .compatible = "regulator-gpio", }, + {}, +}; +#endif + static struct platform_driver gpio_regulator_driver = { .probe = gpio_regulator_probe, - .remove = __devexit_p(gpio_regulator_remove), + .remove = gpio_regulator_remove, .driver = { .name = "gpio-regulator", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(regulator_gpio_of_match), }, }; diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index d8ecf49a5777..d1e5bee2a26b 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -106,7 +106,7 @@ static const struct regulator_desc isl_rd[] = { }, }; -static int __devinit isl6271a_probe(struct i2c_client *i2c, +static int isl6271a_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct regulator_config config = { }; @@ -151,7 +151,7 @@ error: return err; } -static int __devexit isl6271a_remove(struct i2c_client *i2c) +static int isl6271a_remove(struct i2c_client *i2c) { struct isl_pmic *pmic = i2c_get_clientdata(i2c); int i; @@ -174,7 +174,7 @@ static struct i2c_driver isl6271a_i2c_driver = { .owner = THIS_MODULE, }, .probe = isl6271a_probe, - .remove = __devexit_p(isl6271a_remove), + .remove = isl6271a_remove, .id_table = isl6271a_id, }; diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 7c6e3b8ff484..9cb2c0f34515 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -73,8 +73,6 @@ static const unsigned int buck_voltage_map[] = { }; #define BUCK_TARGET_VOL_MASK 0x3f -#define BUCK_TARGET_VOL_MIN_IDX 0x01 -#define BUCK_TARGET_VOL_MAX_IDX 0x19 #define LP3971_BUCK_RAMP_REG(x) (buck_base_addr[x]+2) @@ -140,7 +138,7 @@ static int lp3971_ldo_disable(struct regulator_dev *dev) return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0); } -static int lp3971_ldo_get_voltage(struct regulator_dev *dev) +static int lp3971_ldo_get_voltage_sel(struct regulator_dev *dev) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3971_LDO1; @@ -149,7 +147,7 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev) reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo)); val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK; - return dev->desc->volt_table[val]; + return val; } static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev, @@ -168,7 +166,7 @@ static struct regulator_ops lp3971_ldo_ops = { .is_enabled = lp3971_ldo_is_enabled, .enable = lp3971_ldo_enable, .disable = lp3971_ldo_disable, - .get_voltage = lp3971_ldo_get_voltage, + .get_voltage_sel = lp3971_ldo_get_voltage_sel, .set_voltage_sel = lp3971_ldo_set_voltage_sel, }; @@ -201,24 +199,16 @@ static int lp3971_dcdc_disable(struct regulator_dev *dev) return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0); } -static int lp3971_dcdc_get_voltage(struct regulator_dev *dev) +static int lp3971_dcdc_get_voltage_sel(struct regulator_dev *dev) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3971_DCDC1; u16 reg; - int val; reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck)); reg &= BUCK_TARGET_VOL_MASK; - if (reg <= BUCK_TARGET_VOL_MAX_IDX) - val = buck_voltage_map[reg]; - else { - val = 0; - dev_warn(&dev->dev, "chip reported incorrect voltage value.\n"); - } - - return val; + return reg; } static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev, @@ -249,7 +239,7 @@ static struct regulator_ops lp3971_dcdc_ops = { .is_enabled = lp3971_dcdc_is_enabled, .enable = lp3971_dcdc_enable, .disable = lp3971_dcdc_disable, - .get_voltage = lp3971_dcdc_get_voltage, + .get_voltage_sel = lp3971_dcdc_get_voltage_sel, .set_voltage_sel = lp3971_dcdc_set_voltage_sel, }; @@ -386,7 +376,7 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val) return ret; } -static int __devinit setup_regulators(struct lp3971 *lp3971, +static int setup_regulators(struct lp3971 *lp3971, struct lp3971_platform_data *pdata) { int i, err; @@ -429,7 +419,7 @@ err_nomem: return err; } -static int __devinit lp3971_i2c_probe(struct i2c_client *i2c, +static int lp3971_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct lp3971 *lp3971; @@ -472,7 +462,7 @@ err_detect: return ret; } -static int __devexit lp3971_i2c_remove(struct i2c_client *i2c) +static int lp3971_i2c_remove(struct i2c_client *i2c) { struct lp3971 *lp3971 = i2c_get_clientdata(i2c); int i; @@ -498,7 +488,7 @@ static struct i2c_driver lp3971_i2c_driver = { .owner = THIS_MODULE, }, .probe = lp3971_i2c_probe, - .remove = __devexit_p(lp3971_i2c_remove), + .remove = lp3971_i2c_remove, .id_table = lp3971_i2c_id, }; diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index 3cdc755d9b22..0baabcfb578a 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -165,8 +165,6 @@ static const int buck_base_addr[] = { #define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x]) #define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x]) #define LP3972_BUCK_VOL_MASK 0x1f -#define LP3972_BUCK_VOL_MIN_IDX(x) ((x) ? 0x01 : 0x00) -#define LP3972_BUCK_VOL_MAX_IDX(x) ((x) ? 0x19 : 0x1f) static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count, u16 *dest) @@ -257,7 +255,7 @@ static int lp3972_ldo_disable(struct regulator_dev *dev) mask, 0); } -static int lp3972_ldo_get_voltage(struct regulator_dev *dev) +static int lp3972_ldo_get_voltage_sel(struct regulator_dev *dev) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3972_LDO1; @@ -267,7 +265,7 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev) reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo)); val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask; - return dev->desc->volt_table[val]; + return val; } static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev, @@ -314,7 +312,7 @@ static struct regulator_ops lp3972_ldo_ops = { .is_enabled = lp3972_ldo_is_enabled, .enable = lp3972_ldo_enable, .disable = lp3972_ldo_disable, - .get_voltage = lp3972_ldo_get_voltage, + .get_voltage_sel = lp3972_ldo_get_voltage_sel, .set_voltage_sel = lp3972_ldo_set_voltage_sel, }; @@ -353,24 +351,16 @@ static int lp3972_dcdc_disable(struct regulator_dev *dev) return val; } -static int lp3972_dcdc_get_voltage(struct regulator_dev *dev) +static int lp3972_dcdc_get_voltage_sel(struct regulator_dev *dev) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3972_DCDC1; u16 reg; - int val; reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck)); reg &= LP3972_BUCK_VOL_MASK; - if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck)) - val = dev->desc->volt_table[reg]; - else { - val = 0; - dev_warn(&dev->dev, "chip reported incorrect voltage value." - " reg = %d\n", reg); - } - return val; + return reg; } static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev, @@ -402,7 +392,7 @@ static struct regulator_ops lp3972_dcdc_ops = { .is_enabled = lp3972_dcdc_is_enabled, .enable = lp3972_dcdc_enable, .disable = lp3972_dcdc_disable, - .get_voltage = lp3972_dcdc_get_voltage, + .get_voltage_sel = lp3972_dcdc_get_voltage_sel, .set_voltage_sel = lp3972_dcdc_set_voltage_sel, }; @@ -481,7 +471,7 @@ static const struct regulator_desc regulators[] = { }, }; -static int __devinit setup_regulators(struct lp3972 *lp3972, +static int setup_regulators(struct lp3972 *lp3972, struct lp3972_platform_data *pdata) { int i, err; @@ -523,7 +513,7 @@ err_nomem: return err; } -static int __devinit lp3972_i2c_probe(struct i2c_client *i2c, +static int lp3972_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct lp3972 *lp3972; @@ -569,7 +559,7 @@ err_detect: return ret; } -static int __devexit lp3972_i2c_remove(struct i2c_client *i2c) +static int lp3972_i2c_remove(struct i2c_client *i2c) { struct lp3972 *lp3972 = i2c_get_clientdata(i2c); int i; @@ -594,7 +584,7 @@ static struct i2c_driver lp3972_i2c_driver = { .owner = THIS_MODULE, }, .probe = lp3972_i2c_probe, - .remove = __devexit_p(lp3972_i2c_remove), + .remove = lp3972_i2c_remove, .id_table = lp3972_i2c_id, }; diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 708f4b6a17dc..8e3c7ae0047f 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -181,20 +181,6 @@ static inline int lp872x_update_bits(struct lp872x *lp, u8 addr, return regmap_update_bits(lp->regmap, addr, mask, data); } -static int _rdev_to_offset(struct regulator_dev *rdev) -{ - enum lp872x_regulator_id id = rdev_get_id(rdev); - - switch (id) { - case LP8720_ID_LDO1 ... LP8720_ID_BUCK: - return id; - case LP8725_ID_LDO1 ... LP8725_ID_BUCK2: - return id - LP8725_ID_BASE; - default: - return -EINVAL; - } -} - static int lp872x_get_timestep_usec(struct lp872x *lp) { enum lp872x_id chip = lp->chipid; @@ -234,28 +220,20 @@ static int lp872x_get_timestep_usec(struct lp872x *lp) static int lp872x_regulator_enable_time(struct regulator_dev *rdev) { struct lp872x *lp = rdev_get_drvdata(rdev); - enum lp872x_regulator_id regulator = rdev_get_id(rdev); + enum lp872x_regulator_id rid = rdev_get_id(rdev); int time_step_us = lp872x_get_timestep_usec(lp); - int ret, offset; + int ret; u8 addr, val; if (time_step_us < 0) return -EINVAL; - switch (regulator) { - case LP8720_ID_LDO1 ... LP8720_ID_LDO5: - case LP8725_ID_LDO1 ... LP8725_ID_LILO2: - offset = _rdev_to_offset(rdev); - if (offset < 0) - return -EINVAL; - - addr = LP872X_LDO1_VOUT + offset; - break; - case LP8720_ID_BUCK: - addr = LP8720_BUCK_VOUT1; + switch (rid) { + case LP8720_ID_LDO1 ... LP8720_ID_BUCK: + addr = LP872X_LDO1_VOUT + rid; break; - case LP8725_ID_BUCK1: - addr = LP8725_BUCK1_VOUT1; + case LP8725_ID_LDO1 ... LP8725_ID_BUCK1: + addr = LP872X_LDO1_VOUT + rid - LP8725_ID_BASE; break; case LP8725_ID_BUCK2: addr = LP8725_BUCK2_VOUT1; @@ -893,7 +871,7 @@ err_dev: return ret; } -static int __devexit lp872x_remove(struct i2c_client *cl) +static int lp872x_remove(struct i2c_client *cl) { struct lp872x *lp = i2c_get_clientdata(cl); @@ -914,7 +892,7 @@ static struct i2c_driver lp872x_driver = { .owner = THIS_MODULE, }, .probe = lp872x_probe, - .remove = __devexit_p(lp872x_remove), + .remove = lp872x_remove, .id_table = lp872x_ids, }; diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c new file mode 100644 index 000000000000..f0f6ea05065b --- /dev/null +++ b/drivers/regulator/lp8755.c @@ -0,0 +1,566 @@ +/* + * LP8755 High Performance Power Management Unit : System Interface Driver + * (based on rev. 0.26) + * Copyright 2012 Texas Instruments + * + * Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.com> + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/regmap.h> +#include <linux/delay.h> +#include <linux/uaccess.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/platform_data/lp8755.h> + +#define LP8755_REG_BUCK0 0x00 +#define LP8755_REG_BUCK1 0x03 +#define LP8755_REG_BUCK2 0x04 +#define LP8755_REG_BUCK3 0x01 +#define LP8755_REG_BUCK4 0x05 +#define LP8755_REG_BUCK5 0x02 +#define LP8755_REG_MAX 0xFF + +#define LP8755_BUCK_EN_M BIT(7) +#define LP8755_BUCK_LINEAR_OUT_MAX 0x76 +#define LP8755_BUCK_VOUT_M 0x7F + +struct lp8755_mphase { + int nreg; + int buck_num[LP8755_BUCK_MAX]; +}; + +struct lp8755_chip { + struct device *dev; + struct regmap *regmap; + struct lp8755_platform_data *pdata; + + int irq; + unsigned int irqmask; + + int mphase; + struct regulator_dev *rdev[LP8755_BUCK_MAX]; +}; + +/** + *lp8755_read : read a single register value from lp8755. + *@pchip : device to read from + *@reg : register to read from + *@val : pointer to store read value + */ +static int lp8755_read(struct lp8755_chip *pchip, unsigned int reg, + unsigned int *val) +{ + return regmap_read(pchip->regmap, reg, val); +} + +/** + *lp8755_write : write a single register value to lp8755. + *@pchip : device to write to + *@reg : register to write to + *@val : value to be written + */ +static int lp8755_write(struct lp8755_chip *pchip, unsigned int reg, + unsigned int val) +{ + return regmap_write(pchip->regmap, reg, val); +} + +/** + *lp8755_update_bits : set the values of bit fields in lp8755 register. + *@pchip : device to read from + *@reg : register to update + *@mask : bitmask to be changed + *@val : value for bitmask + */ +static int lp8755_update_bits(struct lp8755_chip *pchip, unsigned int reg, + unsigned int mask, unsigned int val) +{ + return regmap_update_bits(pchip->regmap, reg, mask, val); +} + +static int lp8755_buck_enable_time(struct regulator_dev *rdev) +{ + int ret; + unsigned int regval; + enum lp8755_bucks id = rdev_get_id(rdev); + struct lp8755_chip *pchip = rdev_get_drvdata(rdev); + + ret = lp8755_read(pchip, 0x12 + id, ®val); + if (ret < 0) { + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return ret; + } + return (regval & 0xff) * 100; +} + +static int lp8755_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + int ret; + unsigned int regbval = 0x0; + enum lp8755_bucks id = rdev_get_id(rdev); + struct lp8755_chip *pchip = rdev_get_drvdata(rdev); + + switch (mode) { + case REGULATOR_MODE_FAST: + /* forced pwm mode */ + regbval = (0x01 << id); + break; + case REGULATOR_MODE_NORMAL: + /* enable automatic pwm/pfm mode */ + ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x00); + if (ret < 0) + goto err_i2c; + break; + case REGULATOR_MODE_IDLE: + /* enable automatic pwm/pfm/lppfm mode */ + ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x20); + if (ret < 0) + goto err_i2c; + + ret = lp8755_update_bits(pchip, 0x10, 0x01, 0x01); + if (ret < 0) + goto err_i2c; + break; + default: + dev_err(pchip->dev, "Not supported buck mode %s\n", __func__); + /* forced pwm mode */ + regbval = (0x01 << id); + } + + ret = lp8755_update_bits(pchip, 0x06, 0x01 << id, regbval); + if (ret < 0) + goto err_i2c; + return ret; +err_i2c: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return ret; +} + +static unsigned int lp8755_buck_get_mode(struct regulator_dev *rdev) +{ + int ret; + unsigned int regval; + enum lp8755_bucks id = rdev_get_id(rdev); + struct lp8755_chip *pchip = rdev_get_drvdata(rdev); + + ret = lp8755_read(pchip, 0x06, ®val); + if (ret < 0) + goto err_i2c; + + /* mode fast means forced pwm mode */ + if (regval & (0x01 << id)) + return REGULATOR_MODE_FAST; + + ret = lp8755_read(pchip, 0x08 + id, ®val); + if (ret < 0) + goto err_i2c; + + /* mode idle means automatic pwm/pfm/lppfm mode */ + if (regval & 0x20) + return REGULATOR_MODE_IDLE; + + /* mode normal means automatic pwm/pfm mode */ + return REGULATOR_MODE_NORMAL; + +err_i2c: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return 0; +} + +static int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp) +{ + int ret; + unsigned int regval = 0x00; + enum lp8755_bucks id = rdev_get_id(rdev); + struct lp8755_chip *pchip = rdev_get_drvdata(rdev); + + /* uV/us */ + switch (ramp) { + case 0 ... 230: + regval = 0x07; + break; + case 231 ... 470: + regval = 0x06; + break; + case 471 ... 940: + regval = 0x05; + break; + case 941 ... 1900: + regval = 0x04; + break; + case 1901 ... 3800: + regval = 0x03; + break; + case 3801 ... 7500: + regval = 0x02; + break; + case 7501 ... 15000: + regval = 0x01; + break; + case 15001 ... 30000: + regval = 0x00; + break; + default: + dev_err(pchip->dev, + "Not supported ramp value %d %s\n", ramp, __func__); + return -EINVAL; + } + + ret = lp8755_update_bits(pchip, 0x07 + id, 0x07, regval); + if (ret < 0) + goto err_i2c; + return ret; +err_i2c: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return ret; +} + +static struct regulator_ops lp8755_buck_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .enable_time = lp8755_buck_enable_time, + .set_mode = lp8755_buck_set_mode, + .get_mode = lp8755_buck_get_mode, + .set_ramp_delay = lp8755_buck_set_ramp, +}; + +#define lp8755_rail(_id) "lp8755_buck"#_id +#define lp8755_buck_init(_id)\ +{\ + .constraints = {\ + .name = lp8755_rail(_id),\ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,\ + .min_uV = 500000,\ + .max_uV = 1675000,\ + },\ +} + +static struct regulator_init_data lp8755_reg_default[LP8755_BUCK_MAX] = { + [LP8755_BUCK0] = lp8755_buck_init(0), + [LP8755_BUCK1] = lp8755_buck_init(1), + [LP8755_BUCK2] = lp8755_buck_init(2), + [LP8755_BUCK3] = lp8755_buck_init(3), + [LP8755_BUCK4] = lp8755_buck_init(4), + [LP8755_BUCK5] = lp8755_buck_init(5), +}; + +static const struct lp8755_mphase mphase_buck[MPHASE_CONF_MAX] = { + { 3, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK5 } }, + { 6, { LP8755_BUCK0, LP8755_BUCK1, LP8755_BUCK2, LP8755_BUCK3, + LP8755_BUCK4, LP8755_BUCK5 } }, + { 5, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK4, + LP8755_BUCK5} }, + { 4, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK4, LP8755_BUCK5} }, + { 3, { LP8755_BUCK0, LP8755_BUCK4, LP8755_BUCK5} }, + { 2, { LP8755_BUCK0, LP8755_BUCK5} }, + { 1, { LP8755_BUCK0} }, + { 2, { LP8755_BUCK0, LP8755_BUCK3} }, + { 4, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK5} }, +}; + +static int lp8755_init_data(struct lp8755_chip *pchip) +{ + unsigned int regval; + int ret, icnt, buck_num; + struct lp8755_platform_data *pdata = pchip->pdata; + + /* read back muti-phase configuration */ + ret = lp8755_read(pchip, 0x3D, ®val); + if (ret < 0) + goto out_i2c_error; + pchip->mphase = regval & 0x0F; + + /* set default data based on multi-phase config */ + for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) { + buck_num = mphase_buck[pchip->mphase].buck_num[icnt]; + pdata->buck_data[buck_num] = &lp8755_reg_default[buck_num]; + } + return ret; + +out_i2c_error: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return ret; +} + +#define lp8755_buck_desc(_id)\ +{\ + .name = lp8755_rail(_id),\ + .id = LP8755_BUCK##_id,\ + .ops = &lp8755_buck_ops,\ + .n_voltages = LP8755_BUCK_LINEAR_OUT_MAX+1,\ + .uV_step = 10000,\ + .min_uV = 500000,\ + .type = REGULATOR_VOLTAGE,\ + .owner = THIS_MODULE,\ + .enable_reg = LP8755_REG_BUCK##_id,\ + .enable_mask = LP8755_BUCK_EN_M,\ + .vsel_reg = LP8755_REG_BUCK##_id,\ + .vsel_mask = LP8755_BUCK_VOUT_M,\ +} + +static struct regulator_desc lp8755_regulators[] = { + lp8755_buck_desc(0), + lp8755_buck_desc(1), + lp8755_buck_desc(2), + lp8755_buck_desc(3), + lp8755_buck_desc(4), + lp8755_buck_desc(5), +}; + +static int lp8755_regulator_init(struct lp8755_chip *pchip) +{ + int ret, icnt, buck_num; + struct lp8755_platform_data *pdata = pchip->pdata; + struct regulator_config rconfig = { }; + + rconfig.regmap = pchip->regmap; + rconfig.dev = pchip->dev; + rconfig.driver_data = pchip; + + for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) { + buck_num = mphase_buck[pchip->mphase].buck_num[icnt]; + rconfig.init_data = pdata->buck_data[buck_num]; + rconfig.of_node = pchip->dev->of_node; + pchip->rdev[buck_num] = + regulator_register(&lp8755_regulators[buck_num], &rconfig); + if (IS_ERR(pchip->rdev[buck_num])) { + ret = PTR_ERR(pchip->rdev[buck_num]); + pchip->rdev[buck_num] = NULL; + dev_err(pchip->dev, "regulator init failed: buck %d\n", + buck_num); + goto err_buck; + } + } + + return 0; + +err_buck: + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + regulator_unregister(pchip->rdev[icnt]); + return ret; +} + +static irqreturn_t lp8755_irq_handler(int irq, void *data) +{ + int ret, icnt; + unsigned int flag0, flag1; + struct lp8755_chip *pchip = data; + + /* read flag0 register */ + ret = lp8755_read(pchip, 0x0D, &flag0); + if (ret < 0) + goto err_i2c; + /* clear flag register to pull up int. pin */ + ret = lp8755_write(pchip, 0x0D, 0x00); + if (ret < 0) + goto err_i2c; + + /* sent power fault detection event to specific regulator */ + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + if ((flag0 & (0x4 << icnt)) + && (pchip->irqmask & (0x04 << icnt)) + && (pchip->rdev[icnt] != NULL)) + regulator_notifier_call_chain(pchip->rdev[icnt], + LP8755_EVENT_PWR_FAULT, + NULL); + + /* read flag1 register */ + ret = lp8755_read(pchip, 0x0E, &flag1); + if (ret < 0) + goto err_i2c; + /* clear flag register to pull up int. pin */ + ret = lp8755_write(pchip, 0x0E, 0x00); + if (ret < 0) + goto err_i2c; + + /* send OCP event to all regualtor devices */ + if ((flag1 & 0x01) && (pchip->irqmask & 0x01)) + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + if (pchip->rdev[icnt] != NULL) + regulator_notifier_call_chain(pchip->rdev[icnt], + LP8755_EVENT_OCP, + NULL); + + /* send OVP event to all regualtor devices */ + if ((flag1 & 0x02) && (pchip->irqmask & 0x02)) + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + if (pchip->rdev[icnt] != NULL) + regulator_notifier_call_chain(pchip->rdev[icnt], + LP8755_EVENT_OVP, + NULL); + return IRQ_HANDLED; + +err_i2c: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return IRQ_NONE; +} + +static int lp8755_int_config(struct lp8755_chip *pchip) +{ + int ret; + unsigned int regval; + + if (pchip->irq == 0) { + dev_warn(pchip->dev, "not use interrupt : %s\n", __func__); + return 0; + } + + ret = lp8755_read(pchip, 0x0F, ®val); + if (ret < 0) + goto err_i2c; + pchip->irqmask = regval; + ret = request_threaded_irq(pchip->irq, NULL, lp8755_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "lp8755-irq", pchip); + if (ret) + return ret; + + return ret; + +err_i2c: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return ret; +} + +static const struct regmap_config lp8755_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = LP8755_REG_MAX, +}; + +static int lp8755_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret, icnt; + struct lp8755_chip *pchip; + struct lp8755_platform_data *pdata = client->dev.platform_data; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c functionality check fail.\n"); + return -EOPNOTSUPP; + } + + pchip = devm_kzalloc(&client->dev, + sizeof(struct lp8755_chip), GFP_KERNEL); + if (!pchip) + return -ENOMEM; + + pchip->dev = &client->dev; + pchip->regmap = devm_regmap_init_i2c(client, &lp8755_regmap); + if (IS_ERR(pchip->regmap)) { + ret = PTR_ERR(pchip->regmap); + dev_err(&client->dev, "fail to allocate regmap %d\n", ret); + return ret; + } + i2c_set_clientdata(client, pchip); + + if (pdata != NULL) { + pchip->pdata = pdata; + pchip->mphase = pdata->mphase; + } else { + pchip->pdata = devm_kzalloc(pchip->dev, + sizeof(struct lp8755_platform_data), + GFP_KERNEL); + if (!pchip->pdata) + return -ENOMEM; + ret = lp8755_init_data(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail to initialize chip\n"); + return ret; + } + } + + ret = lp8755_regulator_init(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail to initialize regulators\n"); + goto err_regulator; + } + + pchip->irq = client->irq; + ret = lp8755_int_config(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail to irq config\n"); + goto err_irq; + } + + return ret; + +err_irq: + for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) + regulator_unregister(pchip->rdev[icnt]); + +err_regulator: + /* output disable */ + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + lp8755_write(pchip, icnt, 0x00); + + return ret; +} + +static int lp8755_remove(struct i2c_client *client) +{ + int icnt; + struct lp8755_chip *pchip = i2c_get_clientdata(client); + + for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) + regulator_unregister(pchip->rdev[icnt]); + + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + lp8755_write(pchip, icnt, 0x00); + + if (pchip->irq != 0) + free_irq(pchip->irq, pchip); + + return 0; +} + +static const struct i2c_device_id lp8755_id[] = { + {LP8755_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lp8755_id); + +static struct i2c_driver lp8755_i2c_driver = { + .driver = { + .name = LP8755_NAME, + }, + .probe = lp8755_probe, + .remove = lp8755_remove, + .id_table = lp8755_id, +}; + +static int __init lp8755_init(void) +{ + return i2c_add_driver(&lp8755_i2c_driver); +} + +subsys_initcall(lp8755_init); + +static void __exit lp8755_exit(void) +{ + i2c_del_driver(&lp8755_i2c_driver); +} + +module_exit(lp8755_exit); + +MODULE_DESCRIPTION("Texas Instruments lp8755 driver"); +MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index ba3e0aa402de..97891a7ea7b2 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c @@ -103,16 +103,6 @@ static const int lp8788_buck_vtbl[] = { 1950000, 2000000, }; -static const u8 buck1_vout_addr[] = { - LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1, - LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3, -}; - -static const u8 buck2_vout_addr[] = { - LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1, - LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3, -}; - static void lp8788_buck1_set_dvs(struct lp8788_buck *buck) { struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs; @@ -235,7 +225,7 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck, lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S; } - addr = buck1_vout_addr[idx]; + addr = LP8788_BUCK1_VOUT0 + idx; break; case BUCK2: if (mode == EXTPIN) { @@ -258,7 +248,7 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck, lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S; } - addr = buck2_vout_addr[idx]; + addr = LP8788_BUCK2_VOUT0 + idx; break; default: goto err; @@ -429,19 +419,8 @@ static struct regulator_desc lp8788_buck_desc[] = { }, }; -static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name) -{ - struct device *dev = buck->lp->dev; - - if (!gpio_is_valid(gpio)) { - dev_err(dev, "invalid gpio: %d\n", gpio); - return -EINVAL; - } - - return devm_gpio_request_one(dev, gpio, DVS_LOW, name); -} - -static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, +static int lp8788_dvs_gpio_request(struct platform_device *pdev, + struct lp8788_buck *buck, enum lp8788_buck_id id) { struct lp8788_platform_data *pdata = buck->lp->pdata; @@ -452,16 +431,18 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, switch (id) { case BUCK1: gpio = pdata->buck1_dvs->gpio; - ret = _gpio_request(buck, gpio, b1_name); + ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW, + b1_name); if (ret) return ret; buck->dvs = pdata->buck1_dvs; break; case BUCK2: - for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) { + for (i = 0; i < LP8788_NUM_BUCK2_DVS; i++) { gpio = pdata->buck2_dvs->gpio[i]; - ret = _gpio_request(buck, gpio, b2_name[i]); + ret = devm_gpio_request_one(&pdev->dev, gpio, + DVS_LOW, b2_name[i]); if (ret) return ret; } @@ -474,7 +455,8 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, return 0; } -static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) +static int lp8788_init_dvs(struct platform_device *pdev, + struct lp8788_buck *buck, enum lp8788_buck_id id) { struct lp8788_platform_data *pdata = buck->lp->pdata; u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M }; @@ -482,7 +464,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C }; /* no dvs for buck3, 4 */ - if (id == BUCK3 || id == BUCK4) + if (id > BUCK2) return 0; /* no dvs platform data, then dvs will be selected by I2C registers */ @@ -493,7 +475,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) (id == BUCK2 && !pdata->buck2_dvs)) goto set_default_dvs_mode; - if (lp8788_dvs_gpio_request(buck, id)) + if (lp8788_dvs_gpio_request(pdev, buck, id)) goto set_default_dvs_mode; return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id], @@ -504,7 +486,7 @@ set_default_dvs_mode: default_dvs_mode[id]); } -static __devinit int lp8788_buck_probe(struct platform_device *pdev) +static int lp8788_buck_probe(struct platform_device *pdev) { struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); int id = pdev->id; @@ -513,17 +495,20 @@ static __devinit int lp8788_buck_probe(struct platform_device *pdev) struct regulator_dev *rdev; int ret; - buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL); + if (id >= LP8788_NUM_BUCKS) + return -EINVAL; + + buck = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_buck), GFP_KERNEL); if (!buck) return -ENOMEM; buck->lp = lp; - ret = lp8788_init_dvs(buck, id); + ret = lp8788_init_dvs(pdev, buck, id); if (ret) return ret; - cfg.dev = lp->dev; + cfg.dev = pdev->dev.parent; cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL; cfg.driver_data = buck; cfg.regmap = lp->regmap; @@ -531,7 +516,7 @@ static __devinit int lp8788_buck_probe(struct platform_device *pdev) rdev = regulator_register(&lp8788_buck_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); - dev_err(lp->dev, "BUCK%d regulator register err = %d\n", + dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n", id + 1, ret); return ret; } @@ -542,7 +527,7 @@ static __devinit int lp8788_buck_probe(struct platform_device *pdev) return 0; } -static int __devexit lp8788_buck_remove(struct platform_device *pdev) +static int lp8788_buck_remove(struct platform_device *pdev) { struct lp8788_buck *buck = platform_get_drvdata(pdev); @@ -554,7 +539,7 @@ static int __devexit lp8788_buck_remove(struct platform_device *pdev) static struct platform_driver lp8788_buck_driver = { .probe = lp8788_buck_probe, - .remove = __devexit_p(lp8788_buck_remove), + .remove = lp8788_buck_remove, .driver = { .name = LP8788_DEV_BUCK, .owner = THIS_MODULE, diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index 6796eeb47dc6..cd5a14ad9263 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -88,11 +88,6 @@ #define ENABLE GPIOF_OUT_INIT_HIGH #define DISABLE GPIOF_OUT_INIT_LOW -enum lp8788_enable_mode { - REGISTER, - EXTPIN, -}; - enum lp8788_ldo_id { DLDO1, DLDO2, @@ -126,7 +121,7 @@ struct lp8788_ldo { }; /* DLDO 1, 2, 3, 9 voltage table */ -const int lp8788_dldo1239_vtbl[] = { +static const int lp8788_dldo1239_vtbl[] = { 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, 2600000, 2700000, 2800000, 2900000, 3000000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, @@ -189,114 +184,38 @@ static enum lp8788_ldo_id lp8788_aldo_id[] = { ALDO10, }; -/* DLDO 7, 9 and 11, ALDO 1 ~ 5 and 7 - : can be enabled either by external pin or by i2c register */ -static enum lp8788_enable_mode -lp8788_get_ldo_enable_mode(struct lp8788_ldo *ldo, enum lp8788_ldo_id id) -{ - int ret; - u8 val, mask; - - ret = lp8788_read_byte(ldo->lp, LP8788_EN_SEL, &val); - if (ret) - return ret; - - switch (id) { - case DLDO7: - mask = LP8788_EN_SEL_DLDO7_M; - break; - case DLDO9: - case DLDO11: - mask = LP8788_EN_SEL_DLDO911_M; - break; - case ALDO1: - mask = LP8788_EN_SEL_ALDO1_M; - break; - case ALDO2 ... ALDO4: - mask = LP8788_EN_SEL_ALDO234_M; - break; - case ALDO5: - mask = LP8788_EN_SEL_ALDO5_M; - break; - case ALDO7: - mask = LP8788_EN_SEL_ALDO7_M; - break; - default: - return REGISTER; - } - - return val & mask ? EXTPIN : REGISTER; -} - -static int lp8788_ldo_ctrl_by_extern_pin(struct lp8788_ldo *ldo, int pinstate) -{ - struct lp8788_ldo_enable_pin *pin = ldo->en_pin; - - if (!pin) - return -EINVAL; - - if (gpio_is_valid(pin->gpio)) - gpio_set_value(pin->gpio, pinstate); - - return 0; -} - -static int lp8788_ldo_is_enabled_by_extern_pin(struct lp8788_ldo *ldo) -{ - struct lp8788_ldo_enable_pin *pin = ldo->en_pin; - - if (!pin) - return -EINVAL; - - return gpio_get_value(pin->gpio) ? 1 : 0; -} - static int lp8788_ldo_enable(struct regulator_dev *rdev) { struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); - enum lp8788_ldo_id id = rdev_get_id(rdev); - enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); - switch (mode) { - case EXTPIN: - return lp8788_ldo_ctrl_by_extern_pin(ldo, ENABLE); - case REGISTER: + if (ldo->en_pin) { + gpio_set_value(ldo->en_pin->gpio, ENABLE); + return 0; + } else { return regulator_enable_regmap(rdev); - default: - return -EINVAL; } } static int lp8788_ldo_disable(struct regulator_dev *rdev) { struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); - enum lp8788_ldo_id id = rdev_get_id(rdev); - enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); - switch (mode) { - case EXTPIN: - return lp8788_ldo_ctrl_by_extern_pin(ldo, DISABLE); - case REGISTER: + if (ldo->en_pin) { + gpio_set_value(ldo->en_pin->gpio, DISABLE); + return 0; + } else { return regulator_disable_regmap(rdev); - default: - return -EINVAL; } } static int lp8788_ldo_is_enabled(struct regulator_dev *rdev) { struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); - enum lp8788_ldo_id id = rdev_get_id(rdev); - enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); - switch (mode) { - case EXTPIN: - return lp8788_ldo_is_enabled_by_extern_pin(ldo); - case REGISTER: + if (ldo->en_pin) + return gpio_get_value(ldo->en_pin->gpio) ? 1 : 0; + else return regulator_is_enabled_regmap(rdev); - default: - return -EINVAL; - } } static int lp8788_ldo_enable_time(struct regulator_dev *rdev) @@ -616,10 +535,11 @@ static struct regulator_desc lp8788_aldo_desc[] = { }, }; -static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo, +static int lp8788_gpio_request_ldo_en(struct platform_device *pdev, + struct lp8788_ldo *ldo, enum lp8788_ext_ldo_en_id id) { - struct device *dev = ldo->lp->dev; + struct device *dev = &pdev->dev; struct lp8788_ldo_enable_pin *pin = ldo->en_pin; int ret, gpio, pinstate; char *name[] = { @@ -647,7 +567,8 @@ static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo, return ret; } -static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo, +static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, + struct lp8788_ldo *ldo, enum lp8788_ldo_id id) { int ret; @@ -662,14 +583,6 @@ static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo, [EN_DLDO7] = LP8788_EN_SEL_DLDO7_M, [EN_DLDO911] = LP8788_EN_SEL_DLDO911_M, }; - u8 val[] = { - [EN_ALDO1] = 0 << 5, - [EN_ALDO234] = 0 << 4, - [EN_ALDO5] = 0 << 3, - [EN_ALDO7] = 0 << 2, - [EN_DLDO7] = 0 << 1, - [EN_DLDO911] = 0 << 0, - }; switch (id) { case DLDO7: @@ -701,18 +614,19 @@ static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo, ldo->en_pin = pdata->ldo_pin[enable_id]; - ret = lp8788_gpio_request_ldo_en(ldo, enable_id); - if (ret) + ret = lp8788_gpio_request_ldo_en(pdev, ldo, enable_id); + if (ret) { + ldo->en_pin = NULL; goto set_default_ldo_enable_mode; + } return ret; set_default_ldo_enable_mode: - return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], - val[enable_id]); + return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], 0); } -static __devinit int lp8788_dldo_probe(struct platform_device *pdev) +static int lp8788_dldo_probe(struct platform_device *pdev) { struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); int id = pdev->id; @@ -721,16 +635,16 @@ static __devinit int lp8788_dldo_probe(struct platform_device *pdev) struct regulator_dev *rdev; int ret; - ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); + ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); if (!ldo) return -ENOMEM; ldo->lp = lp; - ret = lp8788_config_ldo_enable_mode(ldo, lp8788_dldo_id[id]); + ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_dldo_id[id]); if (ret) return ret; - cfg.dev = lp->dev; + cfg.dev = pdev->dev.parent; cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL; cfg.driver_data = ldo; cfg.regmap = lp->regmap; @@ -738,7 +652,7 @@ static __devinit int lp8788_dldo_probe(struct platform_device *pdev) rdev = regulator_register(&lp8788_dldo_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); - dev_err(lp->dev, "DLDO%d regulator register err = %d\n", + dev_err(&pdev->dev, "DLDO%d regulator register err = %d\n", id + 1, ret); return ret; } @@ -749,7 +663,7 @@ static __devinit int lp8788_dldo_probe(struct platform_device *pdev) return 0; } -static int __devexit lp8788_dldo_remove(struct platform_device *pdev) +static int lp8788_dldo_remove(struct platform_device *pdev) { struct lp8788_ldo *ldo = platform_get_drvdata(pdev); @@ -761,14 +675,14 @@ static int __devexit lp8788_dldo_remove(struct platform_device *pdev) static struct platform_driver lp8788_dldo_driver = { .probe = lp8788_dldo_probe, - .remove = __devexit_p(lp8788_dldo_remove), + .remove = lp8788_dldo_remove, .driver = { .name = LP8788_DEV_DLDO, .owner = THIS_MODULE, }, }; -static __devinit int lp8788_aldo_probe(struct platform_device *pdev) +static int lp8788_aldo_probe(struct platform_device *pdev) { struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); int id = pdev->id; @@ -777,16 +691,16 @@ static __devinit int lp8788_aldo_probe(struct platform_device *pdev) struct regulator_dev *rdev; int ret; - ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); + ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); if (!ldo) return -ENOMEM; ldo->lp = lp; - ret = lp8788_config_ldo_enable_mode(ldo, lp8788_aldo_id[id]); + ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_aldo_id[id]); if (ret) return ret; - cfg.dev = lp->dev; + cfg.dev = pdev->dev.parent; cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL; cfg.driver_data = ldo; cfg.regmap = lp->regmap; @@ -794,7 +708,7 @@ static __devinit int lp8788_aldo_probe(struct platform_device *pdev) rdev = regulator_register(&lp8788_aldo_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); - dev_err(lp->dev, "ALDO%d regulator register err = %d\n", + dev_err(&pdev->dev, "ALDO%d regulator register err = %d\n", id + 1, ret); return ret; } @@ -805,7 +719,7 @@ static __devinit int lp8788_aldo_probe(struct platform_device *pdev) return 0; } -static int __devexit lp8788_aldo_remove(struct platform_device *pdev) +static int lp8788_aldo_remove(struct platform_device *pdev) { struct lp8788_ldo *ldo = platform_get_drvdata(pdev); @@ -817,7 +731,7 @@ static int __devexit lp8788_aldo_remove(struct platform_device *pdev) static struct platform_driver lp8788_aldo_driver = { .probe = lp8788_aldo_probe, - .remove = __devexit_p(lp8788_aldo_remove), + .remove = lp8788_aldo_remove, .driver = { .name = LP8788_DEV_ALDO, .owner = THIS_MODULE, diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index f67af3c1b963..8c5a54f541b5 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -44,6 +44,9 @@ struct max1586_data { unsigned int min_uV; unsigned int max_uV; + unsigned int v3_curr_sel; + unsigned int v6_curr_sel; + struct regulator_dev *rdev[0]; }; @@ -63,31 +66,60 @@ static int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; * R24 and R25=100kOhm as described in the data sheet. * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm */ +static int max1586_v3_get_voltage_sel(struct regulator_dev *rdev) +{ + struct max1586_data *max1586 = rdev_get_drvdata(rdev); + + return max1586->v3_curr_sel; +} + static int max1586_v3_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct max1586_data *max1586 = rdev_get_drvdata(rdev); struct i2c_client *client = max1586->client; + int ret; u8 v3_prog; dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", regulator_list_voltage_linear(rdev, selector) / 1000); v3_prog = I2C_V3_SELECT | (u8) selector; - return i2c_smbus_write_byte(client, v3_prog); + ret = i2c_smbus_write_byte(client, v3_prog); + if (ret) + return ret; + + max1586->v3_curr_sel = selector; + + return 0; +} + +static int max1586_v6_get_voltage_sel(struct regulator_dev *rdev) +{ + struct max1586_data *max1586 = rdev_get_drvdata(rdev); + + return max1586->v6_curr_sel; } static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector) { - struct i2c_client *client = rdev_get_drvdata(rdev); + struct max1586_data *max1586 = rdev_get_drvdata(rdev); + struct i2c_client *client = max1586->client; u8 v6_prog; + int ret; dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", rdev->desc->volt_table[selector] / 1000); v6_prog = I2C_V6_SELECT | (u8) selector; - return i2c_smbus_write_byte(client, v6_prog); + ret = i2c_smbus_write_byte(client, v6_prog); + if (ret) + return ret; + + max1586->v6_curr_sel = selector; + + return 0; } /* @@ -95,12 +127,14 @@ static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev, * the set up value. */ static struct regulator_ops max1586_v3_ops = { + .get_voltage_sel = max1586_v3_get_voltage_sel, .set_voltage_sel = max1586_v3_set_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, }; static struct regulator_ops max1586_v6_ops = { + .get_voltage_sel = max1586_v6_get_voltage_sel, .set_voltage_sel = max1586_v6_set_voltage_sel, .list_voltage = regulator_list_voltage_table, }; @@ -125,7 +159,7 @@ static struct regulator_desc max1586_reg[] = { }, }; -static int __devinit max1586_pmic_probe(struct i2c_client *client, +static int max1586_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { struct regulator_dev **rdev; @@ -148,6 +182,10 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client, max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000; max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000; + /* Set curr_sel to default voltage on power-up */ + max1586->v3_curr_sel = 24; /* 1.3V */ + max1586->v6_curr_sel = 0; + rdev = max1586->rdev; for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { id = pdata->subdevs[i].id; @@ -188,7 +226,7 @@ err: return ret; } -static int __devexit max1586_pmic_remove(struct i2c_client *client) +static int max1586_pmic_remove(struct i2c_client *client) { struct max1586_data *max1586 = i2c_get_clientdata(client); int i; @@ -207,7 +245,7 @@ MODULE_DEVICE_TABLE(i2c, max1586_id); static struct i2c_driver max1586_pmic_driver = { .probe = max1586_pmic_probe, - .remove = __devexit_p(max1586_pmic_remove), + .remove = max1586_pmic_remove, .driver = { .name = "max1586", .owner = THIS_MODULE, diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c index 2a67d08658ad..e4586ee8858d 100644 --- a/drivers/regulator/max77686.c +++ b/drivers/regulator/max77686.c @@ -67,8 +67,96 @@ enum max77686_ramp_rate { struct max77686_data { struct regulator_dev *rdev[MAX77686_REGULATORS]; + unsigned int opmode[MAX77686_REGULATORS]; }; +/* Some BUCKS supports Normal[ON/OFF] mode during suspend */ +static int max77686_buck_set_suspend_disable(struct regulator_dev *rdev) +{ + unsigned int val; + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + + if (id == MAX77686_BUCK1) + val = 0x1; + else + val = 0x1 << MAX77686_OPMODE_BUCK234_SHIFT; + + max77686->opmode[id] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + val); +} + +/* Some LDOs supports [LPM/Normal]ON mode during suspend state */ +static int max77686_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + unsigned int val; + int id = rdev_get_id(rdev); + + /* BUCK[5-9] doesn't support this feature */ + if (id >= MAX77686_BUCK5) + return 0; + + switch (mode) { + case REGULATOR_MODE_IDLE: /* ON in LP Mode */ + val = 0x2 << MAX77686_OPMODE_SHIFT; + break; + case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ + val = 0x3 << MAX77686_OPMODE_SHIFT; + break; + default: + pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + max77686->opmode[id] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + val); +} + +/* Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state */ +static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + unsigned int val; + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + + switch (mode) { + case REGULATOR_MODE_STANDBY: /* switch off */ + val = 0x1 << MAX77686_OPMODE_SHIFT; + break; + case REGULATOR_MODE_IDLE: /* ON in LP Mode */ + val = 0x2 << MAX77686_OPMODE_SHIFT; + break; + case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ + val = 0x3 << MAX77686_OPMODE_SHIFT; + break; + default: + pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", + rdev->desc->name, mode); + return -EINVAL; + } + + max77686->opmode[rdev_get_id(rdev)] = val; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + val); +} + +static int max77686_enable(struct regulator_dev *rdev) +{ + struct max77686_data *max77686 = rdev_get_drvdata(rdev); + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + max77686->opmode[rdev_get_id(rdev)]); +} + static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { unsigned int ramp_value = RAMP_RATE_NO_CTRL; @@ -98,23 +186,49 @@ static struct regulator_ops max77686_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, + .enable = max77686_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_mode = max77686_set_suspend_mode, +}; + +static struct regulator_ops max77686_ldo_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77686_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_mode = max77686_ldo_set_suspend_mode, +}; + +static struct regulator_ops max77686_buck1_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = max77686_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_disable = max77686_buck_set_suspend_disable, }; static struct regulator_ops max77686_buck_dvs_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, + .enable = max77686_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, .set_ramp_delay = max77686_set_ramp_delay, + .set_suspend_disable = max77686_buck_set_suspend_disable, }; #define regulator_desc_ldo(num) { \ @@ -133,9 +247,41 @@ static struct regulator_ops max77686_buck_dvs_ops = { .enable_mask = MAX77686_OPMODE_MASK \ << MAX77686_OPMODE_SHIFT, \ } +#define regulator_desc_lpm_ldo(num) { \ + .name = "LDO"#num, \ + .id = MAX77686_LDO##num, \ + .ops = &max77686_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_LDO_MINUV, \ + .uV_step = MAX77686_LDO_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_SHIFT, \ +} #define regulator_desc_ldo_low(num) { \ .name = "LDO"#num, \ .id = MAX77686_LDO##num, \ + .ops = &max77686_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = MAX77686_LDO_LOW_MINUV, \ + .uV_step = MAX77686_LDO_LOW_UVSTEP, \ + .ramp_delay = MAX77686_RAMP_DELAY, \ + .n_voltages = MAX77686_VSEL_MASK + 1, \ + .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .vsel_mask = MAX77686_VSEL_MASK, \ + .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ + .enable_mask = MAX77686_OPMODE_MASK \ + << MAX77686_OPMODE_SHIFT, \ +} +#define regulator_desc_ldo1_low(num) { \ + .name = "LDO"#num, \ + .id = MAX77686_LDO##num, \ .ops = &max77686_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -167,7 +313,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { #define regulator_desc_buck1(num) { \ .name = "BUCK"#num, \ .id = MAX77686_BUCK##num, \ - .ops = &max77686_ops, \ + .ops = &max77686_buck1_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ .min_uV = MAX77686_BUCK_MINUV, \ @@ -197,7 +343,7 @@ static struct regulator_ops max77686_buck_dvs_ops = { } static struct regulator_desc regulators[] = { - regulator_desc_ldo_low(1), + regulator_desc_ldo1_low(1), regulator_desc_ldo_low(2), regulator_desc_ldo(3), regulator_desc_ldo(4), @@ -206,13 +352,13 @@ static struct regulator_desc regulators[] = { regulator_desc_ldo_low(7), regulator_desc_ldo_low(8), regulator_desc_ldo(9), - regulator_desc_ldo(10), - regulator_desc_ldo(11), - regulator_desc_ldo(12), + regulator_desc_lpm_ldo(10), + regulator_desc_lpm_ldo(11), + regulator_desc_lpm_ldo(12), regulator_desc_ldo(13), - regulator_desc_ldo(14), + regulator_desc_lpm_ldo(14), regulator_desc_ldo_low(15), - regulator_desc_ldo(16), + regulator_desc_lpm_ldo(16), regulator_desc_ldo(17), regulator_desc_ldo(18), regulator_desc_ldo(19), @@ -235,9 +381,10 @@ static struct regulator_desc regulators[] = { }; #ifdef CONFIG_OF -static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, +static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev, struct max77686_platform_data *pdata) { + struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct device_node *pmic_np, *regulators_np; struct max77686_regulator_data *rdata; struct of_regulator_match rmatch; @@ -246,15 +393,15 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, pmic_np = iodev->dev->of_node; regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators"); if (!regulators_np) { - dev_err(iodev->dev, "could not find regulators sub-node\n"); + dev_err(&pdev->dev, "could not find regulators sub-node\n"); return -EINVAL; } pdata->num_regulators = ARRAY_SIZE(regulators); - rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) * + rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * pdata->num_regulators, GFP_KERNEL); if (!rdata) { - dev_err(iodev->dev, + dev_err(&pdev->dev, "could not allocate memory for regulator data\n"); return -ENOMEM; } @@ -263,7 +410,7 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, rmatch.name = regulators[i].name; rmatch.init_data = NULL; rmatch.of_node = NULL; - of_regulator_match(iodev->dev, regulators_np, &rmatch, 1); + of_regulator_match(&pdev->dev, regulators_np, &rmatch, 1); rdata[i].initdata = rmatch.init_data; rdata[i].of_node = rmatch.of_node; } @@ -273,14 +420,14 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, return 0; } #else -static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev, +static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev, struct max77686_platform_data *pdata) { return 0; } #endif /* CONFIG_OF */ -static __devinit int max77686_pmic_probe(struct platform_device *pdev) +static int max77686_pmic_probe(struct platform_device *pdev) { struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev); @@ -296,7 +443,7 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev) } if (iodev->dev->of_node) { - ret = max77686_pmic_dt_parse_pdata(iodev, pdata); + ret = max77686_pmic_dt_parse_pdata(pdev, pdata); if (ret) return ret; } @@ -314,12 +461,14 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev) config.dev = &pdev->dev; config.regmap = iodev->regmap; + config.driver_data = max77686; platform_set_drvdata(pdev, max77686); for (i = 0; i < MAX77686_REGULATORS; i++) { config.init_data = pdata->regulators[i].initdata; config.of_node = pdata->regulators[i].of_node; + max77686->opmode[i] = regulators[i].enable_mask; max77686->rdev[i] = regulator_register(®ulators[i], &config); if (IS_ERR(max77686->rdev[i])) { ret = PTR_ERR(max77686->rdev[i]); @@ -337,7 +486,7 @@ err: return ret; } -static int __devexit max77686_pmic_remove(struct platform_device *pdev) +static int max77686_pmic_remove(struct platform_device *pdev) { struct max77686_data *max77686 = platform_get_drvdata(pdev); int i; @@ -360,7 +509,7 @@ static struct platform_driver max77686_pmic_driver = { .owner = THIS_MODULE, }, .probe = max77686_pmic_probe, - .remove = __devexit_p(max77686_pmic_remove), + .remove = max77686_pmic_remove, .id_table = max77686_pmic_id, }; diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 9d540cd02dab..3ca14380f22d 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -176,7 +176,7 @@ static struct regmap_config max8649_regmap_config = { .val_bits = 8, }; -static int __devinit max8649_regulator_probe(struct i2c_client *client, +static int max8649_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max8649_platform_data *pdata = client->dev.platform_data; @@ -271,7 +271,7 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, return 0; } -static int __devexit max8649_regulator_remove(struct i2c_client *client) +static int max8649_regulator_remove(struct i2c_client *client) { struct max8649_regulator_info *info = i2c_get_clientdata(client); @@ -291,7 +291,7 @@ MODULE_DEVICE_TABLE(i2c, max8649_id); static struct i2c_driver max8649_driver = { .probe = max8649_regulator_probe, - .remove = __devexit_p(max8649_regulator_remove), + .remove = max8649_regulator_remove, .driver = { .name = "max8649", }, diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 8d531742f593..4d7c635c36c2 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -305,7 +305,7 @@ static const struct regulator_desc max8660_reg[] = { }, }; -static int __devinit max8660_probe(struct i2c_client *client, +static int max8660_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { struct regulator_dev **rdev; @@ -420,7 +420,7 @@ err_out: return ret; } -static int __devexit max8660_remove(struct i2c_client *client) +static int max8660_remove(struct i2c_client *client) { struct max8660 *max8660 = i2c_get_clientdata(client); int i; @@ -440,7 +440,7 @@ MODULE_DEVICE_TABLE(i2c, max8660_id); static struct i2c_driver max8660_driver = { .probe = max8660_probe, - .remove = __devexit_p(max8660_remove), + .remove = max8660_remove, .driver = { .name = "max8660", .owner = THIS_MODULE, diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c index af7607515ab9..4568c15fa78d 100644 --- a/drivers/regulator/max8907-regulator.c +++ b/drivers/regulator/max8907-regulator.c @@ -224,11 +224,11 @@ static struct of_regulator_match max8907_matches[] = { static int max8907_regulator_parse_dt(struct platform_device *pdev) { - struct device_node *np = pdev->dev.parent->of_node; - struct device_node *regulators; + struct device_node *np, *regulators; int ret; - if (!pdev->dev.parent->of_node) + np = of_node_get(pdev->dev.parent->of_node); + if (!np) return 0; regulators = of_find_node_by_name(np, "regulators"); @@ -237,9 +237,9 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev) return -EINVAL; } - ret = of_regulator_match(pdev->dev.parent, regulators, - max8907_matches, + ret = of_regulator_match(&pdev->dev, regulators, max8907_matches, ARRAY_SIZE(max8907_matches)); + of_node_put(regulators); if (ret < 0) { dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); @@ -275,7 +275,7 @@ static inline struct device_node *match_of_node(int index) } #endif -static __devinit int max8907_regulator_probe(struct platform_device *pdev) +static int max8907_regulator_probe(struct platform_device *pdev) { struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent); struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev); @@ -368,7 +368,7 @@ err_unregister_regulator: return ret; } -static __devexit int max8907_regulator_remove(struct platform_device *pdev) +static int max8907_regulator_remove(struct platform_device *pdev) { struct max8907_regulator *pmic = platform_get_drvdata(pdev); int i; @@ -385,7 +385,7 @@ static struct platform_driver max8907_regulator_driver = { .owner = THIS_MODULE, }, .probe = max8907_regulator_probe, - .remove = __devexit_p(max8907_regulator_remove), + .remove = max8907_regulator_remove, }; static int __init max8907_regulator_init(void) diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 9bb0be37495f..0d5f64a805a0 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -17,6 +17,8 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/mfd/max8925.h> +#include <linux/of.h> +#include <linux/regulator/of_regulator.h> #define SD1_DVM_VMIN 850000 #define SD1_DVM_VMAX 1000000 @@ -187,6 +189,34 @@ static struct regulator_ops max8925_regulator_ldo_ops = { .enable_reg = MAX8925_LDOCTL##_id, \ } +#ifdef CONFIG_OF +static struct of_regulator_match max8925_regulator_matches[] = { + { .name = "SDV1",}, + { .name = "SDV2",}, + { .name = "SDV3",}, + { .name = "LDO1",}, + { .name = "LDO2",}, + { .name = "LDO3",}, + { .name = "LDO4",}, + { .name = "LDO5",}, + { .name = "LDO6",}, + { .name = "LDO7",}, + { .name = "LDO8",}, + { .name = "LDO9",}, + { .name = "LDO10",}, + { .name = "LDO11",}, + { .name = "LDO12",}, + { .name = "LDO13",}, + { .name = "LDO14",}, + { .name = "LDO15",}, + { .name = "LDO16",}, + { .name = "LDO17",}, + { .name = "LDO18",}, + { .name = "LDO19",}, + { .name = "LDO20",}, +}; +#endif + static struct max8925_regulator_info max8925_regulator_info[] = { MAX8925_SDV(1, 637.5, 1425, 12.5), MAX8925_SDV(2, 650, 2225, 25), @@ -214,7 +244,38 @@ static struct max8925_regulator_info max8925_regulator_info[] = { MAX8925_LDO(20, 750, 3900, 50), }; -static int __devinit max8925_regulator_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static int max8925_regulator_dt_init(struct platform_device *pdev, + struct max8925_regulator_info *info, + struct regulator_config *config, + int ridx) +{ + struct device_node *nproot, *np; + int rcount; + nproot = of_node_get(pdev->dev.parent->of_node); + if (!nproot) + return -ENODEV; + np = of_find_node_by_name(nproot, "regulators"); + if (!np) { + dev_err(&pdev->dev, "failed to find regulators node\n"); + return -ENODEV; + } + + rcount = of_regulator_match(&pdev->dev, np, + &max8925_regulator_matches[ridx], 1); + of_node_put(np); + if (rcount < 0) + return -ENODEV; + config->init_data = max8925_regulator_matches[ridx].init_data; + config->of_node = max8925_regulator_matches[ridx].of_node; + + return 0; +} +#else +#define max8925_regulator_dt_init(w, x, y, z) (-1) +#endif + +static int max8925_regulator_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); struct regulator_init_data *pdata = pdev->dev.platform_data; @@ -222,7 +283,7 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) struct max8925_regulator_info *ri; struct resource *res; struct regulator_dev *rdev; - int i; + int i, regulator_idx; res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (!res) { @@ -231,9 +292,12 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) } for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) { ri = &max8925_regulator_info[i]; - if (ri->vol_reg == res->start) + if (ri->vol_reg == res->start) { + regulator_idx = i; break; + } } + if (i == ARRAY_SIZE(max8925_regulator_info)) { dev_err(&pdev->dev, "Failed to find regulator %llu\n", (unsigned long long)res->start); @@ -243,9 +307,12 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) ri->chip = chip; config.dev = &pdev->dev; - config.init_data = pdata; config.driver_data = ri; + if (max8925_regulator_dt_init(pdev, ri, &config, regulator_idx)) + if (pdata) + config.init_data = pdata; + rdev = regulator_register(&ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", @@ -257,7 +324,7 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit max8925_regulator_remove(struct platform_device *pdev) +static int max8925_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -273,7 +340,7 @@ static struct platform_driver max8925_regulator_driver = { .owner = THIS_MODULE, }, .probe = max8925_regulator_probe, - .remove = __devexit_p(max8925_regulator_remove), + .remove = max8925_regulator_remove, }; static int __init max8925_regulator_init(void) diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 355ca7bad9d5..fc7935a19e3a 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -126,7 +126,7 @@ static const struct regulator_desc regulator = { .owner = THIS_MODULE, }; -static int __devinit max8952_pmic_probe(struct i2c_client *client, +static int max8952_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); @@ -247,7 +247,7 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, return 0; } -static int __devexit max8952_pmic_remove(struct i2c_client *client) +static int max8952_pmic_remove(struct i2c_client *client) { struct max8952_data *max8952 = i2c_get_clientdata(client); struct max8952_platform_data *pdata = max8952->pdata; @@ -268,7 +268,7 @@ MODULE_DEVICE_TABLE(i2c, max8952_ids); static struct i2c_driver max8952_pmic_driver = { .probe = max8952_pmic_probe, - .remove = __devexit_p(max8952_pmic_remove), + .remove = max8952_pmic_remove, .driver = { .name = "max8952", }, diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c new file mode 100644 index 000000000000..9a8ea9163005 --- /dev/null +++ b/drivers/regulator/max8973-regulator.c @@ -0,0 +1,505 @@ +/* + * max8973-regulator.c -- Maxim max8973 + * + * Regulator driver for MAXIM 8973 DC-DC step-down switching regulator. + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; 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., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/max8973-regulator.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/regmap.h> + +/* Register definitions */ +#define MAX8973_VOUT 0x0 +#define MAX8973_VOUT_DVS 0x1 +#define MAX8973_CONTROL1 0x2 +#define MAX8973_CONTROL2 0x3 +#define MAX8973_CHIPID1 0x4 +#define MAX8973_CHIPID2 0x5 + +#define MAX8973_MAX_VOUT_REG 2 + +/* MAX8973_VOUT */ +#define MAX8973_VOUT_ENABLE BIT(7) +#define MAX8973_VOUT_MASK 0x7F + +/* MAX8973_VOUT_DVS */ +#define MAX8973_DVS_VOUT_MASK 0x7F + +/* MAX8973_CONTROL1 */ +#define MAX8973_SNS_ENABLE BIT(7) +#define MAX8973_FPWM_EN_M BIT(6) +#define MAX8973_NFSR_ENABLE BIT(5) +#define MAX8973_AD_ENABLE BIT(4) +#define MAX8973_BIAS_ENABLE BIT(3) +#define MAX8973_FREQSHIFT_9PER BIT(2) + +#define MAX8973_RAMP_12mV_PER_US 0x0 +#define MAX8973_RAMP_25mV_PER_US 0x1 +#define MAX8973_RAMP_50mV_PER_US 0x2 +#define MAX8973_RAMP_200mV_PER_US 0x3 + +/* MAX8973_CONTROL2 */ +#define MAX8973_WDTMR_ENABLE BIT(6) +#define MAX8973_DISCH_ENBABLE BIT(5) +#define MAX8973_FT_ENABLE BIT(4) + +#define MAX8973_CKKADV_TRIP_DISABLE 0xC +#define MAX8973_CKKADV_TRIP_75mV_PER_US 0x0 +#define MAX8973_CKKADV_TRIP_150mV_PER_US 0x4 +#define MAX8973_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8 +#define MAX8973_CONTROL_CLKADV_TRIP_MASK 0x00030000 + +#define MAX8973_INDUCTOR_MIN_30_PER 0x0 +#define MAX8973_INDUCTOR_NOMINAL 0x1 +#define MAX8973_INDUCTOR_PLUS_30_PER 0x2 +#define MAX8973_INDUCTOR_PLUS_60_PER 0x3 +#define MAX8973_CONTROL_INDUCTOR_VALUE_MASK 0x00300000 + +#define MAX8973_MIN_VOLATGE 606250 +#define MAX8973_MAX_VOLATGE 1400000 +#define MAX8973_VOLATGE_STEP 6250 +#define MAX8973_BUCK_N_VOLTAGE 0x80 + +/* Maxim 8973 chip information */ +struct max8973_chip { + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + struct regmap *regmap; + bool enable_external_control; + int dvs_gpio; + int lru_index[MAX8973_MAX_VOUT_REG]; + int curr_vout_val[MAX8973_MAX_VOUT_REG]; + int curr_vout_reg; + int curr_gpio_val; + bool valid_dvs_gpio; +}; + +/* + * find_voltage_set_register: Find new voltage configuration register (VOUT). + * The finding of the new VOUT register will be based on the LRU mechanism. + * Each VOUT register will have different voltage configured . This + * Function will look if any of the VOUT register have requested voltage set + * or not. + * - If it is already there then it will make that register as most + * recently used and return as found so that caller need not to set + * the VOUT register but need to set the proper gpios to select this + * VOUT register. + * - If requested voltage is not found then it will use the least + * recently mechanism to get new VOUT register for new configuration + * and will return not_found so that caller need to set new VOUT + * register and then gpios (both). + */ +static bool find_voltage_set_register(struct max8973_chip *tps, + int req_vsel, int *vout_reg, int *gpio_val) +{ + int i; + bool found = false; + int new_vout_reg = tps->lru_index[MAX8973_MAX_VOUT_REG - 1]; + int found_index = MAX8973_MAX_VOUT_REG - 1; + + for (i = 0; i < MAX8973_MAX_VOUT_REG; ++i) { + if (tps->curr_vout_val[tps->lru_index[i]] == req_vsel) { + new_vout_reg = tps->lru_index[i]; + found_index = i; + found = true; + goto update_lru_index; + } + } + +update_lru_index: + for (i = found_index; i > 0; i--) + tps->lru_index[i] = tps->lru_index[i - 1]; + + tps->lru_index[0] = new_vout_reg; + *gpio_val = new_vout_reg; + *vout_reg = MAX8973_VOUT + new_vout_reg; + return found; +} + +static int max8973_dcdc_get_voltage_sel(struct regulator_dev *rdev) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + + ret = regmap_read(max->regmap, max->curr_vout_reg, &data); + if (ret < 0) { + dev_err(max->dev, "register %d read failed, err = %d\n", + max->curr_vout_reg, ret); + return ret; + } + return data & MAX8973_VOUT_MASK; +} + +static int max8973_dcdc_set_voltage_sel(struct regulator_dev *rdev, + unsigned vsel) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + int ret; + bool found = false; + int vout_reg = max->curr_vout_reg; + int gpio_val = max->curr_gpio_val; + + /* + * If gpios are available to select the VOUT register then least + * recently used register for new configuration. + */ + if (max->valid_dvs_gpio) + found = find_voltage_set_register(max, vsel, + &vout_reg, &gpio_val); + + if (!found) { + ret = regmap_update_bits(max->regmap, vout_reg, + MAX8973_VOUT_MASK, vsel); + if (ret < 0) { + dev_err(max->dev, "register %d update failed, err %d\n", + vout_reg, ret); + return ret; + } + max->curr_vout_reg = vout_reg; + max->curr_vout_val[gpio_val] = vsel; + } + + /* Select proper VOUT register vio gpios */ + if (max->valid_dvs_gpio) { + gpio_set_value_cansleep(max->dvs_gpio, gpio_val & 0x1); + max->curr_gpio_val = gpio_val; + } + return 0; +} + +static int max8973_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + int ret; + int pwm; + + /* Enable force PWM mode in FAST mode only. */ + switch (mode) { + case REGULATOR_MODE_FAST: + pwm = MAX8973_FPWM_EN_M; + break; + + case REGULATOR_MODE_NORMAL: + pwm = 0; + break; + + default: + return -EINVAL; + } + + ret = regmap_update_bits(max->regmap, MAX8973_CONTROL1, + MAX8973_FPWM_EN_M, pwm); + if (ret < 0) + dev_err(max->dev, "register %d update failed, err %d\n", + MAX8973_CONTROL1, ret); + return ret; +} + +static unsigned int max8973_dcdc_get_mode(struct regulator_dev *rdev) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + + ret = regmap_read(max->regmap, MAX8973_CONTROL1, &data); + if (ret < 0) { + dev_err(max->dev, "register %d read failed, err %d\n", + MAX8973_CONTROL1, ret); + return ret; + } + return (data & MAX8973_FPWM_EN_M) ? + REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; +} + +static struct regulator_ops max8973_dcdc_ops = { + .get_voltage_sel = max8973_dcdc_get_voltage_sel, + .set_voltage_sel = max8973_dcdc_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear, + .set_mode = max8973_dcdc_set_mode, + .get_mode = max8973_dcdc_get_mode, +}; + +static int max8973_init_dcdc(struct max8973_chip *max, + struct max8973_regulator_platform_data *pdata) +{ + int ret; + uint8_t control1 = 0; + uint8_t control2 = 0; + + if (pdata->control_flags & MAX8973_CONTROL_REMOTE_SENSE_ENABLE) + control1 |= MAX8973_SNS_ENABLE; + + if (!(pdata->control_flags & MAX8973_CONTROL_FALLING_SLEW_RATE_ENABLE)) + control1 |= MAX8973_NFSR_ENABLE; + + if (pdata->control_flags & MAX8973_CONTROL_OUTPUT_ACTIVE_DISCH_ENABLE) + control1 |= MAX8973_AD_ENABLE; + + if (pdata->control_flags & MAX8973_CONTROL_BIAS_ENABLE) + control1 |= MAX8973_BIAS_ENABLE; + + if (pdata->control_flags & MAX8973_CONTROL_FREQ_SHIFT_9PER_ENABLE) + control1 |= MAX8973_FREQSHIFT_9PER; + + /* Set ramp delay */ + if (pdata->reg_init_data && + pdata->reg_init_data->constraints.ramp_delay) { + if (pdata->reg_init_data->constraints.ramp_delay < 25000) + control1 = MAX8973_RAMP_12mV_PER_US; + else if (pdata->reg_init_data->constraints.ramp_delay < 50000) + control1 = MAX8973_RAMP_25mV_PER_US; + else if (pdata->reg_init_data->constraints.ramp_delay < 200000) + control1 = MAX8973_RAMP_50mV_PER_US; + else + control1 = MAX8973_RAMP_200mV_PER_US; + } else { + control1 = MAX8973_RAMP_12mV_PER_US; + max->desc.ramp_delay = 12500; + } + + if (!(pdata->control_flags & MAX8973_CONTROL_PULL_DOWN_ENABLE)) + control2 |= MAX8973_DISCH_ENBABLE; + + /* Clock advance trip configuration */ + switch (pdata->control_flags & MAX8973_CONTROL_CLKADV_TRIP_MASK) { + case MAX8973_CONTROL_CLKADV_TRIP_DISABLED: + control2 |= MAX8973_CKKADV_TRIP_DISABLE; + break; + + case MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US: + control2 |= MAX8973_CKKADV_TRIP_75mV_PER_US; + break; + + case MAX8973_CONTROL_CLKADV_TRIP_150mV_PER_US: + control2 |= MAX8973_CKKADV_TRIP_150mV_PER_US; + break; + + case MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US_HIST_DIS: + control2 |= MAX8973_CKKADV_TRIP_75mV_PER_US_HIST_DIS; + break; + } + + /* Configure inductor value */ + switch (pdata->control_flags & MAX8973_CONTROL_INDUCTOR_VALUE_MASK) { + case MAX8973_CONTROL_INDUCTOR_VALUE_NOMINAL: + control2 |= MAX8973_INDUCTOR_NOMINAL; + break; + + case MAX8973_CONTROL_INDUCTOR_VALUE_MINUS_30_PER: + control2 |= MAX8973_INDUCTOR_MIN_30_PER; + break; + + case MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_30_PER: + control2 |= MAX8973_INDUCTOR_PLUS_30_PER; + break; + + case MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_60_PER: + control2 |= MAX8973_INDUCTOR_PLUS_60_PER; + break; + } + + ret = regmap_write(max->regmap, MAX8973_CONTROL1, control1); + if (ret < 0) { + dev_err(max->dev, "register %d write failed, err = %d", + MAX8973_CONTROL1, ret); + return ret; + } + + ret = regmap_write(max->regmap, MAX8973_CONTROL2, control2); + if (ret < 0) { + dev_err(max->dev, "register %d write failed, err = %d", + MAX8973_CONTROL2, ret); + return ret; + } + + /* If external control is enabled then disable EN bit */ + if (max->enable_external_control) { + ret = regmap_update_bits(max->regmap, MAX8973_VOUT, + MAX8973_VOUT_ENABLE, 0); + if (ret < 0) + dev_err(max->dev, "register %d update failed, err = %d", + MAX8973_VOUT, ret); + } + return ret; +} + +static const struct regmap_config max8973_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX8973_CHIPID2, + .cache_type = REGCACHE_RBTREE, +}; + +static int max8973_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max8973_regulator_platform_data *pdata; + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct max8973_chip *max; + int ret; + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "No Platform data"); + return -EIO; + } + + max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL); + if (!max) { + dev_err(&client->dev, "Memory allocation for max failed\n"); + return -ENOMEM; + } + + max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config); + if (IS_ERR(max->regmap)) { + ret = PTR_ERR(max->regmap); + dev_err(&client->dev, "regmap init failed, err %d\n", ret); + return ret; + } + + i2c_set_clientdata(client, max); + max->dev = &client->dev; + max->desc.name = id->name; + max->desc.id = 0; + max->desc.ops = &max8973_dcdc_ops; + max->desc.type = REGULATOR_VOLTAGE; + max->desc.owner = THIS_MODULE; + max->desc.min_uV = MAX8973_MIN_VOLATGE; + max->desc.uV_step = MAX8973_VOLATGE_STEP; + max->desc.n_voltages = MAX8973_BUCK_N_VOLTAGE; + + if (!pdata->enable_ext_control) { + max->desc.enable_reg = MAX8973_VOUT; + max->desc.enable_mask = MAX8973_VOUT_ENABLE; + max8973_dcdc_ops.enable = regulator_enable_regmap; + max8973_dcdc_ops.disable = regulator_disable_regmap; + max8973_dcdc_ops.is_enabled = regulator_is_enabled_regmap; + } + + max->enable_external_control = pdata->enable_ext_control; + max->dvs_gpio = pdata->dvs_gpio; + max->curr_gpio_val = pdata->dvs_def_state; + max->curr_vout_reg = MAX8973_VOUT + pdata->dvs_def_state; + max->lru_index[0] = max->curr_vout_reg; + max->valid_dvs_gpio = false; + + if (gpio_is_valid(max->dvs_gpio)) { + int gpio_flags; + int i; + + gpio_flags = (pdata->dvs_def_state) ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + ret = devm_gpio_request_one(&client->dev, max->dvs_gpio, + gpio_flags, "max8973-dvs"); + if (ret) { + dev_err(&client->dev, + "gpio_request for gpio %d failed, err = %d\n", + max->dvs_gpio, ret); + return ret; + } + max->valid_dvs_gpio = true; + + /* + * Initialize the lru index with vout_reg id + * The index 0 will be most recently used and + * set with the max->curr_vout_reg */ + for (i = 0; i < MAX8973_MAX_VOUT_REG; ++i) + max->lru_index[i] = i; + max->lru_index[0] = max->curr_vout_reg; + max->lru_index[max->curr_vout_reg] = 0; + } + + ret = max8973_init_dcdc(max, pdata); + if (ret < 0) { + dev_err(max->dev, "Max8973 Init failed, err = %d\n", ret); + return ret; + } + + config.dev = &client->dev; + config.init_data = pdata->reg_init_data; + config.driver_data = max; + config.of_node = client->dev.of_node; + config.regmap = max->regmap; + + /* Register the regulators */ + rdev = regulator_register(&max->desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(max->dev, "regulator register failed, err %d\n", ret); + return ret; + } + + max->rdev = rdev; + return 0; +} + +static int max8973_remove(struct i2c_client *client) +{ + struct max8973_chip *max = i2c_get_clientdata(client); + + regulator_unregister(max->rdev); + return 0; +} + +static const struct i2c_device_id max8973_id[] = { + {.name = "max8973",}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, max8973_id); + +static struct i2c_driver max8973_i2c_driver = { + .driver = { + .name = "max8973", + .owner = THIS_MODULE, + }, + .probe = max8973_probe, + .remove = max8973_remove, + .id_table = max8973_id, +}; + +static int __init max8973_init(void) +{ + return i2c_add_driver(&max8973_i2c_driver); +} +subsys_initcall(max8973_init); + +static void __exit max8973_cleanup(void) +{ + i2c_del_driver(&max8973_i2c_driver); +} +module_exit(max8973_cleanup); + +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_DESCRIPTION("MAX8973 voltage regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index e39a0c7260dc..0ac7a87519b4 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -24,6 +24,7 @@ #include <linux/bug.h> #include <linux/err.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -31,6 +32,7 @@ #include <linux/regulator/machine.h> #include <linux/mfd/max8997.h> #include <linux/mfd/max8997-private.h> +#include <linux/regulator/of_regulator.h> struct max8997_data { struct device *dev; @@ -52,6 +54,13 @@ struct max8997_data { u8 saved_states[MAX8997_REG_MAX]; }; +static const unsigned int safeoutvolt[] = { + 4850000, + 4900000, + 4950000, + 3300000, +}; + static inline void max8997_set_gpio(struct max8997_data *max8997) { int set3 = (max8997->buck125_gpioindex) & 0x1; @@ -69,26 +78,26 @@ struct voltage_map_desc { int step; }; -/* Voltage maps in mV */ +/* Voltage maps in uV */ static const struct voltage_map_desc ldo_voltage_map_desc = { - .min = 800, .max = 3950, .step = 50, + .min = 800000, .max = 3950000, .step = 50000, }; /* LDO1 ~ 18, 21 all */ static const struct voltage_map_desc buck1245_voltage_map_desc = { - .min = 650, .max = 2225, .step = 25, + .min = 650000, .max = 2225000, .step = 25000, }; /* Buck1, 2, 4, 5 */ static const struct voltage_map_desc buck37_voltage_map_desc = { - .min = 750, .max = 3900, .step = 50, + .min = 750000, .max = 3900000, .step = 50000, }; /* Buck3, 7 */ -/* current map in mA */ +/* current map in uA */ static const struct voltage_map_desc charger_current_map_desc = { - .min = 200, .max = 950, .step = 50, + .min = 200000, .max = 950000, .step = 50000, }; static const struct voltage_map_desc topoff_current_map_desc = { - .min = 50, .max = 200, .step = 10, + .min = 50000, .max = 200000, .step = 10000, }; static const struct voltage_map_desc *reg_voltage_map[] = { @@ -128,29 +137,6 @@ static const struct voltage_map_desc *reg_voltage_map[] = { [MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc, }; -static int max8997_list_voltage_safeout(struct regulator_dev *rdev, - unsigned int selector) -{ - int rid = rdev_get_id(rdev); - - if (rid == MAX8997_ESAFEOUT1 || rid == MAX8997_ESAFEOUT2) { - switch (selector) { - case 0: - return 4850000; - case 1: - return 4900000; - case 2: - return 4950000; - case 3: - return 3300000; - default: - return -EINVAL; - } - } - - return -EINVAL; -} - static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev, unsigned int selector) { @@ -192,7 +178,7 @@ static int max8997_list_voltage(struct regulator_dev *rdev, if (val > desc->max) return -EINVAL; - return val * 1000; + return val; } static int max8997_get_enable_register(struct regulator_dev *rdev, @@ -483,7 +469,6 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, { struct max8997_data *max8997 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8997->iodev->i2c; - int min_vol = min_uV / 1000, max_vol = max_uV / 1000; const struct voltage_map_desc *desc; int rid = rdev_get_id(rdev); int i, reg, shift, mask, ret; @@ -507,7 +492,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, desc = reg_voltage_map[rid]; - i = max8997_get_voltage_proper_val(desc, min_vol, max_vol); + i = max8997_get_voltage_proper_val(desc, min_uV, max_uV); if (i < 0) return i; @@ -521,7 +506,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, return ret; } -static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev, +static int max8997_set_voltage_buck_time_sel(struct regulator_dev *rdev, unsigned int old_selector, unsigned int new_selector) { @@ -555,7 +540,7 @@ static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev, case MAX8997_BUCK4: case MAX8997_BUCK5: return DIV_ROUND_UP(desc->step * (new_selector - old_selector), - max8997->ramp_delay); + max8997->ramp_delay * 1000); } return 0; @@ -654,7 +639,6 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, const struct voltage_map_desc *desc; int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; bool gpio_dvs_mode = false; - int min_vol = min_uV / 1000, max_vol = max_uV / 1000; if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7) return -EINVAL; @@ -679,7 +663,7 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, selector); desc = reg_voltage_map[rid]; - new_val = max8997_get_voltage_proper_val(desc, min_vol, max_vol); + new_val = max8997_get_voltage_proper_val(desc, min_uV, max_uV); if (new_val < 0) return new_val; @@ -720,49 +704,23 @@ out: return 0; } -static const int safeoutvolt[] = { - 3300000, - 4850000, - 4900000, - 4950000, -}; - /* For SAFEOUT1 and SAFEOUT2 */ -static int max8997_set_voltage_safeout(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) +static int max8997_set_voltage_safeout_sel(struct regulator_dev *rdev, + unsigned selector) { struct max8997_data *max8997 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8997->iodev->i2c; int rid = rdev_get_id(rdev); int reg, shift = 0, mask, ret; - int i = 0; - u8 val; if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(safeoutvolt); i++) { - if (min_uV <= safeoutvolt[i] && - max_uV >= safeoutvolt[i]) - break; - } - - if (i >= ARRAY_SIZE(safeoutvolt)) - return -EINVAL; - - if (i == 0) - val = 0x3; - else - val = i - 1; - ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; - ret = max8997_update_reg(i2c, reg, val << shift, mask << shift); - *selector = val; - - return ret; + return max8997_update_reg(i2c, reg, selector << shift, mask << shift); } static int max8997_reg_disable_suspend(struct regulator_dev *rdev) @@ -799,7 +757,6 @@ static struct regulator_ops max8997_ldo_ops = { .disable = max8997_reg_disable, .get_voltage_sel = max8997_get_voltage_sel, .set_voltage = max8997_set_voltage_ldobuck, - .set_voltage_time_sel = max8997_set_voltage_ldobuck_time_sel, .set_suspend_disable = max8997_reg_disable_suspend, }; @@ -810,7 +767,7 @@ static struct regulator_ops max8997_buck_ops = { .disable = max8997_reg_disable, .get_voltage_sel = max8997_get_voltage_sel, .set_voltage = max8997_set_voltage_buck, - .set_voltage_time_sel = max8997_set_voltage_ldobuck_time_sel, + .set_voltage_time_sel = max8997_set_voltage_buck_time_sel, .set_suspend_disable = max8997_reg_disable_suspend, }; @@ -823,12 +780,12 @@ static struct regulator_ops max8997_fixedvolt_ops = { }; static struct regulator_ops max8997_safeout_ops = { - .list_voltage = max8997_list_voltage_safeout, + .list_voltage = regulator_list_voltage_table, .is_enabled = max8997_reg_is_enabled, .enable = max8997_reg_enable, .disable = max8997_reg_disable, .get_voltage_sel = max8997_get_voltage_sel, - .set_voltage = max8997_set_voltage_safeout, + .set_voltage_sel = max8997_set_voltage_safeout_sel, .set_suspend_disable = max8997_reg_disable_suspend, }; @@ -933,22 +890,162 @@ static struct regulator_desc regulators[] = { max8997_charger_fixedstate_ops), }; -static __devinit int max8997_pmic_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static int max8997_pmic_dt_parse_dvs_gpio(struct platform_device *pdev, + struct max8997_platform_data *pdata, + struct device_node *pmic_np) +{ + int i, gpio; + + for (i = 0; i < 3; i++) { + gpio = of_get_named_gpio(pmic_np, + "max8997,pmic-buck125-dvs-gpios", i); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "invalid gpio[%d]: %d\n", i, gpio); + return -EINVAL; + } + pdata->buck125_gpios[i] = gpio; + } + return 0; +} + +static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, + struct max8997_platform_data *pdata) { struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); + struct device_node *pmic_np, *regulators_np, *reg_np; + struct max8997_regulator_data *rdata; + unsigned int i, dvs_voltage_nr = 1, ret; + + pmic_np = of_node_get(iodev->dev->of_node); + if (!pmic_np) { + dev_err(&pdev->dev, "could not find pmic sub-node\n"); + return -ENODEV; + } + + regulators_np = of_find_node_by_name(pmic_np, "regulators"); + if (!regulators_np) { + dev_err(&pdev->dev, "could not find regulators sub-node\n"); + return -EINVAL; + } + + /* count the number of regulators to be supported in pmic */ + pdata->num_regulators = of_get_child_count(regulators_np); + + rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * + pdata->num_regulators, GFP_KERNEL); + if (!rdata) { + of_node_put(regulators_np); + dev_err(&pdev->dev, "could not allocate memory for regulator data\n"); + return -ENOMEM; + } + + pdata->regulators = rdata; + for_each_child_of_node(regulators_np, reg_np) { + for (i = 0; i < ARRAY_SIZE(regulators); i++) + if (!of_node_cmp(reg_np->name, regulators[i].name)) + break; + + if (i == ARRAY_SIZE(regulators)) { + dev_warn(&pdev->dev, "don't know how to configure regulator %s\n", + reg_np->name); + continue; + } + + rdata->id = i; + rdata->initdata = of_get_regulator_init_data(&pdev->dev, + reg_np); + rdata->reg_node = reg_np; + rdata++; + } + of_node_put(regulators_np); + + if (of_get_property(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs", NULL)) + pdata->buck1_gpiodvs = true; + + if (of_get_property(pmic_np, "max8997,pmic-buck2-uses-gpio-dvs", NULL)) + pdata->buck2_gpiodvs = true; + + if (of_get_property(pmic_np, "max8997,pmic-buck5-uses-gpio-dvs", NULL)) + pdata->buck5_gpiodvs = true; + + if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || + pdata->buck5_gpiodvs) { + ret = max8997_pmic_dt_parse_dvs_gpio(pdev, pdata, pmic_np); + if (ret) + return -EINVAL; + + if (of_property_read_u32(pmic_np, + "max8997,pmic-buck125-default-dvs-idx", + &pdata->buck125_default_idx)) { + pdata->buck125_default_idx = 0; + } else { + if (pdata->buck125_default_idx >= 8) { + pdata->buck125_default_idx = 0; + dev_info(&pdev->dev, "invalid value for default dvs index, using 0 instead\n"); + } + } + + if (of_get_property(pmic_np, + "max8997,pmic-ignore-gpiodvs-side-effect", NULL)) + pdata->ignore_gpiodvs_side_effect = true; + + dvs_voltage_nr = 8; + } + + if (of_property_read_u32_array(pmic_np, + "max8997,pmic-buck1-dvs-voltage", + pdata->buck1_voltage, dvs_voltage_nr)) { + dev_err(&pdev->dev, "buck1 voltages not specified\n"); + return -EINVAL; + } + + if (of_property_read_u32_array(pmic_np, + "max8997,pmic-buck2-dvs-voltage", + pdata->buck2_voltage, dvs_voltage_nr)) { + dev_err(&pdev->dev, "buck2 voltages not specified\n"); + return -EINVAL; + } + + if (of_property_read_u32_array(pmic_np, + "max8997,pmic-buck5-dvs-voltage", + pdata->buck5_voltage, dvs_voltage_nr)) { + dev_err(&pdev->dev, "buck5 voltages not specified\n"); + return -EINVAL; + } + + return 0; +} +#else +static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, + struct max8997_platform_data *pdata) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static int max8997_pmic_probe(struct platform_device *pdev) +{ + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max8997_platform_data *pdata = iodev->pdata; struct regulator_config config = { }; struct regulator_dev **rdev; struct max8997_data *max8997; struct i2c_client *i2c; - int i, ret, size; + int i, ret, size, nr_dvs; u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0; - if (!pdata) { + if (IS_ERR_OR_NULL(pdata)) { dev_err(pdev->dev.parent, "No platform init data supplied.\n"); return -ENODEV; } + if (iodev->dev->of_node) { + ret = max8997_pmic_dt_parse_pdata(pdev, pdata); + if (ret) + return ret; + } + max8997 = devm_kzalloc(&pdev->dev, sizeof(struct max8997_data), GFP_KERNEL); if (!max8997) @@ -973,12 +1070,15 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) memcpy(max8997->buck125_gpios, pdata->buck125_gpios, sizeof(int) * 3); max8997->ignore_gpiodvs_side_effect = pdata->ignore_gpiodvs_side_effect; - for (i = 0; i < 8; i++) { + nr_dvs = (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || + pdata->buck5_gpiodvs) ? 8 : 1; + + for (i = 0; i < nr_dvs; i++) { max8997->buck1_vol[i] = ret = max8997_get_voltage_proper_val( &buck1245_voltage_map_desc, - pdata->buck1_voltage[i] / 1000, - pdata->buck1_voltage[i] / 1000 + + pdata->buck1_voltage[i], + pdata->buck1_voltage[i] + buck1245_voltage_map_desc.step); if (ret < 0) goto err_out; @@ -986,8 +1086,8 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) max8997->buck2_vol[i] = ret = max8997_get_voltage_proper_val( &buck1245_voltage_map_desc, - pdata->buck2_voltage[i] / 1000, - pdata->buck2_voltage[i] / 1000 + + pdata->buck2_voltage[i], + pdata->buck2_voltage[i] + buck1245_voltage_map_desc.step); if (ret < 0) goto err_out; @@ -995,8 +1095,8 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) max8997->buck5_vol[i] = ret = max8997_get_voltage_proper_val( &buck1245_voltage_map_desc, - pdata->buck5_voltage[i] / 1000, - pdata->buck5_voltage[i] / 1000 + + pdata->buck5_voltage[i], + pdata->buck5_voltage[i] + buck1245_voltage_map_desc.step); if (ret < 0) goto err_out; @@ -1019,6 +1119,19 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) max_buck5, 0x3f); } + /* Initialize all the DVS related BUCK registers */ + for (i = 0; i < nr_dvs; i++) { + max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i, + max8997->buck1_vol[i], + 0x3f); + max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i, + max8997->buck2_vol[i], + 0x3f); + max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i, + max8997->buck5_vol[i], + 0x3f); + } + /* * If buck 1, 2, and 5 do not care DVS GPIO settings, ignore them. * If at least one of them cares, set gpios. @@ -1068,19 +1181,6 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) max8997_update_reg(i2c, MAX8997_REG_BUCK5CTRL, (pdata->buck5_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); - /* Initialize all the DVS related BUCK registers */ - for (i = 0; i < 8; i++) { - max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i, - max8997->buck1_vol[i], - 0x3f); - max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i, - max8997->buck2_vol[i], - 0x3f); - max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i, - max8997->buck5_vol[i], - 0x3f); - } - /* Misc Settings */ max8997->ramp_delay = 10; /* set 10mV/us, which is the default */ max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9); @@ -1090,17 +1190,20 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) int id = pdata->regulators[i].id; desc = reg_voltage_map[id]; - if (desc) + if (desc) { regulators[id].n_voltages = (desc->max - desc->min) / desc->step + 1; - else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) - regulators[id].n_voltages = 4; - else if (id == MAX8997_CHARGER_CV) + } else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) { + regulators[id].volt_table = safeoutvolt; + regulators[id].n_voltages = ARRAY_SIZE(safeoutvolt); + } else if (id == MAX8997_CHARGER_CV) { regulators[id].n_voltages = 16; + } config.dev = max8997->dev; config.init_data = pdata->regulators[i].initdata; config.driver_data = max8997; + config.of_node = pdata->regulators[i].reg_node; rdev[i] = regulator_register(®ulators[id], &config); if (IS_ERR(rdev[i])) { @@ -1120,7 +1223,7 @@ err_out: return ret; } -static int __devexit max8997_pmic_remove(struct platform_device *pdev) +static int max8997_pmic_remove(struct platform_device *pdev) { struct max8997_data *max8997 = platform_get_drvdata(pdev); struct regulator_dev **rdev = max8997->rdev; @@ -1143,7 +1246,7 @@ static struct platform_driver max8997_pmic_driver = { .owner = THIS_MODULE, }, .probe = max8997_pmic_probe, - .remove = __devexit_p(max8997_pmic_remove), + .remove = max8997_pmic_remove, .id_table = max8997_pmic_id, }; diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 5dfa920ff0c8..b588f07c7cad 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -51,39 +51,39 @@ struct voltage_map_desc { int step; }; -/* Voltage maps */ +/* Voltage maps in uV*/ static const struct voltage_map_desc ldo23_voltage_map_desc = { - .min = 800, .step = 50, .max = 1300, + .min = 800000, .step = 50000, .max = 1300000, }; static const struct voltage_map_desc ldo456711_voltage_map_desc = { - .min = 1600, .step = 100, .max = 3600, + .min = 1600000, .step = 100000, .max = 3600000, }; static const struct voltage_map_desc ldo8_voltage_map_desc = { - .min = 3000, .step = 100, .max = 3600, + .min = 3000000, .step = 100000, .max = 3600000, }; static const struct voltage_map_desc ldo9_voltage_map_desc = { - .min = 2800, .step = 100, .max = 3100, + .min = 2800000, .step = 100000, .max = 3100000, }; static const struct voltage_map_desc ldo10_voltage_map_desc = { - .min = 950, .step = 50, .max = 1300, + .min = 950000, .step = 50000, .max = 1300000, }; static const struct voltage_map_desc ldo1213_voltage_map_desc = { - .min = 800, .step = 100, .max = 3300, + .min = 800000, .step = 100000, .max = 3300000, }; static const struct voltage_map_desc ldo1415_voltage_map_desc = { - .min = 1200, .step = 100, .max = 3300, + .min = 1200000, .step = 100000, .max = 3300000, }; static const struct voltage_map_desc ldo1617_voltage_map_desc = { - .min = 1600, .step = 100, .max = 3600, + .min = 1600000, .step = 100000, .max = 3600000, }; static const struct voltage_map_desc buck12_voltage_map_desc = { - .min = 750, .step = 25, .max = 1525, + .min = 750000, .step = 25000, .max = 1525000, }; static const struct voltage_map_desc buck3_voltage_map_desc = { - .min = 1600, .step = 100, .max = 3600, + .min = 1600000, .step = 100000, .max = 3600000, }; static const struct voltage_map_desc buck4_voltage_map_desc = { - .min = 800, .step = 100, .max = 2300, + .min = 800000, .step = 100000, .max = 2300000, }; static const struct voltage_map_desc *ldo_voltage_map[] = { @@ -311,25 +311,13 @@ static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev, dev_get_platdata(max8998->iodev->dev); struct i2c_client *i2c = max8998->iodev->i2c; int buck = rdev_get_id(rdev); - int reg, shift = 0, mask, ret; - int j, previous_sel; + int reg, shift = 0, mask, ret, j; static u8 buck1_last_val; ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; - previous_sel = max8998_get_voltage_sel(rdev); - - /* Check if voltage needs to be changed */ - /* if previous_voltage equal new voltage, return */ - if (previous_sel == selector) { - dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n", - regulator_list_voltage_linear(rdev, previous_sel), - regulator_list_voltage_linear(rdev, selector)); - return ret; - } - switch (buck) { case MAX8998_BUCK1: dev_dbg(max8998->dev, @@ -445,9 +433,9 @@ static int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev, if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP)) return 0; - difference = (new_selector - old_selector) * desc->step; + difference = (new_selector - old_selector) * desc->step / 1000; if (difference > 0) - return difference / ((val & 0x0f) + 1); + return DIV_ROUND_UP(difference, (val & 0x0f) + 1); return 0; } @@ -633,7 +621,7 @@ static struct regulator_desc regulators[] = { } }; -static __devinit int max8998_pmic_probe(struct platform_device *pdev) +static int max8998_pmic_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); @@ -702,7 +690,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) i = 0; while (buck12_voltage_map_desc.min + buck12_voltage_map_desc.step*i - < (pdata->buck1_voltage1 / 1000)) + < pdata->buck1_voltage1) i++; max8998->buck1_vol[0] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i); @@ -713,7 +701,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) i = 0; while (buck12_voltage_map_desc.min + buck12_voltage_map_desc.step*i - < (pdata->buck1_voltage2 / 1000)) + < pdata->buck1_voltage2) i++; max8998->buck1_vol[1] = i; @@ -725,7 +713,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) i = 0; while (buck12_voltage_map_desc.min + buck12_voltage_map_desc.step*i - < (pdata->buck1_voltage3 / 1000)) + < pdata->buck1_voltage3) i++; max8998->buck1_vol[2] = i; @@ -737,7 +725,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) i = 0; while (buck12_voltage_map_desc.min + buck12_voltage_map_desc.step*i - < (pdata->buck1_voltage4 / 1000)) + < pdata->buck1_voltage4) i++; max8998->buck1_vol[3] = i; @@ -763,7 +751,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) i = 0; while (buck12_voltage_map_desc.min + buck12_voltage_map_desc.step*i - < (pdata->buck2_voltage1 / 1000)) + < pdata->buck2_voltage1) i++; max8998->buck2_vol[0] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i); @@ -774,7 +762,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) i = 0; while (buck12_voltage_map_desc.min + buck12_voltage_map_desc.step*i - < (pdata->buck2_voltage2 / 1000)) + < pdata->buck2_voltage2) i++; max8998->buck2_vol[1] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i); @@ -792,8 +780,8 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) int count = (desc->max - desc->min) / desc->step + 1; regulators[index].n_voltages = count; - regulators[index].min_uV = desc->min * 1000; - regulators[index].uV_step = desc->step * 1000; + regulators[index].min_uV = desc->min; + regulators[index].uV_step = desc->step; } config.dev = max8998->dev; @@ -818,7 +806,7 @@ err_out: return ret; } -static int __devexit max8998_pmic_remove(struct platform_device *pdev) +static int max8998_pmic_remove(struct platform_device *pdev) { struct max8998_data *max8998 = platform_get_drvdata(pdev); struct regulator_dev **rdev = max8998->rdev; @@ -842,7 +830,7 @@ static struct platform_driver max8998_pmic_driver = { .owner = THIS_MODULE, }, .probe = max8998_pmic_probe, - .remove = __devexit_p(max8998_pmic_remove), + .remove = max8998_pmic_remove, .id_table = max8998_pmic_id, }; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 0801a6d0c122..c46c6705cd74 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -392,7 +392,7 @@ static struct regulator_ops mc13783_gpo_regulator_ops = { .set_voltage = mc13xxx_fixed_regulator_set_voltage, }; -static int __devinit mc13783_regulator_probe(struct platform_device *pdev) +static int mc13783_regulator_probe(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv; struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); @@ -445,7 +445,7 @@ err: return ret; } -static int __devexit mc13783_regulator_remove(struct platform_device *pdev) +static int mc13783_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); struct mc13xxx_regulator_platform_data *pdata = @@ -465,7 +465,7 @@ static struct platform_driver mc13783_regulator_driver = { .name = "mc13783-regulator", .owner = THIS_MODULE, }, - .remove = __devexit_p(mc13783_regulator_remove), + .remove = mc13783_regulator_remove, .probe = mc13783_regulator_probe, }; diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 1fa63812f7ac..9891aec47b57 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -164,6 +164,14 @@ static const unsigned int mc13892_sw1[] = { 1350000, 1375000 }; +/* + * Note: this table is used to derive SWxVSEL by index into + * the array. Offset the values by the index of 1100000uV + * to get the actual register value for that voltage selector + * if the HI bit is to be set as well. + */ +#define MC13892_SWxHI_SEL_OFFSET 20 + static const unsigned int mc13892_sw[] = { 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, 800000, 825000, 850000, 875000, @@ -239,7 +247,6 @@ static const unsigned int mc13892_pwgtdrv[] = { }; static struct regulator_ops mc13892_gpo_regulator_ops; -/* sw regulators need special care due to the "hi bit" */ static struct regulator_ops mc13892_sw_regulator_ops; @@ -396,7 +403,7 @@ static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev) { struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); int ret, id = rdev_get_id(rdev); - unsigned int val; + unsigned int val, selector; dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); @@ -407,12 +414,28 @@ static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev) if (ret) return ret; - val = (val & mc13892_regulators[id].vsel_mask) - >> mc13892_regulators[id].vsel_shift; + /* + * Figure out if the HI bit is set inside the switcher mode register + * since this means the selector value we return is at a different + * offset into the selector table. + * + * According to the MC13892 documentation note 59 (Table 47) the SW1 + * buck switcher does not support output range programming therefore + * the HI bit must always remain 0. So do not do anything strange if + * our register is MC13892_SWITCHERS0. + */ + + selector = val & mc13892_regulators[id].vsel_mask; + + if ((mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) && + (val & MC13892_SWITCHERS0_SWxHI)) { + selector += MC13892_SWxHI_SEL_OFFSET; + } - dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); + dev_dbg(rdev_get_dev(rdev), "%s id: %d val: 0x%08x selector: %d\n", + __func__, id, val, selector); - return val; + return selector; } static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev, @@ -425,18 +448,35 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev, volt = rdev->desc->volt_table[selector]; mask = mc13892_regulators[id].vsel_mask; - reg_value = selector << mc13892_regulators[id].vsel_shift; - - if (volt > 1375000) { - mask |= MC13892_SWITCHERS0_SWxHI; - reg_value |= MC13892_SWITCHERS0_SWxHI; - } else if (volt < 1100000) { - mask |= MC13892_SWITCHERS0_SWxHI; - reg_value &= ~MC13892_SWITCHERS0_SWxHI; + reg_value = selector; + + /* + * Don't mess with the HI bit or support HI voltage offsets for SW1. + * + * Since the get_voltage_sel callback has given a fudged value for + * the selector offset, we need to back out that offset if HI is + * to be set so we write the correct value to the register. + * + * The HI bit addition and selector offset handling COULD be more + * complicated by shifting and masking off the voltage selector part + * of the register then logical OR it back in, but since the selector + * is at bits 4:0 there is very little point. This makes the whole + * thing more readable and we do far less work. + */ + + if (mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) { + if (volt > 1375000) { + reg_value -= MC13892_SWxHI_SEL_OFFSET; + reg_value |= MC13892_SWITCHERS0_SWxHI; + mask |= MC13892_SWITCHERS0_SWxHI; + } else if (volt < 1100000) { + reg_value &= ~MC13892_SWITCHERS0_SWxHI; + mask |= MC13892_SWITCHERS0_SWxHI; + } } mc13xxx_lock(priv->mc13xxx); - ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, mask, + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg, mask, reg_value); mc13xxx_unlock(priv->mc13xxx); @@ -486,7 +526,7 @@ static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) } -static int __devinit mc13892_regulator_probe(struct platform_device *pdev) +static int mc13892_regulator_probe(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv; struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent); @@ -495,15 +535,18 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) struct mc13xxx_regulator_init_data *mc13xxx_data; struct regulator_config config = { }; int i, ret; - int num_regulators = 0; + int num_regulators = 0, num_parsed; u32 val; num_regulators = mc13xxx_get_num_regulators_dt(pdev); + if (num_regulators <= 0 && pdata) num_regulators = pdata->num_regulators; if (num_regulators <= 0) return -EINVAL; + num_parsed = num_regulators; + priv = devm_kzalloc(&pdev->dev, sizeof(*priv) + num_regulators * sizeof(priv->regulators[0]), GFP_KERNEL); @@ -520,7 +563,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) if (ret) goto err_unlock; - /* enable switch auto mode */ + /* enable switch auto mode (on 2.0A silicon only) */ if ((val & 0x0000FFFF) == 0x45d0) { ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4, MC13892_SWITCHERS4_SW1MODE_M | @@ -546,7 +589,39 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) = mc13892_vcam_get_mode; mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators, - ARRAY_SIZE(mc13892_regulators)); + ARRAY_SIZE(mc13892_regulators), + &num_parsed); + + /* + * Perform a little sanity check on the regulator tree - if we found + * a number of regulators from mc13xxx_get_num_regulators_dt and + * then parsed a smaller number in mc13xxx_parse_regulators_dt then + * there is a regulator defined in the regulators node which has + * not matched any usable regulator in the driver. In this case, + * there is one missing and what will happen is the first regulator + * will get registered again. + * + * Fix this by basically making our number of registerable regulators + * equal to the number of regulators we parsed. We are allocating + * too much memory for priv, but this is unavoidable at this point. + * + * As an example of how this can happen, try making a typo in your + * regulators node (vviohi {} instead of viohi {}) so that the name + * does not match.. + * + * The check will basically pass for platform data (non-DT) because + * mc13xxx_parse_regulators_dt for !CONFIG_OF will not touch num_parsed. + * + */ + if (num_parsed != num_regulators) { + dev_warn(&pdev->dev, + "parsed %d != regulators %d - check your device tree!\n", + num_parsed, num_regulators); + + num_regulators = num_parsed; + priv->num_regulators = num_regulators; + } + for (i = 0; i < num_regulators; i++) { struct regulator_init_data *init_data; struct regulator_desc *desc; @@ -588,7 +663,7 @@ err_unlock: return ret; } -static int __devexit mc13892_regulator_remove(struct platform_device *pdev) +static int mc13892_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); int i; @@ -606,7 +681,7 @@ static struct platform_driver mc13892_regulator_driver = { .name = "mc13892-regulator", .owner = THIS_MODULE, }, - .remove = __devexit_p(mc13892_regulator_remove), + .remove = mc13892_regulator_remove, .probe = mc13892_regulator_probe, }; diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 88cbb832d555..23cf9f9c383b 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -162,31 +162,32 @@ struct regulator_ops mc13xxx_fixed_regulator_ops = { EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops); #ifdef CONFIG_OF -int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev) +int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) { - struct device_node *parent, *child; - int num = 0; + struct device_node *parent; + int num; of_node_get(pdev->dev.parent->of_node); parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); if (!parent) return -ENODEV; - for_each_child_of_node(parent, child) - num++; - + num = of_get_child_count(parent); + of_node_put(parent); return num; } EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt); -struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt( +struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( struct platform_device *pdev, struct mc13xxx_regulator *regulators, - int num_regulators) + int num_regulators, int *num_parsed) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); struct mc13xxx_regulator_init_data *data, *p; struct device_node *parent, *child; - int i; + int i, parsed = 0; + + *num_parsed = 0; of_node_get(pdev->dev.parent->of_node); parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); @@ -195,24 +196,32 @@ struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt( data = devm_kzalloc(&pdev->dev, sizeof(*data) * priv->num_regulators, GFP_KERNEL); - if (!data) + if (!data) { + of_node_put(parent); return NULL; + } + p = data; for_each_child_of_node(parent, child) { for (i = 0; i < num_regulators; i++) { if (!of_node_cmp(child->name, regulators[i].desc.name)) { + p->id = i; p->init_data = of_get_regulator_init_data( &pdev->dev, child); p->node = child; p++; + + parsed++; break; } } } + of_node_put(parent); + *num_parsed = parsed; return data; } EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt); diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h index 06c8903f182a..007f83387fd6 100644 --- a/drivers/regulator/mc13xxx.h +++ b/drivers/regulator/mc13xxx.h @@ -39,7 +39,7 @@ extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev); extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( struct platform_device *pdev, struct mc13xxx_regulator *regulators, - int num_regulators); + int num_regulators, int *num_parsed); #else static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) { @@ -48,7 +48,7 @@ static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( struct platform_device *pdev, struct mc13xxx_regulator *regulators, - int num_regulators) + int num_regulators, int *num_parsed) { return NULL; } diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 6f684916fd79..66ca769287ab 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -120,6 +120,12 @@ int of_regulator_match(struct device *dev, struct device_node *node, if (!dev || !node) return -EINVAL; + for (i = 0; i < num_matches; i++) { + struct of_regulator_match *match = &matches[i]; + match->init_data = NULL; + match->of_node = NULL; + } + for_each_child_of_node(node, child) { name = of_get_property(child, "regulator-compatible", NULL); diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 07aee694ba92..39cf14606784 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -4,6 +4,7 @@ * Copyright 2011-2012 Texas Instruments Inc. * * Author: Graeme Gregory <gg@slimlogic.co.uk> + * Author: Ian Lartey <ian@slimlogic.co.uk> * * 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 @@ -156,7 +157,7 @@ static const struct regs_info palmas_regs_info[] = { * * So they are basically (maxV-minV)/stepV */ -#define PALMAS_SMPS_NUM_VOLTAGES 116 +#define PALMAS_SMPS_NUM_VOLTAGES 117 #define PALMAS_SMPS10_NUM_VOLTAGES 2 #define PALMAS_LDO_NUM_VOLTAGES 50 @@ -309,68 +310,22 @@ static int palmas_list_voltage_smps(struct regulator_dev *dev, int id = rdev_get_id(dev); int mult = 1; - if (!selector) - return 0; - /* Read the multiplier set in VSEL register to return * the correct voltage. */ if (pmic->range[id]) mult = 2; - /* Voltage is (0.49V + (selector * 0.01V)) * RANGE - * as defined in data sheet. RANGE is either x1 or x2 - */ - return (490000 + (selector * 10000)) * mult; -} - -static int palmas_get_voltage_smps_sel(struct regulator_dev *dev) -{ - struct palmas_pmic *pmic = rdev_get_drvdata(dev); - int id = rdev_get_id(dev); - int selector; - unsigned int reg; - unsigned int addr; - - addr = palmas_regs_info[id].vsel_addr; - - palmas_smps_read(pmic->palmas, addr, ®); - - selector = reg & PALMAS_SMPS12_VOLTAGE_VSEL_MASK; - - /* Adjust selector to match list_voltage ranges */ - if ((selector > 0) && (selector < 6)) - selector = 6; - if (!selector) - selector = 5; - if (selector > 121) - selector = 121; - selector -= 5; - - return selector; -} - -static int palmas_set_voltage_smps_sel(struct regulator_dev *dev, - unsigned selector) -{ - struct palmas_pmic *pmic = rdev_get_drvdata(dev); - int id = rdev_get_id(dev); - unsigned int reg = 0; - unsigned int addr; - - addr = palmas_regs_info[id].vsel_addr; - - /* Make sure we don't change the value of RANGE */ - if (pmic->range[id]) - reg |= PALMAS_SMPS12_VOLTAGE_RANGE; - - /* Adjust the linux selector into range used in VSEL register */ - if (selector) - reg |= selector + 5; - - palmas_smps_write(pmic->palmas, addr, reg); - - return 0; + if (selector == 0) + return 0; + else if (selector < 6) + return 500000 * mult; + else + /* Voltage is linear mapping starting from selector 6, + * volt = (0.49V + ((selector - 5) * 0.01V)) * RANGE + * RANGE is either x1 or x2 + */ + return (490000 + ((selector - 5) * 10000)) * mult; } static int palmas_map_voltage_smps(struct regulator_dev *rdev, @@ -386,11 +341,11 @@ static int palmas_map_voltage_smps(struct regulator_dev *rdev, if (pmic->range[id]) { /* RANGE is x2 */ if (min_uV < 1000000) min_uV = 1000000; - ret = DIV_ROUND_UP(min_uV - 1000000, 20000) + 1; + ret = DIV_ROUND_UP(min_uV - 1000000, 20000) + 6; } else { /* RANGE is x1 */ if (min_uV < 500000) min_uV = 500000; - ret = DIV_ROUND_UP(min_uV - 500000, 10000) + 1; + ret = DIV_ROUND_UP(min_uV - 500000, 10000) + 6; } /* Map back into a voltage to verify we're still in bounds */ @@ -407,8 +362,8 @@ static struct regulator_ops palmas_ops_smps = { .disable = palmas_disable_smps, .set_mode = palmas_set_mode_smps, .get_mode = palmas_get_mode_smps, - .get_voltage_sel = palmas_get_voltage_smps_sel, - .set_voltage_sel = palmas_set_voltage_smps_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .list_voltage = palmas_list_voltage_smps, .map_voltage = palmas_map_voltage_smps, }; @@ -436,44 +391,14 @@ static int palmas_is_enabled_ldo(struct regulator_dev *dev) return !!(reg); } -static int palmas_list_voltage_ldo(struct regulator_dev *dev, - unsigned selector) -{ - if (!selector) - return 0; - - /* voltage is 0.85V + (selector * 0.05v) */ - return 850000 + (selector * 50000); -} - -static int palmas_map_voltage_ldo(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int ret, voltage; - - if (min_uV == 0) - return 0; - - if (min_uV < 900000) - min_uV = 900000; - ret = DIV_ROUND_UP(min_uV - 900000, 50000) + 1; - - /* Map back into a voltage to verify we're still in bounds */ - voltage = palmas_list_voltage_ldo(rdev, ret); - if (voltage < min_uV || voltage > max_uV) - return -EINVAL; - - return ret; -} - static struct regulator_ops palmas_ops_ldo = { .is_enabled = palmas_is_enabled_ldo, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .list_voltage = palmas_list_voltage_ldo, - .map_voltage = palmas_map_voltage_ldo, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, }; /* @@ -595,7 +520,7 @@ static struct of_regulator_match palmas_matches[] = { { .name = "ldousb", }, }; -static void __devinit palmas_dt_to_pdata(struct device *dev, +static void palmas_dt_to_pdata(struct device *dev, struct device_node *node, struct palmas_pmic_platform_data *pdata) { @@ -603,6 +528,7 @@ static void __devinit palmas_dt_to_pdata(struct device *dev, u32 prop; int idx, ret; + node = of_node_get(node); regulators = of_find_node_by_name(node, "regulators"); if (!regulators) { dev_info(dev, "regulator node not found\n"); @@ -611,6 +537,7 @@ static void __devinit palmas_dt_to_pdata(struct device *dev, ret = of_regulator_match(dev, regulators, palmas_matches, PALMAS_NUM_REGS); + of_node_put(regulators); if (ret < 0) { dev_err(dev, "Error parsing regulator init data: %d\n", ret); return; @@ -642,11 +569,6 @@ static void __devinit palmas_dt_to_pdata(struct device *dev, pdata->reg_init[idx]->mode_sleep = prop; ret = of_property_read_u32(palmas_matches[idx].of_node, - "ti,warm_reset", &prop); - if (!ret) - pdata->reg_init[idx]->warm_reset = prop; - - ret = of_property_read_u32(palmas_matches[idx].of_node, "ti,tstep", &prop); if (!ret) pdata->reg_init[idx]->tstep = prop; @@ -663,7 +585,7 @@ static void __devinit palmas_dt_to_pdata(struct device *dev, } -static __devinit int palmas_probe(struct platform_device *pdev) +static int palmas_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data; @@ -733,6 +655,14 @@ static __devinit int palmas_probe(struct platform_device *pdev) continue; } + /* Initialise sleep/init values from platform data */ + if (pdata && pdata->reg_init[id]) { + reg_init = pdata->reg_init[id]; + ret = palmas_smps_init(palmas, id, reg_init); + if (ret) + goto err_unregister_regulator; + } + /* Register the regulators */ pmic->desc[id].name = palmas_regs_info[id].name; pmic->desc[id].id = id; @@ -753,29 +683,11 @@ static __devinit int palmas_probe(struct platform_device *pdev) pmic->desc[id].uV_step = 1250000; break; default: - pmic->desc[id].ops = &palmas_ops_smps; - pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES; - } - - pmic->desc[id].type = REGULATOR_VOLTAGE; - pmic->desc[id].owner = THIS_MODULE; - - /* Initialise sleep/init values from platform data */ - if (pdata) { - reg_init = pdata->reg_init[id]; - if (reg_init) { - ret = palmas_smps_init(palmas, id, reg_init); - if (ret) - goto err_unregister_regulator; - } - } - - /* - * read and store the RANGE bit for later use - * This must be done before regulator is probed otherwise - * we error in probe with unsuportable ranges. - */ - if (id != PALMAS_REG_SMPS10) { + /* + * Read and store the RANGE bit for later use + * This must be done before regulator is probed, + * otherwise we error in probe with unsupportable ranges. + */ addr = palmas_regs_info[id].vsel_addr; ret = palmas_smps_read(pmic->palmas, addr, ®); @@ -783,8 +695,19 @@ static __devinit int palmas_probe(struct platform_device *pdev) goto err_unregister_regulator; if (reg & PALMAS_SMPS12_VOLTAGE_RANGE) pmic->range[id] = 1; + + pmic->desc[id].ops = &palmas_ops_smps; + pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES; + pmic->desc[id].vsel_reg = + PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, + palmas_regs_info[id].vsel_addr); + pmic->desc[id].vsel_mask = + PALMAS_SMPS12_VOLTAGE_VSEL_MASK; } + pmic->desc[id].type = REGULATOR_VOLTAGE; + pmic->desc[id].owner = THIS_MODULE; + if (pdata) config.init_data = pdata->reg_data[id]; else @@ -821,6 +744,9 @@ static __devinit int palmas_probe(struct platform_device *pdev) pmic->desc[id].type = REGULATOR_VOLTAGE; pmic->desc[id].owner = THIS_MODULE; + pmic->desc[id].min_uV = 900000; + pmic->desc[id].uV_step = 50000; + pmic->desc[id].linear_min_sel = 1; pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, palmas_regs_info[id].vsel_addr); pmic->desc[id].vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK; @@ -868,7 +794,7 @@ err_unregister_regulator: return ret; } -static int __devexit palmas_remove(struct platform_device *pdev) +static int palmas_remove(struct platform_device *pdev) { struct palmas_pmic *pmic = platform_get_drvdata(pdev); int id; @@ -878,7 +804,7 @@ static int __devexit palmas_remove(struct platform_device *pdev) return 0; } -static struct of_device_id __devinitdata of_palmas_match_tbl[] = { +static struct of_device_id of_palmas_match_tbl[] = { { .compatible = "ti,palmas-pmic", }, { /* end */ } }; @@ -890,7 +816,7 @@ static struct platform_driver palmas_driver = { .owner = THIS_MODULE, }, .probe = palmas_probe, - .remove = __devexit_p(palmas_remove), + .remove = palmas_remove, }; static int __init palmas_init(void) diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 68777acc099f..4899342f1fc1 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -236,7 +236,7 @@ static const struct regulator_desc pcap_regulators[] = { VREG(VAUX4), VREG(VSIM), VREG(VSIM2), VREG(VVIB), VREG(SW1), VREG(SW2), }; -static int __devinit pcap_regulator_probe(struct platform_device *pdev) +static int pcap_regulator_probe(struct platform_device *pdev) { struct regulator_dev *rdev; void *pcap = dev_get_drvdata(pdev->dev.parent); @@ -255,7 +255,7 @@ static int __devinit pcap_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit pcap_regulator_remove(struct platform_device *pdev) +static int pcap_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -271,7 +271,7 @@ static struct platform_driver pcap_regulator_driver = { .owner = THIS_MODULE, }, .probe = pcap_regulator_probe, - .remove = __devexit_p(pcap_regulator_remove), + .remove = pcap_regulator_remove, }; static int __init pcap_regulator_init(void) diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 092e5cb848a1..534075e13d6d 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -24,12 +24,15 @@ #include <linux/mfd/pcf50633/core.h> #include <linux/mfd/pcf50633/pmic.h> -#define PCF50633_REGULATOR(_name, _id, _n) \ +#define PCF50633_REGULATOR(_name, _id, _min_uV, _uV_step, _min_sel, _n) \ { \ .name = _name, \ .id = PCF50633_REGULATOR_##_id, \ .ops = &pcf50633_regulator_ops, \ .n_voltages = _n, \ + .min_uV = _min_uV, \ + .uV_step = _uV_step, \ + .linear_min_sel = _min_sel, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ .vsel_reg = PCF50633_REG_##_id##OUT, \ @@ -38,165 +41,42 @@ .enable_mask = PCF50633_REGULATOR_ON, \ } -/* Bits from voltage value */ -static u8 auto_voltage_bits(unsigned int millivolts) -{ - if (millivolts < 1800) - return 0x2f; - if (millivolts > 3800) - return 0xff; - - millivolts -= 625; - - return millivolts / 25; -} - -static u8 down_voltage_bits(unsigned int millivolts) -{ - if (millivolts < 625) - return 0; - else if (millivolts > 3000) - return 0xff; - - millivolts -= 625; - - return millivolts / 25; -} - -static u8 ldo_voltage_bits(unsigned int millivolts) -{ - if (millivolts < 900) - return 0; - else if (millivolts > 3600) - return 0x1f; - - millivolts -= 900; - return millivolts / 100; -} - -/* Obtain voltage value from bits */ -static unsigned int auto_voltage_value(u8 bits) -{ - /* AUTOOUT: 00000000 to 00101110 are reserved. - * Return 0 for bits in reserved range, which means this selector code - * can't be used on this system */ - if (bits < 0x2f) - return 0; - - return 625 + (bits * 25); -} - - -static unsigned int down_voltage_value(u8 bits) -{ - return 625 + (bits * 25); -} - - -static unsigned int ldo_voltage_value(u8 bits) -{ - bits &= 0x1f; - - return 900 + (bits * 100); -} - -static int pcf50633_regulator_map_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - struct pcf50633 *pcf; - int regulator_id, millivolts; - u8 volt_bits; - - pcf = rdev_get_drvdata(rdev); - - regulator_id = rdev_get_id(rdev); - if (regulator_id >= PCF50633_NUM_REGULATORS) - return -EINVAL; - - millivolts = min_uV / 1000; - - switch (regulator_id) { - case PCF50633_REGULATOR_AUTO: - volt_bits = auto_voltage_bits(millivolts); - break; - case PCF50633_REGULATOR_DOWN1: - case PCF50633_REGULATOR_DOWN2: - volt_bits = down_voltage_bits(millivolts); - break; - case PCF50633_REGULATOR_LDO1: - case PCF50633_REGULATOR_LDO2: - case PCF50633_REGULATOR_LDO3: - case PCF50633_REGULATOR_LDO4: - case PCF50633_REGULATOR_LDO5: - case PCF50633_REGULATOR_LDO6: - case PCF50633_REGULATOR_HCLDO: - case PCF50633_REGULATOR_MEMLDO: - volt_bits = ldo_voltage_bits(millivolts); - break; - default: - return -EINVAL; - } - - return volt_bits; -} - -static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev, - unsigned int index) -{ - int regulator_id = rdev_get_id(rdev); - - int millivolts; - - switch (regulator_id) { - case PCF50633_REGULATOR_AUTO: - millivolts = auto_voltage_value(index); - break; - case PCF50633_REGULATOR_DOWN1: - case PCF50633_REGULATOR_DOWN2: - millivolts = down_voltage_value(index); - break; - case PCF50633_REGULATOR_LDO1: - case PCF50633_REGULATOR_LDO2: - case PCF50633_REGULATOR_LDO3: - case PCF50633_REGULATOR_LDO4: - case PCF50633_REGULATOR_LDO5: - case PCF50633_REGULATOR_LDO6: - case PCF50633_REGULATOR_HCLDO: - case PCF50633_REGULATOR_MEMLDO: - millivolts = ldo_voltage_value(index); - break; - default: - return -EINVAL; - } - - return millivolts * 1000; -} - static struct regulator_ops pcf50633_regulator_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .list_voltage = pcf50633_regulator_list_voltage, - .map_voltage = pcf50633_regulator_map_voltage, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, }; static const struct regulator_desc regulators[] = { - [PCF50633_REGULATOR_AUTO] = PCF50633_REGULATOR("auto", AUTO, 128), - [PCF50633_REGULATOR_DOWN1] = PCF50633_REGULATOR("down1", DOWN1, 96), - [PCF50633_REGULATOR_DOWN2] = PCF50633_REGULATOR("down2", DOWN2, 96), - [PCF50633_REGULATOR_LDO1] = PCF50633_REGULATOR("ldo1", LDO1, 28), - [PCF50633_REGULATOR_LDO2] = PCF50633_REGULATOR("ldo2", LDO2, 28), - [PCF50633_REGULATOR_LDO3] = PCF50633_REGULATOR("ldo3", LDO3, 28), - [PCF50633_REGULATOR_LDO4] = PCF50633_REGULATOR("ldo4", LDO4, 28), - [PCF50633_REGULATOR_LDO5] = PCF50633_REGULATOR("ldo5", LDO5, 28), - [PCF50633_REGULATOR_LDO6] = PCF50633_REGULATOR("ldo6", LDO6, 28), - [PCF50633_REGULATOR_HCLDO] = PCF50633_REGULATOR("hcldo", HCLDO, 28), - [PCF50633_REGULATOR_MEMLDO] = PCF50633_REGULATOR("memldo", MEMLDO, 28), + [PCF50633_REGULATOR_AUTO] = + PCF50633_REGULATOR("auto", AUTO, 1800000, 25000, 0x2f, 128), + [PCF50633_REGULATOR_DOWN1] = + PCF50633_REGULATOR("down1", DOWN1, 625000, 25000, 0, 96), + [PCF50633_REGULATOR_DOWN2] = + PCF50633_REGULATOR("down2", DOWN2, 625000, 25000, 0, 96), + [PCF50633_REGULATOR_LDO1] = + PCF50633_REGULATOR("ldo1", LDO1, 900000, 100000, 0, 28), + [PCF50633_REGULATOR_LDO2] = + PCF50633_REGULATOR("ldo2", LDO2, 900000, 100000, 0, 28), + [PCF50633_REGULATOR_LDO3] = + PCF50633_REGULATOR("ldo3", LDO3, 900000, 100000, 0, 28), + [PCF50633_REGULATOR_LDO4] = + PCF50633_REGULATOR("ldo4", LDO4, 900000, 100000, 0, 28), + [PCF50633_REGULATOR_LDO5] = + PCF50633_REGULATOR("ldo5", LDO5, 900000, 100000, 0, 28), + [PCF50633_REGULATOR_LDO6] = + PCF50633_REGULATOR("ldo6", LDO6, 900000, 100000, 0, 28), + [PCF50633_REGULATOR_HCLDO] = + PCF50633_REGULATOR("hcldo", HCLDO, 900000, 100000, 0, 28), + [PCF50633_REGULATOR_MEMLDO] = + PCF50633_REGULATOR("memldo", MEMLDO, 900000, 100000, 0, 28), }; -static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) +static int pcf50633_regulator_probe(struct platform_device *pdev) { struct regulator_dev *rdev; struct pcf50633 *pcf; @@ -222,7 +102,7 @@ static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit pcf50633_regulator_remove(struct platform_device *pdev) +static int pcf50633_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -237,7 +117,7 @@ static struct platform_driver pcf50633_regulator_driver = { .name = "pcf50633-regltr", }, .probe = pcf50633_regulator_probe, - .remove = __devexit_p(pcf50633_regulator_remove), + .remove = pcf50633_regulator_remove, }; static int __init pcf50633_regulator_init(void) diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index 8bf4e8c9de9a..9e6f78694bf1 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -119,7 +119,7 @@ static struct rc5t583_regulator_info rc5t583_reg_info[RC5T583_REGULATOR_MAX] = { RC5T583_REG(LDO9, LDOEN1, 1, LDODIS1, 1, 0x7F, 900, 3400, 25000, 133), }; -static int __devinit rc5t583_regulator_probe(struct platform_device *pdev) +static int rc5t583_regulator_probe(struct platform_device *pdev) { struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); @@ -198,7 +198,7 @@ clean_exit: return ret; } -static int __devexit rc5t583_regulator_remove(struct platform_device *pdev) +static int rc5t583_regulator_remove(struct platform_device *pdev) { struct rc5t583_regulator *regs = platform_get_drvdata(pdev); int id; @@ -214,7 +214,7 @@ static struct platform_driver rc5t583_regulator_driver = { .owner = THIS_MODULE, }, .probe = rc5t583_regulator_probe, - .remove = __devexit_p(rc5t583_regulator_remove), + .remove = rc5t583_regulator_remove, }; static int __init rc5t583_regulator_init(void) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 926f9c8f2fac..cd9ea2ea1826 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -174,9 +174,9 @@ static struct regulator_ops s2mps11_buck_ops = { .min_uV = S2MPS11_BUCK_MIN2, \ .uV_step = S2MPS11_BUCK_STEP2, \ .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ - .vsel_reg = S2MPS11_REG_B9CTRL2, \ + .vsel_reg = S2MPS11_REG_B10CTRL2, \ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ - .enable_reg = S2MPS11_REG_B9CTRL1, \ + .enable_reg = S2MPS11_REG_B10CTRL1, \ .enable_mask = S2MPS11_ENABLE_MASK \ } @@ -231,7 +231,7 @@ static struct regulator_desc regulators[] = { regulator_desc_buck10, }; -static __devinit int s2mps11_pmic_probe(struct platform_device *pdev) +static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); @@ -269,16 +269,16 @@ static __devinit int s2mps11_pmic_probe(struct platform_device *pdev) if (ramp_enable) { if (s2mps11->buck2_ramp) - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) >> 6; + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) << 6; if (s2mps11->buck3_ramp || s2mps11->buck4_ramp) - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) >> 4; + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) << 4; sec_reg_write(iodev, S2MPS11_REG_RAMP, ramp_reg | ramp_enable); } ramp_reg &= 0x00; - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) >> 6; - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) >> 4; - ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) >> 2; + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) << 6; + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) << 4; + ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) << 2; ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9); sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg); @@ -307,7 +307,7 @@ err: return ret; } -static int __devexit s2mps11_pmic_remove(struct platform_device *pdev) +static int s2mps11_pmic_remove(struct platform_device *pdev) { struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev); int i; @@ -330,7 +330,7 @@ static struct platform_driver s2mps11_pmic_driver = { .owner = THIS_MODULE, }, .probe = s2mps11_pmic_probe, - .remove = __devexit_p(s2mps11_pmic_remove), + .remove = s2mps11_pmic_remove, .id_table = s2mps11_pmic_id, }; diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index abe64a32aedf..8a831947c351 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -14,6 +14,7 @@ #include <linux/bug.h> #include <linux/err.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -21,6 +22,9 @@ #include <linux/regulator/machine.h> #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/s5m8767.h> +#include <linux/regulator/of_regulator.h> + +#define S5M8767_OPMODE_NORMAL_MODE 0x1 struct s5m8767_info { struct device *dev; @@ -168,7 +172,7 @@ static unsigned int s5m8767_opmode_reg[][4] = { static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, int *enable_ctrl) { - int reg_id = rdev_get_id(rdev); + int i, reg_id = rdev_get_id(rdev); unsigned int mode; struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); @@ -195,8 +199,17 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, return -EINVAL; } - mode = s5m8767->opmode[reg_id].mode; - *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT; + for (i = 0; i < s5m8767->num_regulators; i++) { + if (s5m8767->opmode[i].id == reg_id) { + mode = s5m8767->opmode[i].mode; + break; + } + } + + if (i < s5m8767->num_regulators) + *enable_ctrl = + s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT; + return 0; } @@ -205,7 +218,7 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); int ret, reg; int mask = 0xc0, enable_ctrl; - u8 val; + unsigned int val; ret = s5m8767_get_register(rdev, ®, &enable_ctrl); if (ret == -EINVAL) @@ -246,10 +259,8 @@ static int s5m8767_reg_disable(struct regulator_dev *rdev) return sec_reg_update(s5m8767->iodev, reg, ~mask, mask); } -static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) +static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767) { - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - int reg_id = rdev_get_id(rdev); int reg; switch (reg_id) { @@ -263,17 +274,17 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) reg = S5M8767_REG_BUCK1CTRL2; break; case S5M8767_BUCK2: - reg = S5M8767_REG_BUCK2DVS2; + reg = S5M8767_REG_BUCK2DVS1; if (s5m8767->buck2_gpiodvs) reg += s5m8767->buck_gpioindex; break; case S5M8767_BUCK3: - reg = S5M8767_REG_BUCK3DVS2; + reg = S5M8767_REG_BUCK3DVS1; if (s5m8767->buck3_gpiodvs) reg += s5m8767->buck_gpioindex; break; case S5M8767_BUCK4: - reg = S5M8767_REG_BUCK4DVS2; + reg = S5M8767_REG_BUCK4DVS1; if (s5m8767->buck4_gpiodvs) reg += s5m8767->buck_gpioindex; break; @@ -287,43 +298,18 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) return -EINVAL; } - *_reg = reg; - - return 0; -} - -static int s5m8767_get_voltage_sel(struct regulator_dev *rdev) -{ - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - int reg, mask, ret; - int reg_id = rdev_get_id(rdev); - u8 val; - - ret = s5m8767_get_voltage_register(rdev, ®); - if (ret) - return ret; - - mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff; - - ret = sec_reg_read(s5m8767->iodev, reg, &val); - if (ret) - return ret; - - val &= mask; - - return val; + return reg; } -static int s5m8767_convert_voltage_to_sel( - const struct sec_voltage_desc *desc, - int min_vol, int max_vol) +static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc, + int min_vol) { int selector = 0; if (desc == NULL) return -EINVAL; - if (max_vol < desc->min || min_vol > desc->max) + if (min_vol > desc->max) return -EINVAL; if (min_vol < desc->min) @@ -331,7 +317,7 @@ static int s5m8767_convert_voltage_to_sel( selector = DIV_ROUND_UP(min_vol - desc->min, desc->step); - if (desc->min + desc->step * selector > max_vol) + if (desc->min + desc->step * selector > desc->max) return -EINVAL; return selector; @@ -364,15 +350,13 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); int reg_id = rdev_get_id(rdev); - int reg, mask, ret = 0, old_index, index = 0; + int old_index, index = 0; u8 *buck234_vol = NULL; switch (reg_id) { case S5M8767_LDO1 ... S5M8767_LDO28: - mask = 0x3f; break; case S5M8767_BUCK1 ... S5M8767_BUCK6: - mask = 0xff; if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs) buck234_vol = &s5m8767->buck2_vol[0]; else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs) @@ -383,7 +367,6 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, case S5M8767_BUCK7 ... S5M8767_BUCK8: return -EINVAL; case S5M8767_BUCK9: - mask = 0xff; break; default: return -EINVAL; @@ -403,11 +386,7 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, else return s5m8767_set_low(s5m8767); } else { - ret = s5m8767_get_voltage_register(rdev, ®); - if (ret) - return ret; - - return sec_reg_update(s5m8767->iodev, reg, selector, mask); + return regulator_set_voltage_sel_regmap(rdev, selector); } } @@ -432,7 +411,7 @@ static struct regulator_ops s5m8767_ops = { .is_enabled = s5m8767_reg_is_enabled, .enable = s5m8767_reg_enable, .disable = s5m8767_reg_disable, - .get_voltage_sel = s5m8767_get_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = s5m8767_set_voltage_sel, .set_voltage_time_sel = s5m8767_set_voltage_time_sel, }; @@ -499,10 +478,182 @@ static struct regulator_desc regulators[] = { s5m8767_regulator_desc(BUCK9), }; -static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, + struct sec_platform_data *pdata, + struct device_node *pmic_np) +{ + int i, gpio; + + for (i = 0; i < 3; i++) { + gpio = of_get_named_gpio(pmic_np, + "s5m8767,pmic-buck-dvs-gpios", i); + if (!gpio_is_valid(gpio)) { + dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); + return -EINVAL; + } + pdata->buck_gpios[i] = gpio; + } + return 0; +} + +static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev, + struct sec_platform_data *pdata, + struct device_node *pmic_np) +{ + int i, gpio; + + for (i = 0; i < 3; i++) { + gpio = of_get_named_gpio(pmic_np, + "s5m8767,pmic-buck-ds-gpios", i); + if (!gpio_is_valid(gpio)) { + dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); + return -EINVAL; + } + pdata->buck_ds[i] = gpio; + } + return 0; +} + +static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, + struct sec_platform_data *pdata) +{ + struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct device_node *pmic_np, *regulators_np, *reg_np; + struct sec_regulator_data *rdata; + struct sec_opmode_data *rmode; + unsigned int i, dvs_voltage_nr = 1, ret; + + pmic_np = iodev->dev->of_node; + if (!pmic_np) { + dev_err(iodev->dev, "could not find pmic sub-node\n"); + return -ENODEV; + } + + regulators_np = of_find_node_by_name(pmic_np, "regulators"); + if (!regulators_np) { + dev_err(iodev->dev, "could not find regulators sub-node\n"); + return -EINVAL; + } + + /* count the number of regulators to be supported in pmic */ + pdata->num_regulators = of_get_child_count(regulators_np); + + rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * + pdata->num_regulators, GFP_KERNEL); + if (!rdata) { + dev_err(iodev->dev, + "could not allocate memory for regulator data\n"); + return -ENOMEM; + } + + rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * + pdata->num_regulators, GFP_KERNEL); + if (!rdata) { + dev_err(iodev->dev, + "could not allocate memory for regulator mode\n"); + return -ENOMEM; + } + + pdata->regulators = rdata; + pdata->opmode = rmode; + for_each_child_of_node(regulators_np, reg_np) { + for (i = 0; i < ARRAY_SIZE(regulators); i++) + if (!of_node_cmp(reg_np->name, regulators[i].name)) + break; + + if (i == ARRAY_SIZE(regulators)) { + dev_warn(iodev->dev, + "don't know how to configure regulator %s\n", + reg_np->name); + continue; + } + + rdata->id = i; + rdata->initdata = of_get_regulator_init_data( + &pdev->dev, reg_np); + rdata->reg_node = reg_np; + rdata++; + rmode->id = i; + if (of_property_read_u32(reg_np, "op_mode", + &rmode->mode)) { + dev_warn(iodev->dev, + "no op_mode property property at %s\n", + reg_np->full_name); + + rmode->mode = S5M8767_OPMODE_NORMAL_MODE; + } + rmode++; + } + + if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) + pdata->buck2_gpiodvs = true; + + if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) + pdata->buck3_gpiodvs = true; + + if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) + pdata->buck4_gpiodvs = true; + + if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || + pdata->buck4_gpiodvs) { + ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); + if (ret) + return -EINVAL; + + if (of_property_read_u32(pmic_np, + "s5m8767,pmic-buck-default-dvs-idx", + &pdata->buck_default_idx)) { + pdata->buck_default_idx = 0; + } else { + if (pdata->buck_default_idx >= 8) { + pdata->buck_default_idx = 0; + dev_info(iodev->dev, + "invalid value for default dvs index, use 0\n"); + } + } + dvs_voltage_nr = 8; + } + + ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np); + if (ret) + return -EINVAL; + + if (of_property_read_u32_array(pmic_np, + "s5m8767,pmic-buck2-dvs-voltage", + pdata->buck2_voltage, dvs_voltage_nr)) { + dev_err(iodev->dev, "buck2 voltages not specified\n"); + return -EINVAL; + } + + if (of_property_read_u32_array(pmic_np, + "s5m8767,pmic-buck3-dvs-voltage", + pdata->buck3_voltage, dvs_voltage_nr)) { + dev_err(iodev->dev, "buck3 voltages not specified\n"); + return -EINVAL; + } + + if (of_property_read_u32_array(pmic_np, + "s5m8767,pmic-buck4-dvs-voltage", + pdata->buck4_voltage, dvs_voltage_nr)) { + dev_err(iodev->dev, "buck4 voltages not specified\n"); + return -EINVAL; + } + + return 0; +} +#else +static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, + struct sec_platform_data *pdata) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static int s5m8767_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); + struct sec_platform_data *pdata = iodev->pdata; struct regulator_config config = { }; struct regulator_dev **rdev; struct s5m8767_info *s5m8767; @@ -513,6 +664,12 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) return -ENODEV; } + if (iodev->dev->of_node) { + ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata); + if (ret) + return ret; + } + if (pdata->buck2_gpiodvs) { if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); @@ -547,7 +704,7 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) rdev = s5m8767->rdev; s5m8767->dev = &pdev->dev; s5m8767->iodev = iodev; - s5m8767->num_regulators = S5M8767_REG_MAX - 2; + s5m8767->num_regulators = pdata->num_regulators; platform_set_drvdata(pdev, s5m8767); s5m8767->buck_gpioindex = pdata->buck_default_idx; @@ -568,23 +725,17 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) s5m8767->opmode = pdata->opmode; buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, - pdata->buck2_init, - pdata->buck2_init + - buck_voltage_val2.step); + pdata->buck2_init); sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, - pdata->buck3_init, - pdata->buck3_init + - buck_voltage_val2.step); + pdata->buck3_init); sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, - pdata->buck4_init, - pdata->buck4_init + - buck_voltage_val2.step); + pdata->buck4_init); sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); @@ -593,33 +744,34 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) s5m8767->buck2_vol[i] = s5m8767_convert_voltage_to_sel( &buck_voltage_val2, - pdata->buck2_voltage[i], - pdata->buck2_voltage[i] + - buck_voltage_val2.step); + pdata->buck2_voltage[i]); } if (s5m8767->buck3_gpiodvs) { s5m8767->buck3_vol[i] = s5m8767_convert_voltage_to_sel( &buck_voltage_val2, - pdata->buck3_voltage[i], - pdata->buck3_voltage[i] + - buck_voltage_val2.step); + pdata->buck3_voltage[i]); } if (s5m8767->buck4_gpiodvs) { s5m8767->buck4_vol[i] = s5m8767_convert_voltage_to_sel( &buck_voltage_val2, - pdata->buck4_voltage[i], - pdata->buck4_voltage[i] + - buck_voltage_val2.step); + pdata->buck4_voltage[i]); } } - if (gpio_is_valid(pdata->buck_gpios[0]) && - gpio_is_valid(pdata->buck_gpios[1]) && - gpio_is_valid(pdata->buck_gpios[2])) { + if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || + pdata->buck4_gpiodvs) { + + if (!gpio_is_valid(pdata->buck_gpios[0]) || + !gpio_is_valid(pdata->buck_gpios[1]) || + !gpio_is_valid(pdata->buck_gpios[2])) { + dev_err(&pdev->dev, "GPIO NOT VALID\n"); + return -EINVAL; + } + ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[0], "S5M8767 SET1"); if (ret) @@ -644,10 +796,6 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) /* SET3 GPIO */ gpio_direction_output(pdata->buck_gpios[2], (s5m8767->buck_gpioindex >> 0) & 0x1); - } else { - dev_err(&pdev->dev, "GPIO NOT VALID\n"); - ret = -EINVAL; - return ret; } ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[0], "S5M8767 DS2"); @@ -748,11 +896,19 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) (desc->max - desc->min) / desc->step + 1; regulators[id].min_uV = desc->min; regulators[id].uV_step = desc->step; + regulators[id].vsel_reg = + s5m8767_get_vsel_reg(id, s5m8767); + if (id < S5M8767_BUCK1) + regulators[id].vsel_mask = 0x3f; + else + regulators[id].vsel_mask = 0xff; } config.dev = s5m8767->dev; config.init_data = pdata->regulators[i].initdata; config.driver_data = s5m8767; + config.regmap = iodev->regmap; + config.of_node = pdata->regulators[i].reg_node; rdev[i] = regulator_register(®ulators[id], &config); if (IS_ERR(rdev[i])) { @@ -773,7 +929,7 @@ err: return ret; } -static int __devexit s5m8767_pmic_remove(struct platform_device *pdev) +static int s5m8767_pmic_remove(struct platform_device *pdev) { struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev); struct regulator_dev **rdev = s5m8767->rdev; @@ -798,7 +954,7 @@ static struct platform_driver s5m8767_pmic_driver = { .owner = THIS_MODULE, }, .probe = s5m8767_pmic_probe, - .remove = __devexit_p(s5m8767_pmic_remove), + .remove = s5m8767_pmic_remove, .id_table = s5m8767_pmic_id, }; diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c new file mode 100644 index 000000000000..6e67be75ea1b --- /dev/null +++ b/drivers/regulator/tps51632-regulator.c @@ -0,0 +1,396 @@ +/* + * tps51632-regulator.c -- TI TPS51632 + * + * Regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down Driverless + * Controller with serial VID control and DVFS. + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; 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., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/regulator/tps51632-regulator.h> +#include <linux/slab.h> + +/* Register definitions */ +#define TPS51632_VOLTAGE_SELECT_REG 0x0 +#define TPS51632_VOLTAGE_BASE_REG 0x1 +#define TPS51632_OFFSET_REG 0x2 +#define TPS51632_IMON_REG 0x3 +#define TPS51632_VMAX_REG 0x4 +#define TPS51632_DVFS_CONTROL_REG 0x5 +#define TPS51632_POWER_STATE_REG 0x6 +#define TPS51632_SLEW_REGS 0x7 +#define TPS51632_FAULT_REG 0x14 + +#define TPS51632_MAX_REG 0x15 + +#define TPS51632_VOUT_MASK 0x7F +#define TPS51632_VOUT_OFFSET_MASK 0x1F +#define TPS51632_VMAX_MASK 0x7F +#define TPS51632_VMAX_LOCK 0x80 + +/* TPS51632_DVFS_CONTROL_REG */ +#define TPS51632_DVFS_PWMEN 0x1 +#define TPS51632_DVFS_STEP_20 0x2 +#define TPS51632_DVFS_VMAX_PG 0x4 +#define TPS51632_DVFS_PWMRST 0x8 +#define TPS51632_DVFS_OCA_EN 0x10 +#define TPS51632_DVFS_FCCM 0x20 + +/* TPS51632_POWER_STATE_REG */ +#define TPS51632_POWER_STATE_MASK 0x03 +#define TPS51632_POWER_STATE_MULTI_PHASE_CCM 0x0 +#define TPS51632_POWER_STATE_SINGLE_PHASE_CCM 0x1 +#define TPS51632_POWER_STATE_SINGLE_PHASE_DCM 0x2 + +#define TPS51632_MIN_VOLATGE 500000 +#define TPS51632_MAX_VOLATGE 1520000 +#define TPS51632_VOLATGE_STEP_10mV 10000 +#define TPS51632_VOLATGE_STEP_20mV 20000 +#define TPS51632_MAX_VSEL 0x7F +#define TPS51632_MIN_VSEL 0x19 +#define TPS51632_DEFAULT_RAMP_DELAY 6000 +#define TPS51632_VOLT_VSEL(uV) \ + (DIV_ROUND_UP(uV - TPS51632_MIN_VOLATGE, \ + TPS51632_VOLATGE_STEP_10mV) + \ + TPS51632_MIN_VSEL) + +/* TPS51632 chip information */ +struct tps51632_chip { + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + struct regmap *regmap; +}; + +static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev, + int ramp_delay) +{ + struct tps51632_chip *tps = rdev_get_drvdata(rdev); + int bit = ramp_delay/6000; + int ret; + + if (bit) + bit--; + ret = regmap_write(tps->regmap, TPS51632_SLEW_REGS, BIT(bit)); + if (ret < 0) + dev_err(tps->dev, "SLEW reg write failed, err %d\n", ret); + return ret; +} + +static struct regulator_ops tps51632_dcdc_ops = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = tps51632_dcdc_set_ramp_delay, +}; + +static int tps51632_init_dcdc(struct tps51632_chip *tps, + struct tps51632_regulator_platform_data *pdata) +{ + int ret; + uint8_t control = 0; + int vsel; + + if (!pdata->enable_pwm_dvfs) + goto skip_pwm_config; + + control |= TPS51632_DVFS_PWMEN; + vsel = TPS51632_VOLT_VSEL(pdata->base_voltage_uV); + ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG, vsel); + if (ret < 0) { + dev_err(tps->dev, "BASE reg write failed, err %d\n", ret); + return ret; + } + + if (pdata->dvfs_step_20mV) + control |= TPS51632_DVFS_STEP_20; + + if (pdata->max_voltage_uV) { + unsigned int vmax; + /** + * TPS51632 hw behavior: VMAX register can be write only + * once as it get locked after first write. The lock get + * reset only when device is power-reset. + * Write register only when lock bit is not enabled. + */ + ret = regmap_read(tps->regmap, TPS51632_VMAX_REG, &vmax); + if (ret < 0) { + dev_err(tps->dev, "VMAX read failed, err %d\n", ret); + return ret; + } + if (!(vmax & TPS51632_VMAX_LOCK)) { + vsel = TPS51632_VOLT_VSEL(pdata->max_voltage_uV); + ret = regmap_write(tps->regmap, TPS51632_VMAX_REG, + vsel); + if (ret < 0) { + dev_err(tps->dev, + "VMAX write failed, err %d\n", ret); + return ret; + } + } + } + +skip_pwm_config: + ret = regmap_write(tps->regmap, TPS51632_DVFS_CONTROL_REG, control); + if (ret < 0) + dev_err(tps->dev, "DVFS reg write failed, err %d\n", ret); + return ret; +} + +static bool is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TPS51632_OFFSET_REG: + case TPS51632_FAULT_REG: + case TPS51632_IMON_REG: + return true; + default: + return false; + } +} + +static bool is_read_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x08 ... 0x0F: + return false; + default: + return true; + } +} + +static bool is_write_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TPS51632_VOLTAGE_SELECT_REG: + case TPS51632_VOLTAGE_BASE_REG: + case TPS51632_VMAX_REG: + case TPS51632_DVFS_CONTROL_REG: + case TPS51632_POWER_STATE_REG: + case TPS51632_SLEW_REGS: + return true; + default: + return false; + } +} + +static const struct regmap_config tps51632_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = is_write_reg, + .readable_reg = is_read_reg, + .volatile_reg = is_volatile_reg, + .max_register = TPS51632_MAX_REG - 1, + .cache_type = REGCACHE_RBTREE, +}; + +#if defined(CONFIG_OF) +static const struct of_device_id tps51632_of_match[] = { + { .compatible = "ti,tps51632",}, + {}, +}; +MODULE_DEVICE_TABLE(of, tps51632_of_match); + +static struct tps51632_regulator_platform_data * + of_get_tps51632_platform_data(struct device *dev) +{ + struct tps51632_regulator_platform_data *pdata; + struct device_node *np = dev->of_node; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "Memory alloc failed for platform data\n"); + return NULL; + } + + pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node); + if (!pdata->reg_init_data) { + dev_err(dev, "Not able to get OF regulator init data\n"); + return NULL; + } + + pdata->enable_pwm_dvfs = + of_property_read_bool(np, "ti,enable-pwm-dvfs"); + pdata->dvfs_step_20mV = of_property_read_bool(np, "ti,dvfs-step-20mV"); + + pdata->base_voltage_uV = pdata->reg_init_data->constraints.min_uV ? : + TPS51632_MIN_VOLATGE; + pdata->max_voltage_uV = pdata->reg_init_data->constraints.max_uV ? : + TPS51632_MAX_VOLATGE; + return pdata; +} +#else +static struct tps51632_regulator_platform_data * + of_get_tps51632_platform_data(struct device *dev) +{ + return NULL; +} +#endif + +static int tps51632_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tps51632_regulator_platform_data *pdata; + struct regulator_dev *rdev; + struct tps51632_chip *tps; + int ret; + struct regulator_config config = { }; + + if (client->dev.of_node) { + const struct of_device_id *match; + match = of_match_device(of_match_ptr(tps51632_of_match), + &client->dev); + if (!match) { + dev_err(&client->dev, "Error: No device match found\n"); + return -ENODEV; + } + } + + pdata = client->dev.platform_data; + if (!pdata && client->dev.of_node) + pdata = of_get_tps51632_platform_data(&client->dev); + if (!pdata) { + dev_err(&client->dev, "No Platform data\n"); + return -EINVAL; + } + + if (pdata->enable_pwm_dvfs) { + if ((pdata->base_voltage_uV < TPS51632_MIN_VOLATGE) || + (pdata->base_voltage_uV > TPS51632_MAX_VOLATGE)) { + dev_err(&client->dev, "Invalid base_voltage_uV setting\n"); + return -EINVAL; + } + + if ((pdata->max_voltage_uV) && + ((pdata->max_voltage_uV < TPS51632_MIN_VOLATGE) || + (pdata->max_voltage_uV > TPS51632_MAX_VOLATGE))) { + dev_err(&client->dev, "Invalid max_voltage_uV setting\n"); + return -EINVAL; + } + } + + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); + if (!tps) { + dev_err(&client->dev, "Memory allocation failed\n"); + return -ENOMEM; + } + + tps->dev = &client->dev; + tps->desc.name = id->name; + tps->desc.id = 0; + tps->desc.ramp_delay = TPS51632_DEFAULT_RAMP_DELAY; + tps->desc.min_uV = TPS51632_MIN_VOLATGE; + tps->desc.uV_step = TPS51632_VOLATGE_STEP_10mV; + tps->desc.linear_min_sel = TPS51632_MIN_VSEL; + tps->desc.n_voltages = TPS51632_MAX_VSEL + 1; + tps->desc.ops = &tps51632_dcdc_ops; + tps->desc.type = REGULATOR_VOLTAGE; + tps->desc.owner = THIS_MODULE; + + if (pdata->enable_pwm_dvfs) + tps->desc.vsel_reg = TPS51632_VOLTAGE_BASE_REG; + else + tps->desc.vsel_reg = TPS51632_VOLTAGE_SELECT_REG; + tps->desc.vsel_mask = TPS51632_VOUT_MASK; + + tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config); + if (IS_ERR(tps->regmap)) { + ret = PTR_ERR(tps->regmap); + dev_err(&client->dev, "regmap init failed, err %d\n", ret); + return ret; + } + i2c_set_clientdata(client, tps); + + ret = tps51632_init_dcdc(tps, pdata); + if (ret < 0) { + dev_err(tps->dev, "Init failed, err = %d\n", ret); + return ret; + } + + /* Register the regulators */ + config.dev = &client->dev; + config.init_data = pdata->reg_init_data; + config.driver_data = tps; + config.regmap = tps->regmap; + config.of_node = client->dev.of_node; + + rdev = regulator_register(&tps->desc, &config); + if (IS_ERR(rdev)) { + dev_err(tps->dev, "regulator register failed\n"); + return PTR_ERR(rdev); + } + + tps->rdev = rdev; + return 0; +} + +static int tps51632_remove(struct i2c_client *client) +{ + struct tps51632_chip *tps = i2c_get_clientdata(client); + + regulator_unregister(tps->rdev); + return 0; +} + +static const struct i2c_device_id tps51632_id[] = { + {.name = "tps51632",}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, tps51632_id); + +static struct i2c_driver tps51632_i2c_driver = { + .driver = { + .name = "tps51632", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tps51632_of_match), + }, + .probe = tps51632_probe, + .remove = tps51632_remove, + .id_table = tps51632_id, +}; + +static int __init tps51632_init(void) +{ + return i2c_add_driver(&tps51632_i2c_driver); +} +subsys_initcall(tps51632_init); + +static void __exit tps51632_cleanup(void) +{ + i2c_del_driver(&tps51632_i2c_driver); +} +module_exit(tps51632_cleanup); + +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_DESCRIPTION("TPS51632 voltage regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c index 1378409efaec..ec9453ffb77f 100644 --- a/drivers/regulator/tps6105x-regulator.c +++ b/drivers/regulator/tps6105x-regulator.c @@ -127,7 +127,7 @@ static const struct regulator_desc tps6105x_regulator_desc = { /* * Registers the chip as a voltage regulator */ -static int __devinit tps6105x_regulator_probe(struct platform_device *pdev) +static int tps6105x_regulator_probe(struct platform_device *pdev) { struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev); struct tps6105x_platform_data *pdata = tps6105x->pdata; @@ -159,7 +159,7 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit tps6105x_regulator_remove(struct platform_device *pdev) +static int tps6105x_regulator_remove(struct platform_device *pdev) { struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev); regulator_unregister(tps6105x->regulator); @@ -172,7 +172,7 @@ static struct platform_driver tps6105x_regulator_driver = { .owner = THIS_MODULE, }, .probe = tps6105x_regulator_probe, - .remove = __devexit_p(tps6105x_regulator_remove), + .remove = tps6105x_regulator_remove, }; static __init int tps6105x_regulator_init(void) diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 68729a7c8709..acbd63fde415 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -243,7 +243,7 @@ static struct regulator_ops tps62360_dcdc_ops = { .get_mode = tps62360_get_mode, }; -static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps, +static int tps62360_init_dcdc(struct tps62360_chip *tps, struct tps62360_regulator_platform_data *pdata) { int ret; @@ -339,7 +339,7 @@ static const struct of_device_id tps62360_of_match[] = { MODULE_DEVICE_TABLE(of, tps62360_of_match); #endif -static int __devinit tps62360_probe(struct i2c_client *client, +static int tps62360_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct regulator_config config = { }; @@ -490,7 +490,7 @@ static int __devinit tps62360_probe(struct i2c_client *client, * * Unregister TPS driver as an i2c client device driver */ -static int __devexit tps62360_remove(struct i2c_client *client) +static int tps62360_remove(struct i2c_client *client) { struct tps62360_chip *tps = i2c_get_clientdata(client); @@ -531,7 +531,7 @@ static struct i2c_driver tps62360_i2c_driver = { .of_match_table = of_match_ptr(tps62360_of_match), }, .probe = tps62360_probe, - .remove = __devexit_p(tps62360_remove), + .remove = tps62360_remove, .shutdown = tps62360_shutdown, .id_table = tps62360_id, }; diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 6998d579d07b..9b9af6d889c8 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -219,7 +219,7 @@ static struct regmap_config tps65023_regmap_config = { .val_bits = 8, }; -static int __devinit tps_65023_probe(struct i2c_client *client, +static int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct tps_driver_data *drv_data = (void *)id->driver_data; @@ -319,7 +319,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client, return error; } -static int __devexit tps_65023_remove(struct i2c_client *client) +static int tps_65023_remove(struct i2c_client *client) { struct tps_pmic *tps = i2c_get_clientdata(client); int i; @@ -446,7 +446,7 @@ static struct i2c_driver tps_65023_i2c_driver = { .owner = THIS_MODULE, }, .probe = tps_65023_probe, - .remove = __devexit_p(tps_65023_remove), + .remove = tps_65023_remove, .id_table = tps_65023_id, }; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 07d01ccdf308..54aa2da7283b 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -23,8 +23,10 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/tps6507x.h> +#include <linux/of.h> #include <linux/slab.h> #include <linux/mfd/tps6507x.h> +#include <linux/regulator/of_regulator.h> /* DCDC's */ #define TPS6507X_DCDC_1 0 @@ -356,7 +358,81 @@ static struct regulator_ops tps6507x_pmic_ops = { .list_voltage = regulator_list_voltage_table, }; -static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static struct of_regulator_match tps6507x_matches[] = { + { .name = "VDCDC1"}, + { .name = "VDCDC2"}, + { .name = "VDCDC3"}, + { .name = "LDO1"}, + { .name = "LDO2"}, +}; + +static struct tps6507x_board *tps6507x_parse_dt_reg_data( + struct platform_device *pdev, + struct of_regulator_match **tps6507x_reg_matches) +{ + struct tps6507x_board *tps_board; + struct device_node *np = pdev->dev.parent->of_node; + struct device_node *regulators; + struct of_regulator_match *matches; + static struct regulator_init_data *reg_data; + int idx = 0, count, ret; + + tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board), + GFP_KERNEL); + if (!tps_board) { + dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n"); + return NULL; + } + + regulators = of_find_node_by_name(np, "regulators"); + if (!regulators) { + dev_err(&pdev->dev, "regulator node not found\n"); + return NULL; + } + + count = ARRAY_SIZE(tps6507x_matches); + matches = tps6507x_matches; + + ret = of_regulator_match(&pdev->dev, regulators, matches, count); + if (ret < 0) { + dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", + ret); + return NULL; + } + + *tps6507x_reg_matches = matches; + + reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data) + * TPS6507X_NUM_REGULATOR), GFP_KERNEL); + if (!reg_data) { + dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n"); + return NULL; + } + + tps_board->tps6507x_pmic_init_data = reg_data; + + for (idx = 0; idx < count; idx++) { + if (!matches[idx].init_data || !matches[idx].of_node) + continue; + + memcpy(®_data[idx], matches[idx].init_data, + sizeof(struct regulator_init_data)); + + } + + return tps_board; +} +#else +static inline struct tps6507x_board *tps6507x_parse_dt_reg_data( + struct platform_device *pdev, + struct of_regulator_match **tps6507x_reg_matches) +{ + *tps6507x_reg_matches = NULL; + return NULL; +} +#endif +static int tps6507x_pmic_probe(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); struct tps_info *info = &tps6507x_pmic_regs[0]; @@ -365,8 +441,10 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) struct regulator_dev *rdev; struct tps6507x_pmic *tps; struct tps6507x_board *tps_board; + struct of_regulator_match *tps6507x_reg_matches = NULL; int i; int error; + unsigned int prop; /** * tps_board points to pmic related constants @@ -374,6 +452,9 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) */ tps_board = dev_get_platdata(tps6507x_dev->dev); + if (!tps_board && tps6507x_dev->dev->of_node) + tps_board = tps6507x_parse_dt_reg_data(pdev, + &tps6507x_reg_matches); if (!tps_board) return -EINVAL; @@ -415,6 +496,17 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) config.init_data = init_data; config.driver_data = tps; + if (tps6507x_reg_matches) { + error = of_property_read_u32( + tps6507x_reg_matches[i].of_node, + "ti,defdcdc_default", &prop); + + if (!error) + tps->info[i]->defdcdc_default = prop; + + config.of_node = tps6507x_reg_matches[i].of_node; + } + rdev = regulator_register(&tps->desc[i], &config); if (IS_ERR(rdev)) { dev_err(tps6507x_dev->dev, @@ -439,7 +531,7 @@ fail: return error; } -static int __devexit tps6507x_pmic_remove(struct platform_device *pdev) +static int tps6507x_pmic_remove(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); struct tps6507x_pmic *tps = tps6507x_dev->pmic; @@ -456,7 +548,7 @@ static struct platform_driver tps6507x_pmic_driver = { .owner = THIS_MODULE, }, .probe = tps6507x_pmic_probe, - .remove = __devexit_p(tps6507x_pmic_remove), + .remove = tps6507x_pmic_remove, }; static int __init tps6507x_pmic_init(void) diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index 001ad554ac62..c8e70451df38 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -18,119 +18,336 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/mfd/tps65090.h> -#include <linux/regulator/tps65090-regulator.h> struct tps65090_regulator { - int id; - /* used by regulator core */ - struct regulator_desc desc; - - /* Device */ struct device *dev; + struct regulator_desc *desc; + struct regulator_dev *rdev; +}; + +static struct regulator_ops tps65090_ext_control_ops = { }; -static struct regulator_ops tps65090_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, +static struct regulator_ops tps65090_reg_contol_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, }; -#define tps65090_REG(_id) \ +static struct regulator_ops tps65090_ldo_ops = { +}; + +#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops) \ { \ - .id = TPS65090_ID_##_id, \ - .desc = { \ - .name = tps65090_rails(_id), \ - .id = TPS65090_ID_##_id, \ - .ops = &tps65090_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .enable_reg = (TPS65090_ID_##_id) + 12, \ - .enable_mask = BIT(0), \ - }, \ + .name = "TPS65090_RAILS"#_id, \ + .supply_name = _sname, \ + .id = TPS65090_REGULATOR_##_id, \ + .ops = &_ops, \ + .enable_reg = _en_reg, \ + .enable_mask = BIT(0), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ } -static struct tps65090_regulator TPS65090_regulator[] = { - tps65090_REG(DCDC1), - tps65090_REG(DCDC2), - tps65090_REG(DCDC3), - tps65090_REG(FET1), - tps65090_REG(FET2), - tps65090_REG(FET3), - tps65090_REG(FET4), - tps65090_REG(FET5), - tps65090_REG(FET6), - tps65090_REG(FET7), +static struct regulator_desc tps65090_regulator_desc[] = { + tps65090_REG_DESC(DCDC1, "vsys1", 0x0C, tps65090_reg_contol_ops), + tps65090_REG_DESC(DCDC2, "vsys2", 0x0D, tps65090_reg_contol_ops), + tps65090_REG_DESC(DCDC3, "vsys3", 0x0E, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET1, "infet1", 0x0F, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET2, "infet2", 0x10, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET3, "infet3", 0x11, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET4, "infet4", 0x12, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_reg_contol_ops), + tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_reg_contol_ops), + tps65090_REG_DESC(LDO1, "vsys-l1", 0, tps65090_ldo_ops), + tps65090_REG_DESC(LDO2, "vsys-l2", 0, tps65090_ldo_ops), }; -static inline struct tps65090_regulator *find_regulator_info(int id) +static inline bool is_dcdc(int id) { - struct tps65090_regulator *ri; - int i; + switch (id) { + case TPS65090_REGULATOR_DCDC1: + case TPS65090_REGULATOR_DCDC2: + case TPS65090_REGULATOR_DCDC3: + return true; + default: + return false; + } +} + +static int tps65090_config_ext_control( + struct tps65090_regulator *ri, bool enable) +{ + int ret; + struct device *parent = ri->dev->parent; + unsigned int reg_en_reg = ri->desc->enable_reg; + + if (enable) + ret = tps65090_set_bits(parent, reg_en_reg, 1); + else + ret = tps65090_clr_bits(parent, reg_en_reg, 1); + if (ret < 0) + dev_err(ri->dev, "Error in updating reg 0x%x\n", reg_en_reg); + return ret; +} + +static int tps65090_regulator_disable_ext_control( + struct tps65090_regulator *ri, + struct tps65090_regulator_plat_data *tps_pdata) +{ + int ret = 0; + struct device *parent = ri->dev->parent; + unsigned int reg_en_reg = ri->desc->enable_reg; + + /* + * First enable output for internal control if require. + * And then disable external control. + */ + if (tps_pdata->reg_init_data->constraints.always_on || + tps_pdata->reg_init_data->constraints.boot_on) { + ret = tps65090_set_bits(parent, reg_en_reg, 0); + if (ret < 0) { + dev_err(ri->dev, "Error in set reg 0x%x\n", reg_en_reg); + return ret; + } + } + return tps65090_config_ext_control(ri, false); +} + +static void tps65090_configure_regulator_config( + struct tps65090_regulator_plat_data *tps_pdata, + struct regulator_config *config) +{ + if (gpio_is_valid(tps_pdata->gpio)) { + int gpio_flag = GPIOF_OUT_INIT_LOW; + + if (tps_pdata->reg_init_data->constraints.always_on || + tps_pdata->reg_init_data->constraints.boot_on) + gpio_flag = GPIOF_OUT_INIT_HIGH; + + config->ena_gpio = tps_pdata->gpio; + config->ena_gpio_flags = gpio_flag; + } +} + +#ifdef CONFIG_OF +static struct of_regulator_match tps65090_matches[] = { + { .name = "dcdc1", }, + { .name = "dcdc2", }, + { .name = "dcdc3", }, + { .name = "fet1", }, + { .name = "fet2", }, + { .name = "fet3", }, + { .name = "fet4", }, + { .name = "fet5", }, + { .name = "fet6", }, + { .name = "fet7", }, + { .name = "ldo1", }, + { .name = "ldo2", }, +}; + +static struct tps65090_platform_data *tps65090_parse_dt_reg_data( + struct platform_device *pdev, + struct of_regulator_match **tps65090_reg_matches) +{ + struct tps65090_platform_data *tps65090_pdata; + struct device_node *np = pdev->dev.parent->of_node; + struct device_node *regulators; + int idx = 0, ret; + struct tps65090_regulator_plat_data *reg_pdata; + + tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata), + GFP_KERNEL); + if (!tps65090_pdata) { + dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n"); + return ERR_PTR(-ENOMEM); + } + + reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * + sizeof(*reg_pdata), GFP_KERNEL); + if (!reg_pdata) { + dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n"); + return ERR_PTR(-ENOMEM); + } + + regulators = of_find_node_by_name(np, "regulators"); + if (!regulators) { + dev_err(&pdev->dev, "regulator node not found\n"); + return ERR_PTR(-ENODEV); + } - for (i = 0; i < ARRAY_SIZE(TPS65090_regulator); i++) { - ri = &TPS65090_regulator[i]; - if (ri->desc.id == id) - return ri; + ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches, + ARRAY_SIZE(tps65090_matches)); + if (ret < 0) { + dev_err(&pdev->dev, + "Error parsing regulator init data: %d\n", ret); + return ERR_PTR(ret); } + + *tps65090_reg_matches = tps65090_matches; + for (idx = 0; idx < ARRAY_SIZE(tps65090_matches); idx++) { + struct regulator_init_data *ri_data; + struct tps65090_regulator_plat_data *rpdata; + + rpdata = ®_pdata[idx]; + ri_data = tps65090_matches[idx].init_data; + if (!ri_data || !tps65090_matches[idx].of_node) + continue; + + rpdata->reg_init_data = ri_data; + rpdata->enable_ext_control = of_property_read_bool( + tps65090_matches[idx].of_node, + "ti,enable-ext-control"); + if (rpdata->enable_ext_control) + rpdata->gpio = of_get_named_gpio(np, + "dcdc-ext-control-gpios", 0); + + tps65090_pdata->reg_pdata[idx] = rpdata; + } + return tps65090_pdata; +} +#else +static inline struct tps65090_platform_data *tps65090_parse_dt_reg_data( + struct platform_device *pdev, + struct of_regulator_match **tps65090_reg_matches) +{ + *tps65090_reg_matches = NULL; return NULL; } +#endif -static int __devinit tps65090_regulator_probe(struct platform_device *pdev) +static int tps65090_regulator_probe(struct platform_device *pdev) { struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent); struct tps65090_regulator *ri = NULL; struct regulator_config config = { }; struct regulator_dev *rdev; - struct tps65090_regulator_platform_data *tps_pdata; - int id = pdev->id; + struct tps65090_regulator_plat_data *tps_pdata; + struct tps65090_regulator *pmic; + struct tps65090_platform_data *tps65090_pdata; + struct of_regulator_match *tps65090_reg_matches = NULL; + int num; + int ret; - dev_dbg(&pdev->dev, "Probing regulator %d\n", id); + dev_dbg(&pdev->dev, "Probing regulator\n"); - ri = find_regulator_info(id); - if (ri == NULL) { - dev_err(&pdev->dev, "invalid regulator ID specified\n"); - return -EINVAL; + tps65090_pdata = dev_get_platdata(pdev->dev.parent); + if (!tps65090_pdata && tps65090_mfd->dev->of_node) + tps65090_pdata = tps65090_parse_dt_reg_data(pdev, + &tps65090_reg_matches); + if (IS_ERR_OR_NULL(tps65090_pdata)) { + dev_err(&pdev->dev, "Platform data missing\n"); + return tps65090_pdata ? PTR_ERR(tps65090_pdata) : -EINVAL; } - tps_pdata = pdev->dev.platform_data; - ri->dev = &pdev->dev; - - config.dev = &pdev->dev; - config.init_data = &tps_pdata->regulator; - config.driver_data = ri; - config.regmap = tps65090_mfd->rmap; - - rdev = regulator_register(&ri->desc, &config); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "failed to register regulator %s\n", - ri->desc.name); - return PTR_ERR(rdev); + + pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic), + GFP_KERNEL); + if (!pmic) { + dev_err(&pdev->dev, "mem alloc for pmic failed\n"); + return -ENOMEM; } - platform_set_drvdata(pdev, rdev); + for (num = 0; num < TPS65090_REGULATOR_MAX; num++) { + tps_pdata = tps65090_pdata->reg_pdata[num]; + + ri = &pmic[num]; + ri->dev = &pdev->dev; + ri->desc = &tps65090_regulator_desc[num]; + + /* + * TPS5090 DCDC support the control from external digital input. + * Configure it as per platform data. + */ + if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data) { + if (tps_pdata->enable_ext_control) { + tps65090_configure_regulator_config( + tps_pdata, &config); + ri->desc->ops = &tps65090_ext_control_ops; + } else { + ret = tps65090_regulator_disable_ext_control( + ri, tps_pdata); + if (ret < 0) { + dev_err(&pdev->dev, + "failed disable ext control\n"); + goto scrub; + } + } + } + + config.dev = pdev->dev.parent; + config.driver_data = ri; + config.regmap = tps65090_mfd->rmap; + if (tps_pdata) + config.init_data = tps_pdata->reg_init_data; + else + config.init_data = NULL; + if (tps65090_reg_matches) + config.of_node = tps65090_reg_matches[num].of_node; + else + config.of_node = NULL; + + rdev = regulator_register(ri->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + ri->desc->name); + ret = PTR_ERR(rdev); + goto scrub; + } + ri->rdev = rdev; + + /* Enable external control if it is require */ + if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data && + tps_pdata->enable_ext_control) { + ret = tps65090_config_ext_control(ri, true); + if (ret < 0) { + /* Increment num to get unregister rdev */ + num++; + goto scrub; + } + } + } + + platform_set_drvdata(pdev, pmic); return 0; + +scrub: + while (--num >= 0) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + } + return ret; } -static int __devexit tps65090_regulator_remove(struct platform_device *pdev) +static int tps65090_regulator_remove(struct platform_device *pdev) { - struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct tps65090_regulator *pmic = platform_get_drvdata(pdev); + struct tps65090_regulator *ri; + int num; - regulator_unregister(rdev); + for (num = 0; num < TPS65090_REGULATOR_MAX; ++num) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + } return 0; } static struct platform_driver tps65090_regulator_driver = { .driver = { - .name = "tps65090-regulator", + .name = "tps65090-pmic", .owner = THIS_MODULE, }, .probe = tps65090_regulator_probe, - .remove = __devexit_p(tps65090_regulator_remove), + .remove = tps65090_regulator_remove, }; static int __init tps65090_regulator_init(void) @@ -148,3 +365,4 @@ module_exit(tps65090_regulator_exit); MODULE_DESCRIPTION("tps65090 regulator driver"); MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:tps65090-pmic"); diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index ab00cab905b7..df395187c063 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -305,8 +305,8 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) if (!regs) return NULL; - count = of_regulator_match(pdev->dev.parent, regs, - reg_matches, TPS65217_NUM_REGULATOR); + count = of_regulator_match(&pdev->dev, regs, reg_matches, + TPS65217_NUM_REGULATOR); of_node_put(regs); if ((count < 0) || (count > TPS65217_NUM_REGULATOR)) return NULL; @@ -332,7 +332,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) } #endif -static int __devinit tps65217_regulator_probe(struct platform_device *pdev) +static int tps65217_regulator_probe(struct platform_device *pdev) { struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); struct tps65217_board *pdata = dev_get_platdata(tps->dev); @@ -397,7 +397,7 @@ err_unregister_regulator: return ret; } -static int __devexit tps65217_regulator_remove(struct platform_device *pdev) +static int tps65217_regulator_remove(struct platform_device *pdev) { struct tps65217 *tps = platform_get_drvdata(pdev); unsigned int i; @@ -415,7 +415,7 @@ static struct platform_driver tps65217_regulator_driver = { .name = "tps65217-pmic", }, .probe = tps65217_regulator_probe, - .remove = __devexit_p(tps65217_regulator_remove), + .remove = tps65217_regulator_remove, }; static int __init tps65217_regulator_init(void) diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 058d2f2675e9..843ee0a9bb92 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -592,7 +592,7 @@ static int pmic_remove(struct spi_device *spi) return 0; } -static int __devinit pmic_probe(struct spi_device *spi) +static int pmic_probe(struct spi_device *spi) { struct tps6524x *hw; struct device *dev = &spi->dev; @@ -649,7 +649,7 @@ fail: static struct spi_driver pmic_driver = { .probe = pmic_probe, - .remove = __devexit_p(pmic_remove), + .remove = pmic_remove, .driver = { .name = "tps6524x", .owner = THIS_MODULE, diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index ce1e7cb8d513..e68382d0e1ea 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -17,10 +17,12 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/of.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/mfd/tps6586x.h> /* supply control and voltage setting */ @@ -59,10 +61,6 @@ struct tps6586x_regulator { int enable_bit[2]; int enable_reg[2]; - - /* for DVM regulators */ - int go_reg; - int go_bit; }; static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev) @@ -70,37 +68,10 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev) return rdev_get_dev(rdev)->parent; } -static int tps6586x_set_voltage_sel(struct regulator_dev *rdev, - unsigned selector) -{ - struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); - struct device *parent = to_tps6586x_dev(rdev); - int ret, val, rid = rdev_get_id(rdev); - uint8_t mask; - - val = selector << (ffs(rdev->desc->vsel_mask) - 1); - mask = rdev->desc->vsel_mask; - - ret = tps6586x_update(parent, rdev->desc->vsel_reg, val, mask); - if (ret) - return ret; - - /* Update go bit for DVM regulators */ - switch (rid) { - case TPS6586X_ID_LDO_2: - case TPS6586X_ID_LDO_4: - case TPS6586X_ID_SM_0: - case TPS6586X_ID_SM_1: - ret = tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit); - break; - } - return ret; -} - static struct regulator_ops tps6586x_regulator_ops = { .list_voltage = regulator_list_voltage_table, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = tps6586x_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, @@ -140,7 +111,7 @@ static const unsigned int tps6586x_dvm_voltages[] = { }; #define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1) \ + ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ .desc = { \ .supply_name = _pin_name, \ .name = "REG-" #_id, \ @@ -154,29 +125,26 @@ static const unsigned int tps6586x_dvm_voltages[] = { .enable_mask = 1 << (ebit0), \ .vsel_reg = TPS6586X_##vreg, \ .vsel_mask = ((1 << (nbits)) - 1) << (shift), \ + .apply_reg = (goreg), \ + .apply_bit = (gobit), \ }, \ .enable_reg[0] = TPS6586X_SUPPLY##ereg0, \ .enable_bit[0] = (ebit0), \ .enable_reg[1] = TPS6586X_SUPPLY##ereg1, \ .enable_bit[1] = (ebit1), -#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ - .go_reg = TPS6586X_##goreg, \ - .go_bit = (gobit), - #define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ { \ TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1) \ + ereg0, ebit0, ereg1, ebit1, 0, 0) \ } #define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ { \ TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1) \ - TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ + ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ } #define TPS6586X_SYS_REGULATOR() \ @@ -205,13 +173,13 @@ static struct tps6586x_regulator tps6586x_regulator[] = { TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7), TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3, - ENB, 3, VCC2, 6), + ENB, 3, TPS6586X_VCC2, BIT(6)), TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3, - END, 3, VCC1, 6), + END, 3, TPS6586X_VCC1, BIT(6)), TPS6586X_DVM(SM_0, "vin-sm0", dvm, SM0V1, 0, 5, ENA, 1, - ENB, 1, VCC1, 2), + ENB, 1, TPS6586X_VCC1, BIT(2)), TPS6586X_DVM(SM_1, "vin-sm1", dvm, SM1V1, 0, 5, ENA, 0, - ENB, 0, VCC1, 0), + ENB, 0, TPS6586X_VCC1, BIT(0)), }; /* @@ -255,10 +223,10 @@ static inline int tps6586x_regulator_preinit(struct device *parent, 1 << ri->enable_bit[1]); } -static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev) +static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev, + int id, struct regulator_init_data *p) { struct device *parent = pdev->dev.parent; - struct regulator_init_data *p = pdev->dev.platform_data; struct tps6586x_settings *setting = p->driver_data; uint8_t reg; @@ -269,7 +237,7 @@ static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev) return 0; /* only SM0 and SM1 can have the slew rate settings */ - switch (pdev->id) { + switch (id) { case TPS6586X_ID_SM_0: reg = TPS6586X_SM0SL; break; @@ -298,58 +266,185 @@ static inline struct tps6586x_regulator *find_regulator_info(int id) return NULL; } -static int __devinit tps6586x_regulator_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static struct of_regulator_match tps6586x_matches[] = { + { .name = "sys", .driver_data = (void *)TPS6586X_ID_SYS }, + { .name = "sm0", .driver_data = (void *)TPS6586X_ID_SM_0 }, + { .name = "sm1", .driver_data = (void *)TPS6586X_ID_SM_1 }, + { .name = "sm2", .driver_data = (void *)TPS6586X_ID_SM_2 }, + { .name = "ldo0", .driver_data = (void *)TPS6586X_ID_LDO_0 }, + { .name = "ldo1", .driver_data = (void *)TPS6586X_ID_LDO_1 }, + { .name = "ldo2", .driver_data = (void *)TPS6586X_ID_LDO_2 }, + { .name = "ldo3", .driver_data = (void *)TPS6586X_ID_LDO_3 }, + { .name = "ldo4", .driver_data = (void *)TPS6586X_ID_LDO_4 }, + { .name = "ldo5", .driver_data = (void *)TPS6586X_ID_LDO_5 }, + { .name = "ldo6", .driver_data = (void *)TPS6586X_ID_LDO_6 }, + { .name = "ldo7", .driver_data = (void *)TPS6586X_ID_LDO_7 }, + { .name = "ldo8", .driver_data = (void *)TPS6586X_ID_LDO_8 }, + { .name = "ldo9", .driver_data = (void *)TPS6586X_ID_LDO_9 }, + { .name = "ldo_rtc", .driver_data = (void *)TPS6586X_ID_LDO_RTC }, +}; + +static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( + struct platform_device *pdev, + struct of_regulator_match **tps6586x_reg_matches) +{ + const unsigned int num = ARRAY_SIZE(tps6586x_matches); + struct device_node *np = pdev->dev.parent->of_node; + struct device_node *regs; + const char *sys_rail = NULL; + unsigned int i; + struct tps6586x_platform_data *pdata; + int err; + + regs = of_find_node_by_name(np, "regulators"); + if (!regs) { + dev_err(&pdev->dev, "regulator node not found\n"); + return NULL; + } + + err = of_regulator_match(&pdev->dev, regs, tps6586x_matches, num); + if (err < 0) { + dev_err(&pdev->dev, "Regulator match failed, e %d\n", err); + of_node_put(regs); + return NULL; + } + + of_node_put(regs); + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "Memory alloction failed\n"); + return NULL; + } + + for (i = 0; i < num; i++) { + int id; + if (!tps6586x_matches[i].init_data) + continue; + + pdata->reg_init_data[i] = tps6586x_matches[i].init_data; + id = (int)tps6586x_matches[i].driver_data; + if (id == TPS6586X_ID_SYS) + sys_rail = pdata->reg_init_data[i]->constraints.name; + + if ((id == TPS6586X_ID_LDO_5) || (id == TPS6586X_ID_LDO_RTC)) + pdata->reg_init_data[i]->supply_regulator = sys_rail; + } + *tps6586x_reg_matches = tps6586x_matches; + return pdata; +} +#else +static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( + struct platform_device *pdev, + struct of_regulator_match **tps6586x_reg_matches) +{ + *tps6586x_reg_matches = NULL; + return NULL; +} +#endif + +static int tps6586x_regulator_probe(struct platform_device *pdev) { struct tps6586x_regulator *ri = NULL; struct regulator_config config = { }; - struct regulator_dev *rdev; - int id = pdev->id; + struct regulator_dev **rdev; + struct regulator_init_data *reg_data; + struct tps6586x_platform_data *pdata; + struct of_regulator_match *tps6586x_reg_matches = NULL; + int id; int err; - dev_dbg(&pdev->dev, "Probing regulator %d\n", id); + dev_dbg(&pdev->dev, "Probing regulator\n"); - ri = find_regulator_info(id); - if (ri == NULL) { - dev_err(&pdev->dev, "invalid regulator ID specified\n"); - return -EINVAL; - } + pdata = dev_get_platdata(pdev->dev.parent); + if ((!pdata) && (pdev->dev.parent->of_node)) + pdata = tps6586x_parse_regulator_dt(pdev, + &tps6586x_reg_matches); - err = tps6586x_regulator_preinit(pdev->dev.parent, ri); - if (err) - return err; + if (!pdata) { + dev_err(&pdev->dev, "Platform data not available, exiting\n"); + return -ENODEV; + } - config.dev = pdev->dev.parent; - config.of_node = pdev->dev.of_node; - config.init_data = pdev->dev.platform_data; - config.driver_data = ri; + rdev = devm_kzalloc(&pdev->dev, TPS6586X_ID_MAX_REGULATOR * + sizeof(*rdev), GFP_KERNEL); + if (!rdev) { + dev_err(&pdev->dev, "Mmemory alloc failed\n"); + return -ENOMEM; + } - rdev = regulator_register(&ri->desc, &config); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "failed to register regulator %s\n", - ri->desc.name); - return PTR_ERR(rdev); + for (id = 0; id < TPS6586X_ID_MAX_REGULATOR; ++id) { + reg_data = pdata->reg_init_data[id]; + + ri = find_regulator_info(id); + if (!ri) { + dev_err(&pdev->dev, "invalid regulator ID specified\n"); + err = -EINVAL; + goto fail; + } + + err = tps6586x_regulator_preinit(pdev->dev.parent, ri); + if (err) { + dev_err(&pdev->dev, + "regulator %d preinit failed, e %d\n", id, err); + goto fail; + } + + config.dev = pdev->dev.parent; + config.init_data = reg_data; + config.driver_data = ri; + + if (tps6586x_reg_matches) + config.of_node = tps6586x_reg_matches[id].of_node; + + rdev[id] = regulator_register(&ri->desc, &config); + if (IS_ERR(rdev[id])) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + ri->desc.name); + err = PTR_ERR(rdev[id]); + goto fail; + } + + if (reg_data) { + err = tps6586x_regulator_set_slew_rate(pdev, id, + reg_data); + if (err < 0) { + dev_err(&pdev->dev, + "Slew rate config failed, e %d\n", err); + regulator_unregister(rdev[id]); + goto fail; + } + } } platform_set_drvdata(pdev, rdev); + return 0; - return tps6586x_regulator_set_slew_rate(pdev); +fail: + while (--id >= 0) + regulator_unregister(rdev[id]); + return err; } -static int __devexit tps6586x_regulator_remove(struct platform_device *pdev) +static int tps6586x_regulator_remove(struct platform_device *pdev) { - struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct regulator_dev **rdev = platform_get_drvdata(pdev); + int id = TPS6586X_ID_MAX_REGULATOR; + + while (--id >= 0) + regulator_unregister(rdev[id]); - regulator_unregister(rdev); return 0; } static struct platform_driver tps6586x_regulator_driver = { .driver = { - .name = "tps6586x-regulator", + .name = "tps6586x-pmic", .owner = THIS_MODULE, }, .probe = tps6586x_regulator_probe, - .remove = __devexit_p(tps6586x_regulator_remove), + .remove = tps6586x_regulator_remove, }; static int __init tps6586x_regulator_init(void) diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 793adda560c3..6ba6931ac855 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -38,6 +38,11 @@ static const unsigned int VIO_VSEL_table[] = { /* VSEL tables for TPS65910 specific LDOs and dcdc's */ +/* supported VRTC voltages in microvolts */ +static const unsigned int VRTC_VSEL_table[] = { + 1800000, +}; + /* supported VDD3 voltages in microvolts */ static const unsigned int VDD3_VSEL_table[] = { 5000000, @@ -95,6 +100,8 @@ static struct tps_info tps65910_regs[] = { { .name = "vrtc", .vin_name = "vcc7", + .n_voltages = ARRAY_SIZE(VRTC_VSEL_table), + .voltage_table = VRTC_VSEL_table, .enable_time_us = 2200, }, { @@ -957,8 +964,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data( { struct tps65910_board *pmic_plat_data; struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); - struct device_node *np = pdev->dev.parent->of_node; - struct device_node *regulators; + struct device_node *np, *regulators; struct of_regulator_match *matches; unsigned int prop; int idx = 0, ret, count; @@ -971,6 +977,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data( return NULL; } + np = of_node_get(pdev->dev.parent->of_node); regulators = of_find_node_by_name(np, "regulators"); if (!regulators) { dev_err(&pdev->dev, "regulator node not found\n"); @@ -987,11 +994,13 @@ static struct tps65910_board *tps65910_parse_dt_reg_data( matches = tps65911_matches; break; default: + of_node_put(regulators); dev_err(&pdev->dev, "Invalid tps chip version\n"); return NULL; } - ret = of_regulator_match(pdev->dev.parent, regulators, matches, count); + ret = of_regulator_match(&pdev->dev, regulators, matches, count); + of_node_put(regulators); if (ret < 0) { dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); @@ -1026,7 +1035,7 @@ static inline struct tps65910_board *tps65910_parse_dt_reg_data( } #endif -static __devinit int tps65910_probe(struct platform_device *pdev) +static int tps65910_probe(struct platform_device *pdev) { struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; @@ -1184,7 +1193,7 @@ err_unregister_regulator: return err; } -static int __devexit tps65910_remove(struct platform_device *pdev) +static int tps65910_remove(struct platform_device *pdev) { struct tps65910_reg *pmic = platform_get_drvdata(pdev); int i; @@ -1231,7 +1240,7 @@ static struct platform_driver tps65910_driver = { .owner = THIS_MODULE, }, .probe = tps65910_probe, - .remove = __devexit_p(tps65910_remove), + .remove = tps65910_remove, .shutdown = tps65910_shutdown, }; diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index 18b2a1dcb4b5..17e994e47dc1 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -459,7 +459,7 @@ static struct regulator_ops tps65912_ops_ldo = { .list_voltage = tps65912_list_voltage, }; -static __devinit int tps65912_probe(struct platform_device *pdev) +static int tps65912_probe(struct platform_device *pdev) { struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; @@ -525,7 +525,7 @@ err: return err; } -static int __devexit tps65912_remove(struct platform_device *pdev) +static int tps65912_remove(struct platform_device *pdev) { struct tps65912_reg *tps65912_reg = platform_get_drvdata(pdev); int i; @@ -541,7 +541,7 @@ static struct platform_driver tps65912_driver = { .owner = THIS_MODULE, }, .probe = tps65912_probe, - .remove = __devexit_p(tps65912_remove), + .remove = tps65912_remove, }; static int __init tps65912_init(void) diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c new file mode 100644 index 000000000000..9019d0e7ecb6 --- /dev/null +++ b/drivers/regulator/tps80031-regulator.c @@ -0,0 +1,788 @@ +/* + * tps80031-regulator.c -- TI TPS80031 regulator driver. + * + * Regulator driver for TI TPS80031/TPS80032 Fully Integrated Power + * Management with Power Path and Battery Charger. + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; 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., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mfd/tps80031.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/slab.h> + +/* Flags for DCDC Voltage reading */ +#define DCDC_OFFSET_EN BIT(0) +#define DCDC_EXTENDED_EN BIT(1) +#define TRACK_MODE_ENABLE BIT(2) + +#define SMPS_MULTOFFSET_VIO BIT(1) +#define SMPS_MULTOFFSET_SMPS1 BIT(3) +#define SMPS_MULTOFFSET_SMPS2 BIT(4) +#define SMPS_MULTOFFSET_SMPS3 BIT(6) +#define SMPS_MULTOFFSET_SMPS4 BIT(0) + +#define SMPS_CMD_MASK 0xC0 +#define SMPS_VSEL_MASK 0x3F +#define LDO_VSEL_MASK 0x1F +#define LDO_TRACK_VSEL_MASK 0x3F + +#define MISC2_LDOUSB_IN_VSYS BIT(4) +#define MISC2_LDOUSB_IN_PMID BIT(3) +#define MISC2_LDOUSB_IN_MASK 0x18 + +#define MISC2_LDO3_SEL_VIB_VAL BIT(0) +#define MISC2_LDO3_SEL_VIB_MASK 0x1 + +#define BOOST_HW_PWR_EN BIT(5) +#define BOOST_HW_PWR_EN_MASK BIT(5) + +#define OPA_MODE_EN BIT(6) +#define OPA_MODE_EN_MASK BIT(6) + +#define USB_VBUS_CTRL_SET 0x04 +#define USB_VBUS_CTRL_CLR 0x05 +#define VBUS_DISCHRG 0x20 + +struct tps80031_regulator_info { + /* Regulator register address.*/ + u8 trans_reg; + u8 state_reg; + u8 force_reg; + u8 volt_reg; + u8 volt_id; + + /*Power request bits */ + int preq_bit; + + /* used by regulator core */ + struct regulator_desc desc; + +}; + +struct tps80031_regulator { + struct device *dev; + struct regulator_dev *rdev; + struct tps80031_regulator_info *rinfo; + + u8 device_flags; + unsigned int config_flags; + unsigned int ext_ctrl_flag; +}; + +static inline struct device *to_tps80031_dev(struct regulator_dev *rdev) +{ + return rdev_get_dev(rdev)->parent->parent; +} + +static int tps80031_reg_is_enabled(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + u8 reg_val; + int ret; + + if (ri->ext_ctrl_flag & TPS80031_EXT_PWR_REQ) + return true; + + ret = tps80031_read(parent, TPS80031_SLAVE_ID1, ri->rinfo->state_reg, + ®_val); + if (ret < 0) { + dev_err(&rdev->dev, "Reg 0x%02x read failed, err = %d\n", + ri->rinfo->state_reg, ret); + return ret; + } + return ((reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON); +} + +static int tps80031_reg_enable(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret; + + if (ri->ext_ctrl_flag & TPS80031_EXT_PWR_REQ) + return 0; + + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, ri->rinfo->state_reg, + TPS80031_STATE_ON, TPS80031_STATE_MASK); + if (ret < 0) { + dev_err(&rdev->dev, "Reg 0x%02x update failed, err = %d\n", + ri->rinfo->state_reg, ret); + return ret; + } + return ret; +} + +static int tps80031_reg_disable(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret; + + if (ri->ext_ctrl_flag & TPS80031_EXT_PWR_REQ) + return 0; + + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, ri->rinfo->state_reg, + TPS80031_STATE_OFF, TPS80031_STATE_MASK); + if (ret < 0) + dev_err(&rdev->dev, "Reg 0x%02x update failed, err = %d\n", + ri->rinfo->state_reg, ret); + return ret; +} + +/* DCDC voltages for the selector of 58 to 63 */ +static int tps80031_dcdc_voltages[4][5] = { + { 1350, 1500, 1800, 1900, 2100}, + { 1350, 1500, 1800, 1900, 2100}, + { 2084, 2315, 2778, 2932, 3241}, + { 4167, 2315, 2778, 2932, 3241}, +}; + +static int tps80031_dcdc_list_voltage(struct regulator_dev *rdev, unsigned sel) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + int volt_index = ri->device_flags & 0x3; + + if (sel == 0) + return 0; + else if (sel < 58) + return regulator_list_voltage_linear(rdev, sel - 1); + else + return tps80031_dcdc_voltages[volt_index][sel - 58] * 1000; +} + +static int tps80031_dcdc_set_voltage_sel(struct regulator_dev *rdev, + unsigned vsel) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret; + u8 reg_val; + + if (ri->rinfo->force_reg) { + ret = tps80031_read(parent, ri->rinfo->volt_id, + ri->rinfo->force_reg, ®_val); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + ri->rinfo->force_reg, ret); + return ret; + } + if (!(reg_val & SMPS_CMD_MASK)) { + ret = tps80031_update(parent, ri->rinfo->volt_id, + ri->rinfo->force_reg, vsel, SMPS_VSEL_MASK); + if (ret < 0) + dev_err(ri->dev, + "reg 0x%02x update failed, e = %d\n", + ri->rinfo->force_reg, ret); + return ret; + } + } + ret = tps80031_update(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, vsel, SMPS_VSEL_MASK); + if (ret < 0) + dev_err(ri->dev, "reg 0x%02x update failed, e = %d\n", + ri->rinfo->volt_reg, ret); + return ret; +} + +static int tps80031_dcdc_get_voltage_sel(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + uint8_t vsel = 0; + int ret; + + if (ri->rinfo->force_reg) { + ret = tps80031_read(parent, ri->rinfo->volt_id, + ri->rinfo->force_reg, &vsel); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + ri->rinfo->force_reg, ret); + return ret; + } + + if (!(vsel & SMPS_CMD_MASK)) + return vsel & SMPS_VSEL_MASK; + } + ret = tps80031_read(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, &vsel); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + ri->rinfo->volt_reg, ret); + return ret; + } + return vsel & SMPS_VSEL_MASK; +} + +static int tps80031_ldo_set_voltage_sel(struct regulator_dev *rdev, + unsigned sel) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret; + + /* Check for valid setting for TPS80031 or TPS80032-ES1.0 */ + if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) && + (ri->device_flags & TRACK_MODE_ENABLE)) { + unsigned nvsel = (sel) & 0x1F; + if (((tps80031_get_chip_info(parent) == TPS80031) || + ((tps80031_get_chip_info(parent) == TPS80032) && + (tps80031_get_pmu_version(parent) == 0x0))) && + ((nvsel == 0x0) || (nvsel >= 0x19 && nvsel <= 0x1F))) { + dev_err(ri->dev, + "Invalid sel %d in track mode LDO2\n", + nvsel); + return -EINVAL; + } + } + + ret = tps80031_write(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, sel); + if (ret < 0) + dev_err(ri->dev, "Error in writing reg 0x%02x, e = %d\n", + ri->rinfo->volt_reg, ret); + return ret; +} + +static int tps80031_ldo_get_voltage_sel(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + uint8_t vsel; + int ret; + + ret = tps80031_read(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, &vsel); + if (ret < 0) { + dev_err(ri->dev, "Error in writing the Voltage register\n"); + return ret; + } + return vsel & rdev->desc->vsel_mask; +} + +static int tps80031_vbus_is_enabled(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret = -EIO; + uint8_t ctrl1 = 0; + uint8_t ctrl3 = 0; + + ret = tps80031_read(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL1, &ctrl1); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL1, ret); + return ret; + } + ret = tps80031_read(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL3, &ctrl3); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL3, ret); + return ret; + } + if ((ctrl1 & OPA_MODE_EN) && (ctrl3 & BOOST_HW_PWR_EN)) + return 1; + return ret; +} + +static int tps80031_vbus_enable(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret; + + ret = tps80031_set_bits(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL1, OPA_MODE_EN); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL1, ret); + return ret; + } + + ret = tps80031_set_bits(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL3, BOOST_HW_PWR_EN); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL3, ret); + return ret; + } + return ret; +} + +static int tps80031_vbus_disable(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + struct device *parent = to_tps80031_dev(rdev); + int ret = 0; + + if (ri->config_flags & TPS80031_VBUS_DISCHRG_EN_PDN) { + ret = tps80031_write(parent, TPS80031_SLAVE_ID2, + USB_VBUS_CTRL_SET, VBUS_DISCHRG); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x write failed, e = %d\n", + USB_VBUS_CTRL_SET, ret); + return ret; + } + } + + ret = tps80031_clr_bits(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL1, OPA_MODE_EN); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x clearbit failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL1, ret); + return ret; + } + + ret = tps80031_clr_bits(parent, TPS80031_SLAVE_ID2, + TPS80031_CHARGERUSB_CTRL3, BOOST_HW_PWR_EN); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x clearbit failed, e = %d\n", + TPS80031_CHARGERUSB_CTRL3, ret); + return ret; + } + + mdelay(DIV_ROUND_UP(ri->rinfo->desc.enable_time, 1000)); + if (ri->config_flags & TPS80031_VBUS_DISCHRG_EN_PDN) { + ret = tps80031_write(parent, TPS80031_SLAVE_ID2, + USB_VBUS_CTRL_CLR, VBUS_DISCHRG); + if (ret < 0) { + dev_err(ri->dev, "reg 0x%02x write failed, e = %d\n", + USB_VBUS_CTRL_CLR, ret); + return ret; + } + } + return ret; +} + +static struct regulator_ops tps80031_dcdc_ops = { + .list_voltage = tps80031_dcdc_list_voltage, + .set_voltage_sel = tps80031_dcdc_set_voltage_sel, + .get_voltage_sel = tps80031_dcdc_get_voltage_sel, + .enable = tps80031_reg_enable, + .disable = tps80031_reg_disable, + .is_enabled = tps80031_reg_is_enabled, +}; + +static struct regulator_ops tps80031_ldo_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = tps80031_ldo_set_voltage_sel, + .get_voltage_sel = tps80031_ldo_get_voltage_sel, + .enable = tps80031_reg_enable, + .disable = tps80031_reg_disable, + .is_enabled = tps80031_reg_is_enabled, +}; + +static struct regulator_ops tps80031_vbus_sw_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = tps80031_vbus_enable, + .disable = tps80031_vbus_disable, + .is_enabled = tps80031_vbus_is_enabled, +}; + +static struct regulator_ops tps80031_vbus_hw_ops = { + .list_voltage = regulator_list_voltage_linear, +}; + +static struct regulator_ops tps80031_ext_reg_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = tps80031_reg_enable, + .disable = tps80031_reg_disable, + .is_enabled = tps80031_reg_is_enabled, +}; + +/* Non-exiting default definition for some register */ +#define TPS80031_SMPS3_CFG_FORCE 0 +#define TPS80031_SMPS4_CFG_FORCE 0 + +#define TPS80031_VBUS_CFG_TRANS 0 +#define TPS80031_VBUS_CFG_STATE 0 + +#define TPS80031_REG_SMPS(_id, _volt_id, _pbit) \ +{ \ + .trans_reg = TPS80031_##_id##_CFG_TRANS, \ + .state_reg = TPS80031_##_id##_CFG_STATE, \ + .force_reg = TPS80031_##_id##_CFG_FORCE, \ + .volt_reg = TPS80031_##_id##_CFG_VOLTAGE, \ + .volt_id = TPS80031_SLAVE_##_volt_id, \ + .preq_bit = _pbit, \ + .desc = { \ + .name = "tps80031_"#_id, \ + .id = TPS80031_REGULATOR_##_id, \ + .n_voltages = 63, \ + .ops = &tps80031_dcdc_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .enable_time = 500, \ + }, \ +} + +#define TPS80031_REG_LDO(_id, _preq_bit) \ +{ \ + .trans_reg = TPS80031_##_id##_CFG_TRANS, \ + .state_reg = TPS80031_##_id##_CFG_STATE, \ + .volt_reg = TPS80031_##_id##_CFG_VOLTAGE, \ + .volt_id = TPS80031_SLAVE_ID1, \ + .preq_bit = _preq_bit, \ + .desc = { \ + .owner = THIS_MODULE, \ + .name = "tps80031_"#_id, \ + .id = TPS80031_REGULATOR_##_id, \ + .ops = &tps80031_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = 1000000, \ + .uV_step = 100000, \ + .linear_min_sel = 1, \ + .n_voltages = 25, \ + .vsel_mask = LDO_VSEL_MASK, \ + .enable_time = 500, \ + }, \ +} + +#define TPS80031_REG_FIXED(_id, max_mV, _ops, _delay, _pbit) \ +{ \ + .trans_reg = TPS80031_##_id##_CFG_TRANS, \ + .state_reg = TPS80031_##_id##_CFG_STATE, \ + .volt_id = TPS80031_SLAVE_ID1, \ + .preq_bit = _pbit, \ + .desc = { \ + .name = "tps80031_"#_id, \ + .id = TPS80031_REGULATOR_##_id, \ + .min_uV = max_mV * 1000, \ + .n_voltages = 1, \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .enable_time = _delay, \ + }, \ +} + +static struct tps80031_regulator_info tps80031_rinfo[TPS80031_REGULATOR_MAX] = { + TPS80031_REG_SMPS(VIO, ID0, 4), + TPS80031_REG_SMPS(SMPS1, ID0, 0), + TPS80031_REG_SMPS(SMPS2, ID0, 1), + TPS80031_REG_SMPS(SMPS3, ID1, 2), + TPS80031_REG_SMPS(SMPS4, ID1, 3), + TPS80031_REG_LDO(VANA, -1), + TPS80031_REG_LDO(LDO1, 8), + TPS80031_REG_LDO(LDO2, 9), + TPS80031_REG_LDO(LDO3, 10), + TPS80031_REG_LDO(LDO4, 11), + TPS80031_REG_LDO(LDO5, 12), + TPS80031_REG_LDO(LDO6, 13), + TPS80031_REG_LDO(LDO7, 14), + TPS80031_REG_LDO(LDOLN, 15), + TPS80031_REG_LDO(LDOUSB, 5), + TPS80031_REG_FIXED(VBUS, 5000, tps80031_vbus_hw_ops, 100000, -1), + TPS80031_REG_FIXED(REGEN1, 3300, tps80031_ext_reg_ops, 0, 16), + TPS80031_REG_FIXED(REGEN2, 3300, tps80031_ext_reg_ops, 0, 17), + TPS80031_REG_FIXED(SYSEN, 3300, tps80031_ext_reg_ops, 0, 18), +}; + +static int tps80031_power_req_config(struct device *parent, + struct tps80031_regulator *ri, + struct tps80031_regulator_platform_data *tps80031_pdata) +{ + int ret = 0; + + if (ri->rinfo->preq_bit < 0) + goto skip_pwr_req_config; + + ret = tps80031_ext_power_req_config(parent, ri->ext_ctrl_flag, + ri->rinfo->preq_bit, ri->rinfo->state_reg, + ri->rinfo->trans_reg); + if (ret < 0) { + dev_err(ri->dev, "ext powerreq config failed, err = %d\n", ret); + return ret; + } + +skip_pwr_req_config: + if (tps80031_pdata->ext_ctrl_flag & TPS80031_PWR_ON_ON_SLEEP) { + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, + ri->rinfo->trans_reg, TPS80031_TRANS_SLEEP_ON, + TPS80031_TRANS_SLEEP_MASK); + if (ret < 0) { + dev_err(ri->dev, "Reg 0x%02x update failed, e %d\n", + ri->rinfo->trans_reg, ret); + return ret; + } + } + return ret; +} + +static int tps80031_regulator_config(struct device *parent, + struct tps80031_regulator *ri, + struct tps80031_regulator_platform_data *tps80031_pdata) +{ + int ret = 0; + + switch (ri->rinfo->desc.id) { + case TPS80031_REGULATOR_LDOUSB: + if (ri->config_flags & (TPS80031_USBLDO_INPUT_VSYS | + TPS80031_USBLDO_INPUT_PMID)) { + unsigned val = 0; + if (ri->config_flags & TPS80031_USBLDO_INPUT_VSYS) + val = MISC2_LDOUSB_IN_VSYS; + else + val = MISC2_LDOUSB_IN_PMID; + + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, + TPS80031_MISC2, val, + MISC2_LDOUSB_IN_MASK); + if (ret < 0) { + dev_err(ri->dev, + "LDOUSB config failed, e= %d\n", ret); + return ret; + } + } + break; + + case TPS80031_REGULATOR_LDO3: + if (ri->config_flags & TPS80031_LDO3_OUTPUT_VIB) { + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, + TPS80031_MISC2, MISC2_LDO3_SEL_VIB_VAL, + MISC2_LDO3_SEL_VIB_MASK); + if (ret < 0) { + dev_err(ri->dev, + "LDO3 config failed, e = %d\n", ret); + return ret; + } + } + break; + + case TPS80031_REGULATOR_VBUS: + /* Provide SW control Ops if VBUS is SW control */ + if (!(ri->config_flags & TPS80031_VBUS_SW_ONLY)) + ri->rinfo->desc.ops = &tps80031_vbus_sw_ops; + break; + default: + break; + } + + /* Configure Active state to ON, SLEEP to OFF and OFF_state to OFF */ + ret = tps80031_update(parent, TPS80031_SLAVE_ID1, ri->rinfo->trans_reg, + TPS80031_TRANS_ACTIVE_ON | TPS80031_TRANS_SLEEP_OFF | + TPS80031_TRANS_OFF_OFF, TPS80031_TRANS_ACTIVE_MASK | + TPS80031_TRANS_SLEEP_MASK | TPS80031_TRANS_OFF_MASK); + if (ret < 0) { + dev_err(ri->dev, "trans reg update failed, e %d\n", ret); + return ret; + } + + return ret; +} + +static int check_smps_mode_mult(struct device *parent, + struct tps80031_regulator *ri) +{ + int mult_offset; + int ret; + u8 smps_offset; + u8 smps_mult; + + ret = tps80031_read(parent, TPS80031_SLAVE_ID1, + TPS80031_SMPS_OFFSET, &smps_offset); + if (ret < 0) { + dev_err(parent, "Error in reading smps offset register\n"); + return ret; + } + + ret = tps80031_read(parent, TPS80031_SLAVE_ID1, + TPS80031_SMPS_MULT, &smps_mult); + if (ret < 0) { + dev_err(parent, "Error in reading smps mult register\n"); + return ret; + } + + switch (ri->rinfo->desc.id) { + case TPS80031_REGULATOR_VIO: + mult_offset = SMPS_MULTOFFSET_VIO; + break; + case TPS80031_REGULATOR_SMPS1: + mult_offset = SMPS_MULTOFFSET_SMPS1; + break; + case TPS80031_REGULATOR_SMPS2: + mult_offset = SMPS_MULTOFFSET_SMPS2; + break; + case TPS80031_REGULATOR_SMPS3: + mult_offset = SMPS_MULTOFFSET_SMPS3; + break; + case TPS80031_REGULATOR_SMPS4: + mult_offset = SMPS_MULTOFFSET_SMPS4; + break; + case TPS80031_REGULATOR_LDO2: + ri->device_flags = smps_mult & BIT(5) ? TRACK_MODE_ENABLE : 0; + /* TRACK mode the ldo2 varies from 600mV to 1300mV */ + if (ri->device_flags & TRACK_MODE_ENABLE) { + ri->rinfo->desc.min_uV = 600000; + ri->rinfo->desc.uV_step = 12500; + ri->rinfo->desc.n_voltages = 57; + ri->rinfo->desc.vsel_mask = LDO_TRACK_VSEL_MASK; + } + return 0; + default: + return 0; + } + + ri->device_flags = (smps_offset & mult_offset) ? DCDC_OFFSET_EN : 0; + ri->device_flags |= (smps_mult & mult_offset) ? DCDC_EXTENDED_EN : 0; + switch (ri->device_flags) { + case 0: + ri->rinfo->desc.min_uV = 607700; + ri->rinfo->desc.uV_step = 12660; + break; + case DCDC_OFFSET_EN: + ri->rinfo->desc.min_uV = 700000; + ri->rinfo->desc.uV_step = 12500; + break; + case DCDC_EXTENDED_EN: + ri->rinfo->desc.min_uV = 1852000; + ri->rinfo->desc.uV_step = 38600; + break; + case DCDC_OFFSET_EN | DCDC_EXTENDED_EN: + ri->rinfo->desc.min_uV = 2161000; + ri->rinfo->desc.uV_step = 38600; + break; + } + return 0; +} + +static int tps80031_regulator_probe(struct platform_device *pdev) +{ + struct tps80031_platform_data *pdata; + struct tps80031_regulator_platform_data *tps_pdata; + struct tps80031_regulator *ri; + struct tps80031_regulator *pmic; + struct regulator_dev *rdev; + struct regulator_config config = { }; + int ret; + int num; + + pdata = dev_get_platdata(pdev->dev.parent); + + if (!pdata) { + dev_err(&pdev->dev, "No platform data\n"); + return -EINVAL; + } + + pmic = devm_kzalloc(&pdev->dev, + TPS80031_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL); + if (!pmic) { + dev_err(&pdev->dev, "mem alloc for pmic failed\n"); + return -ENOMEM; + } + + for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) { + tps_pdata = pdata->regulator_pdata[num]; + ri = &pmic[num]; + ri->rinfo = &tps80031_rinfo[num]; + ri->dev = &pdev->dev; + + check_smps_mode_mult(pdev->dev.parent, ri); + config.dev = &pdev->dev; + config.init_data = NULL; + config.driver_data = ri; + if (tps_pdata) { + config.init_data = tps_pdata->reg_init_data; + ri->config_flags = tps_pdata->config_flags; + ri->ext_ctrl_flag = tps_pdata->ext_ctrl_flag; + ret = tps80031_regulator_config(pdev->dev.parent, + ri, tps_pdata); + if (ret < 0) { + dev_err(&pdev->dev, + "regulator config failed, e %d\n", ret); + goto fail; + } + + ret = tps80031_power_req_config(pdev->dev.parent, + ri, tps_pdata); + if (ret < 0) { + dev_err(&pdev->dev, + "pwr_req config failed, err %d\n", ret); + goto fail; + } + } + rdev = regulator_register(&ri->rinfo->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "register regulator failed %s\n", + ri->rinfo->desc.name); + ret = PTR_ERR(rdev); + goto fail; + } + ri->rdev = rdev; + } + + platform_set_drvdata(pdev, pmic); + return 0; +fail: + while (--num >= 0) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + } + return ret; +} + +static int tps80031_regulator_remove(struct platform_device *pdev) +{ + struct tps80031_regulator *pmic = platform_get_drvdata(pdev); + struct tps80031_regulator *ri = NULL; + int num; + + for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + } + return 0; +} + +static struct platform_driver tps80031_regulator_driver = { + .driver = { + .name = "tps80031-pmic", + .owner = THIS_MODULE, + }, + .probe = tps80031_regulator_probe, + .remove = tps80031_regulator_remove, +}; + +static int __init tps80031_regulator_init(void) +{ + return platform_driver_register(&tps80031_regulator_driver); +} +subsys_initcall(tps80031_regulator_init); + +static void __exit tps80031_regulator_exit(void) +{ + platform_driver_unregister(&tps80031_regulator_driver); +} +module_exit(tps80031_regulator_exit); + +MODULE_ALIAS("platform:tps80031-regulator"); +MODULE_DESCRIPTION("Regulator Driver for TI TPS80031/TPS80032 PMIC"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 7eb986a40746..f705d25b437c 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -471,24 +471,23 @@ twl4030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) selector); } -static int twl4030ldo_get_voltage(struct regulator_dev *rdev) +static int twl4030ldo_get_voltage_sel(struct regulator_dev *rdev) { struct twlreg_info *info = rdev_get_drvdata(rdev); - int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, - VREG_VOLTAGE); + int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE); if (vsel < 0) return vsel; vsel &= info->table_len - 1; - return LDO_MV(info->table[vsel]) * 1000; + return vsel; } static struct regulator_ops twl4030ldo_ops = { .list_voltage = twl4030ldo_list_voltage, .set_voltage_sel = twl4030ldo_set_voltage_sel, - .get_voltage = twl4030ldo_get_voltage, + .get_voltage_sel = twl4030ldo_get_voltage_sel, .enable = twl4030reg_enable, .disable = twl4030reg_disable, @@ -1064,7 +1063,7 @@ static u8 twl_get_smps_mult(void) #define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label) #define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label) -static const struct of_device_id twl_of_match[] __devinitconst = { +static const struct of_device_id twl_of_match[] = { TWL4030_OF_MATCH("ti,twl4030-vaux1", VAUX1), TWL4030_OF_MATCH("ti,twl4030-vaux2", VAUX2_4030), TWL4030_OF_MATCH("ti,twl5030-vaux2", VAUX2), @@ -1116,7 +1115,7 @@ static const struct of_device_id twl_of_match[] __devinitconst = { }; MODULE_DEVICE_TABLE(of, twl_of_match); -static int __devinit twlreg_probe(struct platform_device *pdev) +static int twlreg_probe(struct platform_device *pdev) { int i, id; struct twlreg_info *info; @@ -1241,7 +1240,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev) return 0; } -static int __devexit twlreg_remove(struct platform_device *pdev) +static int twlreg_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); struct twlreg_info *info = rdev->reg_data; @@ -1255,7 +1254,7 @@ MODULE_ALIAS("platform:twl_reg"); static struct platform_driver twlreg_driver = { .probe = twlreg_probe, - .remove = __devexit_p(twlreg_remove), + .remove = twlreg_remove, /* NOTE: short name, to work around driver model truncation of * "twl_regulator.12" (and friends) to "twl_regulator.1". */ diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c new file mode 100644 index 000000000000..4668c7f8133d --- /dev/null +++ b/drivers/regulator/vexpress.c @@ -0,0 +1,147 @@ +/* + * 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. + * + * Copyright (C) 2012 ARM Limited + */ + +#define DRVNAME "vexpress-regulator" +#define pr_fmt(fmt) DRVNAME ": " fmt + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/vexpress.h> + +struct vexpress_regulator { + struct regulator_desc desc; + struct regulator_dev *regdev; + struct vexpress_config_func *func; +}; + +static int vexpress_regulator_get_voltage(struct regulator_dev *regdev) +{ + struct vexpress_regulator *reg = rdev_get_drvdata(regdev); + u32 uV; + int err = vexpress_config_read(reg->func, 0, &uV); + + return err ? err : uV; +} + +static int vexpress_regulator_set_voltage(struct regulator_dev *regdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct vexpress_regulator *reg = rdev_get_drvdata(regdev); + + return vexpress_config_write(reg->func, 0, min_uV); +} + +static struct regulator_ops vexpress_regulator_ops_ro = { + .get_voltage = vexpress_regulator_get_voltage, +}; + +static struct regulator_ops vexpress_regulator_ops = { + .get_voltage = vexpress_regulator_get_voltage, + .set_voltage = vexpress_regulator_set_voltage, +}; + +static int vexpress_regulator_probe(struct platform_device *pdev) +{ + int err; + struct vexpress_regulator *reg; + struct regulator_init_data *init_data; + struct regulator_config config = { }; + + reg = devm_kzalloc(&pdev->dev, sizeof(*reg), GFP_KERNEL); + if (!reg) { + err = -ENOMEM; + goto error_kzalloc; + } + + reg->func = vexpress_config_func_get_by_dev(&pdev->dev); + if (!reg->func) { + err = -ENXIO; + goto error_get_func; + } + + reg->desc.name = dev_name(&pdev->dev); + reg->desc.type = REGULATOR_VOLTAGE; + reg->desc.owner = THIS_MODULE; + reg->desc.continuous_voltage_range = true; + + init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); + if (!init_data) { + err = -EINVAL; + goto error_get_regulator_init_data; + } + + init_data->constraints.apply_uV = 0; + if (init_data->constraints.min_uV && init_data->constraints.max_uV) + reg->desc.ops = &vexpress_regulator_ops; + else + reg->desc.ops = &vexpress_regulator_ops_ro; + + config.dev = &pdev->dev; + config.init_data = init_data; + config.driver_data = reg; + config.of_node = pdev->dev.of_node; + + reg->regdev = regulator_register(®->desc, &config); + if (IS_ERR(reg->regdev)) { + err = PTR_ERR(reg->regdev); + goto error_regulator_register; + } + + platform_set_drvdata(pdev, reg); + + return 0; + +error_regulator_register: +error_get_regulator_init_data: + vexpress_config_func_put(reg->func); +error_get_func: +error_kzalloc: + return err; +} + +static int vexpress_regulator_remove(struct platform_device *pdev) +{ + struct vexpress_regulator *reg = platform_get_drvdata(pdev); + + vexpress_config_func_put(reg->func); + regulator_unregister(reg->regdev); + + return 0; +} + +static struct of_device_id vexpress_regulator_of_match[] = { + { .compatible = "arm,vexpress-volt", }, + { } +}; + +static struct platform_driver vexpress_regulator_driver = { + .probe = vexpress_regulator_probe, + .remove = vexpress_regulator_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + .of_match_table = vexpress_regulator_of_match, + }, +}; + +module_platform_driver(vexpress_regulator_driver); + +MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>"); +MODULE_DESCRIPTION("Versatile Express regulator"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:vexpress-regulator"); diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index c038e7422538..01c66e9712a4 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -285,7 +285,7 @@ static const struct attribute_group regulator_virtual_attr_group = { .attrs = regulator_virtual_attributes, }; -static int __devinit regulator_virtual_probe(struct platform_device *pdev) +static int regulator_virtual_probe(struct platform_device *pdev) { char *reg_id = pdev->dev.platform_data; struct virtual_consumer_data *drvdata; @@ -321,7 +321,7 @@ static int __devinit regulator_virtual_probe(struct platform_device *pdev) return 0; } -static int __devexit regulator_virtual_remove(struct platform_device *pdev) +static int regulator_virtual_remove(struct platform_device *pdev) { struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev); @@ -337,7 +337,7 @@ static int __devexit regulator_virtual_remove(struct platform_device *pdev) static struct platform_driver regulator_virtual_consumer_driver = { .probe = regulator_virtual_probe, - .remove = __devexit_p(regulator_virtual_remove), + .remove = regulator_virtual_remove, .driver = { .name = "reg-virt-consumer", .owner = THIS_MODULE, diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 782c228a19bd..0af6898bcd79 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -223,7 +223,7 @@ static int wm831x_buckv_map_voltage(struct regulator_dev *rdev, if (min_uV < 600000) vsel = 0; else if (min_uV <= 1800000) - vsel = ((min_uV - 600000) / 12500) + 8; + vsel = DIV_ROUND_UP(min_uV - 600000, 12500) + 8; else return -EINVAL; @@ -290,7 +290,7 @@ static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev, if (vsel > dcdc->dvs_vsel) { ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, - dcdc->dvs_vsel); + vsel); if (ret == 0) dcdc->dvs_vsel = vsel; else @@ -387,7 +387,7 @@ static struct regulator_ops wm831x_buckv_ops = { * Set up DVS control. We just log errors since we can still run * (with reduced performance) if we fail. */ -static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, +static void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, struct wm831x_buckv_pdata *pdata) { struct wm831x *wm831x = dcdc->wm831x; @@ -448,7 +448,7 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, } } -static __devinit int wm831x_buckv_probe(struct platform_device *pdev) +static int wm831x_buckv_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -562,7 +562,7 @@ err: return ret; } -static __devexit int wm831x_buckv_remove(struct platform_device *pdev) +static int wm831x_buckv_remove(struct platform_device *pdev) { struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); struct wm831x *wm831x = dcdc->wm831x; @@ -582,7 +582,7 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev) static struct platform_driver wm831x_buckv_driver = { .probe = wm831x_buckv_probe, - .remove = __devexit_p(wm831x_buckv_remove), + .remove = wm831x_buckv_remove, .driver = { .name = "wm831x-buckv", .owner = THIS_MODULE, @@ -623,7 +623,7 @@ static struct regulator_ops wm831x_buckp_ops = { .set_suspend_mode = wm831x_dcdc_set_suspend_mode, }; -static __devinit int wm831x_buckp_probe(struct platform_device *pdev) +static int wm831x_buckp_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -710,7 +710,7 @@ err: return ret; } -static __devexit int wm831x_buckp_remove(struct platform_device *pdev) +static int wm831x_buckp_remove(struct platform_device *pdev) { struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); @@ -725,7 +725,7 @@ static __devexit int wm831x_buckp_remove(struct platform_device *pdev) static struct platform_driver wm831x_buckp_driver = { .probe = wm831x_buckp_probe, - .remove = __devexit_p(wm831x_buckp_remove), + .remove = wm831x_buckp_remove, .driver = { .name = "wm831x-buckp", .owner = THIS_MODULE, @@ -771,7 +771,7 @@ static struct regulator_ops wm831x_boostp_ops = { .disable = regulator_disable_regmap, }; -static __devinit int wm831x_boostp_probe(struct platform_device *pdev) +static int wm831x_boostp_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -845,7 +845,7 @@ err: return ret; } -static __devexit int wm831x_boostp_remove(struct platform_device *pdev) +static int wm831x_boostp_remove(struct platform_device *pdev) { struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); @@ -860,7 +860,7 @@ static __devexit int wm831x_boostp_remove(struct platform_device *pdev) static struct platform_driver wm831x_boostp_driver = { .probe = wm831x_boostp_probe, - .remove = __devexit_p(wm831x_boostp_remove), + .remove = wm831x_boostp_remove, .driver = { .name = "wm831x-boostp", .owner = THIS_MODULE, @@ -883,7 +883,7 @@ static struct regulator_ops wm831x_epe_ops = { .get_status = wm831x_dcdc_get_status, }; -static __devinit int wm831x_epe_probe(struct platform_device *pdev) +static int wm831x_epe_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -936,7 +936,7 @@ err: return ret; } -static __devexit int wm831x_epe_remove(struct platform_device *pdev) +static int wm831x_epe_remove(struct platform_device *pdev) { struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); @@ -948,7 +948,7 @@ static __devexit int wm831x_epe_remove(struct platform_device *pdev) static struct platform_driver wm831x_epe_driver = { .probe = wm831x_epe_probe, - .remove = __devexit_p(wm831x_epe_remove), + .remove = wm831x_epe_remove, .driver = { .name = "wm831x-epe", .owner = THIS_MODULE, @@ -993,4 +993,5 @@ MODULE_DESCRIPTION("WM831x DC-DC convertor driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:wm831x-buckv"); MODULE_ALIAS("platform:wm831x-buckp"); +MODULE_ALIAS("platform:wm831x-boostp"); MODULE_ALIAS("platform:wm831x-epe"); diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 2646a1902b33..68586ee3e1cb 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -148,7 +148,7 @@ static irqreturn_t wm831x_isink_irq(int irq, void *data) } -static __devinit int wm831x_isink_probe(struct platform_device *pdev) +static int wm831x_isink_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -221,7 +221,7 @@ err: return ret; } -static __devexit int wm831x_isink_remove(struct platform_device *pdev) +static int wm831x_isink_remove(struct platform_device *pdev) { struct wm831x_isink *isink = platform_get_drvdata(pdev); @@ -236,7 +236,7 @@ static __devexit int wm831x_isink_remove(struct platform_device *pdev) static struct platform_driver wm831x_isink_driver = { .probe = wm831x_isink_probe, - .remove = __devexit_p(wm831x_isink_remove), + .remove = wm831x_isink_remove, .driver = { .name = "wm831x-isink", .owner = THIS_MODULE, diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index c2dc03993dc7..1ec379a9a95c 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -247,7 +247,7 @@ static struct regulator_ops wm831x_gp_ldo_ops = { .disable = regulator_disable_regmap, }; -static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) +static int wm831x_gp_ldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -334,7 +334,7 @@ err: return ret; } -static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev) +static int wm831x_gp_ldo_remove(struct platform_device *pdev) { struct wm831x_ldo *ldo = platform_get_drvdata(pdev); @@ -349,7 +349,7 @@ static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev) static struct platform_driver wm831x_gp_ldo_driver = { .probe = wm831x_gp_ldo_probe, - .remove = __devexit_p(wm831x_gp_ldo_remove), + .remove = wm831x_gp_ldo_remove, .driver = { .name = "wm831x-ldo", .owner = THIS_MODULE, @@ -504,7 +504,7 @@ static struct regulator_ops wm831x_aldo_ops = { .disable = regulator_disable_regmap, }; -static __devinit int wm831x_aldo_probe(struct platform_device *pdev) +static int wm831x_aldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -590,7 +590,7 @@ err: return ret; } -static __devexit int wm831x_aldo_remove(struct platform_device *pdev) +static int wm831x_aldo_remove(struct platform_device *pdev) { struct wm831x_ldo *ldo = platform_get_drvdata(pdev); @@ -603,7 +603,7 @@ static __devexit int wm831x_aldo_remove(struct platform_device *pdev) static struct platform_driver wm831x_aldo_driver = { .probe = wm831x_aldo_probe, - .remove = __devexit_p(wm831x_aldo_remove), + .remove = wm831x_aldo_remove, .driver = { .name = "wm831x-aldo", .owner = THIS_MODULE, @@ -660,7 +660,7 @@ static struct regulator_ops wm831x_alive_ldo_ops = { .disable = regulator_disable_regmap, }; -static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) +static int wm831x_alive_ldo_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -737,7 +737,7 @@ err: return ret; } -static __devexit int wm831x_alive_ldo_remove(struct platform_device *pdev) +static int wm831x_alive_ldo_remove(struct platform_device *pdev) { struct wm831x_ldo *ldo = platform_get_drvdata(pdev); @@ -748,7 +748,7 @@ static __devexit int wm831x_alive_ldo_remove(struct platform_device *pdev) static struct platform_driver wm831x_alive_ldo_driver = { .probe = wm831x_alive_ldo_probe, - .remove = __devexit_p(wm831x_alive_ldo_remove), + .remove = wm831x_alive_ldo_remove, .driver = { .name = "wm831x-alive-ldo", .owner = THIS_MODULE, diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 27c746ef0636..c6a32ea80b9d 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -226,7 +226,7 @@ static struct regulator_desc regulators[] = { }, }; -static int __devinit wm8400_regulator_probe(struct platform_device *pdev) +static int wm8400_regulator_probe(struct platform_device *pdev) { struct wm8400 *wm8400 = container_of(pdev, struct wm8400, regulators[pdev->id]); struct regulator_config config = { }; @@ -246,7 +246,7 @@ static int __devinit wm8400_regulator_probe(struct platform_device *pdev) return 0; } -static int __devexit wm8400_regulator_remove(struct platform_device *pdev) +static int wm8400_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); @@ -261,7 +261,7 @@ static struct platform_driver wm8400_regulator_driver = { .name = "wm8400-regulator", }, .probe = wm8400_regulator_probe, - .remove = __devexit_p(wm8400_regulator_remove), + .remove = wm8400_regulator_remove, }; /** diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 86bb48db149e..6ff872342648 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -99,7 +99,7 @@ static const struct regulator_desc wm8994_ldo_desc[] = { }, }; -static __devinit int wm8994_ldo_probe(struct platform_device *pdev) +static int wm8994_ldo_probe(struct platform_device *pdev) { struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); struct wm8994_pdata *pdata = wm8994->dev->platform_data; @@ -142,7 +142,7 @@ err: return ret; } -static __devexit int wm8994_ldo_remove(struct platform_device *pdev) +static int wm8994_ldo_remove(struct platform_device *pdev) { struct wm8994_ldo *ldo = platform_get_drvdata(pdev); @@ -155,7 +155,7 @@ static __devexit int wm8994_ldo_remove(struct platform_device *pdev) static struct platform_driver wm8994_ldo_driver = { .probe = wm8994_ldo_probe, - .remove = __devexit_p(wm8994_ldo_remove), + .remove = wm8994_ldo_remove, .driver = { .name = "wm8994-ldo", .owner = THIS_MODULE, |