diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-01 13:17:46 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-01 13:17:46 -0700 |
commit | 3786075b5ebc8c4eaefd9e3ebf72883934fb64b3 (patch) | |
tree | a1fdfae07be08bd315c57d3beaee941976ecee17 | |
parent | c6b38ec06e281af0608f02763ac7484ace267024 (diff) | |
parent | 5481b348e80fb280ff9eaa17ad99a5b592c7e145 (diff) |
Merge tag 'regulator-v3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown:
"This release has lots and lots of small cleanups and fixes in the
regulator subsystem, mainly cleaning up some bad patterns that got
duplicated in DT code, but otherwise very little of note outside of
the scope of the relevant drivers:
- Support for configuration of the initial state for gpio regulators
with multi-voltage support.
- Support for calling regulator_set_voltage() on fixed regulators.
- New drivers for Broadcom BCM590xx, Freescale pfuze200, Samsung
S2MPA01 & S2MPS11/4, some PWM controlled regulators found on some
ST boards and TI TPS65218"
* tag 'regulator-v3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (154 commits)
regulator: aat2870: Use regulator_map_voltage_ascend
regulator: st-pwm: Convert to get_voltage_sel
regulator: Add new driver for ST's PWM controlled voltage regulators
regulator: bcm590xx: Remove **rdev from struct bcm590xx_reg
regulator: bcm590xx: Make the modalias matches the driver name
regulator: s5m8767: Convert to use regulator_[enable|disable|is_enabled]_regmap
regulator: db8500-prcmu: Set 1.8V as a fixed voltage for vsmps2
regulator: s2mps11: Add missing of_node_put
regulator: s2mps11: Use of_get_child_by_name
Documentation: mfd: s2mps11: Document support for S2MPS14
regulator: s2mps11: Add set_suspend_disable for S2MPS14
regulator: s2mps11: Add support for S2MPS14 regulators
regulator: max8660: Fix brace alignment
regulator: dbx500: use seq_puts() instead of seq_printf()
regulator: dbx500-prcmu: Silence checkpatch warnings
regulator: anatop: Remove checking control_reg in [set|get]_voltage_sel
regulator: max8952: Silence checkpatch warning
regulator: max8925: Silence checkpatch warning
regulator: max8660: Silence checkpatch warnings
regulator: arizona-ldo1: Correct default regulator init_data
...
82 files changed, 3556 insertions, 746 deletions
diff --git a/Documentation/devicetree/bindings/mfd/s2mpa01.txt b/Documentation/devicetree/bindings/mfd/s2mpa01.txt new file mode 100644 index 000000000000..c13d3d8c3947 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/s2mpa01.txt @@ -0,0 +1,90 @@ + +* Samsung S2MPA01 Voltage and Current Regulator + +The Samsung S2MPA01 is a multi-function device which includes high +efficiency buck converters including Dual-Phase buck converter, various LDOs, +and an RTC. It is interfaced to the host controller using an I2C interface. +Each sub-block is addressed by the host system using different I2C slave +addresses. + +Required properties: +- compatible: Should be "samsung,s2mpa01-pmic". +- reg: Specifies the I2C slave address of the PMIC block. It should be 0x66. + +Optional properties: +- interrupt-parent: Specifies the phandle of the interrupt controller to which + the interrupts from s2mpa01 are delivered to. +- interrupts: An interrupt specifier for the sole interrupt generated by the + device. + +Optional nodes: +- regulators: The regulators of s2mpa01 that have to be instantiated should be + included in a sub-node named 'regulators'. Regulator nodes and constraints + included in this sub-node use the standard regulator bindings which are + documented elsewhere. + +Properties for BUCK regulator nodes: +- regulator-ramp-delay: ramp delay in uV/us. May be 6250, 12500 + (default), 25000, or 50000. May be 0 for disabling the ramp delay on + BUCK{1,2,3,4}. + + In the absence of the regulator-ramp-delay property, the default ramp + delay will be used. + + NOTE: Some BUCKs share the ramp rate setting i.e. same ramp value will be set + for a particular group of BUCKs. So provide same regulator-ramp-delay=<value>. + + The following BUCKs share ramp settings: + * 1 and 6 + * 2 and 4 + * 8, 9, and 10 + +The following are the names of the regulators that the s2mpa01 PMIC block +supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number +as per the datasheet of s2mpa01. + + - LDOn + - valid values for n are 1 to 26 + - Example: LDO1, LD02, LDO26 + - BUCKn + - valid values for n are 1 to 10. + - Example: BUCK1, BUCK2, BUCK9 + +Example: + + s2mpa01_pmic@66 { + compatible = "samsung,s2mpa01-pmic"; + reg = <0x66>; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "VDD_ALIVE"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + ldo2_reg: LDO2 { + regulator-name = "VDDQ_MMC2"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <50000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt index 15ee89c3cc7b..f69bec294f02 100644 --- a/Documentation/devicetree/bindings/mfd/s2mps11.txt +++ b/Documentation/devicetree/bindings/mfd/s2mps11.txt @@ -1,5 +1,5 @@ -* Samsung S2MPS11 Voltage and Current Regulator +* Samsung S2MPS11 and S2MPS14 Voltage and Current Regulator The Samsung S2MPS11 is a multi-function device which includes voltage and current regulators, RTC, charger controller and other sub-blocks. It is @@ -7,7 +7,7 @@ interfaced to the host controller using an I2C interface. Each sub-block is addressed by the host system using different I2C slave addresses. Required properties: -- compatible: Should be "samsung,s2mps11-pmic". +- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps14-pmic". - reg: Specifies the I2C slave address of the pmic block. It should be 0x66. Optional properties: @@ -59,10 +59,14 @@ supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number as per the datasheet of s2mps11. - LDOn - - valid values for n are 1 to 38 + - valid values for n are: + - S2MPS11: 1 to 38 + - S2MPS14: 1 to 25 - Example: LDO1, LD02, LDO28 - BUCKn - - valid values for n are 1 to 10. + - valid values for n are: + - S2MPS11: 1 to 10 + - S2MPS14: 1 to 5 - Example: BUCK1, BUCK2, BUCK9 Example: diff --git a/Documentation/devicetree/bindings/mfd/tps65910.txt b/Documentation/devicetree/bindings/mfd/tps65910.txt index b4bd98af1cc7..38833e63a59f 100644 --- a/Documentation/devicetree/bindings/mfd/tps65910.txt +++ b/Documentation/devicetree/bindings/mfd/tps65910.txt @@ -11,7 +11,7 @@ Required properties: - #interrupt-cells: the number of cells to describe an IRQ, this should be 2. The first cell is the IRQ number. The second cell is the flags, encoded as the trigger masks from - Documentation/devicetree/bindings/interrupts.txt + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt - regulators: This is the list of child nodes that specify the regulator initialization data for defined regulators. Not all regulators for the given device need to be present. The definition for each of these nodes is defined diff --git a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt index 63c659800c03..e5cac1e0ca8a 100644 --- a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt @@ -8,8 +8,12 @@ Required properties: Optional properties: - enable-gpio : GPIO to use to enable/disable the regulator. - gpios : GPIO group used to control voltage. +- gpios-states : gpios pin's initial states array. 0: LOW, 1: HIGH. + defualt is LOW if nothing is specified. - startup-delay-us : Startup time in microseconds. - enable-active-high : Polarity of GPIO is active high (default is low). +- regulator-type : Specifies what is being regulated, must be either + "voltage" or "current", defaults to current. Any property defined as part of the core regulator binding defined in regulator.txt can also be used. diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt index fc989b2e8057..34ef5d16d0f1 100644 --- a/Documentation/devicetree/bindings/regulator/pfuze100.txt +++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt @@ -1,7 +1,7 @@ PFUZE100 family of regulators Required properties: -- compatible: "fsl,pfuze100" +- compatible: "fsl,pfuze100" or "fsl,pfuze200" - reg: I2C slave address Required child node: @@ -10,11 +10,14 @@ Required child node: Documentation/devicetree/bindings/regulator/regulator.txt. The valid names for regulators are: + --PFUZE100 sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6 + --PFUZE200 + sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6 Each regulator is defined using the standard binding for regulators. -Example: +Example 1: PFUZE100 pmic: pfuze100@08 { compatible = "fsl,pfuze100"; @@ -113,3 +116,92 @@ Example: }; }; }; + + +Example 2: PFUZE200 + + pmic: pfuze200@08 { + compatible = "fsl,pfuze200"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + 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; + }; + + 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/s5m8767-regulator.txt b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt index fc6b38f035bd..d290988ed975 100644 --- a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt @@ -69,13 +69,16 @@ sub-node should be of the format as listed below. }; }; The above regulator entries are defined in regulator bindings documentation -except op_mode description. +except these properties: - op_mode: describes the different operating modes of the LDO's with power mode change in SOC. The different possible values are, 0 - always off mode 1 - on in normal mode 2 - low power mode 3 - suspend mode + - s5m8767,pmic-ext-control-gpios: (optional) GPIO specifier for one + GPIO controlling this regulator (enable/disable); This is + valid only for buck9. The following are the names of the regulators that the s5m8767 pmic block supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number @@ -148,5 +151,13 @@ Example: regulator-always-on; regulator-boot-on; }; + + vemmc_reg: BUCK9 { + regulator-name = "VMEM_VDD_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + op_mode = <3>; /* Standby Mode */ + s5m8767,pmic-ext-control-gpios = <&gpk0 2 0>; + }; }; }; diff --git a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt index 2e57a33e9029..c58db75f959e 100644 --- a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt @@ -4,10 +4,14 @@ Required Properties: - compatible: Should be one of: - "ti,abb-v1" for older SoCs like OMAP3 - "ti,abb-v2" for newer SoCs like OMAP4, OMAP5 + - "ti,abb-v3" for a generic definition where setup and control registers are + provided (example: DRA7) - reg: Address and length of the register set for the device. It contains the information of registers in the same order as described by reg-names - reg-names: Should contain the reg names - - "base-address" - contains base address of ABB module + - "base-address" - contains base address of ABB module (ti,abb-v1,ti,abb-v2) + - "control-address" - contains control register address of ABB module (ti,abb-v3) + - "setup-address" - contains setup register address of ABB module (ti,abb-v3) - "int-address" - contains address of interrupt register for ABB module (also see Optional properties) - #address-cell: should be 0 diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 545c4de412c3..db4e264eecb6 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -791,6 +791,32 @@ void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) EXPORT_SYMBOL_GPL(devm_kmalloc); /** + * devm_kstrdup - Allocate resource managed space and + * copy an existing string into that. + * @dev: Device to allocate memory for + * @s: the string to duplicate + * @gfp: the GFP mask used in the devm_kmalloc() call when + * allocating memory + * RETURNS: + * Pointer to allocated string on success, NULL on failure. + */ +char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) +{ + size_t size; + char *buf; + + if (!s) + return NULL; + + size = strlen(s) + 1; + buf = devm_kmalloc(dev, size, gfp); + if (buf) + memcpy(buf, s, size); + return buf; +} +EXPORT_SYMBOL_GPL(devm_kstrdup); + +/** * devm_kfree - Resource-managed kfree * @dev: Device this memory belongs to * @p: Memory to free diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 714e2135210e..281a82747275 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -26,7 +26,9 @@ #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/irq.h> #include <linux/mfd/samsung/rtc.h> +#include <linux/mfd/samsung/s2mpa01.h> #include <linux/mfd/samsung/s2mps11.h> +#include <linux/mfd/samsung/s2mps14.h> #include <linux/mfd/samsung/s5m8763.h> #include <linux/mfd/samsung/s5m8767.h> #include <linux/regmap.h> @@ -69,18 +71,53 @@ static const struct mfd_cell s2mps11_devs[] = { } }; +static const struct mfd_cell s2mps14_devs[] = { + { + .name = "s2mps14-pmic", + }, { + .name = "s2mps14-rtc", + }, { + .name = "s2mps14-clk", + } +}; + +static const struct mfd_cell s2mpa01_devs[] = { + { + .name = "s2mpa01-pmic", + }, +}; + #ifdef CONFIG_OF static struct of_device_id sec_dt_match[] = { { .compatible = "samsung,s5m8767-pmic", .data = (void *)S5M8767X, - }, - { .compatible = "samsung,s2mps11-pmic", + }, { + .compatible = "samsung,s2mps11-pmic", .data = (void *)S2MPS11X, + }, { + .compatible = "samsung,s2mps14-pmic", + .data = (void *)S2MPS14X, + }, { + .compatible = "samsung,s2mpa01-pmic", + .data = (void *)S2MPA01, + }, { + /* Sentinel */ }, - {}, }; #endif +static bool s2mpa01_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S2MPA01_REG_INT1M: + case S2MPA01_REG_INT2M: + case S2MPA01_REG_INT3M: + return false; + default: + return true; + } +} + static bool s2mps11_volatile(struct device *dev, unsigned int reg) { switch (reg) { @@ -111,6 +148,15 @@ static const struct regmap_config sec_regmap_config = { .val_bits = 8, }; +static const struct regmap_config s2mpa01_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPA01_REG_LDO_OVCB4, + .volatile_reg = s2mpa01_volatile, + .cache_type = REGCACHE_FLAT, +}; + static const struct regmap_config s2mps11_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -120,6 +166,15 @@ static const struct regmap_config s2mps11_regmap_config = { .cache_type = REGCACHE_FLAT, }; +static const struct regmap_config s2mps14_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPS14_REG_LDODSCH3, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, +}; + static const struct regmap_config s5m8763_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -138,9 +193,18 @@ static const struct regmap_config s5m8767_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static const struct regmap_config sec_rtc_regmap_config = { +static const struct regmap_config s5m_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = SEC_RTC_REG_MAX, +}; + +static const struct regmap_config s2mps14_rtc_regmap_config = { .reg_bits = 8, .val_bits = 8, + + .max_register = S2MPS_RTC_REG_MAX, }; #ifdef CONFIG_OF @@ -180,24 +244,24 @@ static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata( } #endif -static inline int sec_i2c_get_driver_data(struct i2c_client *i2c, +static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c, const struct i2c_device_id *id) { #ifdef CONFIG_OF if (i2c->dev.of_node) { const struct of_device_id *match; match = of_match_node(sec_dt_match, i2c->dev.of_node); - return (int)match->data; + return (unsigned long)match->data; } #endif - return (int)id->driver_data; + return id->driver_data; } static int sec_pmic_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); - const struct regmap_config *regmap; + const struct regmap_config *regmap, *regmap_rtc; struct sec_pmic_dev *sec_pmic; int ret; @@ -229,17 +293,34 @@ static int sec_pmic_probe(struct i2c_client *i2c, } switch (sec_pmic->device_type) { + case S2MPA01: + regmap = &s2mpa01_regmap_config; + break; case S2MPS11X: regmap = &s2mps11_regmap_config; + /* + * The rtc-s5m driver does not support S2MPS11 and there + * is no mfd_cell for S2MPS11 RTC device. + * However we must pass something to devm_regmap_init_i2c() + * so use S5M-like regmap config even though it wouldn't work. + */ + regmap_rtc = &s5m_rtc_regmap_config; + break; + case S2MPS14X: + regmap = &s2mps14_regmap_config; + regmap_rtc = &s2mps14_rtc_regmap_config; break; case S5M8763X: regmap = &s5m8763_regmap_config; + regmap_rtc = &s5m_rtc_regmap_config; break; case S5M8767X: regmap = &s5m8767_regmap_config; + regmap_rtc = &s5m_rtc_regmap_config; break; default: regmap = &sec_regmap_config; + regmap_rtc = &s5m_rtc_regmap_config; break; } @@ -252,10 +333,13 @@ static int sec_pmic_probe(struct i2c_client *i2c, } sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); + if (!sec_pmic->rtc) { + dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n"); + return -ENODEV; + } i2c_set_clientdata(sec_pmic->rtc, sec_pmic); - sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, - &sec_rtc_regmap_config); + sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc); if (IS_ERR(sec_pmic->regmap_rtc)) { ret = PTR_ERR(sec_pmic->regmap_rtc); dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n", @@ -283,10 +367,18 @@ static int sec_pmic_probe(struct i2c_client *i2c, ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs, ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL); break; + case S2MPA01: + ret = mfd_add_devices(sec_pmic->dev, -1, s2mpa01_devs, + ARRAY_SIZE(s2mpa01_devs), NULL, 0, NULL); + break; case S2MPS11X: ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs, ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL); break; + case S2MPS14X: + ret = mfd_add_devices(sec_pmic->dev, -1, s2mps14_devs, + ARRAY_SIZE(s2mps14_devs), NULL, 0, NULL); + break; default: /* If this happens the probe function is problem */ BUG(); diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index 4de494f51d40..64e7913aadc6 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -1,7 +1,7 @@ /* * sec-irq.c * - * Copyright (c) 2011 Samsung Electronics Co., Ltd + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd * http://www.samsung.com * * This program is free software; you can redistribute it and/or modify it @@ -19,6 +19,7 @@ #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/irq.h> #include <linux/mfd/samsung/s2mps11.h> +#include <linux/mfd/samsung/s2mps14.h> #include <linux/mfd/samsung/s5m8763.h> #include <linux/mfd/samsung/s5m8767.h> @@ -59,13 +60,13 @@ static const struct regmap_irq s2mps11_irqs[] = { .reg_offset = 1, .mask = S2MPS11_IRQ_RTC60S_MASK, }, - [S2MPS11_IRQ_RTCA1] = { + [S2MPS11_IRQ_RTCA0] = { .reg_offset = 1, - .mask = S2MPS11_IRQ_RTCA1_MASK, + .mask = S2MPS11_IRQ_RTCA0_MASK, }, - [S2MPS11_IRQ_RTCA2] = { + [S2MPS11_IRQ_RTCA1] = { .reg_offset = 1, - .mask = S2MPS11_IRQ_RTCA2_MASK, + .mask = S2MPS11_IRQ_RTCA1_MASK, }, [S2MPS11_IRQ_SMPL] = { .reg_offset = 1, @@ -89,6 +90,76 @@ static const struct regmap_irq s2mps11_irqs[] = { }, }; +static const struct regmap_irq s2mps14_irqs[] = { + [S2MPS14_IRQ_PWRONF] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_PWRONF_MASK, + }, + [S2MPS14_IRQ_PWRONR] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_PWRONR_MASK, + }, + [S2MPS14_IRQ_JIGONBF] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_JIGONBF_MASK, + }, + [S2MPS14_IRQ_JIGONBR] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_JIGONBR_MASK, + }, + [S2MPS14_IRQ_ACOKBF] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_ACOKBF_MASK, + }, + [S2MPS14_IRQ_ACOKBR] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_ACOKBR_MASK, + }, + [S2MPS14_IRQ_PWRON1S] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_PWRON1S_MASK, + }, + [S2MPS14_IRQ_MRB] = { + .reg_offset = 0, + .mask = S2MPS11_IRQ_MRB_MASK, + }, + [S2MPS14_IRQ_RTC60S] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_RTC60S_MASK, + }, + [S2MPS14_IRQ_RTCA1] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_RTCA1_MASK, + }, + [S2MPS14_IRQ_RTCA0] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_RTCA0_MASK, + }, + [S2MPS14_IRQ_SMPL] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_SMPL_MASK, + }, + [S2MPS14_IRQ_RTC1S] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_RTC1S_MASK, + }, + [S2MPS14_IRQ_WTSR] = { + .reg_offset = 1, + .mask = S2MPS11_IRQ_WTSR_MASK, + }, + [S2MPS14_IRQ_INT120C] = { + .reg_offset = 2, + .mask = S2MPS11_IRQ_INT120C_MASK, + }, + [S2MPS14_IRQ_INT140C] = { + .reg_offset = 2, + .mask = S2MPS11_IRQ_INT140C_MASK, + }, + [S2MPS14_IRQ_TSD] = { + .reg_offset = 2, + .mask = S2MPS14_IRQ_TSD_MASK, + }, +}; static const struct regmap_irq s5m8767_irqs[] = { [S5M8767_IRQ_PWRR] = { @@ -246,6 +317,16 @@ static const struct regmap_irq_chip s2mps11_irq_chip = { .ack_base = S2MPS11_REG_INT1, }; +static const struct regmap_irq_chip s2mps14_irq_chip = { + .name = "s2mps14", + .irqs = s2mps14_irqs, + .num_irqs = ARRAY_SIZE(s2mps14_irqs), + .num_regs = 3, + .status_base = S2MPS14_REG_INT1, + .mask_base = S2MPS14_REG_INT1M, + .ack_base = S2MPS14_REG_INT1, +}; + static const struct regmap_irq_chip s5m8767_irq_chip = { .name = "s5m8767", .irqs = s5m8767_irqs, @@ -297,6 +378,12 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) sec_pmic->irq_base, &s2mps11_irq_chip, &sec_pmic->irq_data); break; + case S2MPS14X: + ret = regmap_add_irq_chip(sec_pmic->regmap_pmic, sec_pmic->irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + sec_pmic->irq_base, &s2mps14_irq_chip, + &sec_pmic->irq_data); + break; default: dev_err(sec_pmic->dev, "Unknown device type %d\n", sec_pmic->device_type); diff --git a/drivers/of/base.c b/drivers/of/base.c index 89e888a78899..1b95a405628f 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -904,6 +904,38 @@ struct device_node *of_find_node_by_phandle(phandle handle) EXPORT_SYMBOL(of_find_node_by_phandle); /** + * of_property_count_elems_of_size - Count the number of elements in a property + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @elem_size: size of the individual element + * + * Search for a property in a device node and count the number of elements of + * size elem_size in it. Returns number of elements on sucess, -EINVAL if the + * property does not exist or its length does not match a multiple of elem_size + * and -ENODATA if the property does not have a value. + */ +int of_property_count_elems_of_size(const struct device_node *np, + const char *propname, int elem_size) +{ + struct property *prop = of_find_property(np, propname, NULL); + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + if (prop->length % elem_size != 0) { + pr_err("size of %s in node %s is not a multiple of %d\n", + propname, np->full_name, elem_size); + return -EINVAL; + } + + return prop->length / elem_size; +} +EXPORT_SYMBOL_GPL(of_property_count_elems_of_size); + +/** * of_find_property_value_of_size * * @np: device node from which the property value is to be read. diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index d333f7eac106..7a721d67e6ac 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -310,10 +310,8 @@ static int pm800_regulator_probe(struct platform_device *pdev) pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data), GFP_KERNEL); - if (!pm800_data) { - dev_err(&pdev->dev, "Failed to allocate pm800_regualtors"); + if (!pm800_data) return -ENOMEM; - } pm800_data->map = chip->subchip->regmap_power; pm800_data->chip = chip; diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index f704d83c93c4..337634ad0562 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -2,7 +2,7 @@ * Regulators driver for Marvell 88PM8607 * * Copyright (C) 2009 Marvell International Ltd. - * Haojian Zhuang <haojian.zhuang@marvell.com> + * Haojian Zhuang <haojian.zhuang@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 @@ -78,7 +78,7 @@ static const unsigned int BUCK2_suspend_table[] = { }; static const unsigned int BUCK3_table[] = { - 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, + 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, @@ -89,7 +89,7 @@ static const unsigned int BUCK3_table[] = { }; static const unsigned int BUCK3_suspend_table[] = { - 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, + 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000, 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000, 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000, 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000, @@ -322,7 +322,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev, nproot = of_node_get(pdev->dev.parent->of_node); if (!nproot) return -ENODEV; - nproot = of_find_node_by_name(nproot, "regulators"); + nproot = of_get_child_by_name(nproot, "regulators"); if (!nproot) { dev_err(&pdev->dev, "failed to find regulators node\n"); return -ENODEV; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 6a7932822e37..1cd8584a7b88 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -139,6 +139,14 @@ config REGULATOR_AS3722 AS3722 PMIC. This will enable support for all the software controllable DCDC/LDO regulators. +config REGULATOR_BCM590XX + tristate "Broadcom BCM590xx PMU Regulators" + depends on MFD_BCM590XX + help + This driver provides support for the voltage regulators on the + BCM590xx PMUs. This will enable support for the software + controllable LDO/Switching regulators. + config REGULATOR_DA903X tristate "Dialog Semiconductor DA9030/DA9034 regulators" depends on PMIC_DA903X @@ -399,12 +407,12 @@ config REGULATOR_PCF50633 on PCF50633 config REGULATOR_PFUZE100 - tristate "Freescale PFUZE100 regulator driver" + tristate "Freescale PFUZE100/PFUZE200 regulator driver" depends on I2C select REGMAP_I2C help - Say y here to support the regulators found on the Freescale PFUZE100 - PMIC. + Say y here to support the regulators found on the Freescale + PFUZE100/PFUZE200 PMIC. config REGULATOR_RC5T583 tristate "RICOH RC5T583 Power regulators" @@ -416,13 +424,21 @@ config REGULATOR_RC5T583 through regulator interface. The device supports multiple DCDC/LDO outputs which can be controlled by i2c communication. +config REGULATOR_S2MPA01 + tristate "Samsung S2MPA01 voltage regulator" + depends on MFD_SEC_CORE + help + This driver controls Samsung S2MPA01 voltage output regulator + via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs. + config REGULATOR_S2MPS11 - tristate "Samsung S2MPS11 voltage regulator" + tristate "Samsung S2MPS11/S2MPS14 voltage regulator" depends on MFD_SEC_CORE help - This driver supports a Samsung S2MPS11 voltage output regulator - via I2C bus. S2MPS11 is comprised of high efficient Buck converters - including Dual-Phase Buck converter, Buck-Boost converter, various LDOs. + This driver supports a Samsung S2MPS11/S2MPS14 voltage output + regulator via I2C bus. The chip is comprised of high efficient Buck + converters including Dual-Phase Buck converter, Buck-Boost converter, + various LDOs. config REGULATOR_S5M8767 tristate "Samsung S5M8767A voltage regulator" @@ -432,6 +448,12 @@ 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_ST_PWM + tristate "STMicroelectronics PWM voltage regulator" + depends on ARCH_STI + help + This driver supports ST's PWM controlled voltage regulators. + config REGULATOR_TI_ABB tristate "TI Adaptive Body Bias on-chip LDO" depends on ARCH_OMAP @@ -513,6 +535,15 @@ config REGULATOR_TPS65217 voltage regulators. It supports software based voltage control for different voltage domains +config REGULATOR_TPS65218 + tristate "TI TPS65218 Power regulators" + depends on MFD_TPS65218 && OF + help + This driver supports TPS65218 voltage regulator chips. TPS65218 + provides six step-down converters and one general-purpose LDO + voltage regulators. It supports software based voltage control + for different voltage domains + config REGULATOR_TPS6524X tristate "TI TPS6524X Power regulators" depends on SPI diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 979f9ddcf259..f0fe0c50b59c 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o +obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o @@ -57,8 +58,10 @@ 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_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o +obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o @@ -67,6 +70,7 @@ obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o +obj-$(CONFIG_REGULATOR_TPS65218) += tps65218-regulator.o obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index f70a9bfa5ff2..c873ee0082cf 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -99,6 +99,7 @@ static int aat2870_ldo_is_enabled(struct regulator_dev *rdev) static struct regulator_ops aat2870_ldo_ops = { .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = aat2870_ldo_set_voltage_sel, .get_voltage_sel = aat2870_ldo_get_voltage_sel, .enable = aat2870_ldo_enable, diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 084cc0819a52..b92d7dd01a18 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -62,7 +62,6 @@ #define ACT8865_VOLTAGE_NUM 64 struct act8865 { - struct regulator_dev *rdev[ACT8865_REG_NUM]; struct regmap *regmap; }; @@ -213,7 +212,7 @@ static int act8865_pdata_from_dt(struct device *dev, struct device_node *np; struct act8865_regulator_data *regulator; - np = of_find_node_by_name(dev->of_node, "regulators"); + np = of_get_child_by_name(dev->of_node, "regulators"); if (!np) { dev_err(dev, "missing 'regulators' subnode in DT\n"); return -EINVAL; @@ -221,17 +220,15 @@ static int act8865_pdata_from_dt(struct device *dev, matched = of_regulator_match(dev, np, act8865_matches, ARRAY_SIZE(act8865_matches)); + of_node_put(np); if (matched <= 0) return matched; pdata->regulators = devm_kzalloc(dev, sizeof(struct act8865_regulator_data) * ARRAY_SIZE(act8865_matches), GFP_KERNEL); - if (!pdata->regulators) { - dev_err(dev, "%s: failed to allocate act8865 registor\n", - __func__); + if (!pdata->regulators) return -ENOMEM; - } pdata->num_regulators = matched; regulator = pdata->regulators; @@ -258,7 +255,7 @@ static inline int act8865_pdata_from_dt(struct device *dev, static int act8865_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { - struct regulator_dev **rdev; + struct regulator_dev *rdev; struct device *dev = &client->dev; struct act8865_platform_data *pdata = dev_get_platdata(dev); struct regulator_config config = { }; @@ -292,8 +289,6 @@ static int act8865_pmic_probe(struct i2c_client *client, if (!act8865) return -ENOMEM; - rdev = act8865->rdev; - act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config); if (IS_ERR(act8865->regmap)) { error = PTR_ERR(act8865->regmap); @@ -313,12 +308,12 @@ static int act8865_pmic_probe(struct i2c_client *client, config.driver_data = act8865; config.regmap = act8865->regmap; - rdev[i] = devm_regulator_register(&client->dev, - &act8865_reg[i], &config); - if (IS_ERR(rdev[i])) { + rdev = devm_regulator_register(&client->dev, &act8865_reg[i], + &config); + if (IS_ERR(rdev)) { dev_err(dev, "failed to register %s\n", act8865_reg[id].name); - return PTR_ERR(rdev[i]); + return PTR_ERR(rdev); } } diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 862e63e451d0..7c397bb81e01 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -34,6 +34,9 @@ #define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */ #define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */ +#define LDO_POWER_GATE 0x00 +#define LDO_FET_FULL_ON 0x1f + struct anatop_regulator { const char *name; u32 control_reg; @@ -48,19 +51,10 @@ struct anatop_regulator { int max_voltage; struct regulator_desc rdesc; struct regulator_init_data *initdata; + bool bypass; + int sel; }; -static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, - unsigned selector) -{ - struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); - - if (!anatop_reg->control_reg) - return -ENOTSUPP; - - return regulator_set_voltage_sel_regmap(reg, selector); -} - static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg, unsigned int old_sel, unsigned int new_sel) @@ -87,22 +81,99 @@ static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg, return ret; } -static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg) +static int anatop_regmap_enable(struct regulator_dev *reg) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + int sel; - if (!anatop_reg->control_reg) - return -ENOTSUPP; + sel = anatop_reg->bypass ? LDO_FET_FULL_ON : anatop_reg->sel; + return regulator_set_voltage_sel_regmap(reg, sel); +} + +static int anatop_regmap_disable(struct regulator_dev *reg) +{ + return regulator_set_voltage_sel_regmap(reg, LDO_POWER_GATE); +} + +static int anatop_regmap_is_enabled(struct regulator_dev *reg) +{ + return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE; +} + +static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg, + unsigned selector) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + int ret; + + if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) { + anatop_reg->sel = selector; + return 0; + } + + ret = regulator_set_voltage_sel_regmap(reg, selector); + if (!ret) + anatop_reg->sel = selector; + return ret; +} + +static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + + if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) + return anatop_reg->sel; return regulator_get_voltage_sel_regmap(reg); } +static int anatop_regmap_get_bypass(struct regulator_dev *reg, bool *enable) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + int sel; + + sel = regulator_get_voltage_sel_regmap(reg); + if (sel == LDO_FET_FULL_ON) + WARN_ON(!anatop_reg->bypass); + else if (sel != LDO_POWER_GATE) + WARN_ON(anatop_reg->bypass); + + *enable = anatop_reg->bypass; + return 0; +} + +static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + int sel; + + if (enable == anatop_reg->bypass) + return 0; + + sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel; + anatop_reg->bypass = enable; + + return regulator_set_voltage_sel_regmap(reg, sel); +} + static struct regulator_ops anatop_rops = { - .set_voltage_sel = anatop_regmap_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, +}; + +static struct regulator_ops anatop_core_rops = { + .enable = anatop_regmap_enable, + .disable = anatop_regmap_disable, + .is_enabled = anatop_regmap_is_enabled, + .set_voltage_sel = anatop_regmap_core_set_voltage_sel, .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel, - .get_voltage_sel = anatop_regmap_get_voltage_sel, + .get_voltage_sel = anatop_regmap_core_get_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, + .get_bypass = anatop_regmap_get_bypass, + .set_bypass = anatop_regmap_set_bypass, }; static int anatop_regulator_probe(struct platform_device *pdev) @@ -116,6 +187,7 @@ static int anatop_regulator_probe(struct platform_device *pdev) struct regulator_init_data *initdata; struct regulator_config config = { }; int ret = 0; + u32 val; initdata = of_get_regulator_init_data(dev, np); sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); @@ -125,7 +197,6 @@ static int anatop_regulator_probe(struct platform_device *pdev) sreg->name = of_get_property(np, "regulator-name", NULL); rdesc = &sreg->rdesc; rdesc->name = sreg->name; - rdesc->ops = &anatop_rops; rdesc->type = REGULATOR_VOLTAGE; rdesc->owner = THIS_MODULE; @@ -197,6 +268,25 @@ static int anatop_regulator_probe(struct platform_device *pdev) config.of_node = pdev->dev.of_node; config.regmap = sreg->anatop; + /* Only core regulators have the ramp up delay configuration. */ + if (sreg->control_reg && sreg->delay_bit_width) { + rdesc->ops = &anatop_core_rops; + + ret = regmap_read(config.regmap, rdesc->vsel_reg, &val); + if (ret) { + dev_err(dev, "failed to read initial state\n"); + return ret; + } + + sreg->sel = (val & rdesc->vsel_mask) >> sreg->vol_bit_shift; + if (sreg->sel == LDO_FET_FULL_ON) { + sreg->sel = 0; + sreg->bypass = true; + } + } else { + rdesc->ops = &anatop_rops; + } + /* register regulator */ rdev = devm_regulator_register(dev, rdesc, &config); if (IS_ERR(rdev)) { diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 4f6c2055f6b2..b1033d30b504 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -153,11 +153,9 @@ static const struct regulator_desc arizona_ldo1 = { .vsel_reg = ARIZONA_LDO1_CONTROL_1, .vsel_mask = ARIZONA_LDO1_VSEL_MASK, - .bypass_reg = ARIZONA_LDO1_CONTROL_1, - .bypass_mask = ARIZONA_LDO1_BYPASS, .min_uV = 900000, - .uV_step = 50000, - .n_voltages = 7, + .uV_step = 25000, + .n_voltages = 13, .enable_time = 500, .owner = THIS_MODULE, @@ -189,10 +187,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev) int ret; ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL); - if (ldo1 == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!ldo1) return -ENOMEM; - } ldo1->arizona = arizona; @@ -203,6 +199,7 @@ static int arizona_ldo1_probe(struct platform_device *pdev) */ switch (arizona->type) { case WM5102: + case WM8997: desc = &arizona_ldo1_hc; ldo1->init_data = arizona_ldo1_dvfs; break; diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index 034ece707083..6fdd9bf6927f 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -204,10 +204,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev) int ret; micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL); - if (micsupp == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!micsupp) return -ENOMEM; - } micsupp->arizona = arizona; INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp); diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index c77a58478cca..b47283f91e2d 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -191,7 +191,7 @@ static int as3711_regulator_parse_dt(struct device *dev, { struct as3711_regulator_pdata *pdata = dev_get_platdata(dev); struct device_node *regulators = - of_find_node_by_name(dev->parent->of_node, "regulators"); + of_get_child_by_name(dev->parent->of_node, "regulators"); struct of_regulator_match *match; int ret, i; @@ -221,7 +221,6 @@ static int as3711_regulator_probe(struct platform_device *pdev) { struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev); struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent); - struct regulator_init_data *reg_data; struct regulator_config config = {.dev = &pdev->dev,}; struct as3711_regulator *reg = NULL; struct as3711_regulator *regs; @@ -246,22 +245,14 @@ static int as3711_regulator_probe(struct platform_device *pdev) regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM * sizeof(struct as3711_regulator), GFP_KERNEL); - if (!regs) { - dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); + if (!regs) return -ENOMEM; - } for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) { - reg_data = pdata->init_data[id]; - - /* No need to register if there is no regulator data */ - if (!reg_data) - continue; - reg = ®s[id]; reg->reg_info = ri; - config.init_data = reg_data; + config.init_data = pdata->init_data[id]; config.driver_data = reg; config.regmap = as3711->regmap; config.of_node = of_node[id]; diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c index 8b17d786cb71..85585219ce82 100644 --- a/drivers/regulator/as3722-regulator.c +++ b/drivers/regulator/as3722-regulator.c @@ -719,6 +719,7 @@ static int as3722_get_regulator_dt_data(struct platform_device *pdev, ret = of_regulator_match(&pdev->dev, np, as3722_regulator_matches, ARRAY_SIZE(as3722_regulator_matches)); + of_node_put(np); if (ret < 0) { dev_err(&pdev->dev, "Parsing of regulator node failed: %d\n", ret); diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c new file mode 100644 index 000000000000..ab08ca7cfb08 --- /dev/null +++ b/drivers/regulator/bcm590xx-regulator.c @@ -0,0 +1,403 @@ +/* + * Broadcom BCM590xx regulator driver + * + * Copyright 2014 Linaro Limited + * Author: Matt Porter <mporter@linaro.org> + * + * 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/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mfd/bcm590xx.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/slab.h> + +/* Register defs */ +#define BCM590XX_RFLDOPMCTRL1 0x60 +#define BCM590XX_IOSR1PMCTRL1 0x7a +#define BCM590XX_IOSR2PMCTRL1 0x7c +#define BCM590XX_CSRPMCTRL1 0x7e +#define BCM590XX_SDSR1PMCTRL1 0x82 +#define BCM590XX_SDSR2PMCTRL1 0x86 +#define BCM590XX_MSRPMCTRL1 0x8a +#define BCM590XX_VSRPMCTRL1 0x8e +#define BCM590XX_REG_ENABLE BIT(7) + +#define BCM590XX_RFLDOCTRL 0x96 +#define BCM590XX_CSRVOUT1 0xc0 +#define BCM590XX_LDO_VSEL_MASK GENMASK(5, 3) +#define BCM590XX_SR_VSEL_MASK GENMASK(5, 0) + +/* LDO regulator IDs */ +#define BCM590XX_REG_RFLDO 0 +#define BCM590XX_REG_CAMLDO1 1 +#define BCM590XX_REG_CAMLDO2 2 +#define BCM590XX_REG_SIMLDO1 3 +#define BCM590XX_REG_SIMLDO2 4 +#define BCM590XX_REG_SDLDO 5 +#define BCM590XX_REG_SDXLDO 6 +#define BCM590XX_REG_MMCLDO1 7 +#define BCM590XX_REG_MMCLDO2 8 +#define BCM590XX_REG_AUDLDO 9 +#define BCM590XX_REG_MICLDO 10 +#define BCM590XX_REG_USBLDO 11 +#define BCM590XX_REG_VIBLDO 12 + +/* DCDC regulator IDs */ +#define BCM590XX_REG_CSR 13 +#define BCM590XX_REG_IOSR1 14 +#define BCM590XX_REG_IOSR2 15 +#define BCM590XX_REG_MSR 16 +#define BCM590XX_REG_SDSR1 17 +#define BCM590XX_REG_SDSR2 18 +#define BCM590XX_REG_VSR 19 + +#define BCM590XX_NUM_REGS 20 + +#define BCM590XX_REG_IS_LDO(n) (n < BCM590XX_REG_CSR) + +struct bcm590xx_board { + struct regulator_init_data *bcm590xx_pmu_init_data[BCM590XX_NUM_REGS]; +}; + +/* LDO group A: supported voltages in microvolts */ +static const unsigned int ldo_a_table[] = { + 1200000, 1800000, 2500000, 2700000, 2800000, + 2900000, 3000000, 3300000, +}; + +/* LDO group C: supported voltages in microvolts */ +static const unsigned int ldo_c_table[] = { + 3100000, 1800000, 2500000, 2700000, 2800000, + 2900000, 3000000, 3300000, +}; + +/* DCDC group CSR: supported voltages in microvolts */ +static const struct regulator_linear_range dcdc_csr_ranges[] = { + REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000), + REGULATOR_LINEAR_RANGE(1360000, 51, 55, 20000), + REGULATOR_LINEAR_RANGE(900000, 56, 63, 0), +}; + +/* DCDC group IOSR1: supported voltages in microvolts */ +static const struct regulator_linear_range dcdc_iosr1_ranges[] = { + REGULATOR_LINEAR_RANGE(860000, 2, 51, 10000), + REGULATOR_LINEAR_RANGE(1500000, 52, 52, 0), + REGULATOR_LINEAR_RANGE(1800000, 53, 53, 0), + REGULATOR_LINEAR_RANGE(900000, 54, 63, 0), +}; + +/* DCDC group SDSR1: supported voltages in microvolts */ +static const struct regulator_linear_range dcdc_sdsr1_ranges[] = { + REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000), + REGULATOR_LINEAR_RANGE(1340000, 51, 51, 0), + REGULATOR_LINEAR_RANGE(900000, 52, 63, 0), +}; + +struct bcm590xx_info { + const char *name; + const char *vin_name; + u8 n_voltages; + const unsigned int *volt_table; + u8 n_linear_ranges; + const struct regulator_linear_range *linear_ranges; +}; + +#define BCM590XX_REG_TABLE(_name, _table) \ + { \ + .name = #_name, \ + .n_voltages = ARRAY_SIZE(_table), \ + .volt_table = _table, \ + } + +#define BCM590XX_REG_RANGES(_name, _ranges) \ + { \ + .name = #_name, \ + .n_linear_ranges = ARRAY_SIZE(_ranges), \ + .linear_ranges = _ranges, \ + } + +static struct bcm590xx_info bcm590xx_regs[] = { + BCM590XX_REG_TABLE(rfldo, ldo_a_table), + BCM590XX_REG_TABLE(camldo1, ldo_c_table), + BCM590XX_REG_TABLE(camldo2, ldo_c_table), + BCM590XX_REG_TABLE(simldo1, ldo_a_table), + BCM590XX_REG_TABLE(simldo2, ldo_a_table), + BCM590XX_REG_TABLE(sdldo, ldo_c_table), + BCM590XX_REG_TABLE(sdxldo, ldo_a_table), + BCM590XX_REG_TABLE(mmcldo1, ldo_a_table), + BCM590XX_REG_TABLE(mmcldo2, ldo_a_table), + BCM590XX_REG_TABLE(audldo, ldo_a_table), + BCM590XX_REG_TABLE(micldo, ldo_a_table), + BCM590XX_REG_TABLE(usbldo, ldo_a_table), + BCM590XX_REG_TABLE(vibldo, ldo_c_table), + BCM590XX_REG_RANGES(csr, dcdc_csr_ranges), + BCM590XX_REG_RANGES(iosr1, dcdc_iosr1_ranges), + BCM590XX_REG_RANGES(iosr2, dcdc_iosr1_ranges), + BCM590XX_REG_RANGES(msr, dcdc_iosr1_ranges), + BCM590XX_REG_RANGES(sdsr1, dcdc_sdsr1_ranges), + BCM590XX_REG_RANGES(sdsr2, dcdc_iosr1_ranges), + BCM590XX_REG_RANGES(vsr, dcdc_iosr1_ranges), +}; + +struct bcm590xx_reg { + struct regulator_desc *desc; + struct bcm590xx *mfd; + struct bcm590xx_info **info; +}; + +static int bcm590xx_get_vsel_register(int id) +{ + if (BCM590XX_REG_IS_LDO(id)) + return BCM590XX_RFLDOCTRL + id; + else + return BCM590XX_CSRVOUT1 + (id - BCM590XX_REG_CSR) * 3; +} + +static int bcm590xx_get_enable_register(int id) +{ + int reg = 0; + + if (BCM590XX_REG_IS_LDO(id)) + reg = BCM590XX_RFLDOPMCTRL1 + id * 2; + else + switch (id) { + case BCM590XX_REG_CSR: + reg = BCM590XX_CSRPMCTRL1; + break; + case BCM590XX_REG_IOSR1: + reg = BCM590XX_IOSR1PMCTRL1; + break; + case BCM590XX_REG_IOSR2: + reg = BCM590XX_IOSR2PMCTRL1; + break; + case BCM590XX_REG_MSR: + reg = BCM590XX_MSRPMCTRL1; + break; + case BCM590XX_REG_SDSR1: + reg = BCM590XX_SDSR1PMCTRL1; + break; + case BCM590XX_REG_SDSR2: + reg = BCM590XX_SDSR2PMCTRL1; + break; + }; + + return reg; +} + +static struct regulator_ops bcm590xx_ops_ldo = { + .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 = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, +}; + +static struct regulator_ops bcm590xx_ops_dcdc = { + .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 = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, +}; + +#define BCM590XX_MATCH(_name, _id) \ + { \ + .name = #_name, \ + .driver_data = (void *)&bcm590xx_regs[BCM590XX_REG_##_id], \ + } + +static struct of_regulator_match bcm590xx_matches[] = { + BCM590XX_MATCH(rfldo, RFLDO), + BCM590XX_MATCH(camldo1, CAMLDO1), + BCM590XX_MATCH(camldo2, CAMLDO2), + BCM590XX_MATCH(simldo1, SIMLDO1), + BCM590XX_MATCH(simldo2, SIMLDO2), + BCM590XX_MATCH(sdldo, SDLDO), + BCM590XX_MATCH(sdxldo, SDXLDO), + BCM590XX_MATCH(mmcldo1, MMCLDO1), + BCM590XX_MATCH(mmcldo2, MMCLDO2), + BCM590XX_MATCH(audldo, AUDLDO), + BCM590XX_MATCH(micldo, MICLDO), + BCM590XX_MATCH(usbldo, USBLDO), + BCM590XX_MATCH(vibldo, VIBLDO), + BCM590XX_MATCH(csr, CSR), + BCM590XX_MATCH(iosr1, IOSR1), + BCM590XX_MATCH(iosr2, IOSR2), + BCM590XX_MATCH(msr, MSR), + BCM590XX_MATCH(sdsr1, SDSR1), + BCM590XX_MATCH(sdsr2, SDSR2), + BCM590XX_MATCH(vsr, VSR), +}; + +static struct bcm590xx_board *bcm590xx_parse_dt_reg_data( + struct platform_device *pdev, + struct of_regulator_match **bcm590xx_reg_matches) +{ + struct bcm590xx_board *data; + struct device_node *np = pdev->dev.parent->of_node; + struct device_node *regulators; + struct of_regulator_match *matches = bcm590xx_matches; + int count = ARRAY_SIZE(bcm590xx_matches); + int idx = 0; + int ret; + + if (!np) { + dev_err(&pdev->dev, "of node not found\n"); + return NULL; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + dev_err(&pdev->dev, "failed to allocate regulator board data\n"); + return NULL; + } + + np = of_node_get(np); + regulators = of_get_child_by_name(np, "regulators"); + if (!regulators) { + dev_warn(&pdev->dev, "regulator node not found\n"); + return NULL; + } + + ret = of_regulator_match(&pdev->dev, regulators, matches, count); + of_node_put(regulators); + if (ret < 0) { + dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", + ret); + return NULL; + } + + *bcm590xx_reg_matches = matches; + + for (idx = 0; idx < count; idx++) { + if (!matches[idx].init_data || !matches[idx].of_node) + continue; + + data->bcm590xx_pmu_init_data[idx] = matches[idx].init_data; + } + + return data; +} + +static int bcm590xx_probe(struct platform_device *pdev) +{ + struct bcm590xx *bcm590xx = dev_get_drvdata(pdev->dev.parent); + struct bcm590xx_board *pmu_data = NULL; + struct bcm590xx_reg *pmu; + struct regulator_config config = { }; + struct bcm590xx_info *info; + struct regulator_init_data *reg_data; + struct regulator_dev *rdev; + struct of_regulator_match *bcm590xx_reg_matches = NULL; + int i; + + pmu_data = bcm590xx_parse_dt_reg_data(pdev, + &bcm590xx_reg_matches); + + pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); + if (!pmu) { + dev_err(&pdev->dev, "Memory allocation failed for pmu\n"); + return -ENOMEM; + } + + pmu->mfd = bcm590xx; + + platform_set_drvdata(pdev, pmu); + + pmu->desc = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * + sizeof(struct regulator_desc), GFP_KERNEL); + if (!pmu->desc) { + dev_err(&pdev->dev, "Memory alloc fails for desc\n"); + return -ENOMEM; + } + + pmu->info = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * + sizeof(struct bcm590xx_info *), GFP_KERNEL); + if (!pmu->info) { + dev_err(&pdev->dev, "Memory alloc fails for info\n"); + return -ENOMEM; + } + + info = bcm590xx_regs; + + for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) { + if (pmu_data) + reg_data = pmu_data->bcm590xx_pmu_init_data[i]; + else + reg_data = NULL; + + /* Register the regulators */ + pmu->info[i] = info; + + pmu->desc[i].name = info->name; + pmu->desc[i].supply_name = info->vin_name; + pmu->desc[i].id = i; + pmu->desc[i].volt_table = info->volt_table; + pmu->desc[i].n_voltages = info->n_voltages; + pmu->desc[i].linear_ranges = info->linear_ranges; + pmu->desc[i].n_linear_ranges = info->n_linear_ranges; + + if (BCM590XX_REG_IS_LDO(i)) { + pmu->desc[i].ops = &bcm590xx_ops_ldo; + pmu->desc[i].vsel_mask = BCM590XX_LDO_VSEL_MASK; + } else { + pmu->desc[i].ops = &bcm590xx_ops_dcdc; + pmu->desc[i].vsel_mask = BCM590XX_SR_VSEL_MASK; + } + + pmu->desc[i].vsel_reg = bcm590xx_get_vsel_register(i); + pmu->desc[i].enable_is_inverted = true; + pmu->desc[i].enable_mask = BCM590XX_REG_ENABLE; + pmu->desc[i].enable_reg = bcm590xx_get_enable_register(i); + pmu->desc[i].type = REGULATOR_VOLTAGE; + pmu->desc[i].owner = THIS_MODULE; + + config.dev = bcm590xx->dev; + config.init_data = reg_data; + config.driver_data = pmu; + config.regmap = bcm590xx->regmap; + + if (bcm590xx_reg_matches) + config.of_node = bcm590xx_reg_matches[i].of_node; + + rdev = devm_regulator_register(&pdev->dev, &pmu->desc[i], + &config); + if (IS_ERR(rdev)) { + dev_err(bcm590xx->dev, + "failed to register %s regulator\n", + pdev->name); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static struct platform_driver bcm590xx_regulator_driver = { + .driver = { + .name = "bcm590xx-vregs", + .owner = THIS_MODULE, + }, + .probe = bcm590xx_probe, +}; +module_platform_driver(bcm590xx_regulator_driver); + +MODULE_AUTHOR("Matt Porter <mporter@linaro.org>"); +MODULE_DESCRIPTION("BCM590xx voltage regulator driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bcm590xx-vregs"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index afca1bc24f26..bac485acc7f3 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2399,6 +2399,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) struct regulator_dev *rdev = regulator->rdev; int ret = 0; int old_min_uV, old_max_uV; + int current_uV; mutex_lock(&rdev->mutex); @@ -2409,6 +2410,19 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) if (regulator->min_uV == min_uV && regulator->max_uV == max_uV) goto out; + /* If we're trying to set a range that overlaps the current voltage, + * return succesfully even though the regulator does not support + * changing the voltage. + */ + if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { + current_uV = _regulator_get_voltage(rdev); + if (min_uV <= current_uV && current_uV <= max_uV) { + regulator->min_uV = min_uV; + regulator->max_uV = max_uV; + goto out; + } + } + /* sanity check */ if (!rdev->desc->ops->set_voltage && !rdev->desc->ops->set_voltage_sel) { diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 3adeaeffc485..fdb6ea8ae7e6 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -240,6 +240,31 @@ static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, return ret; } +static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_sel, + unsigned int new_sel) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int id = rdev_get_id(rdev); + int ret = 0; + + /* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling + * the activate bit. + */ + switch (id) { + case DA9052_ID_BUCK1: + case DA9052_ID_BUCK2: + case DA9052_ID_BUCK3: + case DA9052_ID_LDO2: + case DA9052_ID_LDO3: + ret = (new_sel - old_sel) * info->step_uV / 6250; + break; + } + + return ret; +} + static struct regulator_ops da9052_dcdc_ops = { .get_current_limit = da9052_dcdc_get_current_limit, .set_current_limit = da9052_dcdc_set_current_limit, @@ -248,6 +273,7 @@ static struct regulator_ops da9052_dcdc_ops = { .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = da9052_regulator_set_voltage_sel, + .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -258,6 +284,7 @@ static struct regulator_ops da9052_ldo_ops = { .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = da9052_regulator_set_voltage_sel, + .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -401,7 +428,7 @@ static int da9052_regulator_probe(struct platform_device *pdev) if (!nproot) return -ENODEV; - nproot = of_find_node_by_name(nproot, "regulators"); + nproot = of_get_child_by_name(nproot, "regulators"); if (!nproot) return -ENODEV; diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index b14ebdad5dd2..9516317e1a9f 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -19,6 +19,8 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/of.h> +#include <linux/regulator/of_regulator.h> #include <linux/mfd/da9055/core.h> #include <linux/mfd/da9055/reg.h> @@ -446,6 +448,9 @@ static int da9055_gpio_init(struct da9055_regulator *regulator, struct da9055_regulator_info *info = regulator->info; int ret = 0; + if (!pdata) + return 0; + if (pdata->gpio_ren && pdata->gpio_ren[id]) { char name[18]; int gpio_mux = pdata->gpio_ren[id]; @@ -530,6 +535,59 @@ static inline struct da9055_regulator_info *find_regulator_info(int id) return NULL; } +#ifdef CONFIG_OF +static struct of_regulator_match da9055_reg_matches[] = { + { .name = "BUCK1", }, + { .name = "BUCK2", }, + { .name = "LDO1", }, + { .name = "LDO2", }, + { .name = "LDO3", }, + { .name = "LDO4", }, + { .name = "LDO5", }, + { .name = "LDO6", }, +}; + +static int da9055_regulator_dt_init(struct platform_device *pdev, + struct da9055_regulator *regulator, + struct regulator_config *config, + int regid) +{ + struct device_node *nproot, *np; + int ret; + + nproot = of_node_get(pdev->dev.parent->of_node); + if (!nproot) + return -ENODEV; + + np = of_get_child_by_name(nproot, "regulators"); + if (!np) + return -ENODEV; + + ret = of_regulator_match(&pdev->dev, np, &da9055_reg_matches[regid], 1); + of_node_put(nproot); + if (ret < 0) { + dev_err(&pdev->dev, "Error matching regulator: %d\n", ret); + return ret; + } + + config->init_data = da9055_reg_matches[regid].init_data; + config->of_node = da9055_reg_matches[regid].of_node; + + if (!config->of_node) + return -ENODEV; + + return 0; +} +#else +static inline int da9055_regulator_dt_init(struct platform_device *pdev, + struct da9055_regulator *regulator, + struct regulator_config *config, + int regid) +{ + return -ENODEV; +} +#endif /* CONFIG_OF */ + static int da9055_regulator_probe(struct platform_device *pdev) { struct regulator_config config = { }; @@ -538,9 +596,6 @@ static int da9055_regulator_probe(struct platform_device *pdev) struct da9055_pdata *pdata = dev_get_platdata(da9055->dev); int ret, irq; - if (pdata == NULL || pdata->regulators[pdev->id] == NULL) - return -ENODEV; - regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9055_regulator), GFP_KERNEL); if (!regulator) @@ -557,8 +612,14 @@ static int da9055_regulator_probe(struct platform_device *pdev) config.driver_data = regulator; config.regmap = da9055->regmap; - if (pdata && pdata->regulators) + if (pdata && pdata->regulators) { config.init_data = pdata->regulators[pdev->id]; + } else { + ret = da9055_regulator_dt_init(pdev, regulator, &config, + pdev->id); + if (ret < 0) + return ret; + } ret = da9055_gpio_init(regulator, &config, pdata, pdev->id); if (ret < 0) diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 91e99a2c8dc1..7c9461d13313 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -365,7 +365,7 @@ static int da9063_set_suspend_voltage(struct regulator_dev *rdev, int uV) sel = regulator_map_voltage_linear(rdev, uV, uV); if (sel < 0) - return -EINVAL; + return sel; sel <<= ffs(rdev->desc->vsel_mask) - 1; @@ -666,7 +666,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( struct device_node *node; int i, n, num; - node = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); + node = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); if (!node) { dev_err(&pdev->dev, "Regulators device node not found\n"); return ERR_PTR(-ENODEV); @@ -674,6 +674,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( num = of_regulator_match(&pdev->dev, node, da9063_matches, ARRAY_SIZE(da9063_matches)); + of_node_put(node); if (num < 0) { dev_err(&pdev->dev, "Failed to match regulators\n"); return ERR_PTR(-EINVAL); @@ -710,7 +711,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( struct platform_device *pdev, struct of_regulator_match **da9063_reg_matches) { - da9063_reg_matches = NULL; + *da9063_reg_matches = NULL; return ERR_PTR(-ENODEV); } #endif @@ -756,7 +757,7 @@ static int da9063_regulator_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "Error while reading BUCKs configuration\n"); - return -EIO; + return ret; } bcores_merged = val & DA9063_BCORE_MERGE; bmem_bio_merged = val & DA9063_BUCK_MERGE; @@ -775,10 +776,8 @@ static int da9063_regulator_probe(struct platform_device *pdev) 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"); + if (!regulators) return -ENOMEM; - } regulators->n_regulators = n_regulators; platform_set_drvdata(pdev, regulators); diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index 6f5ecbe1132e..7a320dd11c46 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -134,11 +134,8 @@ static int da9210_i2c_probe(struct i2c_client *i2c, 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"); + if (!chip) return -ENOMEM; - } chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config); if (IS_ERR(chip->regmap)) { diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 846acf240e48..617c1adca816 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -263,6 +263,8 @@ dbx500_regulator_info[DB8500_NUM_REGULATORS] = { .ops = &db8500_regulator_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, + .fixed_uV = 1800000, + .n_voltages = 1, }, .exclude_from_power_state = true, }, diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index ce89f7848a57..2d16b9f16de7 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -78,6 +78,7 @@ static struct ux500_regulator_debug { void ux500_regulator_suspend_debug(void) { int i; + for (i = 0; i < rdebug.num_regulators; i++) rdebug.state_before_suspend[i] = rdebug.regulator_array[i].is_enabled; @@ -86,6 +87,7 @@ void ux500_regulator_suspend_debug(void) void ux500_regulator_resume_debug(void) { int i; + for (i = 0; i < rdebug.num_regulators; i++) rdebug.state_after_suspend[i] = rdebug.regulator_array[i].is_enabled; @@ -127,9 +129,9 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p) int i; /* print dump header */ - err = seq_printf(s, "ux500-regulator status:\n"); + err = seq_puts(s, "ux500-regulator status:\n"); if (err < 0) - dev_err(dev, "seq_printf overflow\n"); + dev_err(dev, "seq_puts overflow\n"); err = seq_printf(s, "%31s : %8s : %8s\n", "current", "before", "after"); @@ -202,18 +204,12 @@ ux500_regulator_debug_init(struct platform_device *pdev, rdebug.num_regulators = num_regulators; rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL); - if (!rdebug.state_before_suspend) { - dev_err(&pdev->dev, - "could not allocate memory for saving state\n"); + if (!rdebug.state_before_suspend) goto exit_destroy_power_state; - } rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL); - if (!rdebug.state_after_suspend) { - dev_err(&pdev->dev, - "could not allocate memory for saving state\n"); + if (!rdebug.state_after_suspend) goto exit_free; - } dbx500_regulator_testcase(regulator_info, num_regulators); return 0; diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index df9f42524abb..2436db9e2ca3 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c @@ -25,7 +25,11 @@ struct regulator_dev *dummy_regulator_rdev; -static struct regulator_init_data dummy_initdata; +static struct regulator_init_data dummy_initdata = { + .constraints = { + .always_on = 1, + }, +}; static struct regulator_ops dummy_ops; diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 7ca3d9e3b0fe..714fd9a89aa1 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -90,11 +90,11 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) return 0; ret = regulator_map_voltage_linear(rdev, uV, uV); if (ret < 0) - return -EINVAL; + return ret; ret = regmap_update_bits(di->regmap, di->sleep_reg, VSEL_NSEL_MASK, ret); if (ret < 0) - return -EINVAL; + return ret; /* Cache the sleep voltage setting. * Might not be the real voltage which is rounded */ di->sleep_vol_cache = uV; @@ -244,10 +244,9 @@ static int fan53555_regulator_probe(struct i2c_client *client, di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info), GFP_KERNEL); - if (!di) { - dev_err(&client->dev, "Failed to allocate device info data!\n"); + if (!di) return -ENOMEM; - } + di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config); if (IS_ERR(di->regmap)) { dev_err(&client->dev, "Failed to allocate regmap!\n"); @@ -260,14 +259,14 @@ static int fan53555_regulator_probe(struct i2c_client *client, ret = regmap_read(di->regmap, FAN53555_ID1, &val); if (ret < 0) { dev_err(&client->dev, "Failed to get chip ID!\n"); - return -ENODEV; + return ret; } di->chip_id = val & DIE_ID; /* Get chip revision */ ret = regmap_read(di->regmap, FAN53555_ID2, &val); if (ret < 0) { dev_err(&client->dev, "Failed to get chip Rev!\n"); - return -ENODEV; + return ret; } di->chip_rev = val & DIE_REV; dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n", diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 5ea64b94341c..c61f7e97e4f8 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -130,17 +130,15 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data), GFP_KERNEL); - if (drvdata == NULL) { - dev_err(&pdev->dev, "Failed to allocate device data\n"); - ret = -ENOMEM; - goto err; - } + if (!drvdata) + return -ENOMEM; - drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); + drvdata->desc.name = devm_kstrdup(&pdev->dev, + config->supply_name, + GFP_KERNEL); if (drvdata->desc.name == NULL) { dev_err(&pdev->dev, "Failed to allocate supply name\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } drvdata->desc.type = REGULATOR_VOLTAGE; drvdata->desc.owner = THIS_MODULE; @@ -149,13 +147,13 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.enable_time = config->startup_delay; if (config->input_supply) { - drvdata->desc.supply_name = kstrdup(config->input_supply, - GFP_KERNEL); + drvdata->desc.supply_name = devm_kstrdup(&pdev->dev, + config->input_supply, + GFP_KERNEL); if (!drvdata->desc.supply_name) { dev_err(&pdev->dev, "Failed to allocate input supply\n"); - ret = -ENOMEM; - goto err_name; + return -ENOMEM; } } @@ -186,11 +184,12 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) cfg.driver_data = drvdata; cfg.of_node = pdev->dev.of_node; - drvdata->dev = regulator_register(&drvdata->desc, &cfg); + drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc, + &cfg); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); - goto err_input; + return ret; } platform_set_drvdata(pdev, drvdata); @@ -199,24 +198,6 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.fixed_uV); return 0; - -err_input: - kfree(drvdata->desc.supply_name); -err_name: - kfree(drvdata->desc.name); -err: - return ret; -} - -static int reg_fixed_voltage_remove(struct platform_device *pdev) -{ - struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); - - regulator_unregister(drvdata->dev); - kfree(drvdata->desc.supply_name); - kfree(drvdata->desc.name); - - return 0; } #if defined(CONFIG_OF) @@ -229,7 +210,6 @@ MODULE_DEVICE_TABLE(of, fixed_of_match); static struct platform_driver regulator_fixed_voltage_driver = { .probe = reg_fixed_voltage_probe, - .remove = reg_fixed_voltage_remove, .driver = { .name = "reg-fixed-voltage", .owner = THIS_MODULE, diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index c0a1d00b78c9..989b23b377c0 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -136,7 +136,6 @@ static struct gpio_regulator_config * of_get_gpio_regulator_config(struct device *dev, struct device_node *np) { struct gpio_regulator_config *config; - struct property *prop; const char *regtype; int proplen, gpio, i; int ret; @@ -172,22 +171,35 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np) if (!config->gpios) return ERR_PTR(-ENOMEM); + proplen = of_property_count_u32_elems(np, "gpios-states"); + /* optional property */ + if (proplen < 0) + proplen = 0; + + if (proplen > 0 && proplen != config->nr_gpios) { + dev_warn(dev, "gpios <-> gpios-states mismatch\n"); + proplen = 0; + } + for (i = 0; i < config->nr_gpios; i++) { gpio = of_get_named_gpio(np, "gpios", i); if (gpio < 0) break; config->gpios[i].gpio = gpio; + if (proplen > 0) { + of_property_read_u32_index(np, "gpios-states", i, &ret); + if (ret) + config->gpios[i].flags = GPIOF_OUT_INIT_HIGH; + } } /* Fetch states. */ - prop = of_find_property(np, "states", NULL); - if (!prop) { + proplen = of_property_count_u32_elems(np, "states"); + if (proplen < 0) { dev_err(dev, "No 'states' property found\n"); return ERR_PTR(-EINVAL); } - proplen = prop->length / sizeof(int); - config->states = devm_kzalloc(dev, sizeof(struct gpio_regulator_state) * (proplen / 2), @@ -196,10 +208,10 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np) return ERR_PTR(-ENOMEM); for (i = 0; i < proplen / 2; i++) { - config->states[i].value = - be32_to_cpup((int *)prop->value + (i * 2)); - config->states[i].gpios = - be32_to_cpup((int *)prop->value + (i * 2 + 1)); + of_property_read_u32_index(np, "states", i * 2, + &config->states[i].value); + of_property_read_u32_index(np, "states", i * 2 + 1, + &config->states[i].gpios); } config->nr_states = i; @@ -239,10 +251,8 @@ static int gpio_regulator_probe(struct platform_device *pdev) drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), GFP_KERNEL); - if (drvdata == NULL) { - dev_err(&pdev->dev, "Failed to allocate device data\n"); + if (drvdata == NULL) return -ENOMEM; - } drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); if (drvdata->desc.name == NULL) { diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index e221a271ba56..cbc39096c78d 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -37,10 +37,17 @@ int regulator_is_enabled_regmap(struct regulator_dev *rdev) 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; + val &= rdev->desc->enable_mask; + + if (rdev->desc->enable_is_inverted) { + if (rdev->desc->enable_val) + return val != rdev->desc->enable_val; + return val == 0; + } else { + if (rdev->desc->enable_val) + return val == rdev->desc->enable_val; + return val != 0; + } } EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); @@ -57,10 +64,13 @@ 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; + if (rdev->desc->enable_is_inverted) { + val = rdev->desc->disable_val; + } else { + val = rdev->desc->enable_val; + if (!val) + val = rdev->desc->enable_mask; + } return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, rdev->desc->enable_mask, val); @@ -80,10 +90,13 @@ 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; + if (rdev->desc->enable_is_inverted) { + val = rdev->desc->enable_val; + if (!val) + val = rdev->desc->enable_mask; + } else { + val = rdev->desc->disable_val; + } return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, rdev->desc->enable_mask, val); @@ -419,10 +432,13 @@ int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable) { unsigned int val; - if (enable) - val = rdev->desc->bypass_mask; - else - val = 0; + if (enable) { + val = rdev->desc->bypass_val_on; + if (!val) + val = rdev->desc->bypass_mask; + } else { + val = rdev->desc->bypass_val_off; + } return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg, rdev->desc->bypass_mask, val); diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 3b1102b75071..66fd2330dca0 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -327,7 +327,7 @@ static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count, return -EIO; ret = i2c_smbus_read_byte_data(i2c, reg); if (ret < 0) - return -EIO; + return ret; *dest = ret; return 0; diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 2e4734ff79fc..2e022aabd951 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -211,7 +211,7 @@ static int lp872x_get_timestep_usec(struct lp872x *lp) ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val); if (ret) - return -EINVAL; + return ret; val = (val & mask) >> shift; if (val >= size) @@ -229,7 +229,7 @@ static int lp872x_regulator_enable_time(struct regulator_dev *rdev) u8 addr, val; if (time_step_us < 0) - return -EINVAL; + return time_step_us; switch (rid) { case LP8720_ID_LDO1 ... LP8720_ID_BUCK: diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c index e0619526708c..ed60baaeceec 100644 --- a/drivers/regulator/max14577.c +++ b/drivers/regulator/max14577.c @@ -1,7 +1,7 @@ /* * max14577.c - Regulator driver for the Maxim 14577 * - * Copyright (C) 2013 Samsung Electronics + * Copyright (C) 2013,2014 Samsung Electronics * Krzysztof Kozlowski <k.kozlowski@samsung.com> * * This program is free software; you can redistribute it and/or modify @@ -22,12 +22,6 @@ #include <linux/mfd/max14577-private.h> #include <linux/regulator/of_regulator.h> -struct max14577_regulator { - struct device *dev; - struct max14577 *max14577; - struct regulator_dev **regulators; -}; - static int max14577_reg_is_enabled(struct regulator_dev *rdev) { int rid = rdev_get_id(rdev); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index e242dd316d36..d23d0577754b 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -46,8 +46,6 @@ struct max1586_data { unsigned int v3_curr_sel; unsigned int v6_curr_sel; - - struct regulator_dev *rdev[0]; }; /* @@ -162,14 +160,12 @@ static struct regulator_desc max1586_reg[] = { 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 = dev_get_platdata(&client->dev); struct regulator_config config = { }; struct max1586_data *max1586; int i, id; - max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data) + - sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), + max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data), GFP_KERNEL); if (!max1586) return -ENOMEM; @@ -186,8 +182,9 @@ static int max1586_pmic_probe(struct i2c_client *client, max1586->v3_curr_sel = 24; /* 1.3V */ max1586->v6_curr_sel = 0; - rdev = max1586->rdev; for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { + struct regulator_dev *rdev; + id = pdata->subdevs[i].id; if (!pdata->subdevs[i].platform_data) continue; @@ -207,12 +204,12 @@ static int max1586_pmic_probe(struct i2c_client *client, config.init_data = pdata->subdevs[i].platform_data; config.driver_data = max1586; - rdev[i] = devm_regulator_register(&client->dev, + rdev = devm_regulator_register(&client->dev, &max1586_reg[id], &config); - if (IS_ERR(rdev[i])) { + if (IS_ERR(rdev)) { dev_err(&client->dev, "failed to register %s\n", max1586_reg[id].name); - return PTR_ERR(rdev[i]); + return PTR_ERR(rdev); } } diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c index ae001ccf26f4..ef1af2debbd2 100644 --- a/drivers/regulator/max77686.c +++ b/drivers/regulator/max77686.c @@ -65,7 +65,6 @@ enum max77686_ramp_rate { }; struct max77686_data { - struct regulator_dev *rdev[MAX77686_REGULATORS]; unsigned int opmode[MAX77686_REGULATORS]; }; @@ -400,7 +399,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev, unsigned int i; pmic_np = iodev->dev->of_node; - regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators"); + regulators_np = of_get_child_by_name(pmic_np, "voltage-regulators"); if (!regulators_np) { dev_err(&pdev->dev, "could not find regulators sub-node\n"); return -EINVAL; @@ -410,8 +409,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev, rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * pdata->num_regulators, GFP_KERNEL); if (!rdata) { - dev_err(&pdev->dev, - "could not allocate memory for regulator data\n"); + of_node_put(regulators_np); return -ENOMEM; } @@ -425,6 +423,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev, } pdata->regulators = rdata; + of_node_put(regulators_np); return 0; } @@ -474,16 +473,18 @@ static int max77686_pmic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, max77686); for (i = 0; i < MAX77686_REGULATORS; i++) { + struct regulator_dev *rdev; + config.init_data = pdata->regulators[i].initdata; config.of_node = pdata->regulators[i].of_node; max77686->opmode[i] = regulators[i].enable_mask; - max77686->rdev[i] = devm_regulator_register(&pdev->dev, + rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); - if (IS_ERR(max77686->rdev[i])) { + if (IS_ERR(rdev)) { dev_err(&pdev->dev, "regulator init failed for %d\n", i); - return PTR_ERR(max77686->rdev[i]); + return PTR_ERR(rdev); } } diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c index 5fb899f461d0..653a58b49cdf 100644 --- a/drivers/regulator/max77693.c +++ b/drivers/regulator/max77693.c @@ -34,13 +34,6 @@ #define CHGIN_ILIM_STEP_20mA 20000 -struct max77693_pmic_dev { - struct device *dev; - struct max77693_dev *iodev; - int num_regulators; - struct regulator_dev **rdev; -}; - /* CHARGER regulator ops */ /* CHARGER regulator uses two bits for enabling */ static int max77693_chg_is_enabled(struct regulator_dev *rdev) @@ -170,19 +163,22 @@ static int max77693_pmic_dt_parse_rdata(struct device *dev, struct max77693_regulator_data *tmp; int i, matched = 0; - np = of_find_node_by_name(dev->parent->of_node, "regulators"); + np = of_get_child_by_name(dev->parent->of_node, "regulators"); if (!np) return -EINVAL; rmatch = devm_kzalloc(dev, sizeof(*rmatch) * ARRAY_SIZE(regulators), GFP_KERNEL); - if (!rmatch) + if (!rmatch) { + of_node_put(np); return -ENOMEM; + } for (i = 0; i < ARRAY_SIZE(regulators); i++) rmatch[i].name = regulators[i].name; matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(regulators)); + of_node_put(np); if (matched <= 0) return matched; *rdata = devm_kzalloc(dev, sizeof(**rdata) * matched, GFP_KERNEL); @@ -229,7 +225,6 @@ static int max77693_pmic_init_rdata(struct device *dev, static int max77693_pmic_probe(struct platform_device *pdev) { struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct max77693_pmic_dev *max77693_pmic; struct max77693_regulator_data *rdata = NULL; int num_rdata, i; struct regulator_config config; @@ -240,39 +235,22 @@ static int max77693_pmic_probe(struct platform_device *pdev) return -ENODEV; } - max77693_pmic = devm_kzalloc(&pdev->dev, - sizeof(struct max77693_pmic_dev), - GFP_KERNEL); - if (!max77693_pmic) - return -ENOMEM; - - max77693_pmic->rdev = devm_kzalloc(&pdev->dev, - sizeof(struct regulator_dev *) * num_rdata, - GFP_KERNEL); - if (!max77693_pmic->rdev) - return -ENOMEM; - - max77693_pmic->dev = &pdev->dev; - max77693_pmic->iodev = iodev; - max77693_pmic->num_regulators = num_rdata; - config.dev = &pdev->dev; config.regmap = iodev->regmap; - config.driver_data = max77693_pmic; - platform_set_drvdata(pdev, max77693_pmic); - for (i = 0; i < max77693_pmic->num_regulators; i++) { + for (i = 0; i < num_rdata; i++) { int id = rdata[i].id; + struct regulator_dev *rdev; config.init_data = rdata[i].initdata; config.of_node = rdata[i].of_node; - max77693_pmic->rdev[i] = devm_regulator_register(&pdev->dev, + rdev = devm_regulator_register(&pdev->dev, ®ulators[id], &config); - if (IS_ERR(max77693_pmic->rdev[i])) { - dev_err(max77693_pmic->dev, + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to initialize regulator-%d\n", id); - return PTR_ERR(max77693_pmic->rdev[i]); + return PTR_ERR(rdev); } } diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 7f049c92ee52..3172da847d24 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -49,7 +49,6 @@ #define MAX8649_RAMP_DOWN (1 << 1) struct max8649_regulator_info { - struct regulator_dev *regulator; struct device *dev; struct regmap *regmap; @@ -154,6 +153,7 @@ static int max8649_regulator_probe(struct i2c_client *client, { struct max8649_platform_data *pdata = dev_get_platdata(&client->dev); struct max8649_regulator_info *info = NULL; + struct regulator_dev *regulator; struct regulator_config config = { }; unsigned int val; unsigned char data; @@ -234,12 +234,12 @@ static int max8649_regulator_probe(struct i2c_client *client, config.driver_data = info; config.regmap = info->regmap; - info->regulator = devm_regulator_register(&client->dev, &dcdc_desc, + regulator = devm_regulator_register(&client->dev, &dcdc_desc, &config); - if (IS_ERR(info->regulator)) { + if (IS_ERR(regulator)) { dev_err(info->dev, "failed to register regulator %s\n", dcdc_desc.name); - return PTR_ERR(info->regulator); + return PTR_ERR(regulator); } return 0; diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 8d94d3d7f97f..2fc411188794 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -81,16 +81,17 @@ enum { struct max8660 { struct i2c_client *client; u8 shadow_regs[MAX8660_N_REGS]; /* as chip is write only */ - struct regulator_dev *rdev[]; }; static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val) { - static const u8 max8660_addresses[MAX8660_N_REGS] = - { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 }; + static const u8 max8660_addresses[MAX8660_N_REGS] = { + 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 + }; int ret; u8 reg_val = (max8660->shadow_regs[reg] & mask) | val; + dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n", max8660_addresses[reg], reg_val); @@ -112,6 +113,7 @@ static int max8660_dcdc_is_enabled(struct regulator_dev *rdev) struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 val = max8660->shadow_regs[MAX8660_OVER1]; u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4; + return !!(val & mask); } @@ -119,6 +121,7 @@ static int max8660_dcdc_enable(struct regulator_dev *rdev) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4; + return max8660_write(max8660, MAX8660_OVER1, 0xff, bit); } @@ -126,15 +129,16 @@ static int max8660_dcdc_disable(struct regulator_dev *rdev) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4; + return max8660_write(max8660, MAX8660_OVER1, mask, 0); } static int max8660_dcdc_get_voltage_sel(struct regulator_dev *rdev) { struct max8660 *max8660 = rdev_get_drvdata(rdev); - u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2; u8 selector = max8660->shadow_regs[reg]; + return selector; } @@ -207,6 +211,7 @@ static int max8660_ldo67_is_enabled(struct regulator_dev *rdev) struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 val = max8660->shadow_regs[MAX8660_OVER2]; u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4; + return !!(val & mask); } @@ -214,6 +219,7 @@ static int max8660_ldo67_enable(struct regulator_dev *rdev) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4; + return max8660_write(max8660, MAX8660_OVER2, 0xff, bit); } @@ -221,15 +227,16 @@ static int max8660_ldo67_disable(struct regulator_dev *rdev) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4; + return max8660_write(max8660, MAX8660_OVER2, mask, 0); } static int max8660_ldo67_get_voltage_sel(struct regulator_dev *rdev) { struct max8660 *max8660 = rdev_get_drvdata(rdev); - u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4; u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf; + return selector; } @@ -330,7 +337,7 @@ static int max8660_pdata_from_dt(struct device *dev, struct max8660_subdev_data *sub; struct of_regulator_match rmatch[ARRAY_SIZE(max8660_reg)]; - np = of_find_node_by_name(dev->of_node, "regulators"); + np = of_get_child_by_name(dev->of_node, "regulators"); if (!np) { dev_err(dev, "missing 'regulators' subnode in DT\n"); return -EINVAL; @@ -340,6 +347,7 @@ static int max8660_pdata_from_dt(struct device *dev, rmatch[i].name = max8660_reg[i].name; matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch)); + of_node_put(np); if (matched <= 0) return matched; @@ -373,7 +381,6 @@ static inline int max8660_pdata_from_dt(struct device *dev, static int max8660_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { - struct regulator_dev **rdev; struct device *dev = &client->dev; struct max8660_platform_data *pdata = dev_get_platdata(dev); struct regulator_config config = { }; @@ -406,14 +413,11 @@ static int max8660_probe(struct i2c_client *client, return -EINVAL; } - max8660 = devm_kzalloc(dev, sizeof(struct max8660) + - sizeof(struct regulator_dev *) * MAX8660_V_END, - GFP_KERNEL); + max8660 = devm_kzalloc(dev, sizeof(struct max8660), GFP_KERNEL); if (!max8660) return -ENOMEM; max8660->client = client; - rdev = max8660->rdev; if (pdata->en34_is_high) { /* Simulate always on */ @@ -481,6 +485,7 @@ static int max8660_probe(struct i2c_client *client, /* Finally register devices */ for (i = 0; i < pdata->num_subdevs; i++) { + struct regulator_dev *rdev; id = pdata->subdevs[i].id; @@ -489,13 +494,13 @@ static int max8660_probe(struct i2c_client *client, config.of_node = of_node[i]; config.driver_data = max8660; - rdev[i] = devm_regulator_register(&client->dev, + rdev = devm_regulator_register(&client->dev, &max8660_reg[id], &config); - if (IS_ERR(rdev[i])) { - ret = PTR_ERR(rdev[i]); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); dev_err(&client->dev, "failed to register %s\n", max8660_reg[id].name); - return PTR_ERR(rdev[i]); + return PTR_ERR(rdev); } } diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c index 0c5fe6c6ac26..9623e9e290bf 100644 --- a/drivers/regulator/max8907-regulator.c +++ b/drivers/regulator/max8907-regulator.c @@ -34,7 +34,6 @@ struct max8907_regulator { struct regulator_desc desc[MAX8907_NUM_REGULATORS]; - struct regulator_dev *rdev[MAX8907_NUM_REGULATORS]; }; #define REG_MBATT() \ @@ -231,7 +230,7 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev) if (!np) return 0; - regulators = of_find_node_by_name(np, "regulators"); + regulators = of_get_child_by_name(np, "regulators"); if (!regulators) { dev_err(&pdev->dev, "regulators node not found\n"); return -EINVAL; @@ -292,10 +291,9 @@ static int max8907_regulator_probe(struct platform_device *pdev) return ret; pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); - if (!pmic) { - dev_err(&pdev->dev, "Failed to alloc pmic\n"); + if (!pmic) return -ENOMEM; - } + platform_set_drvdata(pdev, pmic); memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc)); @@ -311,6 +309,8 @@ static int max8907_regulator_probe(struct platform_device *pdev) } for (i = 0; i < MAX8907_NUM_REGULATORS; i++) { + struct regulator_dev *rdev; + config.dev = pdev->dev.parent; if (pdata) idata = pdata->init_data[i]; @@ -350,13 +350,13 @@ static int max8907_regulator_probe(struct platform_device *pdev) pmic->desc[i].ops = &max8907_out5v_hwctl_ops; } - pmic->rdev[i] = devm_regulator_register(&pdev->dev, + rdev = devm_regulator_register(&pdev->dev, &pmic->desc[i], &config); - if (IS_ERR(pmic->rdev[i])) { + if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s regulator\n", pmic->desc[i].name); - return PTR_ERR(pmic->rdev[i]); + return PTR_ERR(rdev); } } diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 759510789e71..dad2bcd14e96 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -36,9 +36,7 @@ struct max8925_regulator_info { struct regulator_desc desc; - struct regulator_dev *regulator; struct i2c_client *i2c; - struct max8925_chip *chip; int vol_reg; int enable_reg; @@ -251,10 +249,11 @@ static int max8925_regulator_dt_init(struct platform_device *pdev, { struct device_node *nproot, *np; int rcount; + nproot = of_node_get(pdev->dev.parent->of_node); if (!nproot) return -ENODEV; - np = of_find_node_by_name(nproot, "regulators"); + np = of_get_child_by_name(nproot, "regulators"); if (!np) { dev_err(&pdev->dev, "failed to find regulators node\n"); return -ENODEV; @@ -264,7 +263,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev, &max8925_regulator_matches[ridx], 1); of_node_put(np); if (rcount < 0) - return -ENODEV; + return rcount; config->init_data = max8925_regulator_matches[ridx].init_data; config->of_node = max8925_regulator_matches[ridx].of_node; @@ -303,7 +302,6 @@ static int max8925_regulator_probe(struct platform_device *pdev) return -EINVAL; } ri->i2c = chip->i2c; - ri->chip = chip; config.dev = &pdev->dev; config.driver_data = ri; diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 788e5ae2af1b..d920f5a32ec8 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -48,9 +48,7 @@ enum { struct max8952_data { struct i2c_client *client; - struct device *dev; struct max8952_platform_data *pdata; - struct regulator_dev *rdev; bool vid0; bool vid1; @@ -59,6 +57,7 @@ struct max8952_data { static int max8952_read_reg(struct max8952_data *max8952, u8 reg) { int ret = i2c_smbus_read_byte_data(max8952->client, reg); + if (ret > 0) ret &= 0xff; @@ -144,10 +143,8 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev) int i; pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); - if (!pd) { - dev_err(dev, "Failed to allocate platform data\n"); + if (!pd) return NULL; - } pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0); pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1); @@ -199,6 +196,7 @@ static int max8952_pmic_probe(struct i2c_client *client, struct max8952_platform_data *pdata = dev_get_platdata(&client->dev); struct regulator_config config = { }; struct max8952_data *max8952; + struct regulator_dev *rdev; int ret = 0, err = 0; @@ -219,10 +217,9 @@ static int max8952_pmic_probe(struct i2c_client *client, return -ENOMEM; max8952->client = client; - max8952->dev = &client->dev; max8952->pdata = pdata; - config.dev = max8952->dev; + config.dev = &client->dev; config.init_data = pdata->reg_data; config.driver_data = max8952; config.of_node = client->dev.of_node; @@ -231,11 +228,11 @@ static int max8952_pmic_probe(struct i2c_client *client, if (pdata->reg_data->constraints.boot_on) config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; - max8952->rdev = regulator_register(®ulator, &config); + rdev = devm_regulator_register(&client->dev, ®ulator, &config); - if (IS_ERR(max8952->rdev)) { - ret = PTR_ERR(max8952->rdev); - dev_err(max8952->dev, "regulator init failed (%d)\n", ret); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&client->dev, "regulator init failed (%d)\n", ret); return ret; } @@ -263,7 +260,7 @@ static int max8952_pmic_probe(struct i2c_client *client, err = 3; if (err) { - dev_warn(max8952->dev, "VID0/1 gpio invalid: " + dev_warn(&client->dev, "VID0/1 gpio invalid: " "DVS not available.\n"); max8952->vid0 = 0; max8952->vid1 = 0; @@ -274,7 +271,7 @@ static int max8952_pmic_probe(struct i2c_client *client, /* Disable Pulldown of EN only */ max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60); - dev_err(max8952->dev, "DVS modes disabled because VID0 and VID1" + dev_err(&client->dev, "DVS modes disabled because VID0 and VID1" " do not have proper controls.\n"); } else { /* @@ -321,9 +318,6 @@ static int max8952_pmic_remove(struct i2c_client *client) { struct max8952_data *max8952 = i2c_get_clientdata(client); struct max8952_platform_data *pdata = max8952->pdata; - struct regulator_dev *rdev = max8952->rdev; - - regulator_unregister(rdev); gpio_free(pdata->gpio_vid0); gpio_free(pdata->gpio_vid1); diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 892aa1e5b96c..dbedf1768db0 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -93,7 +93,6 @@ struct max8973_chip { struct device *dev; struct regulator_desc desc; - struct regulator_dev *rdev; struct regmap *regmap; bool enable_external_control; int dvs_gpio; @@ -379,10 +378,8 @@ static int max8973_probe(struct i2c_client *client, } max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL); - if (!max) { - dev_err(&client->dev, "Memory allocation for max failed\n"); + if (!max) return -ENOMEM; - } max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config); if (IS_ERR(max->regmap)) { @@ -474,7 +471,6 @@ static int max8973_probe(struct i2c_client *client, return ret; } - max->rdev = rdev; return 0; } diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 2d618fc9c1af..90b4c530dee5 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -38,7 +38,6 @@ struct max8997_data { struct device *dev; struct max8997_dev *iodev; int num_regulators; - struct regulator_dev **rdev; int ramp_delay; /* in mV/us */ bool buck1_gpiodvs; @@ -924,7 +923,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, return -ENODEV; } - regulators_np = of_find_node_by_name(pmic_np, "regulators"); + regulators_np = of_get_child_by_name(pmic_np, "regulators"); if (!regulators_np) { dev_err(&pdev->dev, "could not find regulators sub-node\n"); return -EINVAL; @@ -937,7 +936,6 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, pdata->num_regulators, GFP_KERNEL); if (!rdata) { of_node_put(regulators_np); - dev_err(&pdev->dev, "could not allocate memory for regulator data\n"); return -ENOMEM; } @@ -1030,10 +1028,10 @@ static int max8997_pmic_probe(struct platform_device *pdev) struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8997_platform_data *pdata = iodev->pdata; struct regulator_config config = { }; - struct regulator_dev **rdev; + struct regulator_dev *rdev; struct max8997_data *max8997; struct i2c_client *i2c; - int i, ret, size, nr_dvs; + int i, ret, nr_dvs; u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0; if (!pdata) { @@ -1052,12 +1050,6 @@ static int max8997_pmic_probe(struct platform_device *pdev) if (!max8997) return -ENOMEM; - size = sizeof(struct regulator_dev *) * pdata->num_regulators; - max8997->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!max8997->rdev) - return -ENOMEM; - - rdev = max8997->rdev; max8997->dev = &pdev->dev; max8997->iodev = iodev; max8997->num_regulators = pdata->num_regulators; @@ -1205,12 +1197,12 @@ static int max8997_pmic_probe(struct platform_device *pdev) config.driver_data = max8997; config.of_node = pdata->regulators[i].reg_node; - rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], - &config); - if (IS_ERR(rdev[i])) { + rdev = devm_regulator_register(&pdev->dev, ®ulators[id], + &config); + if (IS_ERR(rdev)) { dev_err(max8997->dev, "regulator init failed for %d\n", id); - return PTR_ERR(rdev[i]); + return PTR_ERR(rdev); } } diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index ae3f0656feb0..961091b46557 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -40,7 +40,6 @@ struct max8998_data { struct device *dev; struct max8998_dev *iodev; int num_regulators; - struct regulator_dev **rdev; u8 buck1_vol[4]; /* voltages for selection */ u8 buck2_vol[2]; unsigned int buck1_idx; /* index to last changed voltage */ @@ -674,8 +673,10 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev, rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) * pdata->num_regulators, GFP_KERNEL); - if (!rdata) + if (!rdata) { + of_node_put(regulators_np); return -ENOMEM; + } pdata->regulators = rdata; for (i = 0; i < ARRAY_SIZE(regulators); ++i) { @@ -692,6 +693,9 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev, } pdata->num_regulators = rdata - pdata->regulators; + of_node_put(reg_np); + of_node_put(regulators_np); + ret = max8998_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); if (ret) return -EINVAL; @@ -741,10 +745,10 @@ static int max8998_pmic_probe(struct platform_device *pdev) struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = iodev->pdata; struct regulator_config config = { }; - struct regulator_dev **rdev; + struct regulator_dev *rdev; struct max8998_data *max8998; struct i2c_client *i2c; - int i, ret, size; + int i, ret; unsigned int v; if (!pdata) { @@ -763,12 +767,6 @@ static int max8998_pmic_probe(struct platform_device *pdev) if (!max8998) return -ENOMEM; - size = sizeof(struct regulator_dev *) * pdata->num_regulators; - max8998->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); - if (!max8998->rdev) - return -ENOMEM; - - rdev = max8998->rdev; max8998->dev = &pdev->dev; max8998->iodev = iodev; max8998->num_regulators = pdata->num_regulators; @@ -872,13 +870,12 @@ static int max8998_pmic_probe(struct platform_device *pdev) config.init_data = pdata->regulators[i].initdata; config.driver_data = max8998; - rdev[i] = devm_regulator_register(&pdev->dev, - ®ulators[index], &config); - if (IS_ERR(rdev[i])) { - ret = PTR_ERR(rdev[i]); + rdev = devm_regulator_register(&pdev->dev, ®ulators[index], + &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); dev_err(max8998->dev, "regulator %s init failed (%d)\n", regulators[index].name, ret); - rdev[i] = NULL; return ret; } } diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index da4859282302..05b971726ffa 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -167,8 +167,10 @@ int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) struct device_node *parent; int num; - of_node_get(pdev->dev.parent->of_node); - parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); + if (!pdev->dev.parent->of_node) + return -ENODEV; + + parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); if (!parent) return -ENODEV; @@ -187,8 +189,10 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( struct device_node *parent, *child; int i, parsed = 0; - of_node_get(pdev->dev.parent->of_node); - parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); + if (!pdev->dev.parent->of_node) + return NULL; + + parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); if (!parent) return NULL; diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index ab174f20ca11..67e678c4301c 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -56,6 +56,8 @@ #define PFUZE100_VGEN5VOL 0x70 #define PFUZE100_VGEN6VOL 0x71 +enum chips { PFUZE100, PFUZE200 }; + struct pfuze_regulator { struct regulator_desc desc; unsigned char stby_reg; @@ -63,6 +65,7 @@ struct pfuze_regulator { }; struct pfuze_chip { + int chip_id; struct regmap *regmap; struct device *dev; struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; @@ -78,21 +81,23 @@ static const int pfuze100_vsnvs[] = { }; static const struct i2c_device_id pfuze_device_id[] = { - {.name = "pfuze100"}, - {}, + {.name = "pfuze100", .driver_data = PFUZE100}, + {.name = "pfuze200", .driver_data = PFUZE200}, + { } }; MODULE_DEVICE_TABLE(i2c, pfuze_device_id); static const struct of_device_id pfuze_dt_ids[] = { - { .compatible = "fsl,pfuze100" }, - {}, + { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100}, + { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200}, + { } }; 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; + int id = rdev_get_id(rdev); unsigned int ramp_bits; int ret; @@ -139,14 +144,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { }; -#define PFUZE100_FIXED_REG(_name, base, voltage) \ - [PFUZE100_ ## _name] = { \ +#define PFUZE100_FIXED_REG(_chip, _name, base, voltage) \ + [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name, \ .n_voltages = 1, \ .ops = &pfuze100_fixed_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ - .id = PFUZE100_ ## _name, \ + .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .min_uV = (voltage), \ .enable_reg = (base), \ @@ -154,14 +159,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { }, \ } -#define PFUZE100_SW_REG(_name, base, min, max, step) \ - [PFUZE100_ ## _name] = { \ +#define PFUZE100_SW_REG(_chip, _name, base, min, max, step) \ + [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name,\ .n_voltages = ((max) - (min)) / (step) + 1, \ .ops = &pfuze100_sw_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ - .id = PFUZE100_ ## _name, \ + .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .min_uV = (min), \ .uV_step = (step), \ @@ -172,14 +177,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { .stby_mask = 0x3f, \ } -#define PFUZE100_SWB_REG(_name, base, mask, voltages) \ - [PFUZE100_ ## _name] = { \ +#define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages) \ + [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name, \ .n_voltages = ARRAY_SIZE(voltages), \ .ops = &pfuze100_swb_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ - .id = PFUZE100_ ## _name, \ + .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .volt_table = voltages, \ .vsel_reg = (base), \ @@ -187,14 +192,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { }, \ } -#define PFUZE100_VGEN_REG(_name, base, min, max, step) \ - [PFUZE100_ ## _name] = { \ +#define PFUZE100_VGEN_REG(_chip, _name, base, min, max, step) \ + [_chip ## _ ## _name] = { \ .desc = { \ .name = #_name, \ .n_voltages = ((max) - (min)) / (step) + 1, \ .ops = &pfuze100_ldo_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ - .id = PFUZE100_ ## _name, \ + .id = _chip ## _ ## _name, \ .owner = THIS_MODULE, \ .min_uV = (min), \ .uV_step = (step), \ @@ -207,25 +212,45 @@ static struct regulator_ops pfuze100_swb_regulator_ops = { .stby_mask = 0x20, \ } +/* PFUZE100 */ 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), + PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), + PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000), + PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(PFUZE100, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(PFUZE100, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(PFUZE100, SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000), + PFUZE100_SWB_REG(PFUZE100, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), + PFUZE100_SWB_REG(PFUZE100, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), + PFUZE100_FIXED_REG(PFUZE100, VREFDDR, PFUZE100_VREFDDRCON, 750000), + PFUZE100_VGEN_REG(PFUZE100, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), + PFUZE100_VGEN_REG(PFUZE100, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), + PFUZE100_VGEN_REG(PFUZE100, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), +}; + +static struct pfuze_regulator pfuze200_regulators[] = { + PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), + PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), + PFUZE100_SW_REG(PFUZE200, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), + PFUZE100_SWB_REG(PFUZE200, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), + PFUZE100_SWB_REG(PFUZE200, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), + PFUZE100_FIXED_REG(PFUZE200, VREFDDR, PFUZE100_VREFDDRCON, 750000), + PFUZE100_VGEN_REG(PFUZE200, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), + PFUZE100_VGEN_REG(PFUZE200, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), + PFUZE100_VGEN_REG(PFUZE200, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), }; +static struct pfuze_regulator *pfuze_regulators; + #ifdef CONFIG_OF +/* PFUZE100 */ static struct of_regulator_match pfuze100_matches[] = { { .name = "sw1ab", }, { .name = "sw1c", }, @@ -244,24 +269,56 @@ static struct of_regulator_match pfuze100_matches[] = { { .name = "vgen6", }, }; +/* PFUZE200 */ +static struct of_regulator_match pfuze200_matches[] = { + + { .name = "sw1ab", }, + { .name = "sw2", }, + { .name = "sw3a", }, + { .name = "sw3b", }, + { .name = "swbst", }, + { .name = "vsnvs", }, + { .name = "vrefddr", }, + { .name = "vgen1", }, + { .name = "vgen2", }, + { .name = "vgen3", }, + { .name = "vgen4", }, + { .name = "vgen5", }, + { .name = "vgen6", }, +}; + +static struct of_regulator_match *pfuze_matches; + 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); + np = of_node_get(dev->of_node); if (!np) - return 0; + return -EINVAL; - parent = of_find_node_by_name(np, "regulators"); + parent = of_get_child_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)); + switch (chip->chip_id) { + case PFUZE200: + pfuze_matches = pfuze200_matches; + ret = of_regulator_match(dev, parent, pfuze200_matches, + ARRAY_SIZE(pfuze200_matches)); + break; + + case PFUZE100: + default: + pfuze_matches = pfuze100_matches; + ret = of_regulator_match(dev, parent, pfuze100_matches, + ARRAY_SIZE(pfuze100_matches)); + break; + } of_node_put(parent); if (ret < 0) { @@ -275,12 +332,12 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) static inline struct regulator_init_data *match_init_data(int index) { - return pfuze100_matches[index].init_data; + return pfuze_matches[index].init_data; } static inline struct device_node *match_of_node(int index) { - return pfuze100_matches[index].of_node; + return pfuze_matches[index].of_node; } #else static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) @@ -308,16 +365,14 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip) if (ret) return ret; - switch (value & 0x0f) { - /* - * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013 - * as ID=8 - */ - case 0x8: + if (((value & 0x0f) == 0x8) && (pfuze_chip->chip_id == PFUZE100)) { + /* + * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013 + * as ID=8 in PFUZE100 + */ dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8"); - case 0x0: - break; - default: + } else if ((value & 0x0f) != pfuze_chip->chip_id) { + /* device id NOT match with your setting */ dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value); return -ENODEV; } @@ -353,17 +408,31 @@ static int pfuze100_regulator_probe(struct i2c_client *client, dev_get_platdata(&client->dev); struct regulator_config config = { }; int i, ret; + const struct of_device_id *match; + u32 regulator_num; + u32 sw_check_start, sw_check_end; 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)); + if (client->dev.of_node) { + match = of_match_device(of_match_ptr(pfuze_dt_ids), + &client->dev); + if (!match) { + dev_err(&client->dev, "Error: No device match found\n"); + return -ENODEV; + } + pfuze_chip->chip_id = (int)(long)match->data; + } else if (id) { + pfuze_chip->chip_id = id->driver_data; + } else { + dev_err(&client->dev, "No dts match or id table match found\n"); + return -ENODEV; + } + i2c_set_clientdata(client, pfuze_chip); pfuze_chip->dev = &client->dev; pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config); @@ -380,11 +449,34 @@ static int pfuze100_regulator_probe(struct i2c_client *client, return ret; } + /* use the right regulators after identify the right device */ + switch (pfuze_chip->chip_id) { + case PFUZE200: + pfuze_regulators = pfuze200_regulators; + regulator_num = ARRAY_SIZE(pfuze200_regulators); + sw_check_start = PFUZE200_SW2; + sw_check_end = PFUZE200_SW3B; + break; + + case PFUZE100: + default: + pfuze_regulators = pfuze100_regulators; + regulator_num = ARRAY_SIZE(pfuze100_regulators); + sw_check_start = PFUZE100_SW2; + sw_check_end = PFUZE100_SW4; + break; + } + dev_info(&client->dev, "pfuze%s found.\n", + (pfuze_chip->chip_id == PFUZE100) ? "100" : "200"); + + memcpy(pfuze_chip->regulator_descs, pfuze_regulators, + sizeof(pfuze_chip->regulator_descs)); + ret = pfuze_parse_regulators_dt(pfuze_chip); if (ret) return ret; - for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) { + for (i = 0; i < regulator_num; i++) { struct regulator_init_data *init_data; struct regulator_desc *desc; int val; @@ -397,7 +489,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client, init_data = match_init_data(i); /* SW2~SW4 high bit check and modify the voltage value table */ - if (i > PFUZE100_SW1C && i < PFUZE100_SWBST) { + if (i >= sw_check_start && i <= sw_check_end) { regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val); if (val & 0x40) { desc->min_uV = 800000; @@ -415,7 +507,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client, devm_regulator_register(&client->dev, desc, &config); if (IS_ERR(pfuze_chip->regulators[i])) { dev_err(&client->dev, "register regulator%s failed\n", - pfuze100_regulators[i].desc.name); + pfuze_regulators[i].desc.name); return PTR_ERR(pfuze_chip->regulators[i]); } } @@ -435,6 +527,6 @@ static struct i2c_driver pfuze_driver = { module_i2c_driver(pfuze_driver); MODULE_AUTHOR("Robin Gong <b38343@freescale.com>"); -MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100 PMIC"); +MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("i2c:pfuze100-regulator"); diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index b58affb33143..4c414ae109ae 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -119,7 +119,6 @@ static int rc5t583_regulator_probe(struct platform_device *pdev) { struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); - struct regulator_init_data *reg_data; struct regulator_config config = { }; struct rc5t583_regulator *reg = NULL; struct rc5t583_regulator *regs; @@ -135,19 +134,11 @@ static int rc5t583_regulator_probe(struct platform_device *pdev) regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX * sizeof(struct rc5t583_regulator), GFP_KERNEL); - if (!regs) { - dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); + if (!regs) return -ENOMEM; - } for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) { - reg_data = pdata->reg_init_data[id]; - - /* No need to register if there is no regulator data */ - if (!reg_data) - continue; - reg = ®s[id]; ri = &rc5t583_reg_info[id]; reg->reg_info = ri; @@ -169,7 +160,7 @@ static int rc5t583_regulator_probe(struct platform_device *pdev) skip_ext_pwr_config: config.dev = &pdev->dev; - config.init_data = reg_data; + config.init_data = pdata->reg_init_data[id]; config.driver_data = reg; config.regmap = rc5t583->regmap; diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c new file mode 100644 index 000000000000..808b3aa7a42c --- /dev/null +++ b/drivers/regulator/s2mpa01.c @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd + * http://www.samsung.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/bug.h> +#include <linux/err.h> +#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/s2mpa01.h> + +#define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators) + +struct s2mpa01_info { + int ramp_delay24; + int ramp_delay3; + int ramp_delay5; + int ramp_delay16; + int ramp_delay7; + int ramp_delay8910; +}; + +static int get_ramp_delay(int ramp_delay) +{ + unsigned char cnt = 0; + + ramp_delay /= 6250; + + while (true) { + ramp_delay = ramp_delay >> 1; + if (ramp_delay == 0) + break; + cnt++; + } + + if (cnt > 3) + cnt = 3; + + return cnt; +} + +static int s2mpa01_regulator_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev); + unsigned int ramp_delay = 0; + int old_volt, new_volt; + + switch (rdev->desc->id) { + case S2MPA01_BUCK2: + case S2MPA01_BUCK4: + ramp_delay = s2mpa01->ramp_delay24; + break; + case S2MPA01_BUCK3: + ramp_delay = s2mpa01->ramp_delay3; + break; + case S2MPA01_BUCK5: + ramp_delay = s2mpa01->ramp_delay5; + break; + case S2MPA01_BUCK1: + case S2MPA01_BUCK6: + ramp_delay = s2mpa01->ramp_delay16; + break; + case S2MPA01_BUCK7: + ramp_delay = s2mpa01->ramp_delay7; + break; + case S2MPA01_BUCK8: + case S2MPA01_BUCK9: + case S2MPA01_BUCK10: + ramp_delay = s2mpa01->ramp_delay8910; + break; + } + + 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 s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev); + unsigned int ramp_val, ramp_shift, ramp_reg = S2MPA01_REG_RAMP2; + unsigned int ramp_enable = 1, enable_shift = 0; + int ret; + + switch (rdev->desc->id) { + case S2MPA01_BUCK1: + enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mpa01->ramp_delay16) + s2mpa01->ramp_delay16 = ramp_delay; + else + ramp_delay = s2mpa01->ramp_delay16; + + ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT; + ramp_reg = S2MPA01_REG_RAMP1; + break; + case S2MPA01_BUCK2: + enable_shift = S2MPA01_BUCK2_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mpa01->ramp_delay24) + s2mpa01->ramp_delay24 = ramp_delay; + else + ramp_delay = s2mpa01->ramp_delay24; + + ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT; + ramp_reg = S2MPA01_REG_RAMP1; + break; + case S2MPA01_BUCK3: + enable_shift = S2MPA01_BUCK3_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + s2mpa01->ramp_delay3 = ramp_delay; + ramp_shift = S2MPA01_BUCK3_RAMP_SHIFT; + ramp_reg = S2MPA01_REG_RAMP1; + break; + case S2MPA01_BUCK4: + enable_shift = S2MPA01_BUCK4_RAMP_EN_SHIFT; + if (!ramp_delay) { + ramp_enable = 0; + break; + } + + if (ramp_delay > s2mpa01->ramp_delay24) + s2mpa01->ramp_delay24 = ramp_delay; + else + ramp_delay = s2mpa01->ramp_delay24; + + ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT; + ramp_reg = S2MPA01_REG_RAMP1; + break; + case S2MPA01_BUCK5: + s2mpa01->ramp_delay5 = ramp_delay; + ramp_shift = S2MPA01_BUCK5_RAMP_SHIFT; + break; + case S2MPA01_BUCK6: + if (ramp_delay > s2mpa01->ramp_delay16) + s2mpa01->ramp_delay16 = ramp_delay; + else + ramp_delay = s2mpa01->ramp_delay16; + + ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT; + break; + case S2MPA01_BUCK7: + s2mpa01->ramp_delay7 = ramp_delay; + ramp_shift = S2MPA01_BUCK7_RAMP_SHIFT; + break; + case S2MPA01_BUCK8: + case S2MPA01_BUCK9: + case S2MPA01_BUCK10: + if (ramp_delay > s2mpa01->ramp_delay8910) + s2mpa01->ramp_delay8910 = ramp_delay; + else + ramp_delay = s2mpa01->ramp_delay8910; + + ramp_shift = S2MPA01_BUCK8910_RAMP_SHIFT; + break; + default: + return 0; + } + + if (!ramp_enable) + goto ramp_disable; + + if (enable_shift) { + ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1, + 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, S2MPA01_REG_RAMP1, + 1 << enable_shift, 0); +} + +static struct regulator_ops s2mpa01_ldo_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .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, +}; + +static struct regulator_ops s2mpa01_buck_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = s2mpa01_regulator_set_voltage_time_sel, + .set_ramp_delay = s2mpa01_set_ramp_delay, +}; + +#define regulator_desc_ldo1(num) { \ + .name = "LDO"#num, \ + .id = S2MPA01_LDO##num, \ + .ops = &s2mpa01_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_LDO_MIN, \ + .uV_step = S2MPA01_LDO_STEP1, \ + .n_voltages = S2MPA01_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPA01_LDO_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} +#define regulator_desc_ldo2(num) { \ + .name = "LDO"#num, \ + .id = S2MPA01_LDO##num, \ + .ops = &s2mpa01_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_LDO_MIN, \ + .uV_step = S2MPA01_LDO_STEP2, \ + .n_voltages = S2MPA01_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPA01_LDO_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck1_4(num) { \ + .name = "BUCK"#num, \ + .id = S2MPA01_BUCK##num, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN1, \ + .uV_step = S2MPA01_BUCK_STEP1, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B1CTRL2 + (num - 1) * 2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B1CTRL1 + (num - 1) * 2, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck5 { \ + .name = "BUCK5", \ + .id = S2MPA01_BUCK5, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN2, \ + .uV_step = S2MPA01_BUCK_STEP1, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B5CTRL2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B5CTRL1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck6_7(num) { \ + .name = "BUCK"#num, \ + .id = S2MPA01_BUCK##num, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN1, \ + .uV_step = S2MPA01_BUCK_STEP1, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B6CTRL2 + (num - 6) * 2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B6CTRL1 + (num - 6) * 2, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck8 { \ + .name = "BUCK8", \ + .id = S2MPA01_BUCK8, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN2, \ + .uV_step = S2MPA01_BUCK_STEP2, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B8CTRL2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B8CTRL1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck9 { \ + .name = "BUCK9", \ + .id = S2MPA01_BUCK9, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN4, \ + .uV_step = S2MPA01_BUCK_STEP2, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B9CTRL2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B9CTRL1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +#define regulator_desc_buck10 { \ + .name = "BUCK10", \ + .id = S2MPA01_BUCK10, \ + .ops = &s2mpa01_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPA01_BUCK_MIN3, \ + .uV_step = S2MPA01_BUCK_STEP2, \ + .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \ + .ramp_delay = S2MPA01_RAMP_DELAY, \ + .vsel_reg = S2MPA01_REG_B10CTRL2, \ + .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \ + .enable_reg = S2MPA01_REG_B10CTRL1, \ + .enable_mask = S2MPA01_ENABLE_MASK \ +} + +static struct regulator_desc regulators[] = { + regulator_desc_ldo2(1), + regulator_desc_ldo1(2), + regulator_desc_ldo1(3), + regulator_desc_ldo1(4), + regulator_desc_ldo1(5), + regulator_desc_ldo2(6), + regulator_desc_ldo1(7), + regulator_desc_ldo1(8), + regulator_desc_ldo1(9), + regulator_desc_ldo1(10), + regulator_desc_ldo2(11), + regulator_desc_ldo1(12), + regulator_desc_ldo1(13), + regulator_desc_ldo1(14), + regulator_desc_ldo1(15), + regulator_desc_ldo1(16), + regulator_desc_ldo1(17), + regulator_desc_ldo1(18), + regulator_desc_ldo1(19), + regulator_desc_ldo1(20), + regulator_desc_ldo1(21), + regulator_desc_ldo2(22), + regulator_desc_ldo2(23), + regulator_desc_ldo1(24), + regulator_desc_ldo1(25), + regulator_desc_ldo1(26), + regulator_desc_buck1_4(1), + regulator_desc_buck1_4(2), + regulator_desc_buck1_4(3), + regulator_desc_buck1_4(4), + regulator_desc_buck5, + regulator_desc_buck6_7(6), + regulator_desc_buck6_7(7), + regulator_desc_buck8, + regulator_desc_buck9, + regulator_desc_buck10, +}; + +static int s2mpa01_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[S2MPA01_REGULATOR_MAX]; + struct device_node *reg_np = NULL; + struct regulator_config config = { }; + struct s2mpa01_info *s2mpa01; + int i; + + s2mpa01 = devm_kzalloc(&pdev->dev, sizeof(*s2mpa01), GFP_KERNEL); + if (!s2mpa01) + return -ENOMEM; + + for (i = 0; i < S2MPA01_REGULATOR_CNT; i++) + rdata[i].name = regulators[i].name; + + if (iodev->dev->of_node) { + reg_np = of_get_child_by_name(iodev->dev->of_node, + "regulators"); + if (!reg_np) { + dev_err(&pdev->dev, + "could not find regulators sub-node\n"); + return -EINVAL; + } + + of_regulator_match(&pdev->dev, reg_np, rdata, + S2MPA01_REGULATOR_MAX); + of_node_put(reg_np); + } + + platform_set_drvdata(pdev, s2mpa01); + + config.dev = &pdev->dev; + config.regmap = iodev->regmap_pmic; + config.driver_data = s2mpa01; + + for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) { + struct regulator_dev *rdev; + if (pdata) + config.init_data = pdata->regulators[i].initdata; + else + config.init_data = rdata[i].init_data; + + if (reg_np) + config.of_node = rdata[i].of_node; + + rdev = devm_regulator_register(&pdev->dev, + ®ulators[i], &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "regulator init failed for %d\n", + i); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id s2mpa01_pmic_id[] = { + { "s2mpa01-pmic", 0}, + { }, +}; +MODULE_DEVICE_TABLE(platform, s2mpa01_pmic_id); + +static struct platform_driver s2mpa01_pmic_driver = { + .driver = { + .name = "s2mpa01-pmic", + .owner = THIS_MODULE, + }, + .probe = s2mpa01_pmic_probe, + .id_table = s2mpa01_pmic_id, +}; + +module_platform_driver(s2mpa01_pmic_driver); + +/* Module information */ +MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); +MODULE_AUTHOR("Sachin Kamat <sachin.kamat@samsung.com>"); +MODULE_DESCRIPTION("SAMSUNG S2MPA01 Regulator Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index cd0b9e35a56d..68fd54702edb 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -1,13 +1,18 @@ /* * s2mps11.c * - * Copyright (c) 2012 Samsung Electronics Co., Ltd + * Copyright (c) 2012-2014 Samsung Electronics Co., Ltd * http://www.samsung.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. + * 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. * */ @@ -24,18 +29,21 @@ #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) +#include <linux/mfd/samsung/s2mps14.h> struct s2mps11_info { - struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX]; - + unsigned int rdev_num; int ramp_delay2; int ramp_delay34; int ramp_delay5; int ramp_delay16; int ramp_delay7810; int ramp_delay9; + /* + * One bit for each S2MPS14 regulator whether the suspend mode + * was enabled. + */ + unsigned int s2mps14_suspend_state:30; }; static int get_ramp_delay(int ramp_delay) @@ -65,7 +73,7 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int ramp_delay = 0; int old_volt, new_volt; - switch (rdev->desc->id) { + switch (rdev_get_id(rdev)) { case S2MPS11_BUCK2: ramp_delay = s2mps11->ramp_delay2; break; @@ -105,7 +113,7 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) unsigned int ramp_enable = 1, enable_shift = 0; int ret; - switch (rdev->desc->id) { + switch (rdev_get_id(rdev)) { case S2MPS11_BUCK1: if (ramp_delay > s2mps11->ramp_delay16) s2mps11->ramp_delay16 = ramp_delay; @@ -236,7 +244,7 @@ static struct regulator_ops s2mps11_buck_ops = { .set_ramp_delay = s2mps11_set_ramp_delay, }; -#define regulator_desc_ldo1(num) { \ +#define regulator_desc_s2mps11_ldo1(num) { \ .name = "LDO"#num, \ .id = S2MPS11_LDO##num, \ .ops = &s2mps11_ldo_ops, \ @@ -250,7 +258,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \ .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_ldo2(num) { \ +#define regulator_desc_s2mps11_ldo2(num) { \ .name = "LDO"#num, \ .id = S2MPS11_LDO##num, \ .ops = &s2mps11_ldo_ops, \ @@ -265,7 +273,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_buck1_4(num) { \ +#define regulator_desc_s2mps11_buck1_4(num) { \ .name = "BUCK"#num, \ .id = S2MPS11_BUCK##num, \ .ops = &s2mps11_buck_ops, \ @@ -281,7 +289,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_buck5 { \ +#define regulator_desc_s2mps11_buck5 { \ .name = "BUCK5", \ .id = S2MPS11_BUCK5, \ .ops = &s2mps11_buck_ops, \ @@ -297,7 +305,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_buck6_8(num) { \ +#define regulator_desc_s2mps11_buck6_8(num) { \ .name = "BUCK"#num, \ .id = S2MPS11_BUCK##num, \ .ops = &s2mps11_buck_ops, \ @@ -313,7 +321,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_buck9 { \ +#define regulator_desc_s2mps11_buck9 { \ .name = "BUCK9", \ .id = S2MPS11_BUCK9, \ .ops = &s2mps11_buck_ops, \ @@ -329,7 +337,7 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_buck10 { \ +#define regulator_desc_s2mps11_buck10 { \ .name = "BUCK10", \ .id = S2MPS11_BUCK10, \ .ops = &s2mps11_buck_ops, \ @@ -345,72 +353,252 @@ static struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -static struct regulator_desc regulators[] = { - regulator_desc_ldo2(1), - regulator_desc_ldo1(2), - regulator_desc_ldo1(3), - regulator_desc_ldo1(4), - regulator_desc_ldo1(5), - regulator_desc_ldo2(6), - regulator_desc_ldo1(7), - regulator_desc_ldo1(8), - regulator_desc_ldo1(9), - regulator_desc_ldo1(10), - regulator_desc_ldo2(11), - regulator_desc_ldo1(12), - regulator_desc_ldo1(13), - regulator_desc_ldo1(14), - regulator_desc_ldo1(15), - regulator_desc_ldo1(16), - regulator_desc_ldo1(17), - regulator_desc_ldo1(18), - regulator_desc_ldo1(19), - regulator_desc_ldo1(20), - regulator_desc_ldo1(21), - regulator_desc_ldo2(22), - regulator_desc_ldo2(23), - regulator_desc_ldo1(24), - regulator_desc_ldo1(25), - regulator_desc_ldo1(26), - regulator_desc_ldo2(27), - regulator_desc_ldo1(28), - regulator_desc_ldo1(29), - regulator_desc_ldo1(30), - regulator_desc_ldo1(31), - regulator_desc_ldo1(32), - regulator_desc_ldo1(33), - regulator_desc_ldo1(34), - regulator_desc_ldo1(35), - regulator_desc_ldo1(36), - regulator_desc_ldo1(37), - regulator_desc_ldo1(38), - regulator_desc_buck1_4(1), - regulator_desc_buck1_4(2), - regulator_desc_buck1_4(3), - regulator_desc_buck1_4(4), - regulator_desc_buck5, - regulator_desc_buck6_8(6), - regulator_desc_buck6_8(7), - regulator_desc_buck6_8(8), - regulator_desc_buck9, - regulator_desc_buck10, +static const struct regulator_desc s2mps11_regulators[] = { + regulator_desc_s2mps11_ldo2(1), + regulator_desc_s2mps11_ldo1(2), + regulator_desc_s2mps11_ldo1(3), + regulator_desc_s2mps11_ldo1(4), + regulator_desc_s2mps11_ldo1(5), + regulator_desc_s2mps11_ldo2(6), + regulator_desc_s2mps11_ldo1(7), + regulator_desc_s2mps11_ldo1(8), + regulator_desc_s2mps11_ldo1(9), + regulator_desc_s2mps11_ldo1(10), + regulator_desc_s2mps11_ldo2(11), + regulator_desc_s2mps11_ldo1(12), + regulator_desc_s2mps11_ldo1(13), + regulator_desc_s2mps11_ldo1(14), + regulator_desc_s2mps11_ldo1(15), + regulator_desc_s2mps11_ldo1(16), + regulator_desc_s2mps11_ldo1(17), + regulator_desc_s2mps11_ldo1(18), + regulator_desc_s2mps11_ldo1(19), + regulator_desc_s2mps11_ldo1(20), + regulator_desc_s2mps11_ldo1(21), + regulator_desc_s2mps11_ldo2(22), + regulator_desc_s2mps11_ldo2(23), + regulator_desc_s2mps11_ldo1(24), + regulator_desc_s2mps11_ldo1(25), + regulator_desc_s2mps11_ldo1(26), + regulator_desc_s2mps11_ldo2(27), + regulator_desc_s2mps11_ldo1(28), + regulator_desc_s2mps11_ldo1(29), + regulator_desc_s2mps11_ldo1(30), + regulator_desc_s2mps11_ldo1(31), + regulator_desc_s2mps11_ldo1(32), + regulator_desc_s2mps11_ldo1(33), + regulator_desc_s2mps11_ldo1(34), + regulator_desc_s2mps11_ldo1(35), + regulator_desc_s2mps11_ldo1(36), + regulator_desc_s2mps11_ldo1(37), + regulator_desc_s2mps11_ldo1(38), + regulator_desc_s2mps11_buck1_4(1), + regulator_desc_s2mps11_buck1_4(2), + regulator_desc_s2mps11_buck1_4(3), + regulator_desc_s2mps11_buck1_4(4), + regulator_desc_s2mps11_buck5, + regulator_desc_s2mps11_buck6_8(6), + regulator_desc_s2mps11_buck6_8(7), + regulator_desc_s2mps11_buck6_8(8), + regulator_desc_s2mps11_buck9, + regulator_desc_s2mps11_buck10, +}; + +static int s2mps14_regulator_enable(struct regulator_dev *rdev) +{ + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + unsigned int val; + + if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev))) + val = S2MPS14_ENABLE_SUSPEND; + else + val = rdev->desc->enable_mask; + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val); +} + +static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev) +{ + int ret; + unsigned int val; + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + + /* LDO3 should be always on and does not support suspend mode */ + if (rdev_get_id(rdev) == S2MPS14_LDO3) + return 0; + + ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); + if (ret < 0) + return ret; + + s2mps11->s2mps14_suspend_state |= (1 << rdev_get_id(rdev)); + /* + * Don't enable suspend mode if regulator is already disabled because + * this would effectively for a short time turn on the regulator after + * resuming. + * However we still want to toggle the suspend_state bit for regulator + * in case if it got enabled before suspending the system. + */ + if (!(val & rdev->desc->enable_mask)) + return 0; + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, S2MPS14_ENABLE_SUSPEND); +} + +static struct regulator_ops s2mps14_reg_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = s2mps14_regulator_enable, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_disable = s2mps14_regulator_set_suspend_disable, +}; + +#define regulator_desc_s2mps14_ldo1(num) { \ + .name = "LDO"#num, \ + .id = S2MPS14_LDO##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS14_LDO_MIN_800MV, \ + .uV_step = S2MPS14_LDO_STEP_25MV, \ + .n_voltages = S2MPS14_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPS14_LDO_VSEL_MASK, \ + .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} +#define regulator_desc_s2mps14_ldo2(num) { \ + .name = "LDO"#num, \ + .id = S2MPS14_LDO##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS14_LDO_MIN_1800MV, \ + .uV_step = S2MPS14_LDO_STEP_25MV, \ + .n_voltages = S2MPS14_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPS14_LDO_VSEL_MASK, \ + .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} +#define regulator_desc_s2mps14_ldo3(num) { \ + .name = "LDO"#num, \ + .id = S2MPS14_LDO##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS14_LDO_MIN_800MV, \ + .uV_step = S2MPS14_LDO_STEP_12_5MV, \ + .n_voltages = S2MPS14_LDO_N_VOLTAGES, \ + .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .vsel_mask = S2MPS14_LDO_VSEL_MASK, \ + .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} +#define regulator_desc_s2mps14_buck1235(num) { \ + .name = "BUCK"#num, \ + .id = S2MPS14_BUCK##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS14_BUCK1235_MIN_600MV, \ + .uV_step = S2MPS14_BUCK1235_STEP_6_25MV, \ + .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \ + .linear_min_sel = S2MPS14_BUCK1235_START_SEL, \ + .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \ + .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \ + .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} +#define regulator_desc_s2mps14_buck4(num) { \ + .name = "BUCK"#num, \ + .id = S2MPS14_BUCK##num, \ + .ops = &s2mps14_reg_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = S2MPS14_BUCK4_MIN_1400MV, \ + .uV_step = S2MPS14_BUCK4_STEP_12_5MV, \ + .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \ + .linear_min_sel = S2MPS14_BUCK4_START_SEL, \ + .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \ + .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \ + .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \ + .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \ + .enable_mask = S2MPS14_ENABLE_MASK \ +} + +static const struct regulator_desc s2mps14_regulators[] = { + regulator_desc_s2mps14_ldo3(1), + regulator_desc_s2mps14_ldo3(2), + regulator_desc_s2mps14_ldo1(3), + regulator_desc_s2mps14_ldo1(4), + regulator_desc_s2mps14_ldo3(5), + regulator_desc_s2mps14_ldo3(6), + regulator_desc_s2mps14_ldo1(7), + regulator_desc_s2mps14_ldo2(8), + regulator_desc_s2mps14_ldo3(9), + regulator_desc_s2mps14_ldo3(10), + regulator_desc_s2mps14_ldo1(11), + regulator_desc_s2mps14_ldo2(12), + regulator_desc_s2mps14_ldo2(13), + regulator_desc_s2mps14_ldo2(14), + regulator_desc_s2mps14_ldo2(15), + regulator_desc_s2mps14_ldo2(16), + regulator_desc_s2mps14_ldo2(17), + regulator_desc_s2mps14_ldo2(18), + regulator_desc_s2mps14_ldo1(19), + regulator_desc_s2mps14_ldo1(20), + regulator_desc_s2mps14_ldo1(21), + regulator_desc_s2mps14_ldo3(22), + regulator_desc_s2mps14_ldo1(23), + regulator_desc_s2mps14_ldo2(24), + regulator_desc_s2mps14_ldo2(25), + regulator_desc_s2mps14_buck1235(1), + regulator_desc_s2mps14_buck1235(2), + regulator_desc_s2mps14_buck1235(3), + regulator_desc_s2mps14_buck4(4), + regulator_desc_s2mps14_buck1235(5), }; 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 sec_platform_data *pdata = iodev->pdata; + struct of_regulator_match *rdata = NULL; struct device_node *reg_np = NULL; struct regulator_config config = { }; struct s2mps11_info *s2mps11; - int i, ret; + int i, ret = 0; + const struct regulator_desc *regulators; + enum sec_device_type dev_type; s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info), GFP_KERNEL); if (!s2mps11) return -ENOMEM; + dev_type = platform_get_device_id(pdev)->driver_data; + switch (dev_type) { + case S2MPS11X: + s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators); + regulators = s2mps11_regulators; + break; + case S2MPS14X: + s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators); + regulators = s2mps14_regulators; + break; + default: + dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type); + return -EINVAL; + }; + if (!iodev->dev->of_node) { if (pdata) { goto common_reg; @@ -421,16 +609,22 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) } } - for (i = 0; i < S2MPS11_REGULATOR_CNT; i++) + rdata = kzalloc(sizeof(*rdata) * s2mps11->rdev_num, GFP_KERNEL); + if (!rdata) + return -ENOMEM; + + for (i = 0; i < s2mps11->rdev_num; i++) rdata[i].name = regulators[i].name; - reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators"); + reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators"); if (!reg_np) { dev_err(&pdev->dev, "could not find regulators sub-node\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } - of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX); + of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); + of_node_put(reg_np); common_reg: platform_set_drvdata(pdev, s2mps11); @@ -438,7 +632,9 @@ common_reg: config.dev = &pdev->dev; config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; - for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { + for (i = 0; i < s2mps11->rdev_num; i++) { + struct regulator_dev *regulator; + if (!reg_np) { config.init_data = pdata->regulators[i].initdata; config.of_node = pdata->regulators[i].reg_node; @@ -447,21 +643,25 @@ common_reg: config.of_node = rdata[i].of_node; } - s2mps11->rdev[i] = devm_regulator_register(&pdev->dev, + regulator = devm_regulator_register(&pdev->dev, ®ulators[i], &config); - if (IS_ERR(s2mps11->rdev[i])) { - ret = PTR_ERR(s2mps11->rdev[i]); + if (IS_ERR(regulator)) { + ret = PTR_ERR(regulator); dev_err(&pdev->dev, "regulator init failed for %d\n", i); - return ret; + goto out; } } - return 0; +out: + kfree(rdata); + + return ret; } static const struct platform_device_id s2mps11_pmic_id[] = { - { "s2mps11-pmic", 0}, + { "s2mps11-pmic", S2MPS11X}, + { "s2mps14-pmic", S2MPS14X}, { }, }; MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id); @@ -489,5 +689,5 @@ module_exit(s2mps11_pmic_exit); /* Module information */ MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); -MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver"); +MODULE_DESCRIPTION("SAMSUNG S2MPS11/S2MPS14 Regulator Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index d958dfa05125..f05badabd69e 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -11,11 +11,8 @@ * */ -#include <linux/bug.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/of_gpio.h> -#include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> @@ -170,12 +167,11 @@ static unsigned int s5m8767_opmode_reg[][4] = { {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */ }; -static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, - int *enable_ctrl) +static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id, + int *reg, int *enable_ctrl) { - int i, reg_id = rdev_get_id(rdev); + int i; unsigned int mode; - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); switch (reg_id) { case S5M8767_LDO1 ... S5M8767_LDO2: @@ -214,53 +210,6 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, return 0; } -static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) -{ - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - int ret, reg; - int enable_ctrl; - unsigned int val; - - ret = s5m8767_get_register(rdev, ®, &enable_ctrl); - if (ret == -EINVAL) - return 1; - else if (ret) - return ret; - - ret = regmap_read(s5m8767->iodev->regmap_pmic, reg, &val); - if (ret) - return ret; - - return (val & S5M8767_ENCTRL_MASK) == enable_ctrl; -} - -static int s5m8767_reg_enable(struct regulator_dev *rdev) -{ - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - int ret, reg; - int enable_ctrl; - - ret = s5m8767_get_register(rdev, ®, &enable_ctrl); - if (ret) - return ret; - - return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg, - S5M8767_ENCTRL_MASK, enable_ctrl); -} - -static int s5m8767_reg_disable(struct regulator_dev *rdev) -{ - struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - int ret, reg, enable_ctrl; - - ret = s5m8767_get_register(rdev, ®, &enable_ctrl); - if (ret) - return ret; - - return regmap_update_bits(s5m8767->iodev->regmap_pmic, reg, - S5M8767_ENCTRL_MASK, ~S5M8767_ENCTRL_MASK); -} - static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767) { int reg; @@ -410,9 +359,9 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, static struct regulator_ops s5m8767_ops = { .list_voltage = regulator_list_voltage_linear, - .is_enabled = s5m8767_reg_is_enabled, - .enable = s5m8767_reg_enable, - .disable = s5m8767_reg_disable, + .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 = s5m8767_set_voltage_sel, .set_voltage_time_sel = s5m8767_set_voltage_time_sel, @@ -420,9 +369,9 @@ static struct regulator_ops s5m8767_ops = { static struct regulator_ops s5m8767_buck78_ops = { .list_voltage = regulator_list_voltage_linear, - .is_enabled = s5m8767_reg_is_enabled, - .enable = s5m8767_reg_enable, - .disable = s5m8767_reg_disable, + .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, }; @@ -483,6 +432,66 @@ static struct regulator_desc regulators[] = { s5m8767_regulator_desc(BUCK9), }; +/* + * Enable GPIO control over BUCK9 in regulator_config for that regulator. + */ +static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767, + struct sec_regulator_data *rdata, + struct regulator_config *config) +{ + int i, mode = 0; + + if (rdata->id != S5M8767_BUCK9) + return; + + /* Check if opmode for regulator matches S5M8767_ENCTRL_USE_GPIO */ + for (i = 0; i < s5m8767->num_regulators; i++) { + const struct sec_opmode_data *opmode = &s5m8767->opmode[i]; + if (opmode->id == rdata->id) { + mode = s5m8767_opmode_reg[rdata->id][opmode->mode]; + break; + } + } + if (mode != S5M8767_ENCTRL_USE_GPIO) { + dev_warn(s5m8767->dev, + "ext-control for %s: mismatched op_mode (%x), ignoring\n", + rdata->reg_node->name, mode); + return; + } + + if (!gpio_is_valid(rdata->ext_control_gpio)) { + dev_warn(s5m8767->dev, + "ext-control for %s: GPIO not valid, ignoring\n", + rdata->reg_node->name); + return; + } + + config->ena_gpio = rdata->ext_control_gpio; + config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; +} + +/* + * Turn on GPIO control over BUCK9. + */ +static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767, + struct regulator_dev *rdev) +{ + int id = rdev_get_id(rdev); + int ret, reg, enable_ctrl; + + if (id != S5M8767_BUCK9) + return -EINVAL; + + ret = s5m8767_get_register(s5m8767, id, ®, &enable_ctrl); + if (ret) + return ret; + + return regmap_update_bits(s5m8767->iodev->regmap_pmic, + reg, S5M8767_ENCTRL_MASK, + S5M8767_ENCTRL_USE_GPIO << S5M8767_ENCTRL_SHIFT); +} + + #ifdef CONFIG_OF static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, struct sec_platform_data *pdata, @@ -520,6 +529,16 @@ static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev, return 0; } +static void s5m8767_pmic_dt_parse_ext_control_gpio(struct sec_pmic_dev *iodev, + struct sec_regulator_data *rdata, + struct device_node *reg_np) +{ + rdata->ext_control_gpio = of_get_named_gpio(reg_np, + "s5m8767,pmic-ext-control-gpios", 0); + if (!gpio_is_valid(rdata->ext_control_gpio)) + rdata->ext_control_gpio = 0; +} + static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, struct sec_platform_data *pdata) { @@ -546,19 +565,13 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) * pdata->num_regulators, GFP_KERNEL); - if (!rdata) { - dev_err(iodev->dev, - "could not allocate memory for regulator data\n"); + if (!rdata) return -ENOMEM; - } rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) * pdata->num_regulators, GFP_KERNEL); - if (!rmode) { - dev_err(iodev->dev, - "could not allocate memory for regulator mode\n"); + if (!rmode) return -ENOMEM; - } pdata->regulators = rdata; pdata->opmode = rmode; @@ -574,6 +587,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, continue; } + s5m8767_pmic_dt_parse_ext_control_gpio(iodev, rdata, reg_np); + rdata->id = i; rdata->initdata = of_get_regulator_init_data( &pdev->dev, reg_np); @@ -922,6 +937,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) for (i = 0; i < pdata->num_regulators; i++) { const struct sec_voltage_desc *desc; int id = pdata->regulators[i].id; + int enable_reg, enable_val; desc = reg_voltage_map[id]; if (desc) { @@ -935,6 +951,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) regulators[id].vsel_mask = 0x3f; else regulators[id].vsel_mask = 0xff; + + s5m8767_get_register(s5m8767, id, &enable_reg, + &enable_val); + regulators[id].enable_reg = enable_reg; + regulators[id].enable_mask = S5M8767_ENCTRL_MASK; + regulators[id].enable_val = enable_val; } config.dev = s5m8767->dev; @@ -942,6 +964,9 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) config.driver_data = s5m8767; config.regmap = iodev->regmap_pmic; config.of_node = pdata->regulators[i].reg_node; + if (pdata->regulators[i].ext_control_gpio) + s5m8767_regulator_config_ext_control(s5m8767, + &pdata->regulators[i], &config); rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], &config); @@ -951,6 +976,16 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) id); return ret; } + + if (pdata->regulators[i].ext_control_gpio) { + ret = s5m8767_enable_ext_control(s5m8767, rdev[i]); + if (ret < 0) { + dev_err(s5m8767->dev, + "failed to enable gpio control over %s: %d\n", + rdev[i]->desc->name, ret); + return ret; + } + } } return 0; diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c new file mode 100644 index 000000000000..e367af1c5f9d --- /dev/null +++ b/drivers/regulator/st-pwm.c @@ -0,0 +1,190 @@ +/* + * Regulator driver for ST's PWM Regulators + * + * Copyright (C) 2014 - STMicroelectronics Inc. + * + * Author: Lee Jones <lee.jones@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pwm.h> + +#define ST_PWM_REG_PERIOD 8448 + +struct st_pwm_regulator_pdata { + const struct regulator_desc *desc; + struct st_pwm_voltages *duty_cycle_table; +}; + +struct st_pwm_regulator_data { + const struct st_pwm_regulator_pdata *pdata; + struct pwm_device *pwm; + bool enabled; + int state; +}; + +struct st_pwm_voltages { + unsigned int uV; + unsigned int dutycycle; +}; + +static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev) +{ + struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + + return drvdata->state; +} + +static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) +{ + struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + int dutycycle; + int ret; + + dutycycle = (ST_PWM_REG_PERIOD / 100) * + drvdata->pdata->duty_cycle_table[selector].dutycycle; + + ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD); + if (ret) { + dev_err(&dev->dev, "Failed to configure PWM\n"); + return ret; + } + + drvdata->state = selector; + + if (!drvdata->enabled) { + ret = pwm_enable(drvdata->pwm); + if (ret) { + dev_err(&dev->dev, "Failed to enable PWM\n"); + return ret; + } + drvdata->enabled = true; + } + + return 0; +} + +static int st_pwm_regulator_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + + if (selector >= dev->desc->n_voltages) + return -EINVAL; + + return drvdata->pdata->duty_cycle_table[selector].uV; +} + +static struct regulator_ops st_pwm_regulator_voltage_ops = { + .set_voltage_sel = st_pwm_regulator_set_voltage_sel, + .get_voltage_sel = st_pwm_regulator_get_voltage_sel, + .list_voltage = st_pwm_regulator_list_voltage, + .map_voltage = regulator_map_voltage_iterate, +}; + +static struct st_pwm_voltages b2105_duty_cycle_table[] = { + { .uV = 1114000, .dutycycle = 0, }, + { .uV = 1095000, .dutycycle = 10, }, + { .uV = 1076000, .dutycycle = 20, }, + { .uV = 1056000, .dutycycle = 30, }, + { .uV = 1036000, .dutycycle = 40, }, + { .uV = 1016000, .dutycycle = 50, }, + /* WARNING: Values above 50% duty-cycle cause boot failures. */ +}; + +static const struct regulator_desc b2105_desc = { + .name = "b2105-pwm-regulator", + .ops = &st_pwm_regulator_voltage_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(b2105_duty_cycle_table), + .supply_name = "pwm", +}; + +static const struct st_pwm_regulator_pdata b2105_info = { + .desc = &b2105_desc, + .duty_cycle_table = b2105_duty_cycle_table, +}; + +static struct of_device_id st_pwm_of_match[] = { + { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, }, + { }, +}; +MODULE_DEVICE_TABLE(of, st_pwm_of_match); + +static int st_pwm_regulator_probe(struct platform_device *pdev) +{ + struct st_pwm_regulator_data *drvdata; + struct regulator_dev *regulator; + struct regulator_config config = { }; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_match; + + if (!np) { + dev_err(&pdev->dev, "Device Tree node missing\n"); + return -EINVAL; + } + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + of_match = of_match_device(st_pwm_of_match, &pdev->dev); + if (!of_match) { + dev_err(&pdev->dev, "failed to match of device\n"); + return -ENODEV; + } + drvdata->pdata = of_match->data; + + config.init_data = of_get_regulator_init_data(&pdev->dev, np); + if (!config.init_data) + return -ENOMEM; + + config.of_node = np; + config.dev = &pdev->dev; + config.driver_data = drvdata; + + drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); + if (IS_ERR(drvdata->pwm)) { + dev_err(&pdev->dev, "Failed to get PWM\n"); + return PTR_ERR(drvdata->pwm); + } + + regulator = devm_regulator_register(&pdev->dev, + drvdata->pdata->desc, &config); + if (IS_ERR(regulator)) { + dev_err(&pdev->dev, "Failed to register regulator %s\n", + drvdata->pdata->desc->name); + return PTR_ERR(regulator); + } + + return 0; +} + +static struct platform_driver st_pwm_regulator_driver = { + .driver = { + .name = "st-pwm-regulator", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(st_pwm_of_match), + }, + .probe = st_pwm_regulator_probe, +}; + +module_platform_driver(st_pwm_regulator_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); +MODULE_DESCRIPTION("ST PWM Regulator Driver"); +MODULE_ALIAS("platform:st_pwm-regulator"); diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index b187b6bba7ad..a2dabb575b97 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -54,8 +54,8 @@ struct ti_abb_info { /** * struct ti_abb_reg - Register description for ABB block - * @setup_reg: setup register offset from base - * @control_reg: control register offset from base + * @setup_off: setup register offset from base + * @control_off: control register offset from base * @sr2_wtcnt_value_mask: setup register- sr2_wtcnt_value mask * @fbb_sel_mask: setup register- FBB sel mask * @rbb_sel_mask: setup register- RBB sel mask @@ -64,8 +64,8 @@ struct ti_abb_info { * @opp_sel_mask: control register - mask for mode to operate */ struct ti_abb_reg { - u32 setup_reg; - u32 control_reg; + u32 setup_off; + u32 control_off; /* Setup register fields */ u32 sr2_wtcnt_value_mask; @@ -83,6 +83,8 @@ struct ti_abb_reg { * @rdesc: regulator descriptor * @clk: clock(usually sysclk) supplying ABB block * @base: base address of ABB block + * @setup_reg: setup register of ABB block + * @control_reg: control register of ABB block * @int_base: interrupt register base address * @efuse_base: (optional) efuse base address for ABB modes * @ldo_base: (optional) LDOVBB vset override base address @@ -99,6 +101,8 @@ struct ti_abb { struct regulator_desc rdesc; struct clk *clk; void __iomem *base; + void __iomem *setup_reg; + void __iomem *control_reg; void __iomem *int_base; void __iomem *efuse_base; void __iomem *ldo_base; @@ -118,20 +122,18 @@ struct ti_abb { * ti_abb_rmw() - handy wrapper to set specific register bits * @mask: mask for register field * @value: value shifted to mask location and written - * @offset: offset of register - * @base: base address + * @reg: register address * * Return: final register value (may be unused) */ -static inline u32 ti_abb_rmw(u32 mask, u32 value, u32 offset, - void __iomem *base) +static inline u32 ti_abb_rmw(u32 mask, u32 value, void __iomem *reg) { u32 val; - val = readl(base + offset); + val = readl(reg); val &= ~mask; val |= (value << __ffs(mask)) & mask; - writel(val, base + offset); + writel(val, reg); return val; } @@ -263,21 +265,19 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb, if (ret) goto out; - ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, regs->setup_reg, - abb->base); + ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, abb->setup_reg); switch (info->opp_sel) { case TI_ABB_SLOW_OPP: - ti_abb_rmw(regs->rbb_sel_mask, 1, regs->setup_reg, abb->base); + ti_abb_rmw(regs->rbb_sel_mask, 1, abb->setup_reg); break; case TI_ABB_FAST_OPP: - ti_abb_rmw(regs->fbb_sel_mask, 1, regs->setup_reg, abb->base); + ti_abb_rmw(regs->fbb_sel_mask, 1, abb->setup_reg); break; } /* program next state of ABB ldo */ - ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg, - abb->base); + ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, abb->control_reg); /* * program LDO VBB vset override if needed for !bypass mode @@ -288,7 +288,7 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb, ti_abb_program_ldovbb(dev, abb, info); /* Initiate ABB ldo change */ - ti_abb_rmw(regs->opp_change_mask, 1, regs->control_reg, abb->base); + ti_abb_rmw(regs->opp_change_mask, 1, abb->control_reg); /* Wait for ABB LDO to complete transition to new Bias setting */ ret = ti_abb_wait_txdone(dev, abb); @@ -490,8 +490,7 @@ static int ti_abb_init_timings(struct device *dev, struct ti_abb *abb) dev_dbg(dev, "%s: Clk_rate=%ld, sr2_cnt=0x%08x\n", __func__, clk_get_rate(abb->clk), sr2_wt_cnt_val); - ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, regs->setup_reg, - abb->base); + ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, abb->setup_reg); return 0; } @@ -508,32 +507,24 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb, struct regulator_init_data *rinit_data) { struct ti_abb_info *info; - const struct property *prop; - const __be32 *abb_info; const u32 num_values = 6; char *pname = "ti,abb_info"; - u32 num_entries, i; + u32 i; unsigned int *volt_table; - int min_uV = INT_MAX, max_uV = 0; + int num_entries, min_uV = INT_MAX, max_uV = 0; struct regulation_constraints *c = &rinit_data->constraints; - prop = of_find_property(dev->of_node, pname, NULL); - if (!prop) { - dev_err(dev, "No '%s' property?\n", pname); - return -ENODEV; - } - - if (!prop->value) { - dev_err(dev, "Empty '%s' property?\n", pname); - return -ENODATA; - } - /* * Each abb_info is a set of n-tuple, where n is num_values, consisting * of voltage and a set of detection logic for ABB information for that * voltage to apply. */ - num_entries = prop->length / sizeof(u32); + num_entries = of_property_count_u32_elems(dev->of_node, pname); + if (num_entries < 0) { + dev_err(dev, "No '%s' property?\n", pname); + return num_entries; + } + if (!num_entries || (num_entries % num_values)) { dev_err(dev, "All '%s' list entries need %d vals\n", pname, num_values); @@ -542,38 +533,38 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb, num_entries /= num_values; info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL); - if (!info) { - dev_err(dev, "Can't allocate info table for '%s' property\n", - pname); + if (!info) return -ENOMEM; - } + abb->info = info; volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries, GFP_KERNEL); - if (!volt_table) { - dev_err(dev, "Can't allocate voltage table for '%s' property\n", - pname); + if (!volt_table) return -ENOMEM; - } abb->rdesc.n_voltages = num_entries; abb->rdesc.volt_table = volt_table; /* We do not know where the OPP voltage is at the moment */ abb->current_info_idx = -EINVAL; - abb_info = prop->value; for (i = 0; i < num_entries; i++, info++, volt_table++) { u32 efuse_offset, rbb_mask, fbb_mask, vset_mask; u32 efuse_val; /* NOTE: num_values should equal to entries picked up here */ - *volt_table = be32_to_cpup(abb_info++); - info->opp_sel = be32_to_cpup(abb_info++); - efuse_offset = be32_to_cpup(abb_info++); - rbb_mask = be32_to_cpup(abb_info++); - fbb_mask = be32_to_cpup(abb_info++); - vset_mask = be32_to_cpup(abb_info++); + of_property_read_u32_index(dev->of_node, pname, i * num_values, + volt_table); + of_property_read_u32_index(dev->of_node, pname, + i * num_values + 1, &info->opp_sel); + of_property_read_u32_index(dev->of_node, pname, + i * num_values + 2, &efuse_offset); + of_property_read_u32_index(dev->of_node, pname, + i * num_values + 3, &rbb_mask); + of_property_read_u32_index(dev->of_node, pname, + i * num_values + 4, &fbb_mask); + of_property_read_u32_index(dev->of_node, pname, + i * num_values + 5, &vset_mask); dev_dbg(dev, "[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n", @@ -648,8 +639,8 @@ static struct regulator_ops ti_abb_reg_ops = { /* Default ABB block offsets, IF this changes in future, create new one */ static const struct ti_abb_reg abb_regs_v1 = { /* WARNING: registers are wrongly documented in TRM */ - .setup_reg = 0x04, - .control_reg = 0x00, + .setup_off = 0x04, + .control_off = 0x00, .sr2_wtcnt_value_mask = (0xff << 8), .fbb_sel_mask = (0x01 << 2), @@ -661,8 +652,8 @@ static const struct ti_abb_reg abb_regs_v1 = { }; static const struct ti_abb_reg abb_regs_v2 = { - .setup_reg = 0x00, - .control_reg = 0x04, + .setup_off = 0x00, + .control_off = 0x04, .sr2_wtcnt_value_mask = (0xff << 8), .fbb_sel_mask = (0x01 << 2), @@ -673,9 +664,20 @@ static const struct ti_abb_reg abb_regs_v2 = { .opp_sel_mask = (0x03 << 0), }; +static const struct ti_abb_reg abb_regs_generic = { + .sr2_wtcnt_value_mask = (0xff << 8), + .fbb_sel_mask = (0x01 << 2), + .rbb_sel_mask = (0x01 << 1), + .sr2_en_mask = (0x01 << 0), + + .opp_change_mask = (0x01 << 2), + .opp_sel_mask = (0x03 << 0), +}; + static const struct of_device_id ti_abb_of_match[] = { {.compatible = "ti,abb-v1", .data = &abb_regs_v1}, {.compatible = "ti,abb-v2", .data = &abb_regs_v2}, + {.compatible = "ti,abb-v3", .data = &abb_regs_generic}, { }, }; @@ -722,11 +724,29 @@ static int ti_abb_probe(struct platform_device *pdev) abb->regs = match->data; /* Map ABB resources */ - pname = "base-address"; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); - abb->base = devm_ioremap_resource(dev, res); - if (IS_ERR(abb->base)) - return PTR_ERR(abb->base); + if (abb->regs->setup_off || abb->regs->control_off) { + pname = "base-address"; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); + abb->base = devm_ioremap_resource(dev, res); + if (IS_ERR(abb->base)) + return PTR_ERR(abb->base); + + abb->setup_reg = abb->base + abb->regs->setup_off; + abb->control_reg = abb->base + abb->regs->control_off; + + } else { + pname = "control-address"; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); + abb->control_reg = devm_ioremap_resource(dev, res); + if (IS_ERR(abb->control_reg)) + return PTR_ERR(abb->control_reg); + + pname = "setup-address"; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); + abb->setup_reg = devm_ioremap_resource(dev, res); + if (IS_ERR(abb->setup_reg)) + return PTR_ERR(abb->setup_reg); + } pname = "int-address"; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); @@ -860,7 +880,7 @@ skip_opt: platform_set_drvdata(pdev, rdev); /* Enable the ldo if not already done by bootloader */ - ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->regs->setup_reg, abb->base); + ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->setup_reg); return 0; } diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index b3764f594ee9..f31f22e3e1bd 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -227,10 +227,8 @@ static struct tps51632_regulator_platform_data * struct device_node *np = dev->of_node; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(dev, "Memory alloc failed for platform data\n"); + if (!pdata) return NULL; - } pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node); if (!pdata->reg_init_data) { @@ -299,10 +297,8 @@ static int tps51632_probe(struct i2c_client *client, } tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); - if (!tps) { - dev_err(&client->dev, "Memory allocation failed\n"); + if (!tps) return -ENOMEM; - } tps->dev = &client->dev; tps->desc.name = client->name; diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index c3fa15a299b1..a1672044e519 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -299,10 +299,8 @@ static struct tps62360_regulator_platform_data * struct device_node *np = dev->of_node; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(dev, "Memory alloc failed for platform data\n"); + if (!pdata) return NULL; - } pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node); if (!pdata->reg_init_data) { @@ -377,11 +375,8 @@ static int tps62360_probe(struct i2c_client *client, } tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); - if (!tps) { - dev_err(&client->dev, "%s(): Memory allocation failed\n", - __func__); + if (!tps) return -ENOMEM; - } tps->en_discharge = pdata->en_discharge; tps->en_internal_pulldn = pdata->en_internal_pulldn; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 162a0fae20b3..98e66ce26723 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -359,7 +359,6 @@ static struct regulator_ops tps6507x_pmic_ops = { .map_voltage = regulator_map_voltage_ascend, }; -#ifdef CONFIG_OF static struct of_regulator_match tps6507x_matches[] = { { .name = "VDCDC1"}, { .name = "VDCDC2"}, @@ -381,12 +380,10 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data( tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board), GFP_KERNEL); - if (!tps_board) { - dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n"); + if (!tps_board) return NULL; - } - regulators = of_find_node_by_name(np, "regulators"); + regulators = of_get_child_by_name(np, "regulators"); if (!regulators) { dev_err(&pdev->dev, "regulator node not found\n"); return NULL; @@ -396,6 +393,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data( matches = tps6507x_matches; ret = of_regulator_match(&pdev->dev, regulators, matches, count); + of_node_put(regulators); if (ret < 0) { dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); @@ -406,10 +404,8 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data( reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data) * TPS6507X_NUM_REGULATOR), GFP_KERNEL); - if (!reg_data) { - dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n"); + if (!reg_data) return NULL; - } tps_board->tps6507x_pmic_init_data = reg_data; @@ -424,15 +420,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data( return tps_board; } -#else -static inline struct tps6507x_board *tps6507x_parse_dt_reg_data( - struct platform_device *pdev, - struct of_regulator_match **tps6507x_reg_matches) -{ - *tps6507x_reg_matches = NULL; - return NULL; -} -#endif + static int tps6507x_pmic_probe(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); @@ -453,9 +441,10 @@ static int tps6507x_pmic_probe(struct platform_device *pdev) */ tps_board = dev_get_platdata(tps6507x_dev->dev); - if (!tps_board && tps6507x_dev->dev->of_node) + if (IS_ENABLED(CONFIG_OF) && !tps_board && + tps6507x_dev->dev->of_node) tps_board = tps6507x_parse_dt_reg_data(pdev, - &tps6507x_reg_matches); + &tps6507x_reg_matches); if (!tps_board) return -EINVAL; @@ -481,7 +470,7 @@ static int tps6507x_pmic_probe(struct platform_device *pdev) tps->info[i] = info; if (init_data->driver_data) { struct tps6507x_reg_platform_data *data = - init_data->driver_data; + init_data->driver_data; tps->info[i]->defdcdc_default = data->defdcdc_default; } diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index 676f75548f00..2e92ef68574d 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -168,17 +168,13 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata), GFP_KERNEL); - if (!tps65090_pdata) { - dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n"); + if (!tps65090_pdata) return ERR_PTR(-ENOMEM); - } reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*reg_pdata), GFP_KERNEL); - if (!reg_pdata) { - dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n"); + if (!reg_pdata) return ERR_PTR(-ENOMEM); - } regulators = of_get_child_by_name(np, "regulators"); if (!regulators) { @@ -188,6 +184,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches, ARRAY_SIZE(tps65090_matches)); + of_node_put(regulators); if (ret < 0) { dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); @@ -252,10 +249,8 @@ static int tps65090_regulator_probe(struct platform_device *pdev) pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL); - if (!pmic) { - dev_err(&pdev->dev, "mem alloc for pmic failed\n"); + if (!pmic) return -ENOMEM; - } for (num = 0; num < TPS65090_REGULATOR_MAX; num++) { tps_pdata = tps65090_pdata->reg_pdata[num]; diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 9ea1bf26bd13..10b78d2b766a 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -187,7 +187,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) struct device_node *regs; int i, count; - regs = of_find_node_by_name(node, "regulators"); + regs = of_get_child_by_name(node, "regulators"); if (!regs) return NULL; @@ -202,7 +202,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) return NULL; for (i = 0; i < count; i++) { - if (!reg_matches[i].init_data || !reg_matches[i].of_node) + if (!reg_matches[i].of_node) continue; pdata->tps65217_init_data[i] = reg_matches[i].init_data; @@ -222,7 +222,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev) { struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); struct tps65217_board *pdata = dev_get_platdata(tps->dev); - struct regulator_init_data *reg_data; struct regulator_dev *rdev; struct regulator_config config = { }; int i; @@ -243,19 +242,9 @@ static int tps65217_regulator_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tps); for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { - - reg_data = pdata->tps65217_init_data[i]; - - /* - * Regulator API handles empty constraints but not NULL - * constraints - */ - if (!reg_data) - continue; - /* Register the regulators */ config.dev = tps->dev; - config.init_data = reg_data; + config.init_data = pdata->tps65217_init_data[i]; config.driver_data = tps; config.regmap = tps->regmap; if (tps->dev->of_node) diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c new file mode 100644 index 000000000000..cec72fa71d1d --- /dev/null +++ b/drivers/regulator/tps65218-regulator.c @@ -0,0 +1,285 @@ +/* + * tps65218-regulator.c + * + * Regulator driver for TPS65218 PMIC + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether expressed or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/of_device.h> +#include <linux/regulator/of_regulator.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/tps65218.h> + +static unsigned int tps65218_ramp_delay = 4000; + +enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 }; + +#define TPS65218_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _er, _em, _t, \ + _lr, _nlr) \ + { \ + .name = _name, \ + .id = _id, \ + .ops = &_ops, \ + .n_voltages = _n, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = _vr, \ + .vsel_mask = _vm, \ + .enable_reg = _er, \ + .enable_mask = _em, \ + .volt_table = _t, \ + .linear_ranges = _lr, \ + .n_linear_ranges = _nlr, \ + } \ + +#define TPS65218_INFO(_id, _nm, _min, _max) \ + { \ + .id = _id, \ + .name = _nm, \ + .min_uV = _min, \ + .max_uV = _max, \ + } + +static const struct regulator_linear_range dcdc1_dcdc2_ranges[] = { + REGULATOR_LINEAR_RANGE(850000, 0x0, 0x32, 10000), + REGULATOR_LINEAR_RANGE(1375000, 0x33, 0x3f, 25000), +}; + +static const struct regulator_linear_range ldo1_dcdc3_ranges[] = { + REGULATOR_LINEAR_RANGE(900000, 0x0, 0x1a, 25000), + REGULATOR_LINEAR_RANGE(1600000, 0x1b, 0x3f, 50000), +}; + +static const struct regulator_linear_range dcdc4_ranges[] = { + REGULATOR_LINEAR_RANGE(1175000, 0x0, 0xf, 25000), + REGULATOR_LINEAR_RANGE(1550000, 0x10, 0x34, 50000), +}; + +static struct tps_info tps65218_pmic_regs[] = { + TPS65218_INFO(0, "DCDC1", 850000, 167500), + TPS65218_INFO(1, "DCDC2", 850000, 1675000), + TPS65218_INFO(2, "DCDC3", 900000, 3400000), + TPS65218_INFO(3, "DCDC4", 1175000, 3400000), + TPS65218_INFO(4, "DCDC5", 1000000, 1000000), + TPS65218_INFO(5, "DCDC6", 1800000, 1800000), + TPS65218_INFO(6, "LDO1", 900000, 3400000), +}; + +#define TPS65218_OF_MATCH(comp, label) \ + { \ + .compatible = comp, \ + .data = &label, \ + } + +static const struct of_device_id tps65218_of_match[] = { + TPS65218_OF_MATCH("ti,tps65218-dcdc1", tps65218_pmic_regs[DCDC1]), + TPS65218_OF_MATCH("ti,tps65218-dcdc2", tps65218_pmic_regs[DCDC2]), + TPS65218_OF_MATCH("ti,tps65218-dcdc3", tps65218_pmic_regs[DCDC3]), + TPS65218_OF_MATCH("ti,tps65218-dcdc4", tps65218_pmic_regs[DCDC4]), + TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]), + TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]), + TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]), + { } +}; +MODULE_DEVICE_TABLE(of, tps65218_of_match); + +static int tps65218_pmic_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) +{ + int ret; + struct tps65218 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + /* Set the voltage based on vsel value and write protect level is 2 */ + ret = tps65218_set_bits(tps, dev->desc->vsel_reg, dev->desc->vsel_mask, + selector, TPS65218_PROTECT_L1); + + /* Set GO bit for DCDC1/2 to initiate voltage transistion */ + switch (rid) { + case TPS65218_DCDC_1: + case TPS65218_DCDC_2: + ret = tps65218_set_bits(tps, TPS65218_REG_CONTRL_SLEW_RATE, + TPS65218_SLEW_RATE_GO, + TPS65218_SLEW_RATE_GO, + TPS65218_PROTECT_L1); + break; + } + + return ret; +} + +static int tps65218_pmic_enable(struct regulator_dev *dev) +{ + struct tps65218 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) + return -EINVAL; + + /* Enable the regulator and password protection is level 1 */ + return tps65218_set_bits(tps, dev->desc->enable_reg, + dev->desc->enable_mask, dev->desc->enable_mask, + TPS65218_PROTECT_L1); +} + +static int tps65218_pmic_disable(struct regulator_dev *dev) +{ + struct tps65218 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) + return -EINVAL; + + /* Disable the regulator and password protection is level 1 */ + return tps65218_clear_bits(tps, dev->desc->enable_reg, + dev->desc->enable_mask, TPS65218_PROTECT_L1); +} + +static int tps65218_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + int old_uv, new_uv; + + old_uv = regulator_list_voltage_linear_range(rdev, old_selector); + if (old_uv < 0) + return old_uv; + + new_uv = regulator_list_voltage_linear_range(rdev, new_selector); + if (new_uv < 0) + return new_uv; + + return DIV_ROUND_UP(abs(old_uv - new_uv), tps65218_ramp_delay); +} + +/* Operations permitted on DCDC1, DCDC2 */ +static struct regulator_ops tps65218_dcdc12_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = tps65218_pmic_enable, + .disable = tps65218_pmic_disable, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = tps65218_pmic_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_time_sel = tps65218_set_voltage_time_sel, +}; + +/* Operations permitted on DCDC3, DCDC4 and LDO1 */ +static struct regulator_ops tps65218_ldo1_dcdc34_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = tps65218_pmic_enable, + .disable = tps65218_pmic_disable, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = tps65218_pmic_set_voltage_sel, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, +}; + +/* Operations permitted on DCDC5, DCDC6 */ +static struct regulator_ops tps65218_dcdc56_pmic_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = tps65218_pmic_enable, + .disable = tps65218_pmic_disable, +}; + +static const struct regulator_desc regulators[] = { + TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, tps65218_dcdc12_ops, 64, + TPS65218_REG_CONTROL_DCDC1, + TPS65218_CONTROL_DCDC1_MASK, + TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN, NULL, + dcdc1_dcdc2_ranges, 2), + TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, tps65218_dcdc12_ops, 64, + TPS65218_REG_CONTROL_DCDC2, + TPS65218_CONTROL_DCDC2_MASK, + TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN, NULL, + dcdc1_dcdc2_ranges, 2), + TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, tps65218_ldo1_dcdc34_ops, + 64, TPS65218_REG_CONTROL_DCDC3, + TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1, + TPS65218_ENABLE1_DC3_EN, NULL, + ldo1_dcdc3_ranges, 2), + TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, tps65218_ldo1_dcdc34_ops, + 53, TPS65218_REG_CONTROL_DCDC4, + TPS65218_CONTROL_DCDC4_MASK, + TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN, NULL, + dcdc4_ranges, 2), + TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, tps65218_dcdc56_pmic_ops, + 1, -1, -1, TPS65218_REG_ENABLE1, + TPS65218_ENABLE1_DC5_EN, NULL, NULL, 0), + TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, tps65218_dcdc56_pmic_ops, + 1, -1, -1, TPS65218_REG_ENABLE1, + TPS65218_ENABLE1_DC6_EN, NULL, NULL, 0), + TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64, + TPS65218_REG_CONTROL_DCDC4, + TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2, + TPS65218_ENABLE2_LDO1_EN, NULL, ldo1_dcdc3_ranges, + 2), +}; + +static int tps65218_regulator_probe(struct platform_device *pdev) +{ + struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent); + struct regulator_init_data *init_data; + const struct tps_info *template; + struct regulator_dev *rdev; + const struct of_device_id *match; + struct regulator_config config = { }; + int id; + + match = of_match_device(tps65218_of_match, &pdev->dev); + if (!match) + return -ENODEV; + + template = match->data; + id = template->id; + init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); + + platform_set_drvdata(pdev, tps); + + tps->info[id] = &tps65218_pmic_regs[id]; + config.dev = &pdev->dev; + config.init_data = init_data; + config.driver_data = tps; + config.regmap = tps->regmap; + + rdev = devm_regulator_register(&pdev->dev, ®ulators[id], &config); + if (IS_ERR(rdev)) { + dev_err(tps->dev, "failed to register %s regulator\n", + pdev->name); + return PTR_ERR(rdev); + } + + return 0; +} + +static struct platform_driver tps65218_regulator_driver = { + .driver = { + .name = "tps65218-pmic", + .owner = THIS_MODULE, + .of_match_table = tps65218_of_match, + }, + .probe = tps65218_regulator_probe, +}; + +module_platform_driver(tps65218_regulator_driver); + +MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>"); +MODULE_DESCRIPTION("TPS65218 voltage regulator driver"); +MODULE_ALIAS("platform:tps65218-pmic"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 9f6bfda711b7..5b494db9f95c 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -593,10 +593,9 @@ static int pmic_probe(struct spi_device *spi) } hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL); - if (!hw) { - dev_err(dev, "cannot allocate regulator private data\n"); + if (!hw) return -ENOMEM; - } + spi_set_drvdata(spi, hw); memset(hw, 0, sizeof(struct tps6524x)); diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 0485d47f0d8a..32f38a63d944 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -363,10 +363,8 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( } pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&pdev->dev, "Memory alloction failed\n"); + if (!pdata) return NULL; - } for (i = 0; i < num; i++) { int id; @@ -398,7 +396,7 @@ static int tps6586x_regulator_probe(struct platform_device *pdev) { struct tps6586x_regulator *ri = NULL; struct regulator_config config = { }; - struct regulator_dev **rdev; + struct regulator_dev *rdev; struct regulator_init_data *reg_data; struct tps6586x_platform_data *pdata; struct of_regulator_match *tps6586x_reg_matches = NULL; @@ -418,13 +416,6 @@ static int tps6586x_regulator_probe(struct platform_device *pdev) return -ENODEV; } - rdev = devm_kzalloc(&pdev->dev, TPS6586X_ID_MAX_REGULATOR * - sizeof(*rdev), GFP_KERNEL); - if (!rdev) { - dev_err(&pdev->dev, "Mmemory alloc failed\n"); - return -ENOMEM; - } - version = tps6586x_get_version(pdev->dev.parent); for (id = 0; id < TPS6586X_ID_MAX_REGULATOR; ++id) { @@ -451,12 +442,11 @@ static int tps6586x_regulator_probe(struct platform_device *pdev) if (tps6586x_reg_matches) config.of_node = tps6586x_reg_matches[id].of_node; - rdev[id] = devm_regulator_register(&pdev->dev, &ri->desc, - &config); - if (IS_ERR(rdev[id])) { + rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); + if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); - return PTR_ERR(rdev[id]); + return PTR_ERR(rdev); } if (reg_data) { diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index f50dd847eebc..fa7db8847578 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -1011,11 +1011,8 @@ static struct tps65910_board *tps65910_parse_dt_reg_data( pmic_plat_data = devm_kzalloc(&pdev->dev, sizeof(*pmic_plat_data), GFP_KERNEL); - - if (!pmic_plat_data) { - dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n"); + if (!pmic_plat_data) return NULL; - } np = of_node_get(pdev->dev.parent->of_node); regulators = of_get_child_by_name(np, "regulators"); @@ -1098,10 +1095,8 @@ static int tps65910_probe(struct platform_device *pdev) } pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); - if (!pmic) { - dev_err(&pdev->dev, "Memory allocation failed for pmic\n"); + if (!pmic) return -ENOMEM; - } pmic->mfd = tps65910; platform_set_drvdata(pdev, pmic); @@ -1130,24 +1125,18 @@ static int tps65910_probe(struct platform_device *pdev) pmic->desc = devm_kzalloc(&pdev->dev, pmic->num_regulators * sizeof(struct regulator_desc), GFP_KERNEL); - if (!pmic->desc) { - dev_err(&pdev->dev, "Memory alloc fails for desc\n"); + if (!pmic->desc) return -ENOMEM; - } pmic->info = devm_kzalloc(&pdev->dev, pmic->num_regulators * sizeof(struct tps_info *), GFP_KERNEL); - if (!pmic->info) { - dev_err(&pdev->dev, "Memory alloc fails for info\n"); + if (!pmic->info) return -ENOMEM; - } pmic->rdev = devm_kzalloc(&pdev->dev, pmic->num_regulators * sizeof(struct regulator_dev *), GFP_KERNEL); - if (!pmic->rdev) { - dev_err(&pdev->dev, "Memory alloc fails for rdev\n"); + if (!pmic->rdev) return -ENOMEM; - } for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS; i++, info++) { diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c index 71f457a42623..26aa6d9c308f 100644 --- a/drivers/regulator/tps80031-regulator.c +++ b/drivers/regulator/tps80031-regulator.c @@ -115,7 +115,7 @@ static int tps80031_reg_is_enabled(struct regulator_dev *rdev) ri->rinfo->state_reg, ret); return ret; } - return ((reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON); + return (reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON; } static int tps80031_reg_enable(struct regulator_dev *rdev) @@ -693,10 +693,8 @@ static int tps80031_regulator_probe(struct platform_device *pdev) pmic = devm_kzalloc(&pdev->dev, TPS80031_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL); - if (!pmic) { - dev_err(&pdev->dev, "mem alloc for pmic failed\n"); + if (!pmic) return -ENOMEM; - } for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) { tps_pdata = pdata->regulator_pdata[num]; diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 04cf9c16ef23..0d88a82ab2a2 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -469,10 +469,8 @@ static int wm831x_buckv_probe(struct platform_device *pdev) dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); - if (dcdc == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!dcdc) return -ENOMEM; - } dcdc->wm831x = wm831x; @@ -622,10 +620,8 @@ static int wm831x_buckp_probe(struct platform_device *pdev) dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); - if (dcdc == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!dcdc) return -ENOMEM; - } dcdc->wm831x = wm831x; @@ -752,10 +748,8 @@ static int wm831x_boostp_probe(struct platform_device *pdev) return -ENODEV; dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); - if (dcdc == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!dcdc) return -ENOMEM; - } dcdc->wm831x = wm831x; @@ -842,10 +836,8 @@ static int wm831x_epe_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing EPE%d\n", id + 1); dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); - if (dcdc == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!dcdc) return -ENOMEM; - } dcdc->wm831x = wm831x; diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 0339b886df5d..72e385e76a9d 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -165,10 +165,8 @@ static int wm831x_isink_probe(struct platform_device *pdev) isink = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_isink), GFP_KERNEL); - if (isink == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!isink) return -ENOMEM; - } isink->wm831x = wm831x; diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 46d6700467b5..eca0eeb78acd 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -235,10 +235,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); - if (ldo == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!ldo) return -ENOMEM; - } ldo->wm831x = wm831x; @@ -447,10 +445,8 @@ static int wm831x_aldo_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); - if (ldo == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!ldo) return -ENOMEM; - } ldo->wm831x = wm831x; @@ -594,10 +590,8 @@ static int wm831x_alive_ldo_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); - if (ldo == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!ldo) return -ENOMEM; - } ldo->wm831x = wm831x; diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index de7b9c73e3fa..7ec7c390eeda 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -361,7 +361,7 @@ static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV) sel = regulator_map_voltage_linear(rdev, uV, uV); if (sel < 0) - return -EINVAL; + return sel; /* all DCDCs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK; @@ -574,7 +574,7 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) sel = regulator_map_voltage_linear_range(rdev, uV, uV); if (sel < 0) - return -EINVAL; + return sel; /* all LDOs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK; diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 71c5911f2e71..c24346db8a71 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -134,10 +134,8 @@ static int wm8994_ldo_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL); - if (ldo == NULL) { - dev_err(&pdev->dev, "Unable to allocate private data\n"); + if (!ldo) return -ENOMEM; - } ldo->wm8994 = wm8994; ldo->supply = wm8994_ldo_consumer[id]; diff --git a/include/linux/device.h b/include/linux/device.h index 952b01033c32..ec1b6e21f0ef 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -626,6 +626,7 @@ static inline void *devm_kcalloc(struct device *dev, return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO); } extern void devm_kfree(struct device *dev, void *p); +extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp); void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res); void __iomem *devm_request_and_ioremap(struct device *dev, diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 41c9bde410c5..157e32b6ca28 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -18,7 +18,9 @@ enum sec_device_type { S5M8751X, S5M8763X, S5M8767X, + S2MPA01, S2MPS11X, + S2MPS14X, }; /** @@ -50,7 +52,7 @@ struct sec_pmic_dev { struct regmap_irq_chip_data *irq_data; int ono; - int type; + unsigned long type; bool wakeup; bool wtsr_smpl; }; @@ -92,7 +94,7 @@ struct sec_platform_data { int buck3_default_idx; int buck4_default_idx; - int buck_ramp_delay; + int buck_ramp_delay; int buck2_ramp_delay; int buck34_ramp_delay; @@ -100,10 +102,15 @@ struct sec_platform_data { int buck16_ramp_delay; int buck7810_ramp_delay; int buck9_ramp_delay; - - bool buck2_ramp_enable; - bool buck3_ramp_enable; - bool buck4_ramp_enable; + int buck24_ramp_delay; + int buck3_ramp_delay; + int buck7_ramp_delay; + int buck8910_ramp_delay; + + bool buck1_ramp_enable; + bool buck2_ramp_enable; + bool buck3_ramp_enable; + bool buck4_ramp_enable; bool buck6_ramp_enable; int buck2_init; @@ -119,7 +126,8 @@ struct sec_platform_data { struct sec_regulator_data { int id; struct regulator_init_data *initdata; - struct device_node *reg_node; + struct device_node *reg_node; + int ext_control_gpio; }; /* diff --git a/include/linux/mfd/samsung/irq.h b/include/linux/mfd/samsung/irq.h index d43b4f9e7fb2..1224f447356b 100644 --- a/include/linux/mfd/samsung/irq.h +++ b/include/linux/mfd/samsung/irq.h @@ -13,6 +13,56 @@ #ifndef __LINUX_MFD_SEC_IRQ_H #define __LINUX_MFD_SEC_IRQ_H +enum s2mpa01_irq { + S2MPA01_IRQ_PWRONF, + S2MPA01_IRQ_PWRONR, + S2MPA01_IRQ_JIGONBF, + S2MPA01_IRQ_JIGONBR, + S2MPA01_IRQ_ACOKBF, + S2MPA01_IRQ_ACOKBR, + S2MPA01_IRQ_PWRON1S, + S2MPA01_IRQ_MRB, + + S2MPA01_IRQ_RTC60S, + S2MPA01_IRQ_RTCA1, + S2MPA01_IRQ_RTCA0, + S2MPA01_IRQ_SMPL, + S2MPA01_IRQ_RTC1S, + S2MPA01_IRQ_WTSR, + + S2MPA01_IRQ_INT120C, + S2MPA01_IRQ_INT140C, + S2MPA01_IRQ_LDO3_TSD, + S2MPA01_IRQ_B16_TSD, + S2MPA01_IRQ_B24_TSD, + S2MPA01_IRQ_B35_TSD, + + S2MPA01_IRQ_NR, +}; + +#define S2MPA01_IRQ_PWRONF_MASK (1 << 0) +#define S2MPA01_IRQ_PWRONR_MASK (1 << 1) +#define S2MPA01_IRQ_JIGONBF_MASK (1 << 2) +#define S2MPA01_IRQ_JIGONBR_MASK (1 << 3) +#define S2MPA01_IRQ_ACOKBF_MASK (1 << 4) +#define S2MPA01_IRQ_ACOKBR_MASK (1 << 5) +#define S2MPA01_IRQ_PWRON1S_MASK (1 << 6) +#define S2MPA01_IRQ_MRB_MASK (1 << 7) + +#define S2MPA01_IRQ_RTC60S_MASK (1 << 0) +#define S2MPA01_IRQ_RTCA1_MASK (1 << 1) +#define S2MPA01_IRQ_RTCA0_MASK (1 << 2) +#define S2MPA01_IRQ_SMPL_MASK (1 << 3) +#define S2MPA01_IRQ_RTC1S_MASK (1 << 4) +#define S2MPA01_IRQ_WTSR_MASK (1 << 5) + +#define S2MPA01_IRQ_INT120C_MASK (1 << 0) +#define S2MPA01_IRQ_INT140C_MASK (1 << 1) +#define S2MPA01_IRQ_LDO3_TSD_MASK (1 << 2) +#define S2MPA01_IRQ_B16_TSD_MASK (1 << 3) +#define S2MPA01_IRQ_B24_TSD_MASK (1 << 4) +#define S2MPA01_IRQ_B35_TSD_MASK (1 << 5) + enum s2mps11_irq { S2MPS11_IRQ_PWRONF, S2MPS11_IRQ_PWRONR, @@ -24,8 +74,8 @@ enum s2mps11_irq { S2MPS11_IRQ_MRB, S2MPS11_IRQ_RTC60S, + S2MPS11_IRQ_RTCA0, S2MPS11_IRQ_RTCA1, - S2MPS11_IRQ_RTCA2, S2MPS11_IRQ_SMPL, S2MPS11_IRQ_RTC1S, S2MPS11_IRQ_WTSR, @@ -47,7 +97,7 @@ enum s2mps11_irq { #define S2MPS11_IRQ_RTC60S_MASK (1 << 0) #define S2MPS11_IRQ_RTCA1_MASK (1 << 1) -#define S2MPS11_IRQ_RTCA2_MASK (1 << 2) +#define S2MPS11_IRQ_RTCA0_MASK (1 << 2) #define S2MPS11_IRQ_SMPL_MASK (1 << 3) #define S2MPS11_IRQ_RTC1S_MASK (1 << 4) #define S2MPS11_IRQ_WTSR_MASK (1 << 5) @@ -55,6 +105,33 @@ enum s2mps11_irq { #define S2MPS11_IRQ_INT120C_MASK (1 << 0) #define S2MPS11_IRQ_INT140C_MASK (1 << 1) +enum s2mps14_irq { + S2MPS14_IRQ_PWRONF, + S2MPS14_IRQ_PWRONR, + S2MPS14_IRQ_JIGONBF, + S2MPS14_IRQ_JIGONBR, + S2MPS14_IRQ_ACOKBF, + S2MPS14_IRQ_ACOKBR, + S2MPS14_IRQ_PWRON1S, + S2MPS14_IRQ_MRB, + + S2MPS14_IRQ_RTC60S, + S2MPS14_IRQ_RTCA1, + S2MPS14_IRQ_RTCA0, + S2MPS14_IRQ_SMPL, + S2MPS14_IRQ_RTC1S, + S2MPS14_IRQ_WTSR, + + S2MPS14_IRQ_INT120C, + S2MPS14_IRQ_INT140C, + S2MPS14_IRQ_TSD, + + S2MPS14_IRQ_NR, +}; + +/* Masks for interrupts are the same as in s2mps11 */ +#define S2MPS14_IRQ_TSD_MASK (1 << 2) + enum s5m8767_irq { S5M8767_IRQ_PWRR, S5M8767_IRQ_PWRF, diff --git a/include/linux/mfd/samsung/rtc.h b/include/linux/mfd/samsung/rtc.h index 94b7cd6d8891..3e02b768d537 100644 --- a/include/linux/mfd/samsung/rtc.h +++ b/include/linux/mfd/samsung/rtc.h @@ -1,12 +1,17 @@ -/* rtc.h +/* rtc.h * - * Copyright (c) 2011 Samsung Electronics Co., Ltd + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd * http://www.samsung.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. + * 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. * */ @@ -43,6 +48,39 @@ enum sec_rtc_reg { SEC_RTC_STATUS, SEC_WTSR_SMPL_CNTL, SEC_RTC_UDR_CON, + + SEC_RTC_REG_MAX, +}; + +enum s2mps_rtc_reg { + S2MPS_RTC_CTRL, + S2MPS_WTSR_SMPL_CNTL, + S2MPS_RTC_UDR_CON, + S2MPS_RSVD, + S2MPS_RTC_SEC, + S2MPS_RTC_MIN, + S2MPS_RTC_HOUR, + S2MPS_RTC_WEEKDAY, + S2MPS_RTC_DATE, + S2MPS_RTC_MONTH, + S2MPS_RTC_YEAR, + S2MPS_ALARM0_SEC, + S2MPS_ALARM0_MIN, + S2MPS_ALARM0_HOUR, + S2MPS_ALARM0_WEEKDAY, + S2MPS_ALARM0_DATE, + S2MPS_ALARM0_MONTH, + S2MPS_ALARM0_YEAR, + S2MPS_ALARM1_SEC, + S2MPS_ALARM1_MIN, + S2MPS_ALARM1_HOUR, + S2MPS_ALARM1_WEEKDAY, + S2MPS_ALARM1_DATE, + S2MPS_ALARM1_MONTH, + S2MPS_ALARM1_YEAR, + S2MPS_OFFSRC, + + S2MPS_RTC_REG_MAX, }; #define RTC_I2C_ADDR (0x0C >> 1) @@ -54,6 +92,9 @@ enum sec_rtc_reg { #define ALARM1_STATUS (1 << 2) #define UPDATE_AD (1 << 0) +#define S2MPS_ALARM0_STATUS (1 << 2) +#define S2MPS_ALARM1_STATUS (1 << 1) + /* RTC Control Register */ #define BCD_EN_SHIFT 0 #define BCD_EN_MASK (1 << BCD_EN_SHIFT) @@ -62,6 +103,10 @@ enum sec_rtc_reg { /* RTC Update Register1 */ #define RTC_UDR_SHIFT 0 #define RTC_UDR_MASK (1 << RTC_UDR_SHIFT) +#define S2MPS_RTC_WUDR_SHIFT 4 +#define S2MPS_RTC_WUDR_MASK (1 << S2MPS_RTC_WUDR_SHIFT) +#define S2MPS_RTC_RUDR_SHIFT 0 +#define S2MPS_RTC_RUDR_MASK (1 << S2MPS_RTC_RUDR_SHIFT) #define RTC_TCON_SHIFT 1 #define RTC_TCON_MASK (1 << RTC_TCON_SHIFT) #define RTC_TIME_EN_SHIFT 3 diff --git a/include/linux/mfd/samsung/s2mpa01.h b/include/linux/mfd/samsung/s2mpa01.h new file mode 100644 index 000000000000..fbc63bc0d6a2 --- /dev/null +++ b/include/linux/mfd/samsung/s2mpa01.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd + * http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __LINUX_MFD_S2MPA01_H +#define __LINUX_MFD_S2MPA01_H + +/* S2MPA01 registers */ +enum s2mpa01_reg { + S2MPA01_REG_ID, + S2MPA01_REG_INT1, + S2MPA01_REG_INT2, + S2MPA01_REG_INT3, + S2MPA01_REG_INT1M, + S2MPA01_REG_INT2M, + S2MPA01_REG_INT3M, + S2MPA01_REG_ST1, + S2MPA01_REG_ST2, + S2MPA01_REG_PWRONSRC, + S2MPA01_REG_OFFSRC, + S2MPA01_REG_RTC_BUF, + S2MPA01_REG_CTRL1, + S2MPA01_REG_ETC_TEST, + S2MPA01_REG_RSVD1, + S2MPA01_REG_BU_CHG, + S2MPA01_REG_RAMP1, + S2MPA01_REG_RAMP2, + S2MPA01_REG_LDO_DSCH1, + S2MPA01_REG_LDO_DSCH2, + S2MPA01_REG_LDO_DSCH3, + S2MPA01_REG_LDO_DSCH4, + S2MPA01_REG_OTP_ADRL, + S2MPA01_REG_OTP_ADRH, + S2MPA01_REG_OTP_DATA, + S2MPA01_REG_MON1SEL, + S2MPA01_REG_MON2SEL, + S2MPA01_REG_LEE, + S2MPA01_REG_RSVD2, + S2MPA01_REG_RSVD3, + S2MPA01_REG_RSVD4, + S2MPA01_REG_RSVD5, + S2MPA01_REG_RSVD6, + S2MPA01_REG_TOP_RSVD, + S2MPA01_REG_DVS_SEL, + S2MPA01_REG_DVS_PTR, + S2MPA01_REG_DVS_DATA, + S2MPA01_REG_RSVD_NO, + S2MPA01_REG_UVLO, + S2MPA01_REG_LEE_NO, + S2MPA01_REG_B1CTRL1, + S2MPA01_REG_B1CTRL2, + S2MPA01_REG_B2CTRL1, + S2MPA01_REG_B2CTRL2, + S2MPA01_REG_B3CTRL1, + S2MPA01_REG_B3CTRL2, + S2MPA01_REG_B4CTRL1, + S2MPA01_REG_B4CTRL2, + S2MPA01_REG_B5CTRL1, + S2MPA01_REG_B5CTRL2, + S2MPA01_REG_B5CTRL3, + S2MPA01_REG_B5CTRL4, + S2MPA01_REG_B5CTRL5, + S2MPA01_REG_B5CTRL6, + S2MPA01_REG_B6CTRL1, + S2MPA01_REG_B6CTRL2, + S2MPA01_REG_B7CTRL1, + S2MPA01_REG_B7CTRL2, + S2MPA01_REG_B8CTRL1, + S2MPA01_REG_B8CTRL2, + S2MPA01_REG_B9CTRL1, + S2MPA01_REG_B9CTRL2, + S2MPA01_REG_B10CTRL1, + S2MPA01_REG_B10CTRL2, + S2MPA01_REG_L1CTRL, + S2MPA01_REG_L2CTRL, + S2MPA01_REG_L3CTRL, + S2MPA01_REG_L4CTRL, + S2MPA01_REG_L5CTRL, + S2MPA01_REG_L6CTRL, + S2MPA01_REG_L7CTRL, + S2MPA01_REG_L8CTRL, + S2MPA01_REG_L9CTRL, + S2MPA01_REG_L10CTRL, + S2MPA01_REG_L11CTRL, + S2MPA01_REG_L12CTRL, + S2MPA01_REG_L13CTRL, + S2MPA01_REG_L14CTRL, + S2MPA01_REG_L15CTRL, + S2MPA01_REG_L16CTRL, + S2MPA01_REG_L17CTRL, + S2MPA01_REG_L18CTRL, + S2MPA01_REG_L19CTRL, + S2MPA01_REG_L20CTRL, + S2MPA01_REG_L21CTRL, + S2MPA01_REG_L22CTRL, + S2MPA01_REG_L23CTRL, + S2MPA01_REG_L24CTRL, + S2MPA01_REG_L25CTRL, + S2MPA01_REG_L26CTRL, + + S2MPA01_REG_LDO_OVCB1, + S2MPA01_REG_LDO_OVCB2, + S2MPA01_REG_LDO_OVCB3, + S2MPA01_REG_LDO_OVCB4, + +}; + +/* S2MPA01 regulator ids */ +enum s2mpa01_regulators { + S2MPA01_LDO1, + S2MPA01_LDO2, + S2MPA01_LDO3, + S2MPA01_LDO4, + S2MPA01_LDO5, + S2MPA01_LDO6, + S2MPA01_LDO7, + S2MPA01_LDO8, + S2MPA01_LDO9, + S2MPA01_LDO10, + S2MPA01_LDO11, + S2MPA01_LDO12, + S2MPA01_LDO13, + S2MPA01_LDO14, + S2MPA01_LDO15, + S2MPA01_LDO16, + S2MPA01_LDO17, + S2MPA01_LDO18, + S2MPA01_LDO19, + S2MPA01_LDO20, + S2MPA01_LDO21, + S2MPA01_LDO22, + S2MPA01_LDO23, + S2MPA01_LDO24, + S2MPA01_LDO25, + S2MPA01_LDO26, + + S2MPA01_BUCK1, + S2MPA01_BUCK2, + S2MPA01_BUCK3, + S2MPA01_BUCK4, + S2MPA01_BUCK5, + S2MPA01_BUCK6, + S2MPA01_BUCK7, + S2MPA01_BUCK8, + S2MPA01_BUCK9, + S2MPA01_BUCK10, + + S2MPA01_REGULATOR_MAX, +}; + +#define S2MPA01_BUCK_MIN1 600000 +#define S2MPA01_BUCK_MIN2 800000 +#define S2MPA01_BUCK_MIN3 1000000 +#define S2MPA01_BUCK_MIN4 1500000 +#define S2MPA01_LDO_MIN 800000 + +#define S2MPA01_BUCK_STEP1 6250 +#define S2MPA01_BUCK_STEP2 12500 + +#define S2MPA01_LDO_STEP1 50000 +#define S2MPA01_LDO_STEP2 25000 + +#define S2MPA01_LDO_VSEL_MASK 0x3F +#define S2MPA01_BUCK_VSEL_MASK 0xFF +#define S2MPA01_ENABLE_MASK (0x03 << S2MPA01_ENABLE_SHIFT) +#define S2MPA01_ENABLE_SHIFT 0x06 +#define S2MPA01_LDO_N_VOLTAGES (S2MPA01_LDO_VSEL_MASK + 1) +#define S2MPA01_BUCK_N_VOLTAGES (S2MPA01_BUCK_VSEL_MASK + 1) + +#define S2MPA01_RAMP_DELAY 12500 /* uV/us */ + +#define S2MPA01_BUCK16_RAMP_SHIFT 4 +#define S2MPA01_BUCK24_RAMP_SHIFT 6 +#define S2MPA01_BUCK3_RAMP_SHIFT 4 +#define S2MPA01_BUCK5_RAMP_SHIFT 6 +#define S2MPA01_BUCK7_RAMP_SHIFT 2 +#define S2MPA01_BUCK8910_RAMP_SHIFT 0 + +#define S2MPA01_BUCK1_RAMP_EN_SHIFT 3 +#define S2MPA01_BUCK2_RAMP_EN_SHIFT 2 +#define S2MPA01_BUCK3_RAMP_EN_SHIFT 1 +#define S2MPA01_BUCK4_RAMP_EN_SHIFT 0 +#define S2MPA01_PMIC_EN_SHIFT 6 + +#endif /*__LINUX_MFD_S2MPA01_H */ diff --git a/include/linux/mfd/samsung/s2mps14.h b/include/linux/mfd/samsung/s2mps14.h new file mode 100644 index 000000000000..4b449b8ac548 --- /dev/null +++ b/include/linux/mfd/samsung/s2mps14.h @@ -0,0 +1,154 @@ +/* + * s2mps14.h + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd + * http://www.samsung.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. + * + * 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. + * + */ + +#ifndef __LINUX_MFD_S2MPS14_H +#define __LINUX_MFD_S2MPS14_H + +/* S2MPS14 registers */ +enum s2mps14_reg { + S2MPS14_REG_ID, + S2MPS14_REG_INT1, + S2MPS14_REG_INT2, + S2MPS14_REG_INT3, + S2MPS14_REG_INT1M, + S2MPS14_REG_INT2M, + S2MPS14_REG_INT3M, + S2MPS14_REG_ST1, + S2MPS14_REG_ST2, + S2MPS14_REG_PWRONSRC, + S2MPS14_REG_OFFSRC, + S2MPS14_REG_BU_CHG, + S2MPS14_REG_RTCCTRL, + S2MPS14_REG_CTRL1, + S2MPS14_REG_CTRL2, + S2MPS14_REG_RSVD1, + S2MPS14_REG_RSVD2, + S2MPS14_REG_RSVD3, + S2MPS14_REG_RSVD4, + S2MPS14_REG_RSVD5, + S2MPS14_REG_RSVD6, + S2MPS14_REG_CTRL3, + S2MPS14_REG_RSVD7, + S2MPS14_REG_RSVD8, + S2MPS14_REG_WRSTBI, + S2MPS14_REG_B1CTRL1, + S2MPS14_REG_B1CTRL2, + S2MPS14_REG_B2CTRL1, + S2MPS14_REG_B2CTRL2, + S2MPS14_REG_B3CTRL1, + S2MPS14_REG_B3CTRL2, + S2MPS14_REG_B4CTRL1, + S2MPS14_REG_B4CTRL2, + S2MPS14_REG_B5CTRL1, + S2MPS14_REG_B5CTRL2, + S2MPS14_REG_L1CTRL, + S2MPS14_REG_L2CTRL, + S2MPS14_REG_L3CTRL, + S2MPS14_REG_L4CTRL, + S2MPS14_REG_L5CTRL, + S2MPS14_REG_L6CTRL, + S2MPS14_REG_L7CTRL, + S2MPS14_REG_L8CTRL, + S2MPS14_REG_L9CTRL, + S2MPS14_REG_L10CTRL, + S2MPS14_REG_L11CTRL, + S2MPS14_REG_L12CTRL, + S2MPS14_REG_L13CTRL, + S2MPS14_REG_L14CTRL, + S2MPS14_REG_L15CTRL, + S2MPS14_REG_L16CTRL, + S2MPS14_REG_L17CTRL, + S2MPS14_REG_L18CTRL, + S2MPS14_REG_L19CTRL, + S2MPS14_REG_L20CTRL, + S2MPS14_REG_L21CTRL, + S2MPS14_REG_L22CTRL, + S2MPS14_REG_L23CTRL, + S2MPS14_REG_L24CTRL, + S2MPS14_REG_L25CTRL, + S2MPS14_REG_LDODSCH1, + S2MPS14_REG_LDODSCH2, + S2MPS14_REG_LDODSCH3, +}; + +/* S2MPS14 regulator ids */ +enum s2mps14_regulators { + S2MPS14_LDO1, + S2MPS14_LDO2, + S2MPS14_LDO3, + S2MPS14_LDO4, + S2MPS14_LDO5, + S2MPS14_LDO6, + S2MPS14_LDO7, + S2MPS14_LDO8, + S2MPS14_LDO9, + S2MPS14_LDO10, + S2MPS14_LDO11, + S2MPS14_LDO12, + S2MPS14_LDO13, + S2MPS14_LDO14, + S2MPS14_LDO15, + S2MPS14_LDO16, + S2MPS14_LDO17, + S2MPS14_LDO18, + S2MPS14_LDO19, + S2MPS14_LDO20, + S2MPS14_LDO21, + S2MPS14_LDO22, + S2MPS14_LDO23, + S2MPS14_LDO24, + S2MPS14_LDO25, + S2MPS14_BUCK1, + S2MPS14_BUCK2, + S2MPS14_BUCK3, + S2MPS14_BUCK4, + S2MPS14_BUCK5, + + S2MPS14_REGULATOR_MAX, +}; + +/* Regulator constraints for BUCKx */ +#define S2MPS14_BUCK1235_MIN_600MV 600000 +#define S2MPS14_BUCK4_MIN_1400MV 1400000 +#define S2MPS14_BUCK1235_STEP_6_25MV 6250 +#define S2MPS14_BUCK4_STEP_12_5MV 12500 +#define S2MPS14_BUCK1235_START_SEL 0x20 +#define S2MPS14_BUCK4_START_SEL 0x40 +/* + * Default ramp delay in uv/us. Datasheet says that ramp delay can be + * controlled however it does not specify which register is used for that. + * Let's assume that default value will be set. + */ +#define S2MPS14_BUCK_RAMP_DELAY 12500 + +/* Regulator constraints for different types of LDOx */ +#define S2MPS14_LDO_MIN_800MV 800000 +#define S2MPS14_LDO_MIN_1800MV 1800000 +#define S2MPS14_LDO_STEP_12_5MV 12500 +#define S2MPS14_LDO_STEP_25MV 25000 + +#define S2MPS14_LDO_VSEL_MASK 0x3F +#define S2MPS14_BUCK_VSEL_MASK 0xFF +#define S2MPS14_ENABLE_MASK (0x03 << S2MPS14_ENABLE_SHIFT) +#define S2MPS14_ENABLE_SHIFT 6 +/* On/Off controlled by PWREN */ +#define S2MPS14_ENABLE_SUSPEND (0x01 << S2MPS14_ENABLE_SHIFT) +#define S2MPS14_LDO_N_VOLTAGES (S2MPS14_LDO_VSEL_MASK + 1) +#define S2MPS14_BUCK_N_VOLTAGES (S2MPS14_BUCK_VSEL_MASK + 1) + +#endif /* __LINUX_MFD_S2MPS14_H */ diff --git a/include/linux/mfd/samsung/s5m8767.h b/include/linux/mfd/samsung/s5m8767.h index 2ab0b0f03641..243b58fec33d 100644 --- a/include/linux/mfd/samsung/s5m8767.h +++ b/include/linux/mfd/samsung/s5m8767.h @@ -183,10 +183,17 @@ enum s5m8767_regulators { S5M8767_REG_MAX, }; +/* LDO_EN/BUCK_EN field in registers */ #define S5M8767_ENCTRL_SHIFT 6 #define S5M8767_ENCTRL_MASK (0x3 << S5M8767_ENCTRL_SHIFT) /* + * LDO_EN/BUCK_EN register value for controlling this Buck or LDO + * by GPIO (PWREN, BUCKEN). + */ +#define S5M8767_ENCTRL_USE_GPIO 0x1 + +/* * Values for BUCK_RAMP field in DVS_RAMP register, matching raw values * in mV/us. */ diff --git a/include/linux/of.h b/include/linux/of.h index 435cb995904d..83d1ac80c91e 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -198,6 +198,8 @@ extern struct device_node *of_find_node_with_property( extern struct property *of_find_property(const struct device_node *np, const char *name, int *lenp); +extern int of_property_count_elems_of_size(const struct device_node *np, + const char *propname, int elem_size); extern int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value); @@ -390,6 +392,12 @@ static inline struct device_node *of_find_compatible_node( return NULL; } +static inline int of_property_count_elems_of_size(const struct device_node *np, + const char *propname, int elem_size) +{ + return -ENOSYS; +} + static inline int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value) { @@ -536,6 +544,74 @@ static inline struct device_node *of_find_matching_node( } /** + * of_property_count_u8_elems - Count the number of u8 elements in a property + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * + * Search for a property in a device node and count the number of u8 elements + * in it. Returns number of elements on sucess, -EINVAL if the property does + * not exist or its length does not match a multiple of u8 and -ENODATA if the + * property does not have a value. + */ +static inline int of_property_count_u8_elems(const struct device_node *np, + const char *propname) +{ + return of_property_count_elems_of_size(np, propname, sizeof(u8)); +} + +/** + * of_property_count_u16_elems - Count the number of u16 elements in a property + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * + * Search for a property in a device node and count the number of u16 elements + * in it. Returns number of elements on sucess, -EINVAL if the property does + * not exist or its length does not match a multiple of u16 and -ENODATA if the + * property does not have a value. + */ +static inline int of_property_count_u16_elems(const struct device_node *np, + const char *propname) +{ + return of_property_count_elems_of_size(np, propname, sizeof(u16)); +} + +/** + * of_property_count_u32_elems - Count the number of u32 elements in a property + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * + * Search for a property in a device node and count the number of u32 elements + * in it. Returns number of elements on sucess, -EINVAL if the property does + * not exist or its length does not match a multiple of u32 and -ENODATA if the + * property does not have a value. + */ +static inline int of_property_count_u32_elems(const struct device_node *np, + const char *propname) +{ + return of_property_count_elems_of_size(np, propname, sizeof(u32)); +} + +/** + * of_property_count_u64_elems - Count the number of u64 elements in a property + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * + * Search for a property in a device node and count the number of u64 elements + * in it. Returns number of elements on sucess, -EINVAL if the property does + * not exist or its length does not match a multiple of u64 and -ENODATA if the + * property does not have a value. + */ +static inline int of_property_count_u64_elems(const struct device_node *np, + const char *propname) +{ + return of_property_count_elems_of_size(np, propname, sizeof(u64)); +} + +/** * of_property_read_bool - Findfrom a property * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 9370e65348a4..bbe03a1924c0 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -228,10 +228,14 @@ enum regulator_type { * output when using regulator_set_voltage_sel_regmap * @enable_reg: Register for control when using regmap enable/disable ops * @enable_mask: Mask for control when using regmap enable/disable ops + * @enable_val: Enabling value for control when using regmap enable/disable ops + * @disable_val: Disabling value for control when using regmap enable/disable ops * @enable_is_inverted: A flag to indicate set enable_mask bits to disable * when using regulator_enable_regmap and friends APIs. * @bypass_reg: Register for control when using regmap set_bypass * @bypass_mask: Mask for control when using regmap set_bypass + * @bypass_val_on: Enabling value for control when using regmap set_bypass + * @bypass_val_off: Disabling value for control when using regmap set_bypass * * @enable_time: Time taken for initial enable of regulator (in uS). */ @@ -263,9 +267,13 @@ struct regulator_desc { unsigned int apply_bit; unsigned int enable_reg; unsigned int enable_mask; + unsigned int enable_val; + unsigned int disable_val; bool enable_is_inverted; unsigned int bypass_reg; unsigned int bypass_mask; + unsigned int bypass_val_on; + unsigned int bypass_val_off; unsigned int enable_time; }; diff --git a/include/linux/regulator/pfuze100.h b/include/linux/regulator/pfuze100.h index 65d550bf3954..364f7a7c43db 100644 --- a/include/linux/regulator/pfuze100.h +++ b/include/linux/regulator/pfuze100.h @@ -35,6 +35,20 @@ #define PFUZE100_VGEN6 14 #define PFUZE100_MAX_REGULATOR 15 +#define PFUZE200_SW1AB 0 +#define PFUZE200_SW2 1 +#define PFUZE200_SW3A 2 +#define PFUZE200_SW3B 3 +#define PFUZE200_SWBST 4 +#define PFUZE200_VSNVS 5 +#define PFUZE200_VREFDDR 6 +#define PFUZE200_VGEN1 7 +#define PFUZE200_VGEN2 8 +#define PFUZE200_VGEN3 9 +#define PFUZE200_VGEN4 10 +#define PFUZE200_VGEN5 11 +#define PFUZE200_VGEN6 12 + struct regulator_init_data; struct pfuze_regulator_platform_data { |