diff options
74 files changed, 4348 insertions, 3274 deletions
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt index 9cf57fd042d2..2f5b6b1ba15f 100644 --- a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt @@ -8,6 +8,8 @@ Optional properties: - startup-delay-us: startup time in microseconds - enable-active-high: Polarity of GPIO is Active high If this property is missing, the default assumed is Active low. +- gpio-open-drain: GPIO is open drain type. + If this property is missing then default assumption is false. Any property defined as part of the core regulator binding, defined in regulator.txt, can also be used. @@ -25,5 +27,6 @@ Example: gpio = <&gpio1 16 0>; startup-delay-us = <70000>; enable-active-high; - regulator-boot-on + regulator-boot-on; + gpio-open-drain; }; diff --git a/Documentation/devicetree/bindings/regulator/tps62360-regulator.txt b/Documentation/devicetree/bindings/regulator/tps62360-regulator.txt new file mode 100644 index 000000000000..c8ca6b8f6582 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/tps62360-regulator.txt @@ -0,0 +1,44 @@ +TPS62360 Voltage regulators + +Required properties: +- compatible: Must be one of the following. + "ti,tps62360" + "ti,tps62361", + "ti,tps62362", + "ti,tps62363", +- reg: I2C slave address + +Optional properties: +- ti,enable-vout-discharge: Enable output discharge. This is boolean value. +- ti,enable-pull-down: Enable pull down. This is boolean value. +- ti,vsel0-gpio: GPIO for controlling VSEL0 line. + If this property is missing, then assume that there is no GPIO + for vsel0 control. +- ti,vsel1-gpio: Gpio for controlling VSEL1 line. + If this property is missing, then assume that there is no GPIO + for vsel1 control. +- ti,vsel0-state-high: Inital state of vsel0 input is high. + If this property is missing, then assume the state as low (0). +- ti,vsel1-state-high: Inital state of vsel1 input is high. + If this property is missing, then assume the state as low (0). + +Any property defined as part of the core regulator binding, defined in +regulator.txt, can also be used. + +Example: + + abc: tps62360 { + compatible = "ti,tps62361"; + reg = <0x60>; + regulator-name = "tps62361-vout"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on + ti,vsel0-gpio = <&gpio1 16 0>; + ti,vsel1-gpio = <&gpio1 17 0>; + ti,vsel0-state-high; + ti,vsel1-state-high; + ti,enable-pull-down; + ti,enable-force-pwm; + ti,enable-vout-discharge; + }; diff --git a/Documentation/devicetree/bindings/regulator/tps6586x.txt b/Documentation/devicetree/bindings/regulator/tps6586x.txt new file mode 100644 index 000000000000..0fcabaa3baa3 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/tps6586x.txt @@ -0,0 +1,97 @@ +TPS6586x family of regulators + +Required properties: +- compatible: "ti,tps6586x" +- reg: I2C slave address +- interrupts: the interrupt outputs of the controller +- #gpio-cells: number of cells to describe a GPIO +- gpio-controller: mark the device as a GPIO controller +- regulators: list of regulators provided by this controller, must be named + after their hardware counterparts: sm[0-2], ldo[0-9] and ldo_rtc + +Each regulator is defined using the standard binding for regulators. + +Example: + + pmu: tps6586x@34 { + compatible = "ti,tps6586x"; + reg = <0x34>; + interrupts = <0 88 0x4>; + + #gpio-cells = <2>; + gpio-controller; + + regulators { + sm0_reg: sm0 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + sm1_reg: sm1 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + sm2_reg: sm2 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <4550000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo0_reg: ldo0 { + regulator-name = "PCIE CLK"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo1_reg: ldo1 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + }; + + ldo2_reg: ldo2 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + }; + + ldo3_reg: ldo3 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo4_reg: ldo4 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2475000>; + }; + + ldo5_reg: ldo5 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo6_reg: ldo6 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo7_reg: ldo7 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo8_reg: ldo8 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo9_reg: ldo9 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; diff --git a/Documentation/power/regulator/regulator.txt b/Documentation/power/regulator/regulator.txt index e272d9909e39..13902778ae44 100644 --- a/Documentation/power/regulator/regulator.txt +++ b/Documentation/power/regulator/regulator.txt @@ -11,8 +11,7 @@ Registration Drivers can register a regulator by calling :- struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, - struct device *dev, struct regulator_init_data *init_data, - void *driver_data, struct device_node *of_node); + const struct regulator_config *config); This will register the regulators capabilities and operations to the regulator core. diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e35cb6bc9003..b5a0032f616e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -162,6 +162,7 @@ config MFD_TPS6586X bool "TPS6586x Power Management chips" depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS select MFD_CORE + depends on REGULATOR help If you say yes here you get support for the TPS6586X series of Power Management chips. diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index a66d4df51293..47f802bf1848 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -78,17 +78,6 @@ static struct mfd_cell tps65090s[] = { }, }; -struct tps65090 { - struct mutex lock; - struct device *dev; - struct i2c_client *client; - struct regmap *rmap; - struct irq_chip irq_chip; - struct mutex irq_lock; - int irq_base; - unsigned int id; -}; - int tps65090_write(struct device *dev, int reg, uint8_t val) { struct tps65090 *tps = dev_get_drvdata(dev); diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index a5ddf31b60ca..c84b5506d5fb 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/i2c.h> +#include <linux/regulator/of_regulator.h> #include <linux/mfd/core.h> #include <linux/mfd/tps6586x.h> @@ -460,6 +461,7 @@ static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, pdev->dev.parent = tps6586x->dev; pdev->dev.platform_data = subdev->platform_data; + pdev->dev.of_node = subdev->of_node; ret = platform_device_add(pdev); if (ret) { @@ -474,6 +476,86 @@ failed: return ret; } +#ifdef CONFIG_OF +static struct of_regulator_match tps6586x_matches[] = { + { .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_dt(struct i2c_client *client) +{ + const unsigned int num = ARRAY_SIZE(tps6586x_matches); + struct device_node *np = client->dev.of_node; + struct tps6586x_platform_data *pdata; + struct tps6586x_subdev_info *devs; + struct device_node *regs; + unsigned int count; + unsigned int i, j; + int err; + + regs = of_find_node_by_name(np, "regulators"); + if (!regs) + return NULL; + + err = of_regulator_match(&client->dev, regs, tps6586x_matches, num); + if (err < 0) { + of_node_put(regs); + return NULL; + } + + of_node_put(regs); + count = err; + + devs = devm_kzalloc(&client->dev, count * sizeof(*devs), GFP_KERNEL); + if (!devs) + return NULL; + + for (i = 0, j = 0; i < num && j < count; i++) { + if (!tps6586x_matches[i].init_data) + continue; + + devs[j].name = "tps6586x-regulator"; + devs[j].platform_data = tps6586x_matches[i].init_data; + devs[j].id = (int)tps6586x_matches[i].driver_data; + devs[j].of_node = tps6586x_matches[i].of_node; + j++; + } + + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->num_subdevs = count; + pdata->subdevs = devs; + pdata->gpio_base = -1; + pdata->irq_base = -1; + + return pdata; +} + +static struct of_device_id tps6586x_of_match[] = { + { .compatible = "ti,tps6586x", }, + { }, +}; +#else +static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *client) +{ + return NULL; +} +#endif + static int __devinit tps6586x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -481,6 +563,9 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, struct tps6586x *tps6586x; int ret; + if (!pdata && client->dev.of_node) + pdata = tps6586x_parse_dt(client); + if (!pdata) { dev_err(&client->dev, "tps6586x requires platform data\n"); return -ENOTSUPP; @@ -573,6 +658,7 @@ static struct i2c_driver tps6586x_driver = { .driver = { .name = "tps6586x", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tps6586x_of_match), }, .probe = tps6586x_i2c_probe, .remove = __devexit_p(tps6586x_i2c_remove), diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 7c2267e71f8b..6fc90befa79e 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -224,13 +224,6 @@ #define HIGH_PERF_SQ (1 << 3) #define CK32K_LOWPWR_EN (1 << 7) - -/* chip-specific feature flags, for i2c_device_id.driver_data */ -#define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */ -#define TPS_SUBSET BIT(1) /* tps659[23]0 have fewer LDOs */ -#define TWL5031 BIT(2) /* twl5031 has different registers */ -#define TWL6030_CLASS BIT(3) /* TWL6030 class */ - /*----------------------------------------------------------------------*/ /* is driver active, bound to a chip? */ diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 28b81ae4cf7f..c3482b954cb7 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -27,13 +27,8 @@ struct pm8607_regulator_info { unsigned int *vol_table; unsigned int *vol_suspend; - int vol_reg; - int vol_shift; - int vol_nbits; int update_reg; int update_bit; - int enable_reg; - int enable_bit; int slope_double; }; @@ -216,7 +211,7 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); int ret = -EINVAL; - if (info->vol_table && (index < (1 << info->vol_nbits))) { + if (info->vol_table && (index < rdev->desc->n_voltages)) { ret = info->vol_table[index]; if (info->slope_double) ret <<= 1; @@ -224,51 +219,16 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) return ret; } -static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) +static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - int i, ret = -ENOENT; - - if (info->slope_double) { - min_uV = min_uV >> 1; - max_uV = max_uV >> 1; - } - if (info->vol_table) { - for (i = 0; i < (1 << info->vol_nbits); i++) { - if (!info->vol_table[i]) - break; - if ((min_uV <= info->vol_table[i]) - && (max_uV >= info->vol_table[i])) { - ret = i; - break; - } - } - } - if (ret < 0) - pr_err("invalid voltage range (%d %d) uV\n", min_uV, max_uV); - return ret; -} - -static int pm8607_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, unsigned *selector) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - uint8_t val, mask; + uint8_t val; int ret; - if (min_uV > max_uV) { - pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); - return -EINVAL; - } + val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1)); - ret = choose_voltage(rdev, min_uV, max_uV); - if (ret < 0) - return -EINVAL; - *selector = ret; - val = (uint8_t)(ret << info->vol_shift); - mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; - - ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val); + ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, val); if (ret) return ret; switch (info->desc.id) { @@ -282,60 +242,16 @@ static int pm8607_set_voltage(struct regulator_dev *rdev, return ret; } -static int pm8607_get_voltage(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - uint8_t val, mask; - int ret; - - ret = pm860x_reg_read(info->i2c, info->vol_reg); - if (ret < 0) - return ret; - - mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; - val = ((unsigned char)ret & mask) >> info->vol_shift; - - return pm8607_list_voltage(rdev, val); -} - -static int pm8607_enable(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - - return pm860x_set_bits(info->i2c, info->enable_reg, - 1 << info->enable_bit, - 1 << info->enable_bit); -} - -static int pm8607_disable(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - - return pm860x_set_bits(info->i2c, info->enable_reg, - 1 << info->enable_bit, 0); -} - -static int pm8607_is_enabled(struct regulator_dev *rdev) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - int ret; - - ret = pm860x_reg_read(info->i2c, info->enable_reg); - if (ret < 0) - return ret; - - return !!((unsigned char)ret & (1 << info->enable_bit)); -} - static struct regulator_ops pm8607_regulator_ops = { - .set_voltage = pm8607_set_voltage, - .get_voltage = pm8607_get_voltage, - .enable = pm8607_enable, - .disable = pm8607_disable, - .is_enabled = pm8607_is_enabled, + .list_voltage = pm8607_list_voltage, + .set_voltage_sel = pm8607_set_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, }; -#define PM8607_DVC(vreg, nbits, ureg, ubit, ereg, ebit) \ +#define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \ { \ .desc = { \ .name = #vreg, \ @@ -343,20 +259,20 @@ static struct regulator_ops pm8607_regulator_ops = { .type = REGULATOR_VOLTAGE, \ .id = PM8607_ID_##vreg, \ .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(vreg##_table), \ + .vsel_reg = PM8607_##vreg, \ + .vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \ + .enable_reg = PM8607_##ereg, \ + .enable_mask = 1 << (ebit), \ }, \ - .vol_reg = PM8607_##vreg, \ - .vol_shift = (0), \ - .vol_nbits = (nbits), \ .update_reg = PM8607_##ureg, |