diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-03 10:09:29 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-03 10:09:29 -0700 |
commit | ec1882a9391c55332ebf3d1654f40b76e4a6c010 (patch) | |
tree | a72da16d78b1a62e6f4ee01444dd93f0d7a296c1 | |
parent | 5d3fed701d75ac6888f892ea2eb7c5dcc7831750 (diff) | |
parent | a584862221426f461f56674d30fe0d712ee63d00 (diff) | |
download | linux-ec1882a9391c55332ebf3d1654f40b76e4a6c010.tar.gz linux-ec1882a9391c55332ebf3d1654f40b76e4a6c010.tar.bz2 linux-ec1882a9391c55332ebf3d1654f40b76e4a6c010.zip |
Merge tag 'regulator-v3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown:
"Not much exciting going on with the regulator API this time around,
lots of driver fixes and enhancements - the main thing is the addition
of a new API to help make the stubbing code do the right thing for
missing regulator mappings.
Highlights:
- A new regulator_get_optional() API call for regulators that can be
absent in normal operation. This currently does nothing but will
be used to improve the stubbing code for unspecified regulators,
helping avoid some of the issues we've seen with adding new
regulator support.
- Helpers for devices with multiple linear ranges of voltages in the
same regulator.
- Moved the helpers into a separate file since core.c is getting
rather large.
- New drivers for Dialog DA9210 and DA9063, Freescale pfuze100 and
Marvell 88pm800"
* tag 'regulator-v3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (70 commits)
regulator: da9063: Statize da9063_ldo_lim_event
regulator: lp872x: Make REGULATOR_LP872X depend on I2C rather than I2C=y
regulator: tps65217: Convert to use linear ranges
regulator: da9063: Use IS_ERR to check return value of regulator_register()
regulator: da9063: Optimize da9063_set_current_limit implementation
regulator: build: Allow most regulators to be built as modules
regulator: Add devm_regulator_get_exclusive()
regulator: da9063: Add Dialog DA9063 voltage regulators support.
regulator: ti-abb: simplify platform_get_resource_byname/devm_ioremap_resource
hwmon: (sht15) Use devm_regulator_get_optional()
regulator: core: Use bool for exclusivitity flag
regulator: 88pm800: forever loop in pm800_regulator_probe()
cpufreq: cpufreq-cpu0: Use devm_regulator_get_optional()
regulator: da9210: Remove redundant MODULE_ALIAS
regulator: 88pm800: Fix checking whether num_regulator is valid
regulator: s2mps11: Fix setting ramp_delay
regulator: s2mps11: Fix wrong arguments for regmap_update_bits() call
regulator: palmas: Update the DT binding doc for smps10 out1 and out2
regulator: palmas: model SMPS10 as two regulators
regulator: core: Move list_voltage_{linear,linear_range,table} to helpers.c
...
72 files changed, 3840 insertions, 1116 deletions
diff --git a/Documentation/devicetree/bindings/regulator/88pm800.txt b/Documentation/devicetree/bindings/regulator/88pm800.txt new file mode 100644 index 000000000000..e8a54c2a5821 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/88pm800.txt @@ -0,0 +1,38 @@ +Marvell 88PM800 regulator + +Required properties: +- compatible: "marvell,88pm800" +- reg: I2C slave address +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name (or the deprecated + regulator-compatible property if present), with valid values listed below. + The content of each sub-node is defined by the standard binding for + regulators; see regulator.txt. + +The valid names for regulators are: + + buck1, buck2, buck3, buck4, buck5, ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7, + ldo8, ldo9, ldo10, ldo11, ldo12, ldo13, ldo14, ldo15, ldo16, ldo17, ldo18, ldo19 + +Example: + + pmic: 88pm800@31 { + compatible = "marvell,88pm800"; + reg = <0x31>; + + regulators { + buck1 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3950000>; + regulator-boot-on; + regulator-always-on; + }; + ldo1 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <15000000>; + regulator-boot-on; + regulator-always-on; + }; +... + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/max8660.txt b/Documentation/devicetree/bindings/regulator/max8660.txt new file mode 100644 index 000000000000..8ba994d8a142 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/max8660.txt @@ -0,0 +1,47 @@ +Maxim MAX8660 voltage regulator + +Required properties: +- compatible: must be one of "maxim,max8660", "maxim,max8661" +- reg: I2C slave address, usually 0x34 +- any required generic properties defined in regulator.txt + +Example: + + i2c_master { + max8660@34 { + compatible = "maxim,max8660"; + reg = <0x34>; + + regulators { + regulator@0 { + regulator-compatible= "V3(DCDC)"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1800000>; + }; + + regulator@1 { + regulator-compatible= "V4(DCDC)"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1800000>; + }; + + regulator@2 { + regulator-compatible= "V5(LDO)"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2000000>; + }; + + regulator@3 { + regulator-compatible= "V6(LDO)"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + regulator@4 { + regulator-compatible= "V7(LDO)"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt index 30b0581bb1ce..a22e4c70db5c 100644 --- a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt +++ b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt @@ -25,8 +25,8 @@ Optional nodes: Additional custom properties are listed below. For ti,palmas-pmic - smps12, smps123, smps3 depending on OTP, - smps45, smps457, smps7 depending on variant, smps6, smps[8-10], - ldo[1-9], ldoln, ldousb. + smps45, smps457, smps7 depending on variant, smps6, smps[8-9], + smps10_out2, smps10_out1, do[1-9], ldoln, ldousb. Optional sub-node properties: ti,warm-reset - maintain voltage during warm reset(boolean) diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt new file mode 100644 index 000000000000..fc989b2e8057 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt @@ -0,0 +1,115 @@ +PFUZE100 family of regulators + +Required properties: +- compatible: "fsl,pfuze100" +- reg: I2C slave address + +Required child node: +- regulators: This is the list of child nodes that specify the regulator + initialization data for defined regulators. Please refer to below doc + Documentation/devicetree/bindings/regulator/regulator.txt. + + The valid names for regulators are: + sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6 + +Each regulator is defined using the standard binding for regulators. + +Example: + + pmic: pfuze100@08 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 48a3b8e5d6bd..2bd8f0978765 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -12,6 +12,8 @@ Optional properties: - regulator-allow-bypass: allow the regulator to go into bypass mode - <name>-supply: phandle to the parent supply/regulator node - regulator-ramp-delay: ramp delay for regulator(in uV/uS) + For hardwares which support disabling ramp rate, it should be explicitly + intialised to zero (regulator-ramp-delay = <0>) for disabling ramp delay. Deprecated properties: - regulator-compatible: If a regulator chip contains multiple diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index ad1fde277661..e9dedb27deca 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -197,7 +197,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) cpu_dev = &pdev->dev; cpu_dev->of_node = np; - cpu_reg = devm_regulator_get(cpu_dev, "cpu0"); + cpu_reg = devm_regulator_get_optional(cpu_dev, "cpu0"); if (IS_ERR(cpu_reg)) { /* * If cpu0 regulator supply node is present, but regulator is diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 2507f902fb7a..ab5dc3af4cfb 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -957,7 +957,7 @@ static int sht15_probe(struct platform_device *pdev) * If a regulator is available, * query what the supply voltage actually is! */ - data->reg = devm_regulator_get(data->dev, "vcc"); + data->reg = devm_regulator_get_optional(data->dev, "vcc"); if (!IS_ERR(data->reg)) { int voltage; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 49a5bca418bd..5d088551196b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1313,7 +1313,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) supply = devm_regulator_get(dev, "vmmc"); mmc->supply.vmmc = supply; - mmc->supply.vqmmc = devm_regulator_get(dev, "vqmmc"); + mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc"); if (IS_ERR(supply)) return PTR_ERR(supply); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index ee5f1676f14e..542407363dd2 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2231,7 +2231,7 @@ int dw_mci_probe(struct dw_mci *host) } } - host->vmmc = devm_regulator_get(host->dev, "vmmc"); + host->vmmc = devm_regulator_get_optional(host->dev, "vmmc"); if (IS_ERR(host->vmmc)) { ret = PTR_ERR(host->vmmc); if (ret == -EPROBE_DEFER) diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 2c5a91bb8ec3..1956a3df7cf3 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -83,7 +83,7 @@ struct pxamci_host { static inline void pxamci_init_ocr(struct pxamci_host *host) { #ifdef CONFIG_REGULATOR - host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); + host->vcc = regulator_get_optional(mmc_dev(host->mmc), "vmmc"); if (IS_ERR(host->vcc)) host->vcc = NULL; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a78bd4f3aecc..dd2c083c434d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2966,7 +2966,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->caps |= MMC_CAP_NEEDS_POLL; /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ - host->vqmmc = regulator_get(mmc_dev(mmc), "vqmmc"); + host->vqmmc = regulator_get_optional(mmc_dev(mmc), "vqmmc"); if (IS_ERR_OR_NULL(host->vqmmc)) { if (PTR_ERR(host->vqmmc) < 0) { pr_info("%s: no vqmmc regulator found\n", @@ -3042,7 +3042,7 @@ int sdhci_add_host(struct sdhci_host *host) ocr_avail = 0; - host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); + host->vmmc = regulator_get_optional(mmc_dev(mmc), "vmmc"); if (IS_ERR_OR_NULL(host->vmmc)) { if (PTR_ERR(host->vmmc) < 0) { pr_info("%s: no vmmc regulator found\n", diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c new file mode 100644 index 000000000000..3459f60dcfd1 --- /dev/null +++ b/drivers/regulator/88pm800.c @@ -0,0 +1,383 @@ +/* + * Regulators driver for Marvell 88PM800 + * + * Copyright (C) 2012 Marvell International Ltd. + * Joseph(Yossi) Hanin <yhanin@marvell.com> + * Yi Zhang <yizhang@marvell.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/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/88pm80x.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/regulator/of_regulator.h> + +/* LDO1 with DVC[0..3] */ +#define PM800_LDO1_VOUT (0x08) /* VOUT1 */ +#define PM800_LDO1_VOUT_2 (0x09) +#define PM800_LDO1_VOUT_3 (0x0A) +#define PM800_LDO2_VOUT (0x0B) +#define PM800_LDO3_VOUT (0x0C) +#define PM800_LDO4_VOUT (0x0D) +#define PM800_LDO5_VOUT (0x0E) +#define PM800_LDO6_VOUT (0x0F) +#define PM800_LDO7_VOUT (0x10) +#define PM800_LDO8_VOUT (0x11) +#define PM800_LDO9_VOUT (0x12) +#define PM800_LDO10_VOUT (0x13) +#define PM800_LDO11_VOUT (0x14) +#define PM800_LDO12_VOUT (0x15) +#define PM800_LDO13_VOUT (0x16) +#define PM800_LDO14_VOUT (0x17) +#define PM800_LDO15_VOUT (0x18) +#define PM800_LDO16_VOUT (0x19) +#define PM800_LDO17_VOUT (0x1A) +#define PM800_LDO18_VOUT (0x1B) +#define PM800_LDO19_VOUT (0x1C) + +/* BUCK1 with DVC[0..3] */ +#define PM800_BUCK1 (0x3C) +#define PM800_BUCK1_1 (0x3D) +#define PM800_BUCK1_2 (0x3E) +#define PM800_BUCK1_3 (0x3F) +#define PM800_BUCK2 (0x40) +#define PM800_BUCK3 (0x41) +#define PM800_BUCK3 (0x41) +#define PM800_BUCK4 (0x42) +#define PM800_BUCK4_1 (0x43) +#define PM800_BUCK4_2 (0x44) +#define PM800_BUCK4_3 (0x45) +#define PM800_BUCK5 (0x46) + +#define PM800_BUCK_ENA (0x50) +#define PM800_LDO_ENA1_1 (0x51) +#define PM800_LDO_ENA1_2 (0x52) +#define PM800_LDO_ENA1_3 (0x53) + +#define PM800_LDO_ENA2_1 (0x56) +#define PM800_LDO_ENA2_2 (0x57) +#define PM800_LDO_ENA2_3 (0x58) + +#define PM800_BUCK1_MISC1 (0x78) +#define PM800_BUCK3_MISC1 (0x7E) +#define PM800_BUCK4_MISC1 (0x81) +#define PM800_BUCK5_MISC1 (0x84) + +struct pm800_regulator_info { + struct regulator_desc desc; + int max_ua; +}; + +struct pm800_regulators { + struct regulator_dev *regulators[PM800_ID_RG_MAX]; + struct pm80x_chip *chip; + struct regmap *map; +}; + +/* + * vreg - the buck regs string. + * ereg - the string for the enable register. + * ebit - the bit number in the enable register. + * amax - the current + * Buck has 2 kinds of voltage steps. It is easy to find voltage by ranges, + * not the constant voltage table. + * n_volt - Number of available selectors + */ +#define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges, n_volt) \ +{ \ + .desc = { \ + .name = #vreg, \ + .ops = &pm800_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PM800_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = n_volt, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ + .vsel_reg = PM800_##vreg, \ + .vsel_mask = 0x7f, \ + .enable_reg = PM800_##ereg, \ + .enable_mask = 1 << (ebit), \ + }, \ + .max_ua = (amax), \ +} + +/* + * vreg - the LDO regs string + * ereg - the string for the enable register. + * ebit - the bit number in the enable register. + * amax - the current + * volt_table - the LDO voltage table + * For all the LDOes, there are too many ranges. Using volt_table will be + * simpler and faster. + */ +#define PM800_LDO(vreg, ereg, ebit, amax, ldo_volt_table) \ +{ \ + .desc = { \ + .name = #vreg, \ + .ops = &pm800_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PM800_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(ldo_volt_table), \ + .vsel_reg = PM800_##vreg##_VOUT, \ + .vsel_mask = 0x1f, \ + .enable_reg = PM800_##ereg, \ + .enable_mask = 1 << (ebit), \ + .volt_table = ldo_volt_table, \ + }, \ + .max_ua = (amax), \ +} + +/* Ranges are sorted in ascending order. */ +static const struct regulator_linear_range buck1_volt_range[] = { + { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f, + .uV_step = 12500 }, + { .min_uV = 1600000, .max_uV = 1800000, .min_sel = 0x50, + .max_sel = 0x54, .uV_step = 50000 }, +}; + +/* BUCK 2~5 have same ranges. */ +static const struct regulator_linear_range buck2_5_volt_range[] = { + { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f, + .uV_step = 12500 }, + { .min_uV = 1600000, .max_uV = 3300000, .min_sel = 0x50, + .max_sel = 0x72, .uV_step = 50000 }, +}; + +static const unsigned int ldo1_volt_table[] = { + 600000, 650000, 700000, 750000, 800000, 850000, 900000, 950000, + 1000000, 1050000, 1100000, 1150000, 1200000, 1300000, 1400000, 1500000, +}; + +static const unsigned int ldo2_volt_table[] = { + 1700000, 1800000, 1900000, 2000000, 2100000, 2500000, 2700000, 2800000, +}; + +/* LDO 3~17 have same voltage table. */ +static const unsigned int ldo3_17_volt_table[] = { + 1200000, 1250000, 1700000, 1800000, 1850000, 1900000, 2500000, 2600000, + 2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000, +}; + +/* LDO 18~19 have same voltage table. */ +static const unsigned int ldo18_19_volt_table[] = { + 1700000, 1800000, 1900000, 2500000, 2800000, 2900000, 3100000, 3300000, +}; + +static int pm800_get_current_limit(struct regulator_dev *rdev) +{ + struct pm800_regulator_info *info = rdev_get_drvdata(rdev); + + return info->max_ua; +} + +static struct regulator_ops pm800_volt_range_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .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, + .get_current_limit = pm800_get_current_limit, +}; + +static struct regulator_ops pm800_volt_table_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .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, + .get_current_limit = pm800_get_current_limit, +}; + +/* The array is indexed by id(PM800_ID_XXX) */ +static struct pm800_regulator_info pm800_regulator_info[] = { + PM800_BUCK(BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range, 0x55), + PM800_BUCK(BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range, 0x73), + + PM800_LDO(LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table), + PM800_LDO(LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table), + PM800_LDO(LDO3, LDO_ENA1_1, 2, 300000, ldo3_17_volt_table), + PM800_LDO(LDO4, LDO_ENA1_1, 3, 300000, ldo3_17_volt_table), + PM800_LDO(LDO5, LDO_ENA1_1, 4, 300000, ldo3_17_volt_table), + PM800_LDO(LDO6, LDO_ENA1_1, 5, 300000, ldo3_17_volt_table), + PM800_LDO(LDO7, LDO_ENA1_1, 6, 300000, ldo3_17_volt_table), + PM800_LDO(LDO8, LDO_ENA1_1, 7, 300000, ldo3_17_volt_table), + PM800_LDO(LDO9, LDO_ENA1_2, 0, 300000, ldo3_17_volt_table), + PM800_LDO(LDO10, LDO_ENA1_2, 1, 300000, ldo3_17_volt_table), + PM800_LDO(LDO11, LDO_ENA1_2, 2, 300000, ldo3_17_volt_table), + PM800_LDO(LDO12, LDO_ENA1_2, 3, 300000, ldo3_17_volt_table), + PM800_LDO(LDO13, LDO_ENA1_2, 4, 300000, ldo3_17_volt_table), + PM800_LDO(LDO14, LDO_ENA1_2, 5, 300000, ldo3_17_volt_table), + PM800_LDO(LDO15, LDO_ENA1_2, 6, 300000, ldo3_17_volt_table), + PM800_LDO(LDO16, LDO_ENA1_2, 7, 300000, ldo3_17_volt_table), + PM800_LDO(LDO17, LDO_ENA1_3, 0, 300000, ldo3_17_volt_table), + PM800_LDO(LDO18, LDO_ENA1_3, 1, 200000, ldo18_19_volt_table), + PM800_LDO(LDO19, LDO_ENA1_3, 2, 200000, ldo18_19_volt_table), +}; + +#define PM800_REGULATOR_OF_MATCH(_name, _id) \ + [PM800_ID_##_id] = { \ + .name = #_name, \ + .driver_data = &pm800_regulator_info[PM800_ID_##_id], \ + } + +static struct of_regulator_match pm800_regulator_matches[] = { + PM800_REGULATOR_OF_MATCH(buck1, BUCK1), + PM800_REGULATOR_OF_MATCH(buck2, BUCK2), + PM800_REGULATOR_OF_MATCH(buck3, BUCK3), + PM800_REGULATOR_OF_MATCH(buck4, BUCK4), + PM800_REGULATOR_OF_MATCH(buck5, BUCK5), + PM800_REGULATOR_OF_MATCH(ldo1, LDO1), + PM800_REGULATOR_OF_MATCH(ldo2, LDO2), + PM800_REGULATOR_OF_MATCH(ldo3, LDO3), + PM800_REGULATOR_OF_MATCH(ldo4, LDO4), + PM800_REGULATOR_OF_MATCH(ldo5, LDO5), + PM800_REGULATOR_OF_MATCH(ldo6, LDO6), + PM800_REGULATOR_OF_MATCH(ldo7, LDO7), + PM800_REGULATOR_OF_MATCH(ldo8, LDO8), + PM800_REGULATOR_OF_MATCH(ldo9, LDO9), + PM800_REGULATOR_OF_MATCH(ldo10, LDO10), + PM800_REGULATOR_OF_MATCH(ldo11, LDO11), + PM800_REGULATOR_OF_MATCH(ldo12, LDO12), + PM800_REGULATOR_OF_MATCH(ldo13, LDO13), + PM800_REGULATOR_OF_MATCH(ldo14, LDO14), + PM800_REGULATOR_OF_MATCH(ldo15, LDO15), + PM800_REGULATOR_OF_MATCH(ldo16, LDO16), + PM800_REGULATOR_OF_MATCH(ldo17, LDO17), + PM800_REGULATOR_OF_MATCH(ldo18, LDO18), + PM800_REGULATOR_OF_MATCH(ldo19, LDO19), +}; + +static int pm800_regulator_dt_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + + ret = of_regulator_match(&pdev->dev, np, + pm800_regulator_matches, + ARRAY_SIZE(pm800_regulator_matches)); + if (ret < 0) + return ret; + + return 0; +} + +static int pm800_regulator_probe(struct platform_device *pdev) +{ + struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct pm80x_platform_data *pdata = dev_get_platdata(pdev->dev.parent); + struct pm800_regulators *pm800_data; + struct pm800_regulator_info *info; + struct regulator_config config = { }; + struct regulator_init_data *init_data; + int i, ret; + + if (!pdata || pdata->num_regulators == 0) { + if (IS_ENABLED(CONFIG_OF)) { + ret = pm800_regulator_dt_init(pdev); + if (ret) + return ret; + } else { + return -ENODEV; + } + } else if (pdata->num_regulators) { + unsigned int count = 0; + + /* Check whether num_regulator is valid. */ + for (i = 0; i < ARRAY_SIZE(pdata->regulators); i++) { + if (pdata->regulators[i]) + count++; + } + if (count != pdata->num_regulators) + return -EINVAL; + } else { + return -EINVAL; + } + + pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data), + GFP_KERNEL); + if (!pm800_data) { + dev_err(&pdev->dev, "Failed to allocate pm800_regualtors"); + return -ENOMEM; + } + + pm800_data->map = chip->subchip->regmap_power; + pm800_data->chip = chip; + + platform_set_drvdata(pdev, pm800_data); + + for (i = 0; i < PM800_ID_RG_MAX; i++) { + if (!pdata || pdata->num_regulators == 0) + init_data = pm800_regulator_matches[i].init_data; + else + init_data = pdata->regulators[i]; + if (!init_data) + continue; + info = pm800_regulator_matches[i].driver_data; + config.dev = &pdev->dev; + config.init_data = init_data; + config.driver_data = info; + config.regmap = pm800_data->map; + config.of_node = pm800_regulator_matches[i].of_node; + + pm800_data->regulators[i] = + regulator_register(&info->desc, &config); + if (IS_ERR(pm800_data->regulators[i])) { + ret = PTR_ERR(pm800_data->regulators[i]); + dev_err(&pdev->dev, "Failed to register %s\n", + info->desc.name); + + while (--i >= 0) + regulator_unregister(pm800_data->regulators[i]); + + return ret; + } + } + + return 0; +} + +static int pm800_regulator_remove(struct platform_device *pdev) +{ + struct pm800_regulators *pm800_data = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < PM800_ID_RG_MAX; i++) + regulator_unregister(pm800_data->regulators[i]); + + return 0; +} + +static struct platform_driver pm800_regulator_driver = { + .driver = { + .name = "88pm80x-regulator", + .owner = THIS_MODULE, + }, + .probe = pm800_regulator_probe, + .remove = pm800_regulator_remove, +}; + +module_platform_driver(pm800_regulator_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Joseph(Yossi) Hanin <yhanin@marvell.com>"); +MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM800 PMIC"); +MODULE_ALIAS("platform:88pm800-regulator"); diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 8a7cb1f43046..70230974468c 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -346,7 +346,7 @@ 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; - struct regulator_init_data *pdata = pdev->dev.platform_data; + struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev); struct regulator_config config = { }; struct resource *res; int i; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index f1e6ad98eeba..dfe58096b374 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -64,15 +64,21 @@ config REGULATOR_USERSPACE_CONSUMER If unsure, say no. -config REGULATOR_GPIO - tristate "GPIO regulator support" - depends on GPIOLIB +config REGULATOR_88PM800 + tristate "Marvell 88PM800 Power regulators" + depends on MFD_88PM800 help - This driver provides support for regulators that can be - controlled via gpios. - It is capable of supporting current and voltage regulators - and the platform has to provide a mapping of GPIO-states - to target volts/amps. + This driver supports Marvell 88PM800 voltage regulator chips. + It delivers digitally programmable output, + the voltage is programmed via I2C interface. + It's suitable to support PXA988 chips to control VCC_MAIN and + various voltages. + +config REGULATOR_88PM8607 + tristate "Marvell 88PM8607 Power regulators" + depends on MFD_88PM860X=y + help + This driver supports 88PM8607 voltage regulator chips. config REGULATOR_AD5398 tristate "Analog Devices AD5398/AD5821 regulators" @@ -81,6 +87,14 @@ config REGULATOR_AD5398 This driver supports AD5398 and AD5821 current regulator chips. If building into module, its name is ad5398.ko. +config REGULATOR_ANATOP + tristate "Freescale i.MX on-chip ANATOP LDO regulators" + depends on MFD_SYSCON + help + Say y here to support Freescale i.MX on-chip ANATOP LDOs + regulators. It is recommended that this option be + enabled on i.MX6 platform. + config REGULATOR_AAT2870 tristate "AnalogicTech AAT2870 Regulators" depends on MFD_AAT2870_CORE @@ -88,6 +102,22 @@ config REGULATOR_AAT2870 If you have a AnalogicTech AAT2870 say Y to enable the regulator driver. +config REGULATOR_AB3100 + tristate "ST-Ericsson AB3100 Regulator functions" + depends on AB3100_CORE + default y if AB3100_CORE + help + These regulators correspond to functionality in the + AB3100 analog baseband dealing with power regulators + for the system. + +config REGULATOR_AB8500 + bool "ST-Ericsson AB8500 Power Regulators" + depends on AB8500_CORE + help + This driver supports the regulators found on the ST-Ericsson mixed + signal AB8500 PMIC + config REGULATOR_ARIZONA tristate "Wolfson Arizona class devices" depends on MFD_ARIZONA @@ -96,6 +126,13 @@ config REGULATOR_ARIZONA Support for the regulators found on Wolfson Arizona class devices. +config REGULATOR_AS3711 + tristate "AS3711 PMIC" + depends on MFD_AS3711 + help + This driver provides support for the voltage regulators on the + AS3711 PMIC + config REGULATOR_DA903X tristate "Dialog Semiconductor DA9030/DA9034 regulators" depends on PMIC_DA903X @@ -120,6 +157,37 @@ config REGULATOR_DA9055 This driver can also be built as a module. If so, the module will be called da9055-regulator. +config REGULATOR_DA9063 + tristate "Dialog Semiconductor DA9063 regulators" + depends on MFD_DA9063 + help + Say y here to support the BUCKs and LDOs regulators found on + DA9063 PMICs. + + This driver can also be built as a module. If so, the module + will be called da9063-regulator. + +config REGULATOR_DA9210 + tristate "Dialog Semiconductor DA9210 regulator" + depends on I2C + select REGMAP_I2C + help + Say y here to support for the Dialog Semiconductor DA9210. + The DA9210 is a multi-phase synchronous step down + converter 12A DC-DC Buck controlled through an I2C + interface. + +config REGULATOR_DBX500_PRCMU + bool + +config REGULATOR_DB8500_PRCMU + bool "ST-Ericsson DB8500 Voltage Domain Regulators" + depends on MFD_DB8500_PRCMU + select REGULATOR_DBX500_PRCMU + help + This driver supports the voltage domain regulators controlled by the + DB8500 PRCMU + config REGULATOR_FAN53555 tristate "Fairchild FAN53555 Regulator" depends on I2C @@ -131,44 +199,57 @@ config REGULATOR_FAN53555 input voltage supply of 2.5V to 5.5V. The output voltage is programmed through an I2C interface. -config REGULATOR_ANATOP - tristate "Freescale i.MX on-chip ANATOP LDO regulators" - depends on MFD_SYSCON +config REGULATOR_GPIO + tristate "GPIO regulator support" + depends on GPIOLIB help - Say y here to support Freescale i.MX on-chip ANATOP LDOs - regulators. It is recommended that this option be - enabled on i.MX6 platform. + This driver provides support for regulators that can be + controlled via gpios. + It is capable of supporting current and voltage regulators + and the platform has to provide a mapping of GPIO-states + to target volts/amps. -config REGULATOR_MC13XXX_CORE - tristate +config REGULATOR_ISL6271A + tristate "Intersil ISL6271A Power regulator" + depends on I2C + help + This driver supports ISL6271A voltage regulator chip. -config REGULATOR_MC13783 - tristate "Freescale MC13783 regulator driver" - depends on MFD_MC13783 - select REGULATOR_MC13XXX_CORE +config REGULATOR_LP3971 + tristate "National Semiconductors LP3971 PMIC regulator driver" + depends on I2C help - Say y here to support the regulators found on the Freescale MC13783 - PMIC. + Say Y here to support the voltage regulators and convertors + on National Semiconductors LP3971 PMIC -config REGULATOR_MC13892 - tristate "Freescale MC13892 regulator driver" - depends on MFD_MC13XXX - select REGULATOR_MC13XXX_CORE +config REGULATOR_LP3972 + tristate "National Semiconductors LP3972 PMIC regulator driver" + depends on I2C help - Say y here to support the regulators found on the Freescale MC13892 - PMIC. + Say Y here to support the voltage regulators and convertors + on National Semiconductors LP3972 PMIC -config REGULATOR_ISL6271A - tristate "Intersil ISL6271A Power regulator" +config REGULATOR_LP872X + tristate "TI/National Semiconductor LP8720/LP8725 voltage regulators" depends on I2C + select REGMAP_I2C help - This driver supports ISL6271A voltage regulator chip. + This driver supports LP8720/LP8725 PMIC -config REGULATOR_88PM8607 - bool "Marvell 88PM8607 Power regulators" - depends on MFD_88PM860X=y +config REGULATOR_LP8755 + tristate "TI LP8755 High Performance PMU driver" + depends on I2C + select REGMAP_I2C help - This driver supports 88PM8607 voltage regulator chips. + 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 + tristate "TI LP8788 Power Regulators" + depends on MFD_LP8788 + help + This driver supports LP8788 voltage regulator chip. config REGULATOR_MAX1586 tristate "Maxim 1586/1587 voltage regulator" @@ -259,48 +340,43 @@ config REGULATOR_MAX77693 and one current regulator 'CHARGER'. This is suitable for Exynos-4x12 chips. -config REGULATOR_PCAP - tristate "Motorola PCAP2 regulator driver" - depends on EZX_PCAP - help - This driver provides support for the voltage regulators of the - PCAP2 PMIC. +config REGULATOR_MC13XXX_CORE + tristate -config REGULATOR_LP3971 - tristate "National Semiconductors LP3971 PMIC regulator driver" - depends on I2C +config REGULATOR_MC13783 + tristate "Freescale MC13783 regulator driver" + depends on MFD_MC13783 + select REGULATOR_MC13XXX_CORE help - Say Y here to support the voltage regulators and convertors - on National Semiconductors LP3971 PMIC + Say y here to support the regulators found on the Freescale MC13783 + PMIC. -config REGULATOR_LP3972 - tristate "National Semiconductors LP3972 PMIC regulator driver" - depends on I2C +config REGULATOR_MC13892 + tristate "Freescale MC13892 regulator driver" + depends on MFD_MC13XXX + select REGULATOR_MC13XXX_CORE help - Say Y here to support the voltage regulators and convertors - on National Semiconductors LP3972 PMIC + Say y here to support the regulators found on the Freescale MC13892 + PMIC. -config REGULATOR_LP872X - bool "TI/National Semiconductor LP8720/LP8725 voltage regulators" - depends on I2C=y - select REGMAP_I2C +config REGULATOR_PALMAS + tristate "TI Palmas PMIC Regulators" + depends on MFD_PALMAS help - This driver supports LP8720/LP8725 PMIC + If you wish to control the regulators on the Palmas series of + chips say Y here. This will enable support for all the software + controllable SMPS/LDO regulators. -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. + The regulators available on Palmas series chips vary depending + on the muxing. This is handled automatically in the driver by + reading the mux info from OTP. -config REGULATOR_LP8788 - bool "TI LP8788 Power Regulators" - depends on MFD_LP8788 +config REGULATOR_PCAP + tristate "Motorola PCAP2 regulator driver" + depends on EZX_PCAP help - This driver supports LP8788 voltage regulator chip. + This driver provides support for the voltage regulators of the + PCAP2 PMIC. config REGULATOR_PCF50633 tristate "NXP PCF50633 regulator driver" @@ -309,6 +385,14 @@ config REGULATOR_PCF50633 Say Y here to support the voltage regulators and convertors on PCF50633 +config REGULATOR_PFUZE100 + tristate "Support regulators on Freescale PFUZE100 PMIC" + depends on I2C + select REGMAP_I2C + help + Say y here to support the regulators found on the Freescale PFUZE100 + PMIC. + config REGULATOR_RC5T583 tristate "RICOH RC5T583 Power regulators" depends on MFD_RC5T583 @@ -335,44 +419,15 @@ config REGULATOR_S5M8767 via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and supports DVS mode with 8bits of output voltage control. -config REGULATOR_AB3100 - tristate "ST-Ericsson AB3100 Regulator functions" - depends on AB3100_CORE - default y if AB3100_CORE - help - These regulators correspond to functionality in the - AB3100 analog baseband dealing with power regulators - for the system. - -config REGULATOR_AB8500 - bool "ST-Ericsson AB8500 Power Regulators" - depends on AB8500_CORE - help - This driver supports the regulators found on the ST-Ericsson mixed - signal AB8500 PMIC - -config REGULATOR_DBX500_PRCMU - bool - -config REGULATOR_DB8500_PRCMU - bool "ST-Ericsson DB8500 Voltage Domain Regulators" - depends on MFD_DB8500_PRCMU - select REGULATOR_DBX500_PRCMU - help - This driver supports the voltage domain regulators controlled by the - DB8500 PRCMU - -config REGULATOR_PALMAS - tristate "TI Palmas PMIC Regulators" - depends on MFD_PALMAS +config REGULATOR_TI_ABB + tristate "TI Adaptive Body Bias on-chip LDO" + depends on ARCH_OMAP help - If you wish to control the regulators on the Palmas series of - chips say Y here. This will enable support for all the software - controllable SMPS/LDO regulators. - - The regulators available on Palmas series chips vary depending - on the muxing. This is handled automatically in the driver by - reading the mux info from OTP. + Select this option to support Texas Instruments' on-chip Adaptive Body + Bias (ABB) LDO regulators. It is recommended that this option be + enabled on required TI SoC. Certain Operating Performance Points + on TI SoCs may be unstable without enabling this as it provides + device specific optimized bias to allow/optimize functionality. config REGULATOR_TPS51632 tristate "TI TPS51632 Power Regulator" @@ -475,22 +530,12 @@ config REGULATOR_TPS80031 output to control regulators. config REGULATOR_TWL4030 - bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" + tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" depends on TWL4030_CORE help This driver supports the voltage regulators provided by this family of companion chips. -config REGULATOR_TI_ABB - bool "TI Adaptive Body Bias on-chip LDO" - depends on ARCH_OMAP - help - Select this option to support Texas Instruments' on-chip Adaptive Body - Bias (ABB) LDO regulators. It is recommended that this option be - enabled on required TI SoC. Certain Operating Performance Points - on TI SoCs may be unstable without enabling this as it provides - device specific optimized bias to allow/optimize functionality. - config REGULATOR_VEXPRESS tristate "Versatile Express regulators" depends on VEXPRESS_CONFIG @@ -526,12 +571,5 @@ 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 ba4a3cf3afec..185cce246022 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -3,12 +3,13 @@ # -obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o +obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o obj-$(CONFIG_OF) += of_regulator.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o +obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o @@ -20,6 +21,8 @@ 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_DA9063) += da9063-regulator.o +obj-$(CONFIG_REGULATOR_DA9210) += da9210-regulator.o obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o @@ -46,12 +49,14 @@ 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_PFUZE100) += pfuze100-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 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o +obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o @@ -64,7 +69,6 @@ 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_TI_ABB) += ti-abb-regulator.o obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 8b5876356db9..881159dfcb5e 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -174,7 +174,7 @@ static int aat2870_regulator_probe(struct platform_device *pdev) config.dev = &pdev->dev; config.driver_data = ri; - config.init_data = pdev->dev.platform_data; + config.init_data = dev_get_platdata(&pdev->dev); rdev = regulator_register(&ri->desc, &config); if (IS_ERR(rdev)) { diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 3be9e46594a1..7d5eaa874b2d 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -660,7 +660,7 @@ ab3100_regulator_of_probe(struct platform_device *pdev, struct device_node *np) static int ab3100_regulators_probe(struct platform_device *pdev) { - struct ab3100_platform_data *plfdata = pdev->dev.platform_data; + struct ab3100_platform_data *plfdata = dev_get_platdata(&pdev->dev); struct device_node *np = pdev->dev.of_node; int err = 0; u8 data; diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index 6b981b5faa70..b2b203cb6b2f 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -214,7 +214,7 @@ MODULE_DEVICE_TABLE(i2c, ad5398_id); static int ad5398_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct regulator_init_data *init_data = client->dev.platform_data; + struct regulator_init_data *init_data = dev_get_platdata(&client->dev); struct regulator_config config = { }; struct ad5398_chip_info *chip; const struct ad5398_current_data_format *df = diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index 3da6bd6950cf..8406cd745da2 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -30,102 +30,6 @@ struct as3711_regulator { 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: @@ -180,44 +84,14 @@ static unsigned int as3711_get_mode_sd(struct regulator_dev *rdev) 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, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .get_mode = as3711_get_mode_sd, .set_mode = as3711_set_mode_sd, }; @@ -228,8 +102,8 @@ static struct regulator_ops as3711_aldo_ops = { .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, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, }; static struct regulator_ops as3711_dldo_ops = { @@ -238,8 +112,31 @@ static struct regulator_ops as3711_dldo_ops = { .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, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, +}; + +static const struct regulator_linear_range as3711_sd_ranges[] = { + { .min_uV = 612500, .max_uV = 1400000, + .min_sel = 0x1, .max_sel = 0x40, .uV_step = 12500 }, + { .min_uV = 1425000, .max_uV = 2600000, + .min_sel = 0x41, .max_sel = 0x70, .uV_step = 25000 }, + { .min_uV = 2650000, .max_uV = 3350000, + .min_sel = 0x71, .max_sel = 0x7f, .uV_step = 50000 }, +}; + +static const struct regulator_linear_range as3711_aldo_ranges[] = { + { .min_uV = 1200000, .max_uV = 1950000, + .min_sel = 0, .max_sel = 0xf, .uV_step = 50000 }, + { .min_uV = 1800000, .max_uV = 3300000, + .min_sel = 0x10, .max_sel = 0x1f, .uV_step = 100000 }, +}; + +static const struct regulator_linear_range as3711_dldo_ranges[] = { + { .min_uV = 900000, .max_uV = 1700000, + .min_sel = 0, .max_sel = 0x10, .uV_step = 50000 }, + { .min_uV = 1750000, .max_uV = 3300000, + .min_sel = 0x20, .max_sel = 0x3f, .uV_step = 50000 }, }; #define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx) \ @@ -256,6 +153,8 @@ static struct regulator_ops as3711_dldo_ops = { .enable_reg = AS3711_ ## _en_reg, \ .enable_mask = BIT(_en_bit), \ .min_uV = _min_uV, \ + .linear_ranges = as3711_ ## _sfx ## _ranges, \ + .n_linear_ranges = ARRAY_SIZE(as3711_ ## _sfx ## _ranges), \ }, \ .max_uV = _max_uV, \ } diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 288c75abc190..a01b8b3b70ca 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -323,13 +323,14 @@ static ssize_t regulator_uA_show(struct device *dev, } static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL); -static ssize_t regulator_name_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t name_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return sprintf(buf, "%s\n", rdev_get_name(rdev)); } +static DEVICE_ATTR_RO(name); static ssize_t regulator_print_opmode(char *buf, int mode) { @@ -489,15 +490,16 @@ static ssize_t regulator_total_uA_show(struct device *dev, } static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL); -static ssize_t regulator_num_users_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t num_users_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return sprintf(buf, "%d\n", rdev->use_count); } +static DEVICE_ATTR_RO(num_users); -static ssize_t regulator_type_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t type_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); @@ -509,6 +511,7 @@ static ssize_t regulator_type_show(struct device *dev, } return sprintf(buf, "unknown\n"); } +static DEVICE_ATTR_RO(type); static ssize_t regulator_suspend_mem_uV_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -632,12 +635,13 @@ static DEVICE_ATTR(bypass, 0444, * These are the only attributes are present for all regulators. * Other attributes are a function of regulator functionality. */ -static struct device_attribute regulator_dev_attrs[] = { - __ATTR(name, 0444, regulator_name_show, NULL), - __ATTR(num_users, 0444, regulator_num_users_show, NULL), - __ATTR(type, 0444, regulator_type_show, NULL), - __ATTR_NULL, +static struct attribute *regulator_dev_attrs[] = { + &dev_attr_name.attr, + &dev_attr_num_users.attr, + &dev_attr_type.attr, + NULL, }; +ATTRIBUTE_GROUPS(regulator_dev); static void regulator_dev_release(struct device *dev) { @@ -648,7 +652,7 @@ static void regulator_dev_release(struct device *dev) static struct class regulator_class = { .name = "regulator", .dev_release = regulator_dev_release, - .dev_attrs = regulator_dev_attrs, + .dev_groups = regulator_dev_groups, }; /* Calculate the new optimum regulator operating mode based on the new total @@ -984,7 +988,8 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } - if (rdev->constraints->ramp_delay && ops->set_ramp_delay) { + if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable) + && ops->set_ramp_delay) { ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay); if (ret < 0) { rdev_err(rdev, "failed to set ramp_delay\n"); @@ -1238,7 +1243,7 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, /* Internal regulator request function */ static struct regulator *_regulator_get(struct device *dev, const char *id, - int exclusive) + bool exclusive) { struct regulator_dev *rdev; struct regulator *regulator = ERR_PTR(-EPROBE_DEFER); @@ -1344,7 +1349,7 @@ out: */ struct regulator *regulator_get(struct device *dev, const char *id) { - return _regulator_get(dev, id, 0); + return _regulator_get(dev, id, false); } EXPORT_SYMBOL_GPL(regulator_get); @@ -1405,10 +1410,69 @@ EXPORT_SYMBOL_GPL(devm_regulator_get); */ struct regulator *regulator_get_exclusive(struct device *dev, const char *id) { - return _regulator_get(dev, id, 1); + return _regulator_get(dev, id, true); } EXPORT_SYMBOL_GPL(regulator_get_exclusive); +/** + * regulator_get_optional - obtain optional access to a regulator. + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Returns a struct regulator corresponding to the regulator producer, + * or IS_ERR() condition containing errno. Other consumers will be + * unable to obtain this reference is held and the use count for the + * regulator will be initialised to reflect the current state of the + * regulator. + * + * This is intended for use by consumers for devices which can have + * some supplies unconnected in normal use, such as some MMC devices. + * It can allow the regulator core to provide stub supplies for other + * supplies requested using normal regulator_get() calls without + * disrupting the operation of drivers that can handle absent + * supplies. + * + * Use of supply names configured via regulator_set_device_supply() is + * strongly encouraged. It is recommended that the supply name used + * should match the name used for the supply and/or the relevant + * device pins in the datasheet. + */ +struct regulator *regulator_get_optional(struct device *dev, const char *id) +{ + return _regulator_get(dev, id, 0); +} +EXPORT_SYMBOL_GPL(regulator_get_optional); + +/** + * devm_regulator_get_optional - Resource managed regulator_get_optional() + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Managed regulator_get_optional(). Regulators returned from this + * function are automatically regulator_put() on driver detach. See + * regulator_get_optional() for more information. + */ +struct regulator *devm_regulator_get_optional(struct device *dev, + const char *id) +{ + struct regulator **ptr, *regulator; + + ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + regulator = regulator_get_optional(dev, id); + if (!IS_ERR(regulator)) { + *ptr = regulator; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return regulator; +} +EXPORT_SYMBOL_GPL(devm_regulator_get_optional); + /* Locks held by regulator_put() */ static void _regulator_put(struct regulator *regulator) { @@ -1435,6 +1499,36 @@ static void _regulator_put(struct regulator *regulator) } /** + * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive() + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Managed regulator_get_exclusive(). Regulators returned from this function + * are automatically regulator_put() on driver detach. See regulator_get() for + * more information. + */ +struct regulator *devm_regulator_get_exclusive(struct device *dev, + const char *id) +{ + struct regulator **ptr, *regulator; + + ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + regulator = _regulator_get(dev, id, 1); + if (!IS_ERR(regulator)) { + *ptr = regulator; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return regulator; +} +EXPORT_SYMBOL_GPL(devm_regulator_get_exclusive); + +/** * regulator_put - "free" the regulator source * @regulator: regulator source * @@ -1890,8 +1984,9 @@ int regulator_disable_deferred(struct regulator *regulator, int ms) rdev->deferred_disables++; mutex_unlock(&rdev->mutex); - ret = schedule_delayed_work(&rdev->disable_work, - msecs_to_jiffies(ms)); + ret = queue_delayed_work(system_power_efficient_wq, + &rdev->disable_work, + msecs_to_jiffies(ms)); if (ret < 0) return ret; else @@ -1899,77 +1994,6 @@ int regulator_disable_deferred(struct regulator *regulator, int ms) } EXPORT_SYMBOL_GPL(regulator_disable_deferred); -/** - * regulator_is_enabled_regmap - standard is_enabled() for regmap users - * - * @rdev: regulator to operate on - * - * Regulators that use regmap for their register I/O can set the - * enable_reg and enable_mask fields in their descriptor and then use - * this as their is_enabled operation, saving some code. - */ -int regulator_is_enabled_regmap(struct regulator_dev *rdev) -{ - unsigned int val; - int ret; - - ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); - if (ret != 0) - return ret; - - if (rdev->desc->enable_is_inverted) - return (val & rdev->desc->enable_mask) == 0; - else - return (val & rdev->desc->enable_mask) != 0; -} -EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); - -/** - * regulator_enable_regmap - standard enable() for regmap users - * - * @rdev: regulator to operate on - * - * Regulators that use regmap for their register I/O can set the - * enable_reg and enable_mask fields in their descriptor and then use - * this as their enable() operation, saving some code. - */ -int regulator_enable_regmap(struct regulator_dev *rdev) -{ - unsigned int val; - - if (rdev->desc->enable_is_inverted) - val = 0; - else - val = rdev->desc->enable_mask; - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, val); -} -EXPORT_SYMBOL_GPL(regulator_enable_regmap); - -/** - * regulator_disable_regmap - standard disable() for regmap users - * - * @rdev: regulator to operate on - * - * Regulators that use regmap for their register I/O can set the - * enable_reg and enable_mask fields in their descriptor and then use - * this as their disable() operation, saving some code. - */ -int regulator_disable_regmap(struct regulator_dev *rdev) -{ - unsigned int val; - - if (rdev->desc->enable_is_inverted) - val = rdev->desc->enable_mask; - else - val = 0; - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, val); -} -EXPORT_SYMBOL_GPL(regulator_disable_regmap); - static int _regulator_is_enabled(struct regulator_dev *rdev) { /* A GPIO control always takes precedence */ @@ -2055,55 +2079,6 @@ int regulator_count_voltages(struct regulator *regulator) EXPORT_SYMBOL_GPL(regulator_count_voltages); /** - * regulator_list_voltage_linear - List voltages with simple calculation - * - * @rdev: Regulator device - * @selector: Selector to convert into a voltage - * - * Regulators with a simple linear mapping between voltages and - * selectors can set min_uV and uV_step in the regulator descriptor - * and then use this function as their list_voltage() operation, - */ -int regulator_list_voltage_linear(struct regulator_dev *rdev, - unsigned int selector) -{ - 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); -} -EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); - -/** - * regulator_list_voltage_table - List voltages with table based mapping - * - * @rdev: Regulator device - * @selector: Selector to convert into a voltage - * - * Regulators with table based mapping between voltages and - * selectors can set volt_table in the regulator descriptor - * and then use this function as their list_voltage() operation. - */ -int regulator_list_voltage_table(struct regulator_dev *rdev, - unsigned int selector) -{ - if (!rdev->desc->volt_table) { - BUG_ON(!rdev->desc->volt_table); - return -EINVAL; - } - - if (selector >= rdev->desc->n_voltages) - return -EINVAL; - - return rdev->desc->volt_table[selector]; -} -EXPORT_SYMBOL_GPL(regulator_list_voltage_table); - -/** * regulator_list_voltage - enumerate supported voltages * @regulator: regulator source * @selector: identify voltage to list @@ -2197,177 +2172,6 @@ int regulator_is_supported_voltage(struct regulator *regulator, } EXPORT_SYMBOL_GPL(regulator_is_supported_voltage); -/** - * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users - * - * @rdev: regulator to operate on - * - * Regulators that use regmap for their register I/O can set the - * vsel_reg and vsel_mask fields in their descriptor and then use this - * as their get_voltage_vsel operation, saving some code. - */ -int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev) -{ - unsigned int val; - int ret; - - ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val); - if (ret != 0) - return ret; - - val &= rdev->desc->vsel_mask; - val >>= ffs(rdev->desc->vsel_mask) - 1; - - return val; -} -EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap); - -/** - * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users - * - * @rdev: regulator to operate on - * @sel: Selector to set - * - * Regulators that use regmap for their register I/O can set the - * vsel_reg and vsel_mask fields in their descriptor and then use this - * as their set_voltage_vsel operation, saving some code. - */ -int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel) -{ - int ret; - - sel <<= ffs(rdev->desc->vsel_mask) - 1; - - 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); - -/** - * regulator_map_voltage_iterate - map_voltage() based on list_voltage() - * - * @rdev: Regulator to operate on - * @min_uV: Lower bound for voltage - * @max_uV: Upper bound for voltage - * - * Drivers implementing set_voltage_sel() and list_voltage() can use - * this as their map_voltage() operation. It will find a suitable - * voltage by calling list_voltage() until it gets something in bounds - * for the requested voltages. - */ -int regulator_map_voltage_iterate(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int best_val = INT_MAX; - int selector = 0; - int i, ret; - - /* Find the smallest voltage that falls within the specified - * range. - */ - for (i = 0; i < rdev->desc->n_voltages; i++) { - ret = rdev->desc->ops->list_voltage(rdev, i); - if (ret < 0) - continue; - - if (ret < best_val && ret >= min_uV && ret <= max_uV) { - best_val = ret; - selector = i; - } - } - - if (best_val != INT_MAX) - return selector; - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate); - -/** - * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list - * - * @rdev: Regulator to operate on - * @min_uV: Lower bound for voltage - * @max_uV: Upper bound for voltage - * - * Drivers that have ascendant voltage list can use this as their - * map_voltage() operation. - */ -int regulator_map_voltage_ascend(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int i, ret; - - for (i = 0; i < rdev->desc->n_voltages; i++) { - ret = rdev->desc->ops->list_voltage(rdev, i); - if (ret < 0) - continue; - - if (ret > max_uV) - break; - - if (ret >= min_uV && ret <= max_uV) - return i; - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend); - -/** - * regulator_map_voltage_linear - map_voltage() for simple linear mappings - * - * @rdev: Regulator to operate on - * @min_uV: Lower bound for voltage - * @max_uV: Upper bound for voltage - * - * Drivers providing min_uV and uV_step in their regulator_desc can - * use this as their map_voltage() operation. - */ -int regulator_map_voltage_linear(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int ret, voltage; - - /* Allow uV_step to be 0 for fixed voltage */ - if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) { - if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV) - return 0; - else - return -EINVAL; - } - - if (!rdev->desc->uV_step) { - BUG_ON(!rdev->desc->uV_step); - return -EINVAL; - } - - if (min_uV < rdev->desc->min_uV) - min_uV = rdev->desc->min_uV; - - ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step); - 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) - return -EINVAL; - - return ret; -} -EXPORT_SYMBOL_GPL(regulator_map_voltage_linear); - static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { @@ -2438,8 +2242,8 @@ 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 && - old_selector != selector && rdev->desc->ops->set_voltage_time_sel) { + if (ret == 0 && !rdev->constraints->ramp_disable && old_selector >= 0 + && old_selector != selector) { delay = rdev->desc->ops->set_voltage_time_sel(rdev, old_selector, selector); @@ -2971,47 +2775,6 @@ out: EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); /** - * regulator_set_bypass_regmap - Default set_bypass() using regmap - * - * @rdev: device to operate on. - * @enable: state to set. - */ -int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable) -{ - unsigned int val; - - if (enable) - val = rdev->desc->bypass_mask; - else - val = 0; - - return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg, - rdev->desc->bypass_mask, val); -} -EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap); - -/** - * regulator_get_bypass_regmap - Default get_bypass() using regmap - * - * @rdev: device to operate on. - * @enable: current state. - */ -int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable) -{ - unsigned int val; - int ret; - - ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val); - if (ret != 0) - return ret; - - *enable = val & rdev->desc->bypass_mask; - - return 0; -} -EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap); - -/** * regulator_allow_bypass - allow the regulator to go into bypass mode * * @regulator: Regulator to configure @@ -3740,8 +3503,11 @@ void regulator_unregister(struct regulator_dev *rdev) if (rdev == NULL) return; - if (rdev->supply) + if (rdev->supply) { + while (rdev->use_count--) + regulator_disable(rdev->supply); regulator_put(rdev->supply); + } mutex_lock(®ulator_list_mutex); debugfs_remove_recursive(rdev->debugfs); flush_work(&rdev->disable_work.work); diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 2afa5730f324..f06854cf8cf5 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -252,39 +252,12 @@ static int da9034_set_dvc_voltage_sel(struct regulator_dev *rdev, return ret; } -static int da9034_map_ldo12_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - struct da903x_regulator_info *info = rdev_get_drvdata(rdev); - int sel; - - if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); - return -EINVAL; - } - - sel = DIV_ROUND_UP(min_uV - info->desc.min_uV, info->desc.uV_step); - sel = (sel >= 20) ? sel - 12 : ((sel > 7) ? 8 : sel); - - return sel; -} - -static int da9034_list_ldo12_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - struct da903x_regulator_info *info = rdev_get_drvdata(rdev); - int volt; - - if (selector >= 8) - volt = 2700000 + rdev->desc->uV_step * (selector - 8); - else - volt = rdev->desc->min_uV + rdev->desc->uV_step * selector; - - if (volt > info->max_uV) - return -EINVAL; - - return volt; -} +static const struct regulator_linear_range da9034_ldo12_ranges[] = { + { .min_uV = 1700000, .max_uV = 2050000, .min_sel = 0, .max_sel = 7, + .uV_step = 50000 }, + { .min_uV = 2700000, .max_uV = 3050000, .min_sel = 8, .max_sel = 15, + .uV_step = 50000 }, +}; static struct regulator_ops da903x_regulator_ldo_ops = { .set_voltage_sel = da903x_set_voltage_sel, @@ -332,8 +305,8 @@ static struct regulator_ops da9034_regulator_dvc_ops = { static struct regulator_ops da9034_regulator_ldo12_ops = { .set_voltage_sel = da903x_set_voltage_sel, .get_voltage_sel = da903x_get_voltage_sel, - .list_voltage = da9034_list_ldo12_voltage, - .map_voltage = da9034_map_ldo12_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .enable = da903x_enable, .disable = da903x_disable, .is_enabled = da903x_is_enabled, @@ -476,6 +449,8 @@ static int da903x_regulator_probe(struct platform_device *pdev) if (ri->desc.id == DA9034_ID_LDO12) { ri->desc.ops = &da9034_regulator_ldo12_ops; ri->desc.n_voltages = 16; + ri->desc.linear_ranges = da9034_ldo12_ranges; + ri->desc.n_linear_ranges = ARRAY_SIZE(da9034_ldo12_ranges); } if (ri->desc.id == DA9030_ID_LDO14) @@ -485,7 +460,7 @@ static int da903x_regulator_probe(struct platform_device *pdev) ri->desc.ops = &da9030_regulator_ldo1_15_ops; config.dev = &pdev->dev; - config.init_data = pdev->dev.platform_data; + config.init_data = dev_get_platdata(&pdev->dev); config.driver_data = ri; rdev = regulator_register(&ri->desc, &config); diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 96b569abb46c..1e4d483f6163 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -349,7 +349,7 @@ static int da9052_regulator_probe(struct platform_device *pdev) return -ENOMEM; da9052 = dev_get_drvdata(pdev->dev.parent); - pdata = da9052->dev->platform_data; + pdata = dev_get_platdata(da9052->dev); regulator->da9052 = da9052; regulator->info = find_regulator_info(regulator->da9052->chip_id, diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index 30221099d09c..77b53e5a231c 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -535,7 +535,7 @@ 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; + struct da9055_pdata *pdata = dev_get_platdata(da9055->dev); int ret, irq; if (pdata == NULL || pdata->regulators[pdev->id] == NULL) diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c new file mode 100644 index 000000000000..1a7816390773 --- /dev/null +++ b/drivers/regulator/da9063-regulator.c @@ -0,0 +1,934 @@ +/* + * Regulator driver for DA9063 PMIC series + * + * Copyright 2012 Dialog Semiconductors Ltd. + * Copyright 2013 Philipp Zabel, Pengutronix + * + * Author: Krystian Garbaciak <krystian.garbaciak@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/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/of.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/mfd/da9063/core.h> +#include <linux/mfd/da9063/pdata.h> +#include <linux/mfd/da9063/registers.h> + + +/* Definition for registering regmap bit fields using a mask */ +#define BFIELD(_reg, _mask) \ + REG_FIELD(_reg, __builtin_ffs((int)_mask) - 1, \ + sizeof(unsigned int) * 8 - __builtin_clz((_mask)) - 1) + +/* Regulator capabilities and registers description */ +struct da9063_regulator_info { + struct regulator_desc desc; + + /* Current limiting */ + unsigned n_current_limits; + const int *current_limits; + + /* DA9063 main register fields */ + struct reg_field mode; /* buck mode of operation */ + struct reg_field suspend; + struct reg_field sleep; + struct reg_field suspend_sleep; + unsigned int suspend_vsel_reg; + struct reg_field ilimit; + + /* DA9063 event detection bit */ + struct reg_field oc_event; +}; + +/* Macros for LDO */ +#define DA9063_LDO(chip, regl_name, min_mV, step_mV, max_mV) \ + .desc.id = chip##_ID_##regl_name, \ + .desc.name = __stringify(chip##_##regl_name), \ + .desc.ops = &da9063_ldo_ops, \ + .desc.min_uV = (min_mV) * 1000, \ + .desc.uV_step = (step_mV) * 1000, \ + .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1), \ + .desc.enable_reg = DA9063_REG_##regl_name##_CONT, \ + .desc.enable_mask = DA9063_LDO_EN, \ + .desc.vsel_reg = DA9063_REG_V##regl_name##_A, \ + .desc.vsel_mask = DA9063_V##regl_name##_MASK, \ + .desc.linear_min_sel = DA9063_V##regl_name##_BIAS, \ + .sleep = BFIELD(DA9063_REG_V##regl_name##_A, DA9063_LDO_SL), \ + .suspend_sleep = BFIELD(DA9063_REG_V##regl_name##_B, DA9063_LDO_SL), \ + .suspend_vsel_reg = DA9063_REG_V##regl_name##_B + +/* Macros for voltage DC/DC converters (BUCKs) */ +#define DA9063_BUCK(chip, regl_name, min_mV, step_mV, max_mV, limits_array) \ + .desc.id = chip##_ID_##regl_name, \ + .desc.name = __stringify(chip##_##regl_name), \ + .desc.ops = &da9063_buck_ops, \ + .desc.min_uV = (min_mV) * 1000, \ + .desc.uV_step = (step_mV) * 1000, \ + .desc.n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \ + .current_limits = limits_array, \ + .n_current_limits = ARRAY_SIZE(limits_array) + +#define DA9063_BUCK_COMMON_FIELDS(regl_name) \ + .desc.enable_reg = DA9063_REG_##regl_name##_CONT, \ + .desc.enable_mask = DA9063_BUCK_EN, \ + .desc.vsel_reg = DA9063_REG_V##regl_name##_A, \ + .desc.vsel_mask = DA9063_VBUCK_MASK, \ + .desc.linear_min_sel = DA9063_VBUCK_BIAS, \ + .sleep = BFIELD(DA9063_REG_V##regl_name##_A, DA9063_BUCK_SL), \ + .suspend_sleep = BFIELD(DA9063_REG_V##regl_name##_B, DA9063_BUCK_SL), \ + .suspend_vsel_reg = DA9063_REG_V##regl_name##_B, \ + .mode = BFIELD(DA9063_REG_##regl_name##_CFG, DA9063_BUCK_MODE_MASK) + +/* Defines asignment of regulators info table to chip model */ +struct da9063_dev_model { + const struct da9063_regulator_info *regulator_info; + unsigned n_regulators; + unsigned dev_model; +}; + +/* Single regulator settings */ +struct da9063_regulator { + struct regulator_desc desc; + struct regulator_dev *rdev; + struct da9063 *hw; + const struct da9063_regulator_info *info; + + struct regmap_field *mode; + struct regmap_field *suspend; + struct regmap_field *sleep; + struct regmap_field *suspend_sleep; + struct regmap_field *ilimit; +}; + +/* Encapsulates all information for the regulators driver */ +struct da9063_regulators { + int irq_ldo_lim; + int irq_uvov; + + unsigned n_regulators; + /* Array size to be defined during init. Keep at end. */ + struct da9063_regulator regulator[0]; +}; + +/* BUCK modes for DA9063 */ +enum { + BUCK_MODE_MANUAL, /* 0 */ + BUCK_MODE_SLEEP, /* 1 */ + BUCK_MODE_SYNC, /* 2 */ + BUCK_MODE_AUTO /* 3 */ +}; + +/* Regulator operations */ + +/* Current limits array (in uA) for BCORE1, BCORE2, BPRO. + Entry indexes corresponds to register values. */ +static const int da9063_buck_a_limits[] = { + 500000, 600000, 700000, 800000, 900000, 1000000, 1100000, 1200000, + 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000 +}; + +/* Current limits array (in uA) for BMEM, BIO, BPERI. + Entry indexes corresponds to register values. */ +static const int da9063_buck_b_limits[] = { + 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, 2200000, + 2300000, 2400000, 2500000, 2600000, 2700000, 2800000, 2900000, 3000000 +}; + +/* Current limits array (in uA) for merged BCORE1 and BCORE2. + Entry indexes corresponds to register values. */ +static const int da9063_bcores_merged_limits[] = { + 1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2200000, 2400000, + 2600000, 2800000, 3000000, 3200000, 3400000, 3600000, 3800000, 4000000 +}; + +/* Current limits array (in uA) for merged BMEM and BIO. + Entry indexes corresponds to register values. */ +static const int da9063_bmem_bio_merged_limits[] = { + 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, + 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000 +}; + +static int da9063_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + const struct da9063_regulator_info *rinfo = regl->info; + int n, tval; + + for (n = 0; n < rinfo->n_current_limits; n++) { + tval = rinfo->current_limits[n]; + if (tval >= min_uA && tval <= max_uA) + return regmap_field_write(regl->ilimit, n); + } + + return -EINVAL; +} + +static int da9063_get_current_limit(struct regulator_dev *rdev) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + const struct da9063_regulator_info *rinfo = regl->info; + unsigned int sel; + int ret; + + ret = regmap_field_read(regl->ilimit, &sel); + if (ret < 0) + return ret; + + if (sel >= rinfo->n_current_limits) + sel = rinfo->n_current_limits - 1; + + return rinfo->current_limits[sel]; +} + +static int da9063_buck_set_mode(struct regulator_dev *rdev, unsigned mode) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + unsigned val; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = BUCK_MODE_SYNC; + break; + case REGULATOR_MODE_NORMAL: + val = BUCK_MODE_AUTO; + break; + case REGULATOR_MODE_STANDBY: + val = BUCK_MODE_SLEEP; + break; + default: + return -EINVAL; + } + + return regmap_field_write(regl->mode, val); +} + +/* + * Bucks use single mode register field for normal operation + * and suspend state. + * There are 3 modes to map to: FAST, NORMAL, and STANDBY. + */ + +static unsigned da9063_buck_get_mode(struct regulator_dev *rdev) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + struct regmap_field *field; + unsigned int val, mode = 0; + int ret; + + ret = regmap_field_read(regl->mode, &val); + if (ret < 0) + return ret; + + switch (val) { + default: + case BUCK_MODE_MANUAL: + mode = REGULATOR_MODE_FAST | REGULATOR_MODE_STANDBY; + /* Sleep flag bit decides the mode */ + break; + case BUCK_MODE_SLEEP: + return REGULATOR_MODE_STANDBY; + case BUCK_MODE_SYNC: + return REGULATOR_MODE_FAST; + case BUCK_MODE_AUTO: + return REGULATOR_MODE_NORMAL; + } + + /* Detect current regulator state */ + ret = regmap_field_read(regl->suspend, &val); + if (ret < 0) + return 0; + + /* Read regulator mode from proper register, depending on state */ + if (val) + field = regl->suspend_sleep; + else + field = regl->sleep; + + ret = regmap_field_read(field, &val); + if (ret < 0) + return 0; + + if (val) + mode &= REGULATOR_MODE_STANDBY; + else + mode &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST; + + return mode; +} + +/* + * LDOs use sleep flags - one for normal and one for suspend state. + * There are 2 modes to map to: NORMAL and STANDBY (sleep) for each state. + */ + +static int da9063_ldo_set_mode(struct regulator_dev *rdev, unsigned mode) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + unsigned val; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + val = 0; + break; + case REGULATOR_MODE_STANDBY: + val = 1; + break; + default: + return -EINVAL; + } + + return regmap_field_write(regl->sleep, val); +} + +static unsigned da9063_ldo_get_mode(struct regulator_dev *rdev) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + struct regmap_field *field; + int ret, val; + + /* Detect current regulator state */ + ret = regmap_field_read(regl->suspend, &val); + if (ret < 0) + return 0; + + /* Read regulator mode from proper register, depending on state */ + if (val) + field = regl->suspend_sleep; + else + field = regl->sleep; + + ret = regmap_field_read(field, &val); + if (ret < 0) + return 0; + + if (val) + return REGULATOR_MODE_STANDBY; + else + return REGULATOR_MODE_NORMAL; +} + +static int da9063_buck_get_status(struct regulator_dev *rdev) +{ + int ret = regulator_is_enabled_regmap(rdev); + + if (ret == 0) { + ret = REGULATOR_STATUS_OFF; + } else if (ret > 0) { + ret = da9063_buck_get_mode(rdev); + if (ret > 0) + ret = regulator_mode_to_status(ret); + else if (ret == 0) + ret = -EIO; + } + + return ret; +} + +static int da9063_ldo_get_status(struct regulator_dev *rdev) +{ + int ret = regulator_is_enabled_regmap(rdev); + + if (ret == 0) { + ret = REGULATOR_STATUS_OFF; + } else if (ret > 0) { + ret = da9063_ldo_get_mode(rdev); + if (ret > 0) + ret = regulator_mode_to_status(ret); + else if (ret == 0) + ret = -EIO; + } + + return ret; +} + +static int da9063_set_suspend_voltage(struct regulator_dev *rdev, int uV) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + const struct da9063_regulator_info *rinfo = regl->info; + int ret, sel; + + sel = regulator_map_voltage_linear(rdev, uV, uV); + if (sel < 0) + return -EINVAL; + + sel <<= ffs(rdev->desc->vsel_mask) - 1; + + ret = regmap_update_bits(regl->hw->regmap, rinfo->suspend_vsel_reg, + rdev->desc->vsel_mask, sel); + + return ret; +} + +static int da9063_suspend_enable(struct regulator_dev *rdev) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + + return regmap_field_write(regl->suspend, 1); +} + +static int da9063_suspend_disable(struct regulator_dev *rdev) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + + return regmap_field_write(regl->suspend, 0); +} + +static int da9063_buck_set_suspend_mode(struct regulator_dev *rdev, unsigned mode) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + int val; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = BUCK_MODE_SYNC; + break; + case REGULATOR_MODE_NORMAL: + val = BUCK_MODE_AUTO; + break; + case REGULATOR_MODE_STANDBY: + val = BUCK_MODE_SLEEP; + break; + default: + return -EINVAL; + } + + return regmap_field_write(regl->mode, val); +} + +static int da9063_ldo_set_suspend_mode(struct regulator_dev *rdev, unsigned mode) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + unsigned val; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + val = 0; + break; + case REGULATOR_MODE_STANDBY: + val = 1; + break; + default: + return -EINVAL; + } + + return regmap_field_write(regl->suspend_sleep, val); +} + +static struct regulator_ops da9063_buck_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_current_limit = da9063_set_current_limit, + .get_current_limit = da9063_get_current_limit, + .set_mode = da9063_buck_set_mode, + .get_mode = da9063_buck_get_mode, + .get_status = da9063_buck_get_status, + .set_suspend_voltage = da9063_set_suspend_voltage, + .set_suspend_enable = da9063_suspend_enable, + .set_suspend_disable = da9063_suspend_disable, + .set_suspend_mode = da9063_buck_set_suspend_mode, +}; + +static struct regulator_ops da9063_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_mode = da9063_ldo_set_mode, + .get_mode = da9063_ldo_get_mode, + .get_status = da9063_ldo_get_status, + .set_suspend_voltage = da9063_set_suspend_voltage, + .set_suspend_enable = da9063_suspend_enable, + .set_suspend_disable = da9063_suspend_disable, + .set_suspend_mode = da9063_ldo_set_suspend_mode, +}; + +/* Info of regulators for DA9063 */ +static const struct da9063_regulator_info da9063_regulator_info[] = { + { + DA9063_BUCK(DA9063, BCORE1, 300, 10, 1570, + da9063_buck_a_limits), + DA9063_BUCK_COMMON_FIELDS(BCORE1), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE1_SEL), + .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_C, + DA9063_BCORE1_ILIM_MASK), + }, + { + DA9063_BUCK(DA9063, BCORE2, 300, 10, 1570, + da9063_buck_a_limits), + DA9063_BUCK_COMMON_FIELDS(BCORE2), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE2_SEL), + .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_C, + DA9063_BCORE2_ILIM_MASK), + }, + { + DA9063_BUCK(DA9063, BPRO, 530, 10, 1800, + da9063_buck_a_limits), + DA9063_BUCK_COMMON_FIELDS(BPRO), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBPRO_SEL), + .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_B, + DA9063_BPRO_ILIM_MASK), + }, + { + DA9063_BUCK(DA9063, BMEM, 800, 20, 3340, + da9063_buck_b_limits), + DA9063_BUCK_COMMON_FIELDS(BMEM), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBMEM_SEL), + .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_A, + DA9063_BMEM_ILIM_MASK), + }, + { + DA9063_BUCK(DA9063, BIO, 800, 20, 3340, + da9063_buck_b_limits), + DA9063_BUCK_COMMON_FIELDS(BIO), + .suspend = BFIELD(DA9063_REG_DVC_2, DA9063_VBIO_SEL), + .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_A, + DA9063_BIO_ILIM_MASK), + }, + { + DA9063_BUCK(DA9063, BPERI, 800, 20, 3340, + da9063_buck_b_limits), + DA9063_BUCK_COMMON_FIELDS(BPERI), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBPERI_SEL), + .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_B, + DA9063_BPERI_ILIM_MASK), + }, + { + DA9063_BUCK(DA9063, BCORES_MERGED, 300, 10, 1570, + da9063_bcores_merged_limits), + /* BCORES_MERGED uses the same register fields as BCORE1 */ + DA9063_BUCK_COMMON_FIELDS(BCORE1), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE1_SEL), + .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_C, + DA9063_BCORE1_ILIM_MASK), + }, + { + DA9063_BUCK(DA9063, BMEM_BIO_MERGED, 800, 20, 3340, + da9063_bmem_bio_merged_limits), + /* BMEM_BIO_MERGED uses the same register fields as BMEM */ + DA9063_BUCK_COMMON_FIELDS(BMEM), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBMEM_SEL), + .ilimit = BFIELD(DA9063_REG_BUCK_ILIM_A, + DA9063_BMEM_ILIM_MASK), + }, + { + DA9063_LDO(DA9063, LDO1, 600, 20, 1860), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO1_SEL), + }, + { + DA9063_LDO(DA9063, LDO2, 600, 20, 1860), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO2_SEL), + }, + { + DA9063_LDO(DA9063, LDO3, 900, 20, 3440), + .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO3_SEL), + .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO3_LIM), + }, + { + DA9063_LDO(DA9063, LDO4, 900, 20, 3440), + .suspend = BFIELD(DA9063_REG_DVC_2, DA9063_VLDO4_SEL), + .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO4_LIM), + }, + { + DA9063_LDO(DA9063, LDO5, 900, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO5_CONT, DA9063_VLDO5_SEL), + }, + { + DA9063_LDO(DA9063, LDO6, 900, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO6_CONT, DA9063_VLDO6_SEL), + }, + { + DA9063_LDO(DA9063, LDO7, 900, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO7_CONT, DA9063_VLDO7_SEL), + .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO7_LIM), + }, + { + DA9063_LDO(DA9063, LDO8, 900, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO8_CONT, DA9063_VLDO8_SEL), + .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO8_LIM), + }, + { + DA9063_LDO(DA9063, LDO9, 950, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO9_CONT, DA9063_VLDO9_SEL), + }, + { + DA9063_LDO(DA9063, LDO10, 900, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO10_CONT, DA9063_VLDO10_SEL), + }, + { + DA9063_LDO(DA9063, LDO11, 900, 50, 3600), + .suspend = BFIELD(DA9063_REG_LDO11_CONT, DA9063_VLDO11_SEL), + .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO11_LIM), + }, +}; + +/* Link chip model with regulators info table */ +static struct da9063_dev_model regulators_models[] = { + { + .regulator_info = da9063_regulator_info, + .n_regulators = ARRAY_SIZE(da9063_regulator_info), + .dev_model = PMIC_DA9063, + }, + { } +}; + +/* Regulator interrupt handlers */ +static irqreturn_t da9063_ldo_lim_event(int irq, void *data) +{ + struct da9063_regulators *regulators = data; + struct da9063 *hw = regulators->regulator[0].hw; + struct da9063_regulator *regl; + int bits, i , ret; + + ret = regmap_read(hw->regmap, DA9063_REG_STATUS_D, &bits); + if (ret < 0) + return IRQ_NONE; + + for (i = regulators->n_regulators - 1; i >= 0; i--) { + regl = ®ulators->regulator[i]; + if (regl->info->oc_event.reg != DA9063_REG_STATUS_D) + continue; + + if (BIT(regl->info->oc_event.lsb) & bits) + regulator_notifier_call_chain(regl->rdev, + REGULATOR_EVENT_OVER_CURRENT, NULL); + } + + return IRQ_HANDLED; +} + +/* + * Probing and Initialisation functions + */ +static const struct regulator_init_data *da9063_get_regulator_initdata( + const struct da9063_regulators_pdata *regl_pdata, int id) +{ + int i; + + for (i = 0; i < regl_pdata->n_regulators; i++) { + if (id == regl_pdata->regulator_data[i].id) + return regl_pdata->regulator_data[i].initdata; + } + + return NULL; +} + +#ifdef CONFIG_OF +static struct of_regulator_match da9063_matches[] = { + [DA9063_ID_BCORE1] = { .name = "bcore1" }, + [DA9063_ID_BCORE2] = { .name = "bcore2" }, + [DA9063_ID_BPRO] = { .name = "bpro", }, + [DA9063_ID_BMEM] = { .name = "bmem", }, + [DA9063_ID_BIO] = { .name = "bio", }, + [DA9063_ID_BPERI] = { .name = "bperi", }, + [DA9063_ID_BCORES_MERGED] = { .name = "bcores-merged" }, + [DA9063_ID_BMEM_BIO_MERGED] = { .name = "bmem-bio-merged", }, + [DA9063_ID_LDO1] = { .name = "ldo1", }, + [DA9063_ID_LDO2] = { .name = "ldo2", }, + [DA9063_ID_LDO3] = { .name = "ldo3", }, + [DA9063_ID_LDO4] = { .name = "ldo4", }, + [DA9063_ID_LDO5] = { .name = "ldo5", }, + [DA9063_ID_LDO6] = { .name = "ldo6", }, + [DA9063_ID_LDO7] = { .name = "ldo7", }, + [DA9063_ID_LDO8] = { .name = "ldo8", }, + [DA9063_ID_LDO9] = { .name = "ldo9", }, + [DA9063_ID_LDO10] = { .name = "ldo10", }, + [DA9063_ID_LDO11] = { .name = "ldo11", }, +}; + +static struct da9063_regulators_pdata *da9063_parse_regulators_dt( + struct platform_device *pdev, + struct of_regulator_match **da9063_reg_matches) +{ + struct da9063_regulators_pdata *pdata; + struct da9063_regulator_data *rdata; + struct device_node *node; + int i, n, num; + + node = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); + if (!node) { + dev_err(&pdev->dev, "Regulators device node not found\n"); + return ERR_PTR(-ENODEV); + } + + num = of_regulator_match(&pdev->dev, node, da9063_matches, + ARRAY_SIZE(da9063_matches)); + if (num < 0) { + dev_err(&pdev->dev, "Failed to match regulators\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->regulator_data = devm_kzalloc(&pdev->dev, + num * sizeof(*pdata->regulator_data), + GFP_KERNEL); + if (!pdata->regulator_data) + return ERR_PTR(-ENOMEM); + pdata->n_regulators = num; + + n = 0; + for (i = 0; i < ARRAY_SIZE(da9063_matches); i++) { + if (!da9063_matches[i].init_data) + continue; + + rdata = &pdata->regulator_data[n]; + rdata->id = i; + rdata->initdata = da9063_matches[i].init_data; + + n++; + }; + + *da9063_reg_matches = da9063_matches; + return pdata; +} +#else +static struct da9063_regulators_pdata *da9063_parse_regulators_dt( + struct platform_device *pdev, + struct of_regulator_match **da9063_reg_matches) +{ + da9063_reg_matches = NULL; + return PTR_ERR(-ENODEV); +} +#endif + +static int da9063_regulator_probe(struct platform_device *pdev) +{ + struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); + struct da9063_pdata *da9063_pdata = dev_get_platdata(da9063->dev); + struct of_regulator_match *da9063_reg_matches; + struct da9063_regulators_pdata *regl_pdata; + const struct da9063_dev_model *model; + struct da9063_regulators *regulators; + struct da9063_regulator *regl; + struct regulator_config config; + bool bcores_merged, bmem_bio_merged; + int id, irq, n, n_regulators, ret, val; + size_t size; + + regl_pdata = da9063_pdata ? da9063_pdata->regulators_pdata : NULL; + + if (!regl_pdata) + regl_pdata = da9063_parse_regulators_dt(pdev, + &da9063_reg_matches); + + if (IS_ERR(regl_pdata) || regl_pdata->n_regulators == 0) { + dev_err(&pdev->dev, + "No regulators defined for the platform\n"); + return PTR_ERR(regl_pdata); + } + + /* Find regulators set for particular device model */ + for (model = regulators_models; model->regulator_info; model++) { + if (model->dev_model == da9063->model) + break; + } + if (!model->regulator_info) { + dev_err(&pdev->dev, "Chip model not recognised (%u)\n", + da9063->model); + return -ENODEV; + } + + ret = regmap_read(da9063->regmap, DA9063_REG_CONFIG_H, &val); + if (ret < 0) { + dev_err(&pdev->dev, + "Error while reading BUCKs configuration\n"); + return -EIO; + } + bcores_merged = val & DA9063_BCORE_MERGE; + bmem_bio_merged = val & DA9063_BUCK_MERGE; + + n_regulators = model->n_regulators; + if (bcores_merged) + n_regulators -= 2; /* remove BCORE1, BCORE2 */ + else + n_regulators--; /* remove BCORES_MERGED */ + if (bmem_bio_merged) + n_regulators -= 2; /* remove BMEM, BIO */ + else + n_regulators--; /* remove BMEM_BIO_MERGED */ + + /* Allocate memory required by usable regulators */ + size = sizeof(struct da9063_regulators) + + n_regulators * sizeof(struct da9063_regulator); + regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!regulators) { + dev_err(&pdev->dev, "No memory for regulators\n"); + return -ENOMEM; + } + + regulators->n_regulators = n_regulators; + platform_set_drvdata(pdev, regulators); + + /* Register all regulators declared in platform information */ + n = 0; + id = 0; + while (n < regulators->n_regulators) { + /* Skip regulator IDs depending on merge mode configuration */ + switch (id) { + case DA9063_ID_BCORE1: + case DA9063_ID_BCORE2: + if (bcores_merged) { + id++; + continue; + } + break; + case DA9063_ID_BMEM: + case DA9063_ID_BIO: + if (bmem_bio_merged) { + id++; + continue; + } + break; + case DA9063_ID_BCORES_MERGED: + if (!bcores_merged) { + id++; + continue; + } + break; + case DA9063_ID_BMEM_BIO_MERGED: + if (!bmem_bio_merged) { + id++; + continue; + } + break; + } + + /* Initialise regulator structure */ + regl = ®ulators->regulator[n]; + regl->hw = da9063; + regl->info = &model->regulator_info[id]; + regl->desc = regl->info->desc; + regl->desc.type = REGULATOR_VOLTAGE; + regl->desc.owner = THIS_MODULE; + + if (regl->info->mode.reg) + regl->mode = devm_regmap_field_alloc(&pdev->dev, + da9063->regmap, regl->info->mode); + if (regl->info->suspend.reg) + regl->suspend = devm_regmap_field_alloc(&pdev->dev, + da9063->regmap, regl->info->suspend); + if (regl->info->sleep.reg) + regl->sleep = devm_regmap_field_alloc(&pdev->dev, + da9063->regmap, regl->info->sleep); + if (regl->info->suspend_sleep.reg) + regl->suspend_sleep = devm_regmap_field_alloc(&pdev->dev, + da9063->regmap, regl->info->suspend_sleep); + if (regl->info->ilimit.reg) + regl->ilimit = devm_regmap_field_alloc(&pdev->dev, + da9063->regmap, regl->info->ilimit); + + /* Register regulator */ + memset(&config, 0, sizeof(config)); + config.dev = &pdev->dev; + config.init_data = da9063_get_regulator_initdata(regl_pdata, id); + config.driver_data = regl; + if (da9063_reg_matches) + config.of_node = da9063_reg_matches[id].of_node; + config.regmap = da9063->regmap; + regl->rdev = regulator_register(®l->desc, &config); + if (IS_ERR(regl->rdev)) { + dev_err(&pdev->dev, + "Failed to register %s regulator\n", + regl->desc.name); + ret = PTR_ERR(regl->rdev); + goto err; + } + id++; + n++; + } + + /* LDOs overcurrent event support */ + irq = platform_get_irq_byname(pdev, "LDO_LIM"); + if (irq < 0) { + ret = irq; + dev_err(&pdev->dev, "Failed to get IRQ.\n"); + goto err; + } + + regulators->irq_ldo_lim = regmap_irq_get_virq(da9063->regmap_irq, irq); + if (regulators->irq_ldo_lim >= 0) { + ret = request_threaded_irq(regulators->irq_ldo_lim, + NULL, da9063_ldo_lim_event, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "LDO_LIM", regulators); + if (ret) { + dev_err(&pdev->dev, + "Failed to request LDO_LIM IRQ.\n"); + regulators->irq_ldo_lim = -ENXIO; + } + } + + return 0; + +err: + /* Wind back regulators registeration */ + while (--n >= 0) + regulator_unregister(regulators->regulator[n].rdev); + + return ret; +} + +static int da9063_regulator_remove(struct platform_device *pdev) +{ + struct da9063_regulators *regulators = platform_get_drvdata(pdev); + struct da9063_regulator *regl; + + free_irq(regulators->irq_ldo_lim, regulators); + free_irq(regulators->irq_uvov, regulators); + + for (regl = ®ulators->regulator[regulators->n_regulators - 1]; + regl >= ®ulators->regulator[0]; regl--) + regulator_unregister(regl->rdev); + + return 0; +} + +static struct platform_driver da9063_regulator_driver = { + .driver = { + .name = DA9063_DRVNAME_REGULATORS, + .owner = THIS_MODULE, + }, + .probe = da9063_regulator_probe, + .remove = da9063_regulator_remove, +}; + +static int __init da9063_regulator_init(void) +{ + return platform_driver_register(&da9063_regulator_driver); +} +subsys_initcall(da9063_regulator_init); + +static void __exit da9063_regulator_cleanup(void) +{ + platform_driver_unregister(&da9063_regulator_driver); +} +module_exit(da9063_regulator_cleanup); + + +/* Module information */ +MODULE_AUTHOR("Krystian Garbaciak <krystian.garbaciak@diasemi.com>"); +MODULE_DESCRIPTION("DA9063 regulators driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("paltform:" DA9063_DRVNAME_REGULATORS); diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c new file mode 100644 index 000000000000..f0fe54b38977 --- /dev/null +++ b/drivers/regulator/da9210-regulator.c @@ -0,0 +1,196 @@ +/* + * da9210-regulator.c - Regulator device driver for DA9210 + * Copyright (C) 2013 Dialog Semiconductor Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regmap.h> + +#include "da9210-regulator.h" + +struct da9210 { + struct regulator_dev *rdev; + struct regmap *regmap; +}; + +static const struct regmap_config da9210_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA, + int max_uA); +static int da9210_get_current_limit(struct regulator_dev *rdev); + +static struct regulator_ops da9210_buck_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_current_limit = da9210_set_current_limit, + .get_current_limit = da9210_get_current_limit, +}; + +/* Default limits measured in millivolts and milliamps */ +#define DA9210_MIN_MV 300 +#define DA9210_MAX_MV 1570 +#define DA9210_STEP_MV 10 + +/* Current limits for buck (uA) indices corresponds with register values */ +static const int da9210_buck_limits[] = { + 1600000, 1800000, 2000000, 2200000, 2400000, 2600000, 2800000, 3000000, + 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 4600000 +}; + +static const struct regulator_desc da9210_reg = { + .name = "DA9210", + .id = 0, + .ops = &da9210_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = ((DA9210_MAX_MV - DA9210_MIN_MV) / DA9210_STEP_MV) + 1, + .min_uV = (DA9210_MIN_MV * 1000), + .uV_step = (DA9210_STEP_MV * 1000), + .vsel_reg = DA9210_REG_VBUCK_A, + .vsel_mask = DA9210_VBUCK_MASK, + .enable_reg = DA9210_REG_BUCK_CONT, + .enable_mask = DA9210_BUCK_EN, + .owner = THIS_MODULE, +}; + +static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA, + int max_uA) +{ + struct da9210 *chip = rdev_get_drvdata(rdev); + unsigned int sel; + int i; + + /* search for closest to maximum */ + for (i = ARRAY_SIZE(da9210_buck_limits)-1; i >= 0; i--) { + if (min_uA <= da9210_buck_limits[i] && + max_uA >= da9210_buck_limits[i]) { + sel = i; + sel = sel << DA9210_BUCK_ILIM_SHIFT; + return regmap_update_bits(chip->regmap, + DA9210_REG_BUCK_ILIM, + DA9210_BUCK_ILIM_MASK, sel); + } + } + + return -EINVAL; +} + +static int da9210_get_current_limit(struct regulator_dev *rdev) +{ + struct da9210 *chip = rdev_get_drvdata(rdev); + unsigned int data; + unsigned int sel; + int ret; + + ret = regmap_read(chip->regmap, DA9210_REG_BUCK_ILIM, &data); + if (ret < 0) + return ret; + + /* select one of 16 values: 0000 (1600mA) to 1111 (4600mA) */ + sel = (data & DA9210_BUCK_ILIM_MASK) >> DA9210_BUCK_ILIM_SHIFT; + + return da9210_buck_limits[sel]; +} + +/* + * I2C driver interface functions + */ +static int da9210_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da9210 *chip; + struct da9210_pdata *pdata = i2c->dev.platform_data; + struct regulator_dev *rdev = NULL; + struct regulator_config config = { }; + int error; + + chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL); + if (NULL == chip) { + dev_err(&i2c->dev, + "Cannot kzalloc memory for regulator structure\n"); + return -ENOMEM; + } + + chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config); + if (IS_ERR(chip->regmap)) { + error = PTR_ERR(chip->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + error); + return error; + } + + config.dev = &i2c->dev; + if (pdata) + config.init_data = &pdata->da9210_constraints; + config.driver_data = chip; + config.regmap = chip->regmap; + + rdev = regulator_register(&da9210_reg, &config); + if (IS_ERR(rdev)) { + dev_err(&i2c->dev, "Failed to register DA9210 regulator\n"); + return PTR_ERR(rdev); + } + + chip->rdev = rdev; + + i2c_set_clientdata(i2c, chip); + + return 0; +} + +static int da9210_i2c_remove(struct i2c_client *i2c) +{ + struct da9210 *chip = i2c_get_clientdata(i2c); + regulator_unregister(chip->rdev); + return 0; +} + +static const struct i2c_device_id da9210_i2c_id[] = { + {"da9210", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, da9210_i2c_id); + +static struct i2c_driver da9210_regulator_driver = { + .driver = { + .name = "da9210", + .owner = THIS_MODULE, + }, + .probe = da9210_i2c_probe, + .remove = da9210_i2c_remove, + .id_table = da9210_i2c_id, +}; + +module_i2c_driver(da9210_regulator_driver); + +MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>"); +MODULE_DESCRIPTION("Regulator device driver for Dialog DA9210"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/da9210-regulator.h b/drivers/regulator/da9210-regulator.h new file mode 100644 index 000000000000..749c550808b6 --- /dev/null +++ b/drivers/regulator/da9210-regulator.h @@ -0,0 +1,288 @@ + +/* + * da9210-regulator.h - Regulator definitions for DA9210 + * Copyright (C) 2013 Dialog Semiconductor Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __DA9210_REGISTERS_H__ +#define __DA9210_REGISTERS_H__ + +struct da9210_pdata { + struct regulator_init_data da9210_constraints; +}; + +/* Page selection */ +#define DA9210_REG_PAGE_CON 0x00 + +/* System Control and Event Registers */ +#define DA9210_REG_STATUS_A 0x50 +#define DA9210_REG_STATUS_B 0x51 +#define DA9210_REG_EVENT_A 0x52 +#define DA9210_REG_EVENT_B 0x53 +#define DA9210_REG_MASK_A 0x54 +#define DA9210_REG_MASK_B 0x55 +#define DA9210_REG_CONTROL_A 0x56 + +/* GPIO Control Registers */ +#define DA9210_REG_GPIO_0_1 0x58 +#define DA9210_REG_GPIO_2_3 0x59 +#define DA9210_REG_GPIO_4_5 0x5A +#define DA9210_REG_GPIO_6 0x5B + +/* Regulator Registers */ +#define DA9210_REG_BUCK_CONT 0x5D +#define DA9210_REG_BUCK_ILIM 0xD0 +#define DA9210_REG_BUCK_CONF1 0xD1 +#define DA9210_REG_BUCK_CONF2 0xD2 +#define DA9210_REG_VBACK_AUTO 0xD4 +#define DA9210_REG_VBACK_BASE 0xD5 +#define DA9210_REG_VBACK_MAX_DVC_IF 0xD6 +#define DA9210_REG_VBACK_DVC 0xD7 +#define DA9210_REG_VBUCK_A 0xD8 +#define DA9210_REG_VBUCK_B 0xD9 + +/* I2C Interface Settings */ +#define DA9210_REG_INTERFACE 0x105 + +/* OTP */ +#define DA9210_REG_OPT_COUNT 0x140 +#define DA9210_REG_OPT_ADDR 0x141 +#define DA9210_REG_OPT_DATA 0x142 + +/* Customer Trim and Configuration */ +#define DA9210_REG_CONFIG_A 0x143 +#define DA9210_REG_CONFIG_B 0x144 +#define DA9210_REG_CONFIG_C 0x145 +#define DA9210_REG_CONFIG_D 0x146 +#define DA9210_REG_CONFIG_E 0x147 + + +/* + * Registers bits + */ +/* DA9210_REG_PAGE_CON (addr=0x00) */ +#define DA9210_PEG_PAGE_SHIFT 0 +#define DA9210_REG_PAGE_MASK 0x0F +/* On I2C registers 0x00 - 0xFF */ +#define DA9210_REG_PAGE0 0 +/* On I2C registers 0x100 - 0x1FF */ +#define DA9210_REG_PAGE2 2 +#define DA9210_PAGE_WRITE_MODE 0x00 +#define DA9210_REPEAT_WRITE_MODE 0x40 +#define DA9210_PAGE_REVERT 0x80 + +/* DA9210_REG_STATUS_A (addr=0x50) */ +#define DA9210_GPI0 0x01 +#define DA9210_GPI1 0x02 +#define DA9210_GPI2 0x04 +#define DA9210_GPI3 0x08 +#define DA9210_GPI4 0x10 +#define DA9210_GPI5 0x20 +#define DA9210_GPI6 0x40 + +/* DA9210_REG_EVENT_A (addr=0x52) */ +#define DA9210_E_GPI0 0x01 +#define DA9210_E_GPI1 0x02 +#define DA9210_E_GPI2 0x04 +#define DA9210_E_GPI3 0x08 +#define DA9210_E_GPI4 0x10 +#define DA9210_E_GPI5 0x20 +#define DA9210_E_GPI6 0x40 + +/* DA9210_REG_EVENT_B (addr=0x53) */ +#define DA9210_E_OVCURR 0x01 +#define DA9210_E_NPWRGOOD 0x02 +#define DA9210_E_TEMP_WARN 0x04 +#define DA9210_E_TEMP_CRIT 0x08 +#define DA9210_E_VMAX 0x10 + +/* DA9210_REG_MASK_A (addr=0x54) */ +#define DA9210_M_GPI0 0x01 +#define DA9210_M_GPI1 0x02 +#define DA9210_M_GPI2 0x04 +#define DA9210_M_GPI3 0x08 +#define DA9210_M_GPI4 0x10 +#define DA9210_M_GPI5 0x20 +#define DA9210_M_GPI6 0x40 + +/* DA9210_REG_MASK_B (addr=0x55) */ +#define DA9210_M_OVCURR 0x01 +#define DA9210_M_NPWRGOOD 0x02 +#define DA9210_M_TEMP_WARN 0x04 +#define DA9210_M_TEMP_CRIT 0x08 +#define DA9210_M_VMAX 0x10 + +/* DA9210_REG_CONTROL_A (addr=0x56) */ +#define DA9210_DEBOUNCING_SHIFT 0 +#define DA9210_DEBOUNCING_MASK 0x07 +#define DA9210_SLEW_RATE_SHIFT 3 +#define DA9210_SLEW_RATE_MASK 0x18 +#define DA9210_V_LOCK 0x20 + +/* DA9210_REG_GPIO_0_1 (addr=0x58) */ +#define DA9210_GPIO0_PIN_SHIFT 0 +#define DA9210_GPIO0_PIN_MASK 0x03 +#define DA9210_GPIO0_PIN_GPI 0x00 +#define DA9210_GPIO0_PIN_GPO_OD 0x02 +#define DA9210_GPIO0_PIN_GPO 0x03 +#define DA9210_GPIO0_TYPE 0x04 +#define DA9210_GPIO0_TYPE_GPI 0x00 +#define DA9210_GPIO0_TYPE_GPO 0x04 +#define DA9210_GPIO0_MODE 0x08 +#define DA9210_GPIO1_PIN_SHIFT 4 +#define DA9210_GPIO1_PIN_MASK 0x30 +#define DA9210_GPIO1_PIN_GPI 0x00 +#define DA9210_GPIO1_PIN_VERROR 0x10 +#define DA9210_GPIO1_PIN_GPO_OD 0x20 +#define DA9210_GPIO1_PIN_GPO 0x30 +#define DA9210_GPIO1_TYPE_SHIFT 0x40 +#define DA9210_GPIO1_TYPE_GPI 0x00 +#define DA9210_GPIO1_TYPE_GPO 0x40 +#define DA9210_GPIO1_MODE 0x80 + +/* DA9210_REG_GPIO_2_3 (addr=0x59) */ +#define DA9210_GPIO2_PIN_SHIFT 0 +#define DA9210_GPIO2_PIN_MASK 0x03 +#define DA9210_GPIO2_PIN_GPI 0x00 +#define DA9210_GPIO5_PIN_BUCK_CLK 0x10 +#define DA9210_GPIO2_PIN_GPO_OD 0x02 +#define DA9210_GPIO2_PIN_GPO 0x03 +#define DA9210_GPIO2_TYPE 0x04 +#define DA9210_GPIO2_TYPE_GPI 0x00 +#define DA9210_GPIO2_TYPE_GPO 0x04 +#define DA9210_GPIO2_MODE 0x08 +#define DA9210_GPIO3_PIN_SHIFT 4 +#define DA9210_GPIO3_PIN_MASK 0x30 +#define DA9210_GPIO3_PIN_GPI 0x00 +#define DA9210_GPIO3_PIN_IERROR 0x10 +#define DA9210_GPIO3_PIN_GPO_OD 0x20 +#define DA9210_GPIO3_PIN_GPO 0x30 +#define DA9210_GPIO3_TYPE_SHIFT 0x40 +#define DA9210_GPIO3_TYPE_GPI 0x00 +#define DA9210_GPIO3_TYPE_GPO 0x40 +#define DA9210_GPIO3_MODE 0x80 + +/* DA9210_REG_GPIO_4_5 (addr=0x5A) */ +#define DA9210_GPIO4_PIN_SHIFT 0 +#define DA9210_GPIO4_PIN_MASK 0x03 +#define DA9210_GPIO4_PIN_GPI 0x00 +#define DA9210_GPIO4_PIN_GPO_OD 0x02 +#define DA9210_GPIO4_PIN_GPO 0x03 +#define DA9210_GPIO4_TYPE 0x04 +#define DA9210_GPIO4_TYPE_GPI 0x00 +#define DA9210_GPIO4_TYPE_GPO 0x04 +#define DA9210_GPIO4_MODE 0x08 +#define DA9210_GPIO5_PIN_SHIFT 4 +#define DA9210_GPIO5_PIN_MASK 0x30 +#define DA9210_GPIO5_PIN_GPI 0x00 +#define DA9210_GPIO5_PIN_INTERFACE 0x01 +#define DA9210_GPIO5_PIN_GPO_OD 0x20 +#define DA9210_GPIO5_PIN_GPO 0x30 +#define DA9210_GPIO5_TYPE_SHIFT 0x40 +#define DA9210_GPIO5_TYPE_GPI 0x00 +#define DA9210_GPIO5_TYPE_GPO 0x40 +#define DA9210_GPIO5_MODE 0x80 + +/* DA9210_REG_GPIO_6 (addr=0x5B) */ +#define DA9210_GPIO6_PIN_SHIFT 0 +#define DA9210_GPIO6_PIN_MASK 0x03 +#define DA9210_GPIO6_PIN_GPI 0x00 +#define DA9210_GPIO6_PIN_INTERFACE 0x01 +#define DA9210_GPIO6_PIN_GPO_OD 0x02 +#define DA9210_GPIO6_PIN_GPO 0x03 +#define DA9210_GPIO6_TYPE 0x04 +#define DA9210_GPIO6_TYPE_GPI 0x00 +#define DA9210_GPIO6_TYPE_GPO 0x04 +#define DA9210_GPIO6_MODE 0x08 + +/* DA9210_REG_BUCK_CONT (addr=0x5D) */ +#define DA9210_BUCK_EN 0x01 +#define DA9210_BUCK_GPI_SHIFT 1 +#define DA9210_BUCK_GPI_MASK 0x06 +#define DA9210_BUCK_GPI_OFF 0x00 +#define DA9210_BUCK_GPI_GPIO0 0x02 +#define DA9210_BUCK_GPI_GPIO3 0x04 +#define DA9210_BUCK_GPI_GPIO4 0x06 +#define DA9210_BUCK_PD_DIS 0x08 +#define DA9210_VBUCK_SEL 0x10 +#define DA9210_VBUCK_SEL_A 0x00 +#define DA9210_VBUCK_SEL_B 0x10 +#define DA9210_VBUCK_GPI_SHIFT 5 +#define DA9210_VBUCK_GPI_MASK 0x60 +#define DA9210_VBUCK_GPI_OFF 0x00 +#define DA9210_VBUCK_GPI_GPIO0 0x20 +#define DA9210_VBUCK_GPI_GPIO3 0x40 +#define DA9210_VBUCK_GPI_GPIO4 0x60 +#define DA9210_DVC_CTRL_EN 0x80 + +/* DA9210_REG_BUCK_ILIM (addr=0xD0) */ +#define DA9210_BUCK_ILIM_SHIFT 0 +#define DA9210_BUCK_ILIM_MASK 0x0F +#define DA9210_BUCK_IALARM 0x10 + +/* DA9210_REG_BUCK_CONF1 (addr=0xD1) */ +#define DA9210_BUCK_MODE_SHIFT 0 +#define DA9210_BUCK_MODE_MASK 0x03 +#define DA9210_BUCK_MODE_MANUAL 0x00 +#define DA9210_BUCK_MODE_SLEEP 0x01 +#define DA9210_BUCK_MODE_SYNC 0x02 +#define DA9210_BUCK_MODE_AUTO 0x03 +#define DA9210_STARTUP_CTRL_SHIFT 2 +#define DA9210_STARTUP_CTRL_MASK 0x1C +#define DA9210_PWR_DOWN_CTRL_SHIFT 5 +#define DA9210_PWR_DOWN_CTRL_MASK 0xE0 + +/* DA9210_REG_BUCK_CONF2 (addr=0xD2) */ +#define DA9210_PHASE_SEL_SHIFT 0 +#define DA9210_PHASE_SEL_MASK 0x03 +#define DA9210_FREQ_SEL 0x40 + +/* DA9210_REG_BUCK_AUTO (addr=0xD4) */ +#define DA9210_VBUCK_AUTO_SHIFT 0 +#define DA9210_VBUCK_AUTO_MASK 0x7F + +/* DA9210_REG_BUCK_BASE (addr=0xD5) */ +#define DA9210_VBUCK_BASE_SHIFT 0 +#define DA9210_VBUCK_BASE_MASK 0x7F + +/* DA9210_REG_VBUCK_MAX_DVC_IF (addr=0xD6) */ +#define DA9210_VBUCK_MAX_SHIFT 0 +#define DA9210_VBUCK_MAX_MASK 0x7F +#define DA9210_DVC_STEP_SIZE 0x80 +#define DA9210_DVC_STEP_SIZE_10MV 0x00 +#define DA9210_DVC_STEP_SIZE_20MV 0x80 + +/* DA9210_REG_VBUCK_DVC (addr=0xD7) */ +#define DA9210_VBUCK_DVC_SHIFT 0 +#define DA9210_VBUCK_DVC_MASK 0x7F + +/* DA9210_REG_VBUCK_A/B (addr=0xD8/0xD9) */ +#define DA9210_VBUCK_SHIFT 0 +#define DA9210_VBUCK_MASK 0x7F +#define DA9210_VBUCK_BIAS 0 +#define DA9210_BUCK_SL 0x80 + +/* DA9210_REG_INTERFACE (addr=0x105) */ +#define DA9210_IF_BASE_ADDR_SHIFT 4 +#define DA9210_IF_BASE_ADDR_MASK 0xF0 + +/* DA9210_REG_CONFIG_E (addr=0x147) */ +#define DA9210_STAND_ALONE 0x01 + +#endif /* __DA9210_REGISTERS_H__ */ + diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index f0e1ae52bb05..a32b44272a05 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -237,7 +237,7 @@ static int fan53555_regulator_probe(struct i2c_client *client, unsigned int val; int ret; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata || !pdata->regulator) { dev_err(&client->dev, "Platform data not found!\n"); return -ENODEV; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index e5c03b534fae..7610920014d7 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -146,7 +146,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) if (IS_ERR(config)) return PTR_ERR(config); } else { - config = pdev->dev.platform_data; + config = dev_get_platdata(&pdev->dev); } if (!config) diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 9d39eb4aafa3..98a98ffa7fe0 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -219,7 +219,7 @@ static struct regulator_ops gpio_regulator_current_ops = { static int gpio_regulator_probe(struct platform_device *pdev) { - struct gpio_regulator_config *config = pdev->dev.platform_data; + struct gpio_regulator_config *config = dev_get_platdata(&pdev->dev); struct device_node *np = pdev->dev.of_node; struct gpio_regulator_data *drvdata; struct regulator_config cfg = { }; diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c new file mode 100644 index 000000000000..6e30df14714b --- /dev/null +++ b/drivers/regulator/helpers.c @@ -0,0 +1,447 @@ +/* + * helpers.c -- Voltage/Current Regulator framework helper functions. + * + * Copyright 2007, 2008 Wolfson Microelectronics PLC. + * Copyright 2008 SlimLogic Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/module.h> + +/** + * regulator_is_enabled_regmap - standard is_enabled() for regmap users + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the + * enable_reg and enable_mask fields in their descriptor and then use + * this as their is_enabled operation, saving some code. + */ +int regulator_is_enabled_regmap(struct regulator_dev *rdev) +{ + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); + if (ret != 0) + return ret; + + if (rdev->desc->enable_is_inverted) + return (val & rdev->desc->enable_mask) == 0; + else + return (val & rdev->desc->enable_mask) != 0; +} +EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); + +/** + * regulator_enable_regmap - standard enable() for regmap users + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the + * enable_reg and enable_mask fields in their descriptor and then use + * this as their enable() operation, saving some code. + */ +int regulator_enable_regmap(struct regulator_dev *rdev) +{ + unsigned int val; + + if (rdev->desc->enable_is_inverted) + val = 0; + else + val = rdev->desc->enable_mask; + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val); +} +EXPORT_SYMBOL_GPL(regulator_enable_regmap); + +/** + * regulator_disable_regmap - standard disable() for regmap users + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the + * enable_reg and enable_mask fields in their descriptor and then use + * this as their disable() operation, saving some code. + */ +int regulator_disable_regmap(struct regulator_dev *rdev) +{ + unsigned int val; + + if (rdev->desc->enable_is_inverted) + val = rdev->desc->enable_mask; + else + val = 0; + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val); +} +EXPORT_SYMBOL_GPL(regulator_disable_regmap); + +/** + * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the + * vsel_reg and vsel_mask fields in their descriptor and then use this + * as their get_voltage_vsel operation, saving some code. + */ +int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev) +{ + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val); + if (ret != 0) + return ret; + + val &= rdev->desc->vsel_mask; + val >>= ffs(rdev->desc->vsel_mask) - 1; + + return val; +} +EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap); + +/** + * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users + * + * @rdev: regulator to operate on + * @sel: Selector to set + * + * Regulators that use regmap for their register I/O can set the + * vsel_reg and vsel_mask fields in their descriptor and then use this + * as their set_voltage_vsel operation, saving some code. + */ +int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel) +{ + int ret; + + sel <<= ffs(rdev->desc->vsel_mask) - 1; + + 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); + +/** + * regulator_map_voltage_iterate - map_voltage() based on list_voltage() + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers implementing set_voltage_sel() and list_voltage() can use + * this as their map_voltage() operation. It will find a suitable + * voltage by calling list_voltage() until it gets something in bounds + * for the requested voltages. + */ +int regulator_map_voltage_iterate(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int best_val = INT_MAX; + int selector = 0; + int i, ret; + + /* Find the smallest voltage that falls within the specified + * range. + */ + for (i = 0; i < rdev->desc->n_voltages; i++) { + ret = rdev->desc->ops->list_voltage(rdev, i); + if (ret < 0) + continue; + + if (ret < best_val && ret >= min_uV && ret <= max_uV) { + best_val = ret; + selector = i; + } + } + + if (best_val != INT_MAX) + return selector; + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate); + +/** + * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers that have ascendant voltage list can use this as their + * map_voltage() operation. + */ +int regulator_map_voltage_ascend(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int i, ret; + + for (i = 0; i < rdev->desc->n_voltages; i++) { + ret = rdev->desc->ops->list_voltage(rdev, i); + if (ret < 0) + continue; + + if (ret > max_uV) + break; + + if (ret >= min_uV && ret <= max_uV) + return i; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend); + +/** + * regulator_map_voltage_linear - map_voltage() for simple linear mappings + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers providing min_uV and uV_step in their regulator_desc can + * use this as their map_voltage() operation. + */ +int regulator_map_voltage_linear(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret, voltage; + + /* Allow uV_step to be 0 for fixed voltage */ + if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) { + if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV) + return 0; + else + return -EINVAL; + } + + if (!rdev->desc->uV_step) { + BUG_ON(!rdev->desc->uV_step); + return -EINVAL; + } + + if (min_uV < rdev->desc->min_uV) + min_uV = rdev->desc->min_uV; + + ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step); + 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) + return -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_linear); + +/** + * regulator_map_voltage_linear - map_voltage() for multiple linear ranges + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers providing linear_ranges in their descriptor can use this as + * their map_voltage() callback. + */ +int regulator_map_voltage_linear_range(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + const struct regulator_linear_range *range; + int ret = -EINVAL; + int voltage, i; + + if (!rdev->desc->n_linear_ranges) { + BUG_ON(!rdev->desc->n_linear_ranges); + return -EINVAL; + } + + for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + range = &rdev->desc->linear_ranges[i]; + + if (!(min_uV <= range->max_uV && max_uV >= range->min_uV)) + continue; + + if (min_uV <= range->min_uV) + min_uV = range->min_uV; + + /* range->uV_step == 0 means fixed voltage range */ + if (range->uV_step == 0) { + ret = 0; + } else { + ret = DIV_ROUND_UP(min_uV - range->min_uV, + range->uV_step); + if (ret < 0) + return ret; + } + + ret += range->min_sel; + + break; + } + + if (i == rdev->desc->n_linear_ranges) + return -EINVAL; + + /* 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) + return -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range); + +/** + * regulator_list_voltage_linear - List voltages with simple calculation + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * Regulators with a simple linear mapping between voltages and + * selectors can set min_uV and uV_step in the regulator descriptor + * and then use this function as their list_voltage() operation, + */ +int regulator_list_voltage_linear(struct regulator_dev *rdev, + unsigned int selector) +{ + 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); +} +EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); + +/** + * regulator_list_voltage_linear_range - List voltages for linear ranges + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * Regulators with a series of simple linear mappings between voltages + * and selectors can set linear_ranges in the regulator descriptor and + * then use this function as their list_voltage() operation, + */ +int regulator_list_voltage_linear_range(struct regulator_dev *rdev, + unsigned int selector) +{ + const struct regulator_linear_range *range; + int i; + + if (!rdev->desc->n_linear_ranges) { + BUG_ON(!rdev->desc->n_linear_ranges); + return -EINVAL; + } + + for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + range = &rdev->desc->linear_ranges[i]; + + if (!(selector >= range->min_sel && + selector <= range->max_sel)) + continue; + + selector -= range->min_sel; + + return range->min_uV + (range->uV_step * selector); + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_list_voltage_linear_range); + +/** + * regulator_list_voltage_table - List voltages with table based mapping + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * Regulators with table based mapping between voltages and + * selectors can set volt_table in the regulator descriptor + * and then use this function as their list_voltage() operation. + */ +int regulator_list_voltage_table(struct regulator_dev *rdev, + unsigned int selector) +{ + if (!rdev->desc->volt_table) { + BUG_ON(!rdev->desc->volt_table); + return -EINVAL; + } + + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + return rdev->desc->volt_table[selector]; +} +EXPORT_SYMBOL_GPL(regulator_list_voltage_table); + +/** + * regulator_set_bypass_regmap - Default set_bypass() using regmap + * + * @rdev: device to operate on. + * @enable: state to set. + */ +int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable) +{ + unsigned int val; + + if (enable) + val = rdev->desc->bypass_mask; + else + val = 0; + + return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg, + rdev->desc->bypass_mask, val); +} +EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap); + +/** + * regulator_get_bypass_regmap - Default get_bypass() using regmap + * + * @rdev: device to operate on. + * @enable: current state. + */ +int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable) +{ + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val); + if (ret != 0) + return ret; + + *enable = val & rdev->desc->bypass_mask; + + return 0; +} +EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap); diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index b99c49b9aff0..88c1a3acf563 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -110,7 +110,7 @@ static int isl6271a_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct regulator_config config = { }; - struct regulator_init_data *init_data = i2c->dev.platform_data; + struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev); struct isl_pmic *pmic; int err, i; diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 3809b4381606..5a4604ee5ea5 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -425,7 +425,7 @@ static int lp3971_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct lp3971 *lp3971; - struct lp3971_platform_data *pdata = i2c->dev.platform_data; + struct lp3971_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret; u16 val; diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index 573024039ca0..093e6f44ff8a 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -519,7 +519,7 @@ static int lp3972_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct lp3972 *lp3972; - struct lp3972_platform_data *pdata = i2c->dev.platform_data; + struct lp3972_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret; u16 val; diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index b16336bcd4d4..2b84b727a3c4 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -373,7 +373,7 @@ static int lp8725_buck_set_current_limit(struct regulator_dev *rdev, return -EINVAL; } - for (i = ARRAY_SIZE(lp8725_buck_uA) - 1 ; i >= 0; i--) { + for (i = ARRAY_SIZE(lp8725_buck_uA) - 1; i >= 0; i--) { if (lp8725_buck_uA[i] >= min_uA && lp8725_buck_uA[i] <= max_uA) return lp872x_update_bits(lp, addr, @@ -787,7 +787,7 @@ static int lp872x_regulator_register(struct lp872x *lp) struct regulator_dev *rdev; int i, ret; - for (i = 0 ; i < lp->num_regulators ; i++) { + for (i = 0; i < lp->num_regulators; i++) { desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] : &lp8725_regulator_desc[i]; @@ -820,7 +820,7 @@ static void lp872x_regulator_unregister(struct lp872x *lp) struct regulator_dev *rdev; int i; - for (i = 0 ; i < lp->num_regulators ; i++) { + for (i = 0; i < lp->num_regulators; i++) { rdev = *(lp->regulators + i); regulator_unregister(rdev); } @@ -907,7 +907,8 @@ static struct lp872x_platform_data goto out; for (i = 0; i < num_matches; i++) { - pdata->regulator_data[i].id = (int)match[i].driver_data; + pdata->regulator_data[i].id = + (enum lp872x_regulator_id)match[i].driver_data; pdata->regulator_data[i].init_data = match[i].init_data; /* Operation mode configuration for buck/buck1/buck2 */ @@ -961,7 +962,7 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id) } lp->dev = &cl->dev; - lp->pdata = cl->dev.platform_data; + lp->pdata = dev_get_platdata(&cl->dev); lp->chipid = id->driver_data; lp->num_regulators = num_regulators; i2c_set_clientdata(cl, lp); diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c index d9e38b4c2adc..785a25e9a437 100644 --- a/drivers/regulator/lp8755.c +++ b/drivers/regulator/lp8755.c @@ -228,6 +228,7 @@ err_i2c: } static struct regulator_ops lp8755_buck_ops = { + .map_voltage = regulator_map_voltage_linear, .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -449,7 +450,7 @@ static int lp8755_probe(struct i2c_client *client, { int ret, icnt; struct lp8755_chip *pchip; - struct lp8755_platform_data *pdata = client->dev.platform_data; + struct lp8755_platform_data *pdata = dev_get_platdata(&client->dev); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "i2c functionality check fail.\n"); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 54af61015814..3a599ee0a456 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -163,7 +163,7 @@ static int max1586_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { struct regulator_dev **rdev; - struct max1586_platform_data *pdata = client->dev.platform_data; + struct max1586_platform_data *pdata = dev_get_platdata(&client->dev); struct regulator_config config = { }; struct max1586_data *max1586; int i, id, ret = -ENOMEM; diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index db6c9be10f3f..19c6f08eafd5 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -152,7 +152,7 @@ static struct regmap_config max8649_regmap_config = { static int max8649_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct max8649_platform_data *pdata = client->dev.platform_data; + struct max8649_platform_data *pdata = dev_get_platdata(&client->dev); struct max8649_regulator_info *info = NULL; struct regulator_config config = { }; unsigned int val; diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index d428ef9a626f..144bcacd734d 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -44,6 +44,9 @@ #include <linux/regulator/driver.h> #include <linux/slab.h> #include <linux/regulator/max8660.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regulator/of_regulator.h> #define MAX8660_DCDC_MIN_UV 725000 #define MAX8660_DCDC_MAX_UV 1800000 @@ -305,21 +308,105 @@ static const struct regulator_desc max8660_reg[] = { }, }; +enum { + MAX8660 = 0, + MAX8661 = 1, +}; + +#ifdef CONFIG_OF +static const struct of_device_id max8660_dt_ids[] = { + { .compatible = "maxim,max8660", .data = (void *) MAX8660 }, + { .compatible = "maxim,max8661", .data = (void *) MAX8661 }, + { } +}; +MODULE_DEVICE_TABLE(of, max8660_dt_ids); + +static int max8660_pdata_from_dt(struct device *dev, + struct device_node **of_node, + struct max8660_platform_data *pdata) +{ + int matched, i; + struct device_node *np; + struct max8660_subdev_data *sub; + struct of_regulator_match rmatch[ARRAY_SIZE(max8660_reg)]; + + np = of_find_node_by_name(dev->of_node, "regulators"); + if (!np) { + dev_err(dev, "missing 'regulators' subnode in DT\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(rmatch); i++) + rmatch[i].name = max8660_reg[i].name; + + matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch)); + if (matched <= 0) + return matched; + + pdata->subdevs = devm_kzalloc(dev, sizeof(struct max8660_subdev_data) * + matched, GFP_KERNEL); + if (!pdata->subdevs) + return -ENOMEM; + + pdata->num_subdevs = matched; + sub = pdata->subdevs; + + for (i = 0; i < matched; i++) { + sub->id = i; + sub->name = rmatch[i].name; + sub->platform_data = rmatch[i].init_data; + of_node[i] = rmatch[i].of_node; + sub++; + } + + return 0; +} +#else +static inline int max8660_pdata_from_dt(struct device *dev, + struct device_node **of_node, + struct max8660_platform_data *pdata) +{ + return 0; +} +#endif + static int max8660_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { struct regulator_dev **rdev; - struct max8660_platform_data *pdata = client->dev.platform_data; + struct device *dev = &client->dev; + struct max8660_platform_data *pdata = dev_get_platdata(dev); struct regulator_config config = { }; struct max8660 *max8660; int boot_on, i, id, ret = -EINVAL; + struct device_node *of_node[MAX8660_V_END]; + unsigned long type; + + if (dev->of_node && !pdata) { + const struct of_device_id *id; + struct max8660_platform_data pdata_of; + + id = of_match_device(of_match_ptr(max8660_dt_ids), dev); + if (!id) + return -ENODEV; + + ret = max8660_pdata_from_dt(dev, of_node, &pdata_of); + if (ret < 0) + return ret; + + pdata = &pdata_of; + type = (unsigned long) id->data; + } else { + type = i2c_id->driver_data; + memset(of_node, 0, sizeof(of_node)); + } if (pdata->num_subdevs > MAX8660_V_END) { - dev_err(&client->dev, "Too many regulators found!\n"); + dev_err(dev, "Too many regulators found!\n"); return -EINVAL; } - max8660 = devm_kzalloc(&client->dev, sizeof(struct max8660) + + max8660 = devm_kzalloc(dev, sizeof(struct max8660) + sizeof(struct regulator_dev *) * MAX8660_V_END, GFP_KERNEL); if (!max8660) @@ -376,8 +463,8 @@ static int max8660_probe(struct i2c_client *client, break; case MAX8660_V7: - if (!strcmp(i2c_id->name, "max8661")) { - dev_err(&client->dev, "Regulator not on this chip!\n"); + if (type == MAX8661) { + dev_err(dev, "Regulator not on this chip!\n"); goto err_out; } @@ -386,7 +473,7 @@ static int max8660_probe(struct i2c_client *client, break; default: - dev_err(&client->dev, "invalid regulator %s\n", + dev_err(dev, "invalid regulator %s\n", pdata->subdevs[i].name); goto err_out; } @@ -397,14 +484,15 @@ static int max8660_probe(struct i2c_client *client, id = pdata->subdevs[i].id; - config.dev = &client->dev; + config.dev = dev; config.init_data = pdata->subdevs[i].platform_data; + config.of_node = of_node[i]; config.driver_data = max8660; rdev[i] = regulator_register(&max8660_reg[id], &config); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); - dev_err(&client->dev, "failed to register %s\n", + dev_err(dev, "failed to register %s\n", max8660_reg[id].name); goto err_unregister; } @@ -431,8 +519,8 @@ static int max8660_remove(struct i2c_client *client) } static const struct i2c_device_id max8660_id[] = { - { "max8660", 0 }, - { "max8661", 0 }, + { .name = "max8660", .driver_data = MAX8660 }, + { .name = "max8661", .driver_data = MAX8661 }, { } }; MODULE_DEVICE_TABLE(i2c, max8660_id); diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index e6d54a546d36..d80b5fa758ae 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -277,7 +277,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev, 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; + struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev); struct regulator_config config = { }; struct max8925_regulator_info *ri; struct resource *res; diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 5259c2fea90a..788e5ae2af1b 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -196,7 +196,7 @@ 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); - struct max8952_platform_data *pdata = client->dev.platform_data; + struct max8952_platform_data *pdata = dev_get_platdata(&client->dev); struct regulator_config config = { }; struct max8952_data *max8952; diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 0c5195a842e2..5b77ab7762e4 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -371,7 +371,7 @@ static int max8973_probe(struct i2c_client *client, struct max8973_chip *max; int ret; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata && !client->dev.of_node) { dev_err(&client->dev, "No Platform data"); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index f3c8f8f9dc39..7827384680d6 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -21,6 +21,7 @@ static void of_get_regulation_constraints(struct device_node *np, { const __be32 *min_uV, *max_uV, *uV_offset; const __be32 *min_uA, *max_uA, *ramp_delay; + struct property *prop; struct regulation_constraints *constraints = &(*init_data)->constraints; constraints->name = of_get_property(np, "regulator-name", NULL); @@ -64,9 +65,14 @@ static void of_get_regulation_constraints(struct device_node *np, if (of_property_read_bool(np, "regulator-allow-bypass")) constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS; - ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL); - if (ramp_delay) - constraints->ramp_delay = be32_to_cpu(*ramp_delay); + prop = of_find_property(np, "regulator-ramp-delay", NULL); + if (prop && prop->value) { + ramp_delay = prop->value; + if (*ramp_delay) + constraints->ramp_delay = be32_to_cpu(*ramp_delay); + else + constraints->ramp_disable = true; + } } /** diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index d0c87856dd25..488dfe7ce9a6 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -97,11 +97,16 @@ static const struct regs_info palmas_regs_info[] = { .ctrl_addr = PALMAS_SMPS9_CTRL, }, { - .name = "SMPS10", + .name = "SMPS10_OUT2", .sname = "smps10-in", .ctrl_addr = PALMAS_SMPS10_CTRL, }, { + .name = "SMPS10_OUT1", + .sname = "smps10-out2", + .ctrl_addr = PALMAS_SMPS10_CTRL, + }, + { .name = "LDO1", .sname = "ldo1-in", .vsel_addr = PALMAS_LDO1_VOLTAGE, @@ -487,6 +492,8 @@ static struct regulator_ops palmas_ops_smps10 = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, + .set_bypass = regulator_set_bypass_regmap, + .get_bypass = regulator_get_bypass_regmap, }; static int palmas_is_enabled_ldo(struct regulator_dev *dev) @@ -538,7 +545,8 @@ static int palmas_smps_init(struct palmas *palmas, int id, return ret; switch (id) { - case PALMAS_REG_SMPS10: + case PALMAS_REG_SMPS10_OUT1: + case PALMAS_REG_SMPS10_OUT2: reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK; if (reg_init->mode_sleep) reg |= reg_init->mode_sleep << @@ -681,7 +689,8 @@ static struct of_regulator_match palmas_matches[] = { { .name = "smps7", }, { .name = "smps8", }, { .name = "smps9", }, - { .name = "smps10", }, + { .name = "smps10_out2", }, + { .name = "smps10_out1", }, { .name = "ldo1", }, { .name = "ldo2", }, { .name = "ldo3", }, @@ -765,7 +774,7 @@ static void palmas_dt_to_pdata(struct device *dev, static int palmas_regulators_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); - struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data; + struct palmas_pmic_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; struct regulator_dev *rdev; struct regulator_config config = { }; @@ -838,7 +847,8 @@ static int palmas_regulators_probe(struct platform_device *pdev) continue; ramp_delay_support = true; break; - case PALMAS_REG_SMPS10: + case PALMAS_REG_SMPS10_OUT1: + case PALMAS_REG_SMPS10_OUT2: if (!PALMAS_PMIC_HAS(palmas, SMPS10_BOOST)) continue; } @@ -872,7 +882,8 @@ static int palmas_regulators_probe(struct platform_device *pdev) pmic->desc[id].id = id; switch (id) { - case PALMAS_REG_SMPS10: + case PALMAS_REG_SMPS10_OUT1: + case PALMAS_REG_SMPS10_OUT2: pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES; pmic->desc[id].ops = &palmas_ops_smps10; pmic->desc[id].vsel_reg = @@ -882,7 +893,14 @@ static int palmas_regulators_probe(struct platform_device *pdev) pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, PALMAS_SMPS10_CTRL); - pmic->desc[id].enable_mask = SMPS10_BOOST_EN; + if (id == PALMAS_REG_SMPS10_OUT1) + pmic->desc[id].enable_mask = SMPS10_SWITCH_EN; + else + pmic->desc[id].enable_mask = SMPS10_BOOST_EN; + pmic->desc[id].bypass_reg = + PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, + PALMAS_SMPS10_CTRL); + pmic->desc[id].bypass_mask = SMPS10_BYPASS_EN; pmic->desc[id].min_uV = 3750000; pmic->desc[id].uV_step = 1250000; break; diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 1a73a297fe73..b49eaeedea84 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -243,7 +243,7 @@ static int pcap_regulator_probe(struct platform_device *pdev) struct regulator_config config = { }; config.dev = &pdev->dev; - config.init_data = pdev->dev.platform_data; + config.init_data = dev_get_platdata(&pdev->dev); config.driver_data = pcap; rdev = regulator_register(&pcap_regulators[pdev->id], &config); diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 54df9f7cb504..0f3576d48abf 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -86,7 +86,7 @@ static int pcf50633_regulator_probe(struct platform_device *pdev) pcf = dev_to_pcf50633(pdev->dev.parent); config.dev = &pdev->dev; - config.init_data = pdev->dev.platform_data; + config.init_data = dev_get_platdata(&pdev->dev); config.driver_data = pcf; config.regmap = pcf->regmap; diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c new file mode 100644 index 000000000000..ba67b2c4e2e7 --- /dev/null +++ b/drivers/regulator/pfuze100-regulator.c @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 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/of.h> +#include <linux/of_device.h> +#include <linux/regulator/of_regulator.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/pfuze100.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/regmap.h> + +#define PFUZE_NUMREGS 128 +#define PFUZE100_VOL_OFFSET 0 +#define PFUZE100_STANDBY_OFFSET 1 +#define PFUZE100_MODE_OFFSET 3 +#define PFUZE100_CONF_OFFSET 4 + +#define PFUZE100_DEVICEID 0x0 +#define PFUZE100_REVID 0x3 +#define PFUZE100_FABID 0x3 + +#define PFUZE100_SW1ABVOL 0x20 +#define PFUZE100_SW1CVOL 0x2e +#define PFUZE100_SW2VOL 0x35 +#define PFUZE100_SW3AVOL 0x3c +#define PFUZE100_SW3BVOL 0x43 +#define PFUZE100_SW4VOL 0x4a +#define PFUZE100_SWBSTCON1 0x66 +#define PFUZE100_VREFDDRCON 0x6a +#define PFUZE100_VSNVSVOL 0x6b +#define PFUZE100_VGEN1VOL 0x6c +#define PFUZE100_VGEN2VOL 0x6d +#define PFUZE100_VGEN3VOL 0x6e +#define PFUZE100_VGEN4VOL 0x6f +#define PFUZE100_VGEN5VOL 0x70 +#define PFUZE100_VGEN6VOL 0x71 + +struct pfuze_regulator { + struct regulator_desc desc; + unsigned char stby_reg; + unsigned char stby_mask; +}; + +struct pfuze_chip { + struct regmap *regmap; + struct device *dev; + struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; + struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR]; +}; + +static const int pfuze100_swbst[] = { + 5000000, 5050000, 5100000, 5150000, +}; + +static const int pfuze100_vsnvs[] = { + 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, +}; + +static const struct i2c_device_id pfuze_device_id[] = { + {.name = "pfuze100"}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, pfuze_device_id); + +static const struct of_device_id pfuze_dt_ids[] = { + { .compatible = "fsl,pfuze100" }, + {}, +}; +MODULE_DEVICE_TABLE(of, pfuze_dt_ids); + +static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev); + int id = rdev->desc->id; + unsigned int ramp_bits; + int ret; + + if (id < PFUZE100_SWBST) { + ramp_delay = 12500 / ramp_delay; + ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3); + ret = regmap_update_bits(pfuze100->regmap, + rdev->desc->vsel_reg + 4, + 0xc0, ramp_bits << 6); + if (ret < 0) + dev_err(pfuze100->dev, "ramp failed, err %d\n", ret); + } else + ret = -EACCES; + + return ret; +} + +static struct regulator_ops pfuze100_ldo_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static struct regulator_ops pfuze100_fixed_regulator_ops = { + .list_voltage = regulator_list_voltage_linear, +}; + +static struct regulator_ops pfuze100_sw_regulator_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = pfuze100_set_ramp_delay, +}; + +static struct regulator_ops pfuze100_swb_regulator_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + +}; + +#define PFUZE100_FIXED_REG(_name, base, voltage) \ + [PFUZE100_ ## _name] = { \ + .desc = { \ + .name = #_name, \ + .n_voltages = 1, \ + .ops = &pfuze100_fixed_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PFUZE100_ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (voltage), \ + .enable_reg = (base), \ + .enable_mask = 0x10, \ + }, \ + } + +#define PFUZE100_SW_REG(_name, base, min, max, step) \ + [PFUZE100_ ## _name] = { \ + .desc = { \ + .name = #_name,\ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &pfuze100_sw_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PFUZE100_ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (min), \ + .uV_step = (step), \ + .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ + .vsel_mask = 0x3f, \ + }, \ + .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ + .stby_mask = 0x3f, \ + } + +#define PFUZE100_SWB_REG(_name, base, mask, voltages) \ + [PFUZE100_ ## _name] = { \ + .desc = { \ + .name = #_name, \ + .n_voltages = ARRAY_SIZE(voltages), \ + .ops = &pfuze100_swb_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PFUZE100_ ## _name, \ + .owner = THIS_MODULE, \ + .volt_table = voltages, \ + .vsel_reg = (base), \ + .vsel_mask = (mask), \ + }, \ + } + +#define PFUZE100_VGEN_REG(_name, base, min, max, step) \ + [PFUZE100_ ## _name] = { \ + .desc = { \ + .name = #_name, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &pfuze100_ldo_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PFUZE100_ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (min), \ + .uV_step = (step), \ + .vsel_reg = (base), \ + .vsel_mask = 0xf, \ + .enable_reg = (base), \ + .enable_mask = 0x10, \ + }, \ + .stby_reg = (base), \ + .stby_mask = 0x20, \ + } + +static struct pfuze_regulator pfuze100_regulators[] = { + PFUZE100_SW_REG(SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), + PFUZE100_SW_REG(SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000), + PFUZE100_SW_REG(SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000), + PFUZE100_SWB_REG(SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), + PFUZE100_SWB_REG(VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), + PFUZE100_FIXED_REG(VREFDDR, PFUZE100_VREFDDRCON, 750000), + PFUZE100_VGEN_REG(VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), + PFUZE100_VGEN_REG(VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), + PFUZE100_VGEN_REG(VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), +}; + +#ifdef CONFIG_OF +static struct of_regulator_match pfuze100_matches[] = { + { .name = "sw1ab", }, + { .name = "sw1c", }, + { .name = "sw2", }, + { .name = "sw3a", }, + { .name = "sw3b", }, + { .name = "sw4", }, + { .name = "swbst", }, + { .name = "vsnvs", }, + { .name = "vrefddr", }, + { .name = "vgen1", }, + { .name = "vgen2", }, + { .name = "vgen3", }, + { .name = "vgen4", }, + { .name = "vgen5", }, + { .name = "vgen6", }, +}; + +static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) +{ + struct device *dev = chip->dev; + struct device_node *np, *parent; + int ret; + + np = of_node_get(dev->parent->of_node); + if (!np) + return 0; + + parent = of_find_node_by_name(np, "regulators"); + if (!parent) { + dev_err(dev, "regulators node not found\n"); + return -EINVAL; + } + + ret = of_regulator_match(dev, parent, pfuze100_matches, + ARRAY_SIZE(pfuze100_matches)); + + of_node_put(parent); + if (ret < 0) { + dev_err(dev, "Error parsing regulator init data: %d\n", + ret); + return ret; + } + + return 0; +} + +static inline struct regulator_init_data *match_init_data(int index) +{ + return pfuze100_matches[index].init_data; +} + +static inline struct device_node *match_of_node(int index) +{ + return pfuze100_matches[index].of_node; +} +#else +static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) +{ + return 0; +} + +static inline struct regulator_init_data *match_init_data(int index) +{ + return NULL; +} + +static inline struct device_node *match_of_node(int index) +{ + return NULL; +} +#endif + +static int pfuze_identify(struct pfuze_chip *pfuze_chip) +{ + unsigned int value; + int ret; + + ret = regmap_read(pfuze_chip->regmap, PFUZE100_DEVICEID, &value); + if (ret) + return ret; + + if (value & 0x0f) { + dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value); + return -ENODEV; + } + + ret = regmap_read(pfuze_chip->regmap, PFUZE100_REVID, &value); + if (ret) + return ret; + dev_info(pfuze_chip->dev, + "Full lay: %x, Metal lay: %x\n", + (value & 0xf0) >> 4, value & 0x0f); + + ret = regmap_read(pfuze_chip->regmap, PFUZE100_FABID, &value); + if (ret) + return ret; + dev_info(pfuze_chip->dev, "FAB: %x, FIN: %x\n", + (value & 0xc) >> 2, value & 0x3); + + return 0; +} + +static const struct regmap_config pfuze_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = PFUZE_NUMREGS - 1, + .cache_type = REGCACHE_RBTREE, +}; + +static int pfuze100_regulator_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pfuze_chip *pfuze_chip; + struct pfuze_regulator_platform_data *pdata = + dev_get_platdata(&client->dev); + struct regulator_config config = { }; + int i, ret; + + pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip), + GFP_KERNEL); + if (!pfuze_chip) + return -ENOMEM; + + i2c_set_clientdata(client, pfuze_chip); + + memcpy(pfuze_chip->regulator_descs, pfuze100_regulators, + sizeof(pfuze_chip->regulator_descs)); + + pfuze_chip->dev = &client->dev; + + pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config); + if (IS_ERR(pfuze_chip->regmap)) { + ret = PTR_ERR(pfuze_chip->regmap); + dev_err(&client->dev, + "regmap allocation failed with err %d\n", ret); + return ret; + } + + ret = pfuze_identify(pfuze_chip); + if (ret) { + dev_err(&client->dev, "unrecognized pfuze chip ID!\n"); + return ret; + } + + ret = pfuze_parse_regulators_dt(pfuze_chip); + if (ret) + return ret; + + for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) { + struct regulator_init_data *init_data; + struct regulator_desc *desc; + int val; + + desc = &pfuze_chip->regulator_descs[i].desc; + + if (pdata) + init_data = pdata->init_data[i]; + else + init_data = match_init_data(i); + + /* SW2~SW4 high bit check and modify the voltage value table */ + if (i > PFUZE100_SW1C && i < PFUZE100_SWBST) { + regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val); + if (val & 0x40) { + desc->min_uV = 800000; + desc->uV_step = 50000; + desc->n_voltages = 51; + } + } + + config.dev = &client->dev; + config.init_data = init_data; + config.driver_data = pfuze_chip; + config.of_node = match_of_node(i); + + pfuze_chip->regulators[i] = regulator_register(desc, &config); + if (IS_ERR(pfuze_chip->regulators[i])) { + dev_err(&client->dev, "register regulator%s failed\n", + pfuze100_regulators[i].desc.name); + ret = PTR_ERR(pfuze_chip->regulators[i]); + while (--i >= 0) + regulator_unregister(pfuze_chip->regulators[i]); + return ret; + } + } + + return 0; +} + +static int pfuze100_regulator_remove(struct i2c_client *client) +{ + int i; + struct pfuze_chip *pfuze_chip = i2c_get_clientdata(client); + + for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) + regulator_unregister(pfuze_chip->regulators[i]); + + return 0; +} + +static struct i2c_driver pfuze_driver = { + .id_table = pfuze_device_id, + .driver = { + .name = "pfuze100-regulator", + .owner = THIS_MODULE, + .of_match_table = pfuze_dt_ids, + }, + .probe = pfuze100_regulator_probe, + .remove = pfuze100_regulator_remove, +}; +module_i2c_driver(pfuze_driver); + +MODULE_AUTHOR("Robin Gong <b38343@freescale.com>"); +MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100 PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("i2c:pfuze100-regulator"); diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 2f62564ca936..5eba2ff8c0e8 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -16,12 +16,17 @@ #include <linux/gpio.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.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/samsung/core.h> #include <linux/mfd/samsung/s2mps11.h> +#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators) + struct s2mps11_info { struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX]; @@ -31,11 +36,6 @@ struct s2mps11_info { int ramp_delay16; int ramp_delay7810; int ramp_delay9; - - bool buck6_ramp; - bool buck2_ramp; - bool buck3_ramp; - bool buck4_ramp; }; static int get_ramp_delay(int ramp_delay) @@ -50,9 +50,171 @@ static int get_ramp_delay(int ramp_delay) break; cnt++; } + + if (cnt > 3) + cnt = 3; + return cnt; } +static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + unsigned int ramp_delay = 0; + int old_volt, new_volt; + + switch (rdev->desc->id) { + case S2MPS11_BUCK2: + ramp_delay = s2mps11->ramp_delay2; + break; + case S2MPS11_BUCK3: + ramp_delay = s2mps11->ramp_delay34; + break; + case S2MPS11_BUCK4: + ramp_delay = s2mps11->ramp_delay34; + break; + case S2MPS11_BUCK5: + ramp_delay = s2mps11->ramp_delay5; + break; + case S2MPS11_BUCK6: + case S2MPS11_BUCK1: + ramp_delay = s2mps11->ramp_delay16; + break; + case S2MPS11_BUCK7: + case S2MPS11_BUCK8: + case S2MPS11_BUCK10: + ramp_delay = s2mps11->ramp_delay7810; + break; + case S2MPS11_BUCK9: + ramp_delay = s2mps11->ramp_delay9; + } + + if (ramp_delay == 0) + ramp_delay = rdev->desc->ramp_delay; + + old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector); + new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector); + + return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay); +} + +static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + unsigned int ramp_val, ramp_shift, ramp_reg = S2MPS11_REG_RAMP_BUCK; + unsigned int ramp_enable = 1, enable_shift = 0; + int ret; + + switch (rdev->desc->id) { + case S2MPS11_BUCK1: + if (ramp_delay > s2mps11->ramp_delay16) + s2mps11->ramp_delay16 = ramp_delay; + else + ramp_delay = s2mps11->ramp_delay16; + + ramp_shift = S2MPS11_BUCK16_RAMP_SHIFT; + break; + case S2MPS11_BUCK2: + enable_shift = S2MPS11_BUCK2_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + s2mps11->ramp_delay2 = ramp_delay; + ramp_shift = S2MPS11_BUCK2_RAMP_SHIFT; + ramp_reg = S2MPS11_REG_RAMP; + break; + case S2MPS11_BUCK3: + enable_shift = S2MPS11_BUCK3_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mps11->ramp_delay34) + s2mps11->ramp_delay34 = ramp_delay; + else + ramp_delay = s2mps11->ramp_delay34; + + ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT; + ramp_reg = S2MPS11_REG_RAMP; + break; + case S2MPS11_BUCK4: + enable_shift = S2MPS11_BUCK4_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mps11->ramp_delay34) + s2mps11->ramp_delay34 = ramp_delay; + else + ramp_delay = s2mps11->ramp_delay34; + + ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT; + ramp_reg = S2MPS11_REG_RAMP; + break; + case S2MPS11_BUCK5: + s2mps11->ramp_delay5 = ramp_delay; + ramp_shift = S2MPS11_BUCK5_RAMP_SHIFT; + break; + case S2MPS11_BUCK6: + enable_shift = S2MPS11_BUCK6_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mps11->ramp_delay16) + s2mps11->ramp_delay16 = ramp_delay; + else + ramp_delay = s2mps11->ramp_delay16; + + ramp_shift = S2MPS11_BUCK16_RAMP_SHIFT; + break; + case S2MPS11_BUCK7: + case S2MPS11_BUCK8: + case S2MPS11_BUCK10: + if (ramp_delay > s2mps11->ramp_delay7810) + s2mps11->ramp_delay7810 = ramp_delay; + else + ramp_delay = s2mps11->ramp_delay7810; + + ramp_shift = S2MPS11_BUCK7810_RAMP_SHIFT; + break; + case S2MPS11_BUCK9: + s2mps11->ramp_delay9 = ramp_delay; + ramp_shift = S2MPS11_BUCK9_RAMP_SHIFT; + break; + default: + return 0; + } + + if (!ramp_enable) + goto ramp_disable; + + if (enable_shift) { + ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, + 1 << enable_shift, 1 << enable_shift); + if (ret) { + dev_err(&rdev->dev, "failed to enable ramp rate\n"); + return ret; + } + } + + ramp_val = get_ramp_delay(ramp_delay); + + return regmap_update_bits(rdev->regmap, ramp_reg, 0x3 << ramp_shift, + ramp_val << ramp_shift); + +ramp_disable: + return regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, + 1 << enable_shift, 0); +} + static struct regulator_ops s2mps11_ldo_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -72,7 +234,8 @@ static struct regulator_ops s2mps11_buck_ops = { .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_voltage_time_sel = s2mps11_regulator_set_voltage_time_sel, + .set_ramp_delay = s2mps11_set_ramp_delay, }; #define regulator_desc_ldo1(num) { \ @@ -239,59 +402,51 @@ 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); + struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX]; + struct device_node *reg_np = NULL; struct regulator_config config = { }; struct s2mps11_info *s2mps11; int i, ret; - unsigned char ramp_enable, ramp_reg = 0; - - if (!pdata) { - dev_err(pdev->dev.parent, "Platform data not supplied\n"); - return -ENODEV; - } s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info), GFP_KERNEL); if (!s2mps11) return -ENOMEM; - platform_set_drvdata(pdev, s2mps11); + if (!iodev->dev->of_node) { + if (pdata) { + goto common_reg; + } else { + dev_err(pdev->dev.parent, + "Platform data or DT node not supplied\n"); + return -ENODEV; + } + } - s2mps11->ramp_delay2 = pdata->buck2_ramp_delay; - s2mps11->ramp_delay34 = pdata->buck34_ramp_delay; - s2mps11->ramp_delay5 = pdata->buck5_ramp_delay; - s2mps11->ramp_delay16 = pdata->buck16_ramp_delay; - s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay; - s2mps11->ramp_delay9 = pdata->buck9_ramp_delay; - - s2mps11->buck6_ramp = pdata->buck6_ramp_enable; - s2mps11->buck2_ramp = pdata->buck2_ramp_enable; - s2mps11->buck3_ramp = pdata->buck3_ramp_enable; - s2mps11->buck4_ramp = pdata->buck4_ramp_enable; - - ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) | - (s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ; - - if (ramp_enable) { - if (s2mps11->buck2_ramp) - 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; - sec_reg_write(iodev, S2MPS11_REG_RAMP, ramp_reg | ramp_enable); + for (i = 0; i < S2MPS11_REGULATOR_CNT; i++) + rdata[i].name = regulators[i].name; + + reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators"); + if (!reg_np) { + dev_err(&pdev->dev, "could not find regulators sub-node\n"); + return -EINVAL; } - 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_delay9); - sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg); + of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX); - for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { +common_reg: + platform_set_drvdata(pdev, s2mps11); - config.dev = &pdev->dev; - config.regmap = iodev->regmap; - config.init_data = pdata->regulators[i].initdata; - config.driver_data = s2mps11; + config.dev = &pdev->dev; + config.regmap = iodev->regmap; + config.driver_data = s2mps11; + for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { + if (!reg_np) { + config.init_data = pdata->regulators[i].initdata; + } else { + config.init_data = rdata[i].init_data; + config.of_node = rdata[i].of_node; + } s2mps11->rdev[i] = regulator_register(®ulators[i], &config); if (IS_ERR(s2mps11->rdev[i])) { diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index 3753ed05e719..d8e3e1262bc2 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -717,11 +717,6 @@ static int ti_abb_probe(struct platform_device *pdev) /* Map ABB resources */ pname = "base-address"; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); - if (!res) { - dev_err(dev, "Missing '%s' IO resource\n", pname); - ret = -ENODEV; - goto err; - } abb->base = devm_ioremap_resource(dev, res); if (IS_ERR(abb->base)) { ret = PTR_ERR(abb->base); @@ -770,11 +765,6 @@ static int ti_abb_probe(struct platform_device *pdev) pname = "ldo-address"; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); - if (!res) { - dev_dbg(dev, "Missing '%s' IO resource\n", pname); - ret = -ENODEV; - goto skip_opt; - } abb->ldo_base = devm_ioremap_resource(dev, res); if (IS_ERR(abb->ldo_base)) { ret = PTR_ERR(abb->ldo_base); diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index 6e67be75ea1b..9392a7ca3d2d 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -275,7 +275,7 @@ static int tps51632_probe(struct i2c_client *client, } } - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata && client->dev.of_node) pdata = of_get_tps51632_platform_data(&client->dev); if (!pdata) { diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index a490d5b749b2..0b7ebb1ebf85 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -350,7 +350,7 @@ static int tps62360_probe(struct i2c_client *client, int i; int chip_id; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (client->dev.of_node) { const struct of_device_id *match; diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 9d053e23e9eb..a15263d4bdff 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -218,7 +218,7 @@ static int tps_65023_probe(struct i2c_client *client, * init_data points to array of regulator_init structures * coming from the board-evm file. */ - init_data = client->dev.platform_data; + init_data = dev_get_platdata(&client->dev); if (!init_data) return -EIO; diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 2df4616621f5..90861d68a0b0 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -27,7 +27,7 @@ #include <linux/regulator/machine.h> #include <linux/mfd/tps65217.h> -#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t) \ +#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t, _lr, _nlr) \ { \ .name = _name, \ .id = _id, \ @@ -40,17 +40,10 @@ .enable_reg = TPS65217_REG_ENABLE, \ .enable_mask = _em, \ .volt_table = _t, \ + .linear_ranges = _lr, \ + .n_linear_ranges = _nlr, \ } \ -#define TPS65217_INFO(_nm, _min, _max, _f1, _f2) \ - { \ - .name = _nm, \ - .min_uV = _min, \ - .max_uV = _max, \ - .vsel_to_uv = _f1, \ - .uv_to_vsel = _f2, \ - } - static const unsigned int LDO1_VSEL_table[] = { 1000000, 1100000, 1200000, 1250000, 1300000, 1350000, 1400000, 1500000, @@ -58,88 +51,26 @@ static const unsigned int LDO1_VSEL_table[] = { 2800000, 3000000, 3100000, 3300000, }; -static int tps65217_vsel_to_uv1(unsigned int vsel) -{ - int uV = 0; - - if (vsel > 63) - return -EINVAL; - - if (vsel <= 24) - uV = vsel * 25000 + 900000; - else if (vsel <= 52) - uV = (vsel - 24) * 50000 + 1500000; - else if (vsel < 56) - uV = (vsel - 52) * 100000 + 2900000; - else - uV = 3300000; - - return uV; -} - -static int tps65217_uv_to_vsel1(int uV, unsigned int *vsel) -{ - if (uV < 0 || uV > 3300000) - return -EINVAL; - - if (uV <= 1500000) - *vsel = DIV_ROUND_UP(uV - 900000, 25000); - else if (uV <= 2900000) - *vsel = 24 + DIV_ROUND_UP(uV - 1500000, 50000); - else if (uV < 3300000) - *vsel = 52 + DIV_ROUND_UP(uV - 2900000, 100000); - else - *vsel = 56; - - return 0; -} - -static int tps65217_vsel_to_uv2(unsigned int vsel) -{ - int uV = 0; - - if (vsel > 31) - return -EINVAL; - - if (vsel <= 8) - uV = vsel * 50000 + 1500000; - else if (vsel <= 13) - uV = (vsel - 8) * 100000 + 1900000; - else - uV = (vsel - 13) * 50000 + 2400000; - - return uV; -} - -static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel) -{ - if (uV < 0 || uV > 3300000) - return -EINVAL; - - if (uV <= 1900000) - *vsel = DIV_ROUND_UP(uV - 1500000, 50000); - else if (uV <= 2400000) - *vsel = 8 + DIV_ROUND_UP(uV - 1900000, 100000); - else - *vsel = 13 + DIV_ROUND_UP(uV - 2400000, 50000); - - return 0; -} +static const struct regulator_linear_range tps65217_uv1_ranges[] = { + { .min_uV = 900000, .max_uV = 1500000, .min_sel = 0, .max_sel = 24, + .uV_step = 25000 }, + { .min_uV = 1550000, .max_uV = 1800000, .min_sel = 25, .max_sel = 30, + .uV_step = 50000 }, + { .min_uV = 1850000, .max_uV = 2900000, .min_sel = 31, .max_sel = 52, + .uV_step = 50000 }, + { .min_uV = 3000000, .max_uV = 3200000, .min_sel = 53, .max_sel = 55, + .uV_step = 100000 }, + { .min_uV = 3300000, .max_uV = 3300000, .min_sel = 56, .max_sel = 62, + .uV_step = 0 }, +}; -static struct tps_info tps65217_pmic_regs[] = { - TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1, - tps65217_uv_to_vsel1), - TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1, - tps65217_uv_to_vsel1), - TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1, - tps65217_uv_to_vsel1), - TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL), - TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1, - tps65217_uv_to_vsel1), - TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2, - tps65217_uv_to_vsel2), - TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2, - tps65217_uv_to_vsel2), +static const struct regulator_linear_range tps65217_uv2_ranges[] = { + { .min_uV = 1500000, .max_uV = 1900000, .min_sel = 0, .max_sel = 8, + .uV_step = 50000 }, + { .min_uV = 2000000, .max_uV = 2400000, .min_sel = 9, .max_sel = 13, + .uV_step = 100000 }, + { .min_uV = 2450000, .max_uV = 3300000, .min_sel = 14, .max_sel = 31, + .uV_step = 50000 }, }; static int tps65217_pmic_enable(struct regulator_dev *dev) @@ -192,49 +123,6 @@ static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev, return ret; } -static int tps65217_pmic_map_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) -{ - - struct tps65217 *tps = rdev_get_drvdata(dev); - unsigned int sel, rid = rdev_get_id(dev); - int ret; - - /* LDO1 uses regulator_map_voltage_iterate() */ - if (rid == TPS65217_LDO_1) - return -EINVAL; - - if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) - return -EINVAL; - - if (min_uV < tps->info[rid]->min_uV) - min_uV = tps->info[rid]->min_uV; - - if (max_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV) - return -EINVAL; - - ret = tps->info[rid]->uv_to_vsel(min_uV, &sel); - if (ret) - return ret; - - return sel; -} - -static int tps65217_pmic_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - struct tps65217 *tps = rdev_get_drvdata(dev); - unsigned int rid = rdev_get_id(dev); - - if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) - return -EINVAL; - - if (selector >= dev->desc->n_voltages) - return -EINVAL; - - return tps->info[rid]->vsel_to_uv(selector); -} - /* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */ static struct regulator_ops tps65217_pmic_ops = { .is_enabled = regulator_is_enabled_regmap, @@ -242,8 +130,8 @@ static struct regulator_ops tps65217_pmic_ops = { .disable = tps65217_pmic_disable, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = tps65217_pmic_set_voltage_sel, - .list_voltage = tps65217_pmic_list_voltage, - .map_voltage = tps65217_pmic_map_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, }; /* Operations permitted on LDO1 */ @@ -259,27 +147,33 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = { static const struct regulator_desc regulators[] = { TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK, - TPS65217_ENABLE_DC1_EN, NULL), + TPS65217_ENABLE_DC1_EN, NULL, tps65217_uv1_ranges, + 2), /* DCDC1 voltage range: 900000 ~ 1800000 */ TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK, - TPS65217_ENABLE_DC2_EN, NULL), + TPS65217_ENABLE_DC2_EN, NULL, tps65217_uv1_ranges, + ARRAY_SIZE(tps65217_uv1_ranges)), TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK, - TPS65217_ENABLE_DC3_EN, NULL), + TPS65217_ENABLE_DC3_EN, NULL, tps65217_uv1_ranges, + 1), /* DCDC3 voltage range: 900000 ~ 1500000 */ TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16, TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK, - TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table), + TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table, NULL, 0), TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64, TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK, - TPS65217_ENABLE_LDO2_EN, NULL), + TPS65217_ENABLE_LDO2_EN, NULL, tps65217_uv1_ranges, + ARRAY_SIZE(tps65217_uv1_ranges)), TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32, TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK, TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN, - NULL), + NULL, tps65217_uv2_ranges, + ARRAY_SIZE(tps65217_uv2_ranges)), TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32, TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK, TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN, - NULL), + NULL, tps65217_uv2_ranges, + ARRAY_SIZE(tps65217_uv2_ranges)), }; #ifdef CONFIG_OF @@ -368,8 +262,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev) continue; /* Register the regulators */ - tps->info[i] = &tps65217_pmic_regs[i]; - config.dev = tps->dev; config.init_data = reg_data; config.driver_data = tps; diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 1094393155ed..62e8d28beabd 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -601,7 +601,7 @@ static int pmic_probe(struct spi_device *spi) struct regulator_config config = { }; int ret = 0, i; - init_data = dev->platform_data; + init_data = dev_get_platdata(dev); if (!init_data) { dev_err(dev, "could not find regulator platform data\n"); return -EINVAL; diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index 17e994e47dc1..281e52ac64ba 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -118,6 +118,15 @@ struct tps65912_reg { int eco_reg; }; +static const struct regulator_linear_range tps65912_ldo_ranges[] = { + { .min_uV = 800000, .max_uV = 1600000, .min_sel = 0, .max_sel = 32, + .uV_step = 25000 }, + { .min_uV = 1650000, .max_uV = 3000000, .min_sel = 33, .max_sel = 60, + .uV_step = 50000 }, + { .min_uV = 3100000, .max_uV = 3300000, .min_sel = 61, .max_sel = 63, + .uV_step = 100000 }, +}; + static int tps65912_get_range(struct tps65912_reg *pmic, int id) { struct tps65912 *mfd = pmic->mfd; @@ -184,20 +193,6 @@ static unsigned long tps65912_vsel_to_uv_range3(u8 vsel) return uv; } -static unsigned long tps65912_vsel_to_uv_ldo(u8 vsel) -{ - unsigned long uv = 0; - - if (vsel <= 32) - uv = ((vsel * 25000) + 800000); - else if (vsel > 32 && vsel <= 60) - uv = (((vsel - 32) * 50000) + 1600000); - else if (vsel > 60) - uv = (((vsel - 60) * 100000) + 3000000); - - return uv; -} - static int tps65912_get_ctrl_register(int id) { if (id >= TPS65912_REG_DCDC1 && id <= TPS65912_REG_LDO4) @@ -376,9 +371,6 @@ static int tps65912_list_voltage(struct regulator_dev *dev, unsigned selector) struct tps65912_reg *pmic = rdev_get_drvdata(dev); int range, voltage = 0, id = rdev_get_id(dev); - if (id >= TPS65912_REG_LDO1 && id <= TPS65912_REG_LDO10) - return tps65912_vsel_to_uv_ldo(selector); - if (id > TPS65912_REG_DCDC4) return -EINVAL; @@ -456,7 +448,8 @@ static struct regulator_ops tps65912_ops_ldo = { .disable = tps65912_reg_disable, .get_voltage_sel = tps65912_get_voltage_sel, .set_voltage_sel = tps65912_set_voltage_sel, - .list_voltage = tps65912_list_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, }; static int tps65912_probe(struct platform_device *pdev) @@ -495,8 +488,14 @@ static int tps65912_probe(struct platform_device *pdev) pmic->desc[i].name = info->name; pmic->desc[i].id = i; pmic->desc[i].n_voltages = 64; - pmic->desc[i].ops = (i > TPS65912_REG_DCDC4 ? - &tps65912_ops_ldo : &tps65912_ops_dcdc); + if (i > TPS65912_REG_DCDC4) { + pmic->desc[i].ops = &tps65912_ops_ldo; + pmic->desc[i].linear_ranges = tps65912_ldo_ranges; + pmic->desc[i].n_linear_ranges = + ARRAY_SIZE(tps65912_ldo_ranges); + } else { + pmic->desc[i].ops = &tps65912_ops_dcdc; + } pmic->desc[i].type = REGULATOR_VOLTAGE; pmic->desc[i].owner = THIS_MODULE; range = tps65912_get_range(pmic, i); diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 93bc4f456da4..78aae4cbb004 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -1108,7 +1108,7 @@ static int twlreg_probe(struct platform_device *pdev) drvdata = NULL; } else { id = pdev->id; - initdata = pdev->dev.platform_data; + initdata = dev_get_platdata(&pdev->dev); for (i = 0, template = NULL; i < ARRAY_SIZE(twl_of_match); i++) { template = twl_of_match[i].data; if (template && template->desc.id == id) diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c index a7c8deb5f28f..765acc11c9c8 100644 --- a/drivers/regulator/userspace-consumer.c +++ b/drivers/regulator/userspace-consumer.c @@ -111,7 +111,7 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev) struct userspace_consumer_data *drvdata; int ret; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) return -EINVAL; diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index a9d4284ea007..f53e78b9a84e 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -287,7 +287,7 @@ static const struct attribute_group regulator_virtual_attr_group = { static int regulator_virtual_probe(struct platform_device *pdev) { - char *reg_id = pdev->dev.platform_data; + char *reg_id = dev_get_platdata(&pdev->dev); struct virtual_consumer_data *drvdata; int ret; diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 46938cf162ad..11861cb861df 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -451,7 +451,7 @@ static void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, 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; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct regulator_config config = { }; int id; struct wm831x_dcdc *dcdc; @@ -624,7 +624,7 @@ static struct regulator_ops wm831x_buckp_ops = { 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; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct regulator_config config = { }; int id; struct wm831x_dcdc *dcdc; @@ -770,7 +770,7 @@ static struct regulator_ops wm831x_boostp_ops = { 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; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct regulator_config config = { }; int id = pdev->id % ARRAY_SIZE(pdata->dcdc); struct wm831x_dcdc *dcdc; @@ -880,7 +880,7 @@ static struct regulator_ops wm831x_epe_ops = { 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; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct regulator_config config = { }; int id = pdev->id % ARRAY_SIZE(pdata->epe); struct wm831x_dcdc *dcdc; diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 16ebdf94d0a0..4eb373de1fac 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -151,7 +151,7 @@ static irqreturn_t wm831x_isink_irq(int irq, void *data) 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; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct wm831x_isink *isink; int id = pdev->id % ARRAY_SIZE(pdata->isink); struct regulator_config config = { }; diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 9ff883f80878..1432b26ef2e9 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -62,41 +62,12 @@ static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data) * General purpose LDOs */ -#define WM831X_GP_LDO_SELECTOR_LOW 0xe -#define WM831X_GP_LDO_MAX_SELECTOR 0x1f - -static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - /* 0.9-1.6V in 50mV steps */ - if (selector <= WM831X_GP_LDO_SELECTOR_LOW) - return 900000 + (selector * 50000); - /* 1.7-3.3V in 100mV steps */ - if (selector <= WM831X_GP_LDO_MAX_SELECTOR) - return 1600000 + ((selector - WM831X_GP_LDO_SELECTOR_LOW) - * 100000); - return -EINVAL; -} - -static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int volt, vsel; - - if (min_uV < 900000) - vsel = 0; - else if (min_uV < 1700000) - vsel = ((min_uV - 900000) / 50000); - else - vsel = ((min_uV - 1700000) / 100000) - + WM831X_GP_LDO_SELECTOR_LOW + 1; - - volt = wm831x_gp_ldo_list_voltage(rdev, vsel); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return vsel; -} +static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = { + { .min_uV = 900000, .max_uV = 1650000, .min_sel = 0, .max_sel = 14, + .uV_step = 50000 }, + { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, + .uV_step = 100000 }, +}; static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -105,7 +76,7 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, struct wm831x *wm831x = ldo->wm831x; int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; - sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV); + sel = regulator_map_voltage_linear_range(rdev, uV, uV); if (sel < 0) return sel; @@ -230,8 +201,8 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev, static struct regulator_ops wm831x_gp_ldo_ops = { - .list_voltage = wm831x_gp_ldo_list_voltage, - .map_voltage = wm831x_gp_ldo_map_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage, @@ -250,7 +221,7 @@ static struct regulator_ops wm831x_gp_ldo_ops = { 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; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct regulator_config config = { }; int id; struct wm831x_ldo *ldo; @@ -290,7 +261,7 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev) ldo->desc.id = id; ldo->desc.type = REGULATOR_VOLTAGE; - ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1; + ldo->desc.n_voltages = 32; ldo->desc.ops = &wm831x_gp_ldo_ops; ldo->desc.owner = THIS_MODULE; ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL; @@ -299,6 +270,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev) ldo->desc.enable_mask = 1 << id; ldo->desc.bypass_reg = ldo->base; ldo->desc.bypass_mask = WM831X_LDO1_SWI; + ldo->desc.linear_ranges = wm831x_gp_ldo_ranges; + ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_gp_ldo_ranges); config.dev = pdev->dev.parent; if (pdata) @@ -358,43 +331,12 @@ static struct platform_driver wm831x_gp_ldo_driver = { * Analogue LDOs */ - -#define WM831X_ALDO_SELECTOR_LOW 0xc -#define WM831X_ALDO_MAX_SELECTOR 0x1f - -static int wm831x_aldo_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - /* 1-1.6V in 50mV steps */ - if (selector <= WM831X_ALDO_SELECTOR_LOW) - return 1000000 + (selector * 50000); - /* 1.7-3.5V in 100mV steps */ - if (selector <= WM831X_ALDO_MAX_SELECTOR) - return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW) - * 100000); - return -EINVAL; -} - -static int wm831x_aldo_map_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int volt, vsel; - - if (min_uV < 1000000) - vsel = 0; - else if (min_uV < 1700000) - vsel = ((min_uV - 1000000) / 50000); - else - vsel = ((min_uV - 1700000) / 100000) - + WM831X_ALDO_SELECTOR_LOW + 1; - - volt = wm831x_aldo_list_voltage(rdev, vsel); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return vsel; - -} +static const struct regulator_linear_range wm831x_aldo_ranges[] = { + { .min_uV = 1000000, .max_uV = 1650000, .min_sel = 0, .max_sel = 12, + .uV_step = 50000 }, + { .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31, + .uV_step = 100000 }, +}; static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -403,7 +345,7 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, struct wm831x *wm831x = ldo->wm831x; int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; - sel = wm831x_aldo_map_voltage(rdev, uV, uV); + sel = regulator_map_voltage_linear_range(rdev, uV, uV); if (sel < 0) return sel; @@ -486,8 +428,8 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev) } static struct regulator_ops wm831x_aldo_ops = { - .list_voltage = wm831x_aldo_list_voltage, - .map_voltage = wm831x_aldo_map_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_suspend_voltage = wm831x_aldo_set_suspend_voltage, @@ -505,7 +447,7 @@ static struct regulator_ops wm831x_aldo_ops = { 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; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct regulator_config config = { }; int id; struct wm831x_ldo *ldo; @@ -545,7 +487,9 @@ static int wm831x_aldo_probe(struct platform_device *pdev) ldo->desc.id = id; ldo->desc.type = REGULATOR_VOLTAGE; - ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1; + ldo->desc.n_voltages = 32; + ldo->desc.linear_ranges = wm831x_aldo_ranges; + ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_aldo_ranges); ldo->desc.ops = &wm831x_aldo_ops; ldo->desc.owner = THIS_MODULE; ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL; @@ -661,7 +605,7 @@ static struct regulator_ops wm831x_alive_ldo_ops = { 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; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct regulator_config config = { }; int id; struct wm831x_ldo *ldo; diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 7f0fa22ef2aa..835b5f0f344e 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -542,41 +542,12 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev, return 0; } -static int wm8350_ldo_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - if (selector > WM8350_LDO1_VSEL_MASK) - return -EINVAL; - - if (selector < 16) - return (selector * 50000) + 900000; - else - return ((selector - 16) * 100000) + 1800000; -} - -static int wm8350_ldo_map_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV) -{ - int volt, sel; - int min_mV = min_uV / 1000; - int max_mV = max_uV / 1000; - - if (min_mV < 900 || min_mV > 3300) - return -EINVAL; - if (max_mV < 900 || max_mV > 3300) - return -EINVAL; - - if (min_mV < 1800) /* step size is 50mV < 1800mV */ - sel = DIV_ROUND_UP(min_uV - 900, 50); - else /* step size is 100mV > 1800mV */ - sel = DIV_ROUND_UP(min_uV - 1800, 100) + 16; - - volt = wm8350_ldo_list_voltage(rdev, sel); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return sel; -} +static const struct regulator_linear_range wm8350_ldo_ranges[] = { + { .min_uV = 900000, .max_uV = 1750000, .min_sel = 0, .max_sel = 15, + .uV_step = 50000 }, + { .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31, + .uV_step = 100000 }, +}; static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) { @@ -603,7 +574,7 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) return -EINVAL; } - sel = wm8350_ldo_map_voltage(rdev, uV, uV); + sel = regulator_map_voltage_linear_range(rdev, uV, uV); if (sel < 0) return -EINVAL; @@ -998,10 +969,10 @@ static struct regulator_ops wm8350_dcdc2_5_ops = { }; static struct regulator_ops wm8350_ldo_ops = { - .map_voltage = wm8350_ldo_map_voltage, + .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .list_voltage = wm8350_ldo_list_voltage, + .list_voltage = regulator_list_voltage_linear_range, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -1108,6 +1079,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO1, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO1_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO1_CONTROL, .vsel_mask = WM8350_LDO1_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, @@ -1121,6 +1094,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO2, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO2_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO2_CONTROL, .vsel_mask = WM8350_LDO2_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, @@ -1134,6 +1109,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO3, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO3_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO3_CONTROL, .vsel_mask = WM8350_LDO3_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, @@ -1147,6 +1124,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { .irq = WM8350_IRQ_UV_LDO4, .type = REGULATOR_VOLTAGE, .n_voltages = WM8350_LDO4_VSEL_MASK + 1, + .linear_ranges = wm8350_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges), .vsel_reg = WM8350_LDO4_CONTROL, .vsel_mask = WM8350_LDO4_VSEL_MASK, .enable_reg = WM8350_DCDC_LDO_REQUESTED, @@ -1222,7 +1201,7 @@ static int wm8350_regulator_probe(struct platform_device *pdev) } config.dev = &pdev->dev; - config.init_data = pdev->dev.platform_data; + config.init_data = dev_get_platdata(&pdev->dev); config.driver_data = dev_get_drvdata(&pdev->dev); config.regmap = wm8350->regmap; diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index a09f03ee5506..58f51bec13f2 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -19,47 +19,21 @@ #include <linux/regulator/driver.h> #include <linux/mfd/wm8400-private.h> -static int wm8400_ldo_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - if (selector > WM8400_LDO1_VSEL_MASK) - return -EINVAL; - - if (selector < 15) - return 900000 + (selector * 50000); - else - return 1700000 + ((selector - 15) * 100000); -} - -static int wm8400_ldo_map_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) -{ - u16 val; - int volt; - - if (min_uV < 900000 || min_uV > 3300000) - return -EINVAL; - - if (min_uV < 1700000) /* Steps of 50mV from 900mV; */ - val = DIV_ROUND_UP(min_uV - 900000, 50000); - else /* Steps of 100mV from 1700mV */ - val = DIV_ROUND_UP(min_uV - 1700000, 100000) + 15; - - volt = wm8400_ldo_list_voltage(dev, val); - if (volt < min_uV || volt > max_uV) - return -EINVAL; - - return val; -} +static const struct regulator_linear_range wm8400_ldo_ranges[] = { + { .min_uV = 900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14, + .uV_step = 50000 }, + { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, + .uV_step = 100000 }, +}; static struct regulator_ops wm8400_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .list_voltage = wm8400_ldo_list_voltage, + .list_voltage = regulator_list_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .map_voltage = wm8400_ldo_map_voltage, + .map_voltage = regulator_map_voltage_linear_range, }; static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev) @@ -155,6 +129,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO1_CONTROL, .enable_mask = WM8400_LDO1_ENA, .n_voltages = WM8400_LDO1_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .vsel_reg = WM8400_LDO1_CONTROL, .vsel_mask = WM8400_LDO1_VSEL_MASK, .type = REGULATOR_VOLTAGE, @@ -167,6 +143,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO2_CONTROL, .enable_mask = WM8400_LDO2_ENA, .n_voltages = WM8400_LDO2_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .type = REGULATOR_VOLTAGE, .vsel_reg = WM8400_LDO2_CONTROL, .vsel_mask = WM8400_LDO2_VSEL_MASK, @@ -179,6 +157,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO3_CONTROL, .enable_mask = WM8400_LDO3_ENA, .n_voltages = WM8400_LDO3_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .vsel_reg = WM8400_LDO3_CONTROL, .vsel_mask = WM8400_LDO3_VSEL_MASK, .type = REGULATOR_VOLTAGE, @@ -191,6 +171,8 @@ static struct regulator_desc regulators[] = { .enable_reg = WM8400_LDO4_CONTROL, .enable_mask = WM8400_LDO4_ENA, .n_voltages = WM8400_LDO4_VSEL_MASK + 1, + .linear_ranges = wm8400_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges), .vsel_reg = WM8400_LDO4_CONTROL, .vsel_mask = WM8400_LDO4_VSEL_MASK, .type = REGULATOR_VOLTAGE, @@ -233,7 +215,7 @@ static int wm8400_regulator_probe(struct platform_device *pdev) struct regulator_dev *rdev; config.dev = &pdev->dev; - config.init_data = pdev->dev.platform_data; + config.init_data = dev_get_platdata(&pdev->dev); config.driver_data = wm8400; config.regmap = wm8400->regmap; diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 8f2a8a7a3f99..5ee2a208457c 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -125,7 +125,7 @@ static const struct regulator_init_data wm8994_ldo_default[] = { 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; + struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev); int id = pdev->id % ARRAY_SIZE(pdata->ldo); struct regulator_config config = { }; struct wm8994_ldo *ldo; diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index 1a8dd7afe084..c06d78af3342 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -160,7 +160,8 @@ enum palmas_regulators { PALMAS_REG_SMPS7, PALMAS_REG_SMPS8, PALMAS_REG_SMPS9, - PALMAS_REG_SMPS10, + PALMAS_REG_SMPS10_OUT2, + PALMAS_REG_SMPS10_OUT1, /* LDO regulators */ PALMAS_REG_LDO1, PALMAS_REG_LDO2, @@ -355,9 +356,9 @@ struct palmas_pmic { int smps123; int smps457; - int range[PALMAS_REG_SMPS10]; - unsigned int ramp_delay[PALMAS_REG_SMPS10]; - unsigned int current_reg_mode[PALMAS_REG_SMPS10]; + int range[PALMAS_REG_SMPS10_OUT1]; + unsigned int ramp_delay[PALMAS_REG_SMPS10_OUT1]; + unsigned int current_reg_mode[PALMAS_REG_SMPS10_OUT1]; }; struct palmas_resource { diff --git a/include/linux/mfd/samsung/s2mps11.h b/include/linux/mfd/samsung/s2mps11.h index 4e94dc65f987..d0d52ea60074 100644 --- a/include/linux/mfd/samsung/s2mps11.h +++ b/include/linux/mfd/samsung/s2mps11.h @@ -191,6 +191,17 @@ enum s2mps11_regulators { #define S2MPS11_BUCK_N_VOLTAGES (S2MPS11_BUCK_VSEL_MASK + 1) #define S2MPS11_RAMP_DELAY 25000 /* uV/us */ + +#define S2MPS11_BUCK2_RAMP_SHIFT 6 +#define S2MPS11_BUCK34_RAMP_SHIFT 4 +#define S2MPS11_BUCK5_RAMP_SHIFT 6 +#define S2MPS11_BUCK16_RAMP_SHIFT 4 +#define S2MPS11_BUCK7810_RAMP_SHIFT 2 +#define S2MPS11_BUCK9_RAMP_SHIFT 0 +#define S2MPS11_BUCK2_RAMP_EN_SHIFT 3 +#define S2MPS11_BUCK3_RAMP_EN_SHIFT 2 +#define S2MPS11_BUCK4_RAMP_EN_SHIFT 1 +#define S2MPS11_BUCK6_RAMP_EN_SHIFT 0 #define S2MPS11_PMIC_EN_SHIFT 6 #define S2MPS11_REGULATOR_MAX (S2MPS11_REG_MAX - 3) diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index 29eab2bd3dfa..a5a7f0130e96 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -244,24 +244,6 @@ struct tps65217_board { }; /** - * struct tps_info - packages regulator constraints - * @name: Voltage regulator name - * @min_uV: minimum micro volts - * @max_uV: minimum micro volts - * @vsel_to_uv: Function pointer to get voltage from selector - * @uv_to_vsel: Function pointer to get selector from voltage - * - * This data is used to check the regualtor voltage limits while setting. - */ -struct tps_info { - const char *name; - int min_uV; - int max_uV; - int (*vsel_to_uv)(unsigned int vsel); - int (*uv_to_vsel)(int uV, unsigned int *vsel); -}; - -/** * struct tps65217 - tps65217 sub-driver chip access routines * * Device data may be used to access the TPS65217 chip @@ -273,7 +255,6 @@ struct tps65217 { unsigned int id; struct regulator_desc desc[TPS65217_NUM_REGULATOR]; struct regulator_dev *rdev[TPS65217_NUM_REGULATOR]; - struct tps_info *info[TPS65217_NUM_REGULATOR]; struct regmap *regmap; }; diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 3a76389c6aaa..27be915caa96 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -137,6 +137,12 @@ struct regulator *__must_check devm_regulator_get(struct device *dev, const char *id); struct regulator *__must_check regulator_get_exclusive(struct device *dev, const char *id); +struct regulator *__must_check devm_regulator_get_exclusive(struct device *dev, + const char *id); +struct regulator *__must_check regulator_get_optional(struct device *dev, + const char *id); +struct regulator *__must_check devm_regulator_get_optional(struct device *dev, + const char *id); void regulator_put(struct regulator *regulator); void devm_regulator_put(struct regulator *regulator); @@ -217,6 +223,25 @@ devm_regulator_get(struct device *dev, const char *id) return NULL; } +static inline struct regulator *__must_check +regulator_get_exclusive(struct device *dev, const char *id) +{ + return NULL; +} + +static inline struct regulator *__must_check +regulator_get_optional(struct device *dev, const char *id) +{ + return NULL; +} + + +static inline struct regulator *__must_check +devm_regulator_get_optional(struct device *dev, const char *id) +{ + return NULL; +} + static inline void regulator_put(struct regulator *regulator) { } @@ -369,8 +394,11 @@ static inline int regulator_count_voltages(struct regulator *regulator) static inline int regulator_set_voltage_tol(struct regulator *regulator, int new_uV, int tol_uV) { - return regulator_set_voltage(regulator, - new_uV - tol_uV, new_uV + tol_uV); + if (regulator_set_voltage(regulator, new_uV, new_uV + tol_uV) == 0) + return 0; + else + return regulator_set_voltage(regulator, + new_uV - tol_uV, new_uV + tol_uV); } static inline int regulator_is_supported_voltage_tol(struct regulator *regulator, diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 6700cc94bdd1..67e13aa5a478 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -40,6 +40,24 @@ enum regulator_status { }; /** + * Specify a range of voltages for regulator_map_linar_range() and + * regulator_list_linear_range(). + * + * @min_uV: Lowest voltage in range + * @max_uV: Highest voltage in range + * @min_sel: Lowest selector for range + * @max_sel: Highest selector for range + * @uV_step: Step size + */ +struct regulator_linear_range { + unsigned int min_uV; + unsigned int max_uV; + unsigned int min_sel; + unsigned int max_sel; + unsigned int uV_step; +}; + +/** * struct regulator_ops - regulator operations. * * @enable: Configure the regulator as enabled. @@ -223,6 +241,9 @@ struct regulator_desc { unsigned int linear_min_sel; unsigned int ramp_delay; + const struct regulator_linear_range *linear_ranges; + int n_linear_ranges; + const unsigned int *volt_table; unsigned int vsel_reg; @@ -326,10 +347,14 @@ int regulator_mode_to_status(unsigned int); int regulator_list_voltage_linear(struct regulator_dev *rdev, unsigned int selector); +int regulator_list_voltage_linear_range(struct regulator_dev *rdev, + unsigned int selector); int regulator_list_voltage_table(struct regulator_dev *rdev, unsigned int selector); int regulator_map_voltage_linear(struct regulator_dev *rdev, int min_uV, int max_uV); +int regulator_map_voltage_linear_range(struct regulator_dev *rdev, + int min_uV, int max_uV); int regulator_map_voltage_iterate(struct regulator_dev *rdev, int min_uV, int max_uV); int regulator_map_voltage_ascend(struct regulator_dev *rdev, diff --git a/include/linux/regulator/fan53555.h b/include/linux/regulator/fan53555.h index 5c45c85d52ca..f13880e84d85 100644 --- a/include/linux/regulator/fan53555.h +++ b/include/linux/regulator/fan53555.h @@ -11,6 +11,7 @@ */ #ifndef __FAN53555_H__ +#define __FAN53555_H__ /* VSEL ID */ enum { diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 36adbc82de6a..999b20ce06cf 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -134,6 +134,7 @@ struct regulation_constraints { unsigned always_on:1; /* regulator never off when system is on */ unsigned boot_on:1; /* bootloader/firmware enabled regulator */ unsigned apply_uV:1; /* apply uV constraint if min == max */ + unsigned ramp_disable:1; /* disable ramp delay */ }; /** diff --git a/include/linux/regulator/max8660.h b/include/linux/regulator/max8660.h index 9936763621c7..f8a6a4844864 100644 --- a/include/linux/regulator/max8660.h +++ b/include/linux/regulator/max8660.h @@ -39,7 +39,7 @@ enum { */ struct max8660_subdev_data { int id; - char *name; + const char *name; struct regulator_init_data *platform_data; }; diff --git a/include/linux/regulator/pfuze100.h b/include/linux/regulator/pfuze100.h new file mode 100644 index 000000000000..65d550bf3954 --- /dev/null +++ b/include/linux/regulator/pfuze100.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __LINUX_REG_PFUZE100_H +#define __LINUX_REG_PFUZE100_H + +#define PFUZE100_SW1AB 0 +#define PFUZE100_SW1C 1 +#define PFUZE100_SW2 2 +#define PFUZE100_SW3A 3 +#define PFUZE100_SW3B 4 +#define PFUZE100_SW4 5 +#define PFUZE100_SWBST 6 +#define PFUZE100_VSNVS 7 +#define PFUZE100_VREFDDR 8 +#define PFUZE100_VGEN1 9 +#define PFUZE100_VGEN2 10 +#define PFUZE100_VGEN3 11 +#define PFUZE100_VGEN4 12 +#define PFUZE100_VGEN5 13 +#define PFUZE100_VGEN6 14 +#define PFUZE100_MAX_REGULATOR 15 + +struct regulator_init_data; + +struct pfuze_regulator_platform_data { + struct regulator_init_data *init_data[PFUZE100_MAX_REGULATOR]; +}; + +#endif /* __LINUX_REG_PFUZE100_H */ |