regulator: Updates for v4.4
This is quite a quiet release in terms of volume of patches but it includes a couple of really nice core changes - the work Sascha has done in particular is something I've wanted to get done for a long time but just never got round to myself. Highlights include: - Support from Sascha Hauer for setting the voltage of parent supplies based on requests from their children. This is used both to allow set_voltage() to work through a dumb switch and to improve the efficiency of systems where DCDCs are used to supply LDOs by minimising the voltage drop over the LDOs. - Removal of regulator_list by Tomeu Vizoso, meaning we're not duplicating the device list maintained by the driver core. - Support for Wolfson/Cirrus WM8998 and WM1818. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJWOez1AAoJECTWi3JdVIfQZSoH/jk2EQCG7hSIY6qVviHh+zQI TWULXDnldyfT4eCYNAhwe/oQjFs7ngPXz9UpMAQwtWfWNoLBifF+Y5+X413nHY82 pKoRd+DQ1sIzGZb2YB0kS22Zg49Jilgv3y2Cw0aZuL7aqq7CEUGN3itEeWxqW9j8 a1ORD4d2zgki4gK9fUBTiur/dIhMn+8Gi4CmBvujsSCQR4Z5UNOjiodTU0NONiBX znejoAoLJXzAyAoWN+p6sEvi9Gpx4QTV6tBOo56WPlzBgTX2qOFhhmJiQQ1rIJOv MucgNn+cocarWfMyQwvqa0CL4ufjJm2DcYoIhfc2jZip/mAeqcbxpj5bxWzaLec= =CX2S -----END PGP SIGNATURE----- Merge tag 'regulator-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator Pull regulator updates from Mark Brown: "This is quite a quiet release in terms of volume of patches but it includes a couple of really nice core changes - the work Sascha has done in particular is something I've wanted to get done for a long time but just never got round to myself. Highlights include: - Support from Sascha Hauer for setting the voltage of parent supplies based on requests from their children. This is used both to allow set_voltage() to work through a dumb switch and to improve the efficiency of systems where DCDCs are used to supply LDOs by minimising the voltage drop over the LDOs. - Removal of regulator_list by Tomeu Vizoso, meaning we're not duplicating the device list maintained by the driver core. - Support for Wolfson/Cirrus WM8998 and WM1818" * tag 'regulator-v4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (29 commits) regulator: Use regulator_lock_supply() for get_voltage() too regulator: arizona: Add regulator specific device tree binding document regulator: stw481x: compile on COMPILE_TEST regulator: qcom-smd: Correct set_load() unit regulator: core: Propagate voltage changes to supply regulators regulator: core: Factor out regulator_map_voltage regulator: i.MX anatop: Allow supply regulator regulator: introduce min_dropout_uV regulator: core: create unlocked version of regulator_set_voltage regulator: arizona-ldo1: Fix handling of GPIO 0 regulator: da9053: Update regulator for DA9053 BC silicon support regulator: max77802: Separate sections for nodes and properties regulator: max77802: Add input supply properties to DT binding doc regulator: axp20x: set supply names for AXP22X DC1SW/DC5LDO internally regulator: axp20x: Drop AXP221 DC1SW and DC5LDO regulator supplies from bindings mfd: tps6105x: Use i2c regmap to access registers regulator: act8865: add DT binding for property "active-semi,vsel-high" regulator: act8865: support output voltage by VSET2[] bits regulator: arizona: add support for WM8998 and WM1814 regulator: core: create unlocked version of regulator_list_voltage ...
This commit is contained in:
Коммит
52787e91bf
|
@ -60,8 +60,8 @@ DCDC2 : DC-DC buck : vin2-supply
|
|||
DCDC3 : DC-DC buck : vin3-supply
|
||||
DCDC4 : DC-DC buck : vin4-supply
|
||||
DCDC5 : DC-DC buck : vin5-supply
|
||||
DC1SW : On/Off Switch : dcdc1-supply : DCDC1 secondary output
|
||||
DC5LDO : LDO : dcdc5-supply : input from DCDC5
|
||||
DC1SW : On/Off Switch : : DCDC1 secondary output
|
||||
DC5LDO : LDO : : input from DCDC5
|
||||
ALDO1 : LDO : aldoin-supply : shared supply
|
||||
ALDO2 : LDO : aldoin-supply : shared supply
|
||||
ALDO3 : LDO : aldoin-supply : shared supply
|
||||
|
|
|
@ -8,6 +8,8 @@ Required properties:
|
|||
Optional properties:
|
||||
- system-power-controller: Telling whether or not this pmic is controlling
|
||||
the system power. See Documentation/devicetree/bindings/power/power-controller.txt .
|
||||
- active-semi,vsel-high: Indicates the VSEL pin is high.
|
||||
If this property is missing, assume the VSEL pin is low(0).
|
||||
|
||||
Optional input supply properties:
|
||||
- for act8600:
|
||||
|
@ -49,6 +51,7 @@ Example:
|
|||
pmic: act8865@5b {
|
||||
compatible = "active-semi,act8865";
|
||||
reg = <0x5b>;
|
||||
active-semi,vsel-high;
|
||||
status = "disabled";
|
||||
|
||||
regulators {
|
||||
|
|
|
@ -13,6 +13,7 @@ Optional properties:
|
|||
- anatop-delay-reg-offset: Anatop MFD step time register offset
|
||||
- anatop-delay-bit-shift: Bit shift for the step time register
|
||||
- anatop-delay-bit-width: Number of bits used in the step time register
|
||||
- vin-supply: The supply for this regulator
|
||||
|
||||
Any property defined as part of the core regulator
|
||||
binding, defined in regulator.txt, can also be used.
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
Cirrus Logic Arizona class audio SoCs
|
||||
|
||||
These devices are audio SoCs with extensive digital capabilities and a range
|
||||
of analogue I/O.
|
||||
|
||||
This document lists regulator specific bindings, see the primary binding
|
||||
document:
|
||||
../mfd/arizona.txt
|
||||
|
||||
Optional properties:
|
||||
- wlf,ldoena : GPIO specifier for the GPIO controlling LDOENA
|
||||
|
||||
Optional subnodes:
|
||||
- ldo1 : Initial data for the LDO1 regulator, as covered in
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
- micvdd : Initial data for the MICVDD regulator, as covered in
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt
|
|
@ -8,7 +8,28 @@ regulators that can be controlled over I2C.
|
|||
|
||||
Following properties should be present in main device node of the MFD chip.
|
||||
|
||||
Optional node:
|
||||
Optional properties:
|
||||
- inb1-supply: The input supply for BUCK1
|
||||
- inb2-supply: The input supply for BUCK2
|
||||
- inb3-supply: The input supply for BUCK3
|
||||
- inb4-supply: The input supply for BUCK4
|
||||
- inb5-supply: The input supply for BUCK5
|
||||
- inb6-supply: The input supply for BUCK6
|
||||
- inb7-supply: The input supply for BUCK7
|
||||
- inb8-supply: The input supply for BUCK8
|
||||
- inb9-supply: The input supply for BUCK9
|
||||
- inb10-supply: The input supply for BUCK10
|
||||
- inl1-supply: The input supply for LDO8 and LDO15
|
||||
- inl2-supply: The input supply for LDO17, LDO27, LDO30 and LDO35
|
||||
- inl3-supply: The input supply for LDO3, LDO5, LDO6 and LDO7
|
||||
- inl4-supply: The input supply for LDO10, LDO11, LDO13 and LDO14
|
||||
- inl5-supply: The input supply for LDO9 and LDO19
|
||||
- inl6-supply: The input supply for LDO4, LDO21, LDO24 and LDO33
|
||||
- inl7-supply: The input supply for LDO18, LDO20, LDO28 and LDO29
|
||||
- inl9-supply: The input supply for LDO12, LDO23, LDO25, LDO26, LDO32 and LDO34
|
||||
- inl10-supply: The input supply for LDO1 and LDO2
|
||||
|
||||
Optional nodes:
|
||||
- regulators : The regulators of max77802 have to be instantiated
|
||||
under subnode named "regulators" using the following format.
|
||||
|
||||
|
@ -58,6 +79,8 @@ Example:
|
|||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
inb1-supply = <&parent_reg>;
|
||||
|
||||
regulators {
|
||||
ldo1_reg: LDO1 {
|
||||
regulator-name = "vdd_1v0";
|
||||
|
|
|
@ -11,6 +11,7 @@ Optional properties:
|
|||
- regulator-always-on: boolean, regulator should never be disabled
|
||||
- regulator-boot-on: bootloader/firmware enabled regulator
|
||||
- regulator-allow-bypass: allow the regulator to go into bypass mode
|
||||
- regulator-allow-set-load: allow the regulator performance level to be configured
|
||||
- <name>-supply: phandle to the parent supply/regulator node
|
||||
- regulator-ramp-delay: ramp delay for regulator(in uV/uS)
|
||||
For hardware which supports disabling ramp rate, it should be explicitly
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
TPS65023 family of regulators
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be one of the following.
|
||||
"ti,tps65020",
|
||||
"ti,tps65021",
|
||||
"ti,tps65023",
|
||||
- reg: I2C slave address
|
||||
- regulators: list of regulators provided by this controller, must be named
|
||||
after their hardware counterparts: VDCDC[1-3] and LDO[1-2]
|
||||
- regulators: This is the list of child nodes that specify the regulator
|
||||
initialization data for defined regulators. The definition for each of
|
||||
these nodes is defined using the standard binding for regulators found at
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt.
|
||||
|
||||
Each regulator is defined using the standard binding for regulators.
|
||||
|
||||
Example:
|
||||
|
||||
tps65023@48 {
|
||||
compatible = "ti,tps65023";
|
||||
reg = <0x48>;
|
||||
|
||||
regulators {
|
||||
VDCDC1 {
|
||||
regulator-name = "vdd_mpu";
|
||||
regulator-always-on;
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <1200000>;
|
||||
};
|
||||
|
||||
VDCDC2 {
|
||||
regulator-name = "vdd_core";
|
||||
regulator-always-on;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
|
||||
VDCDC3 {
|
||||
regulator-name = "vdd_io";
|
||||
regulator-always-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
};
|
||||
|
||||
LDO1 {
|
||||
regulator-name = "vdd_usb18";
|
||||
regulator-always-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
};
|
||||
|
||||
LDO2 {
|
||||
regulator-name = "vdd_usb33";
|
||||
regulator-always-on;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -16,7 +16,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -25,73 +25,18 @@
|
|||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tps6105x.h>
|
||||
|
||||
int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&tps6105x->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value);
|
||||
mutex_unlock(&tps6105x->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tps6105x_set);
|
||||
|
||||
int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&tps6105x->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
|
||||
mutex_unlock(&tps6105x->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*buf = ret;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tps6105x_get);
|
||||
|
||||
/*
|
||||
* Masks off the bits in the mask and sets the bits in the bitvalues
|
||||
* parameter in one atomic operation
|
||||
*/
|
||||
int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
|
||||
u8 bitmask, u8 bitvalues)
|
||||
{
|
||||
int ret;
|
||||
u8 regval;
|
||||
|
||||
ret = mutex_lock_interruptible(&tps6105x->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = i2c_smbus_read_byte_data(tps6105x->client, reg);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
regval = ret;
|
||||
regval = (~bitmask & regval) | (bitmask & bitvalues);
|
||||
ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval);
|
||||
fail:
|
||||
mutex_unlock(&tps6105x->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tps6105x_mask_and_set);
|
||||
static struct regmap_config tps6105x_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = TPS6105X_REG_3,
|
||||
};
|
||||
|
||||
static int tps6105x_startup(struct tps6105x *tps6105x)
|
||||
{
|
||||
int ret;
|
||||
u8 regval;
|
||||
unsigned int regval;
|
||||
|
||||
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val);
|
||||
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
switch (regval >> TPS6105X_REG0_MODE_SHIFT) {
|
||||
|
@ -145,11 +90,14 @@ static int tps6105x_probe(struct i2c_client *client,
|
|||
if (!tps6105x)
|
||||
return -ENOMEM;
|
||||
|
||||
tps6105x->regmap = devm_regmap_init_i2c(client, &tps6105x_regmap_config);
|
||||
if (IS_ERR(tps6105x->regmap))
|
||||
return PTR_ERR(tps6105x->regmap);
|
||||
|
||||
i2c_set_clientdata(client, tps6105x);
|
||||
tps6105x->client = client;
|
||||
pdata = dev_get_platdata(&client->dev);
|
||||
tps6105x->pdata = pdata;
|
||||
mutex_init(&tps6105x->lock);
|
||||
|
||||
ret = tps6105x_startup(tps6105x);
|
||||
if (ret) {
|
||||
|
@ -198,7 +146,7 @@ static int tps6105x_remove(struct i2c_client *client)
|
|||
mfd_remove_devices(&client->dev);
|
||||
|
||||
/* Put chip in shutdown mode */
|
||||
tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
|
||||
regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_MODE_MASK,
|
||||
TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
|
||||
|
||||
|
|
|
@ -627,7 +627,7 @@ config REGULATOR_TI_ABB
|
|||
|
||||
config REGULATOR_STW481X_VMMC
|
||||
bool "ST Microelectronics STW481X VMMC regulator"
|
||||
depends on MFD_STW481X
|
||||
depends on MFD_STW481X || COMPILE_TEST
|
||||
default y if MFD_STW481X
|
||||
help
|
||||
This driver supports the internal VMMC regulator in the STw481x
|
||||
|
|
|
@ -261,6 +261,16 @@ static const struct regulator_desc act8865_regulators[] = {
|
|||
ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
|
||||
};
|
||||
|
||||
static const struct regulator_desc act8865_alt_regulators[] = {
|
||||
ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET2, "vp1"),
|
||||
ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET2, "vp2"),
|
||||
ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET2, "vp3"),
|
||||
ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"),
|
||||
ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"),
|
||||
ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"),
|
||||
ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id act8865_dt_ids[] = {
|
||||
{ .compatible = "active-semi,act8600", .data = (void *)ACT8600 },
|
||||
|
@ -413,6 +423,7 @@ static int act8865_pmic_probe(struct i2c_client *client,
|
|||
struct act8865 *act8865;
|
||||
unsigned long type;
|
||||
int off_reg, off_mask;
|
||||
int voltage_select = 0;
|
||||
|
||||
pdata = dev_get_platdata(dev);
|
||||
|
||||
|
@ -424,6 +435,10 @@ static int act8865_pmic_probe(struct i2c_client *client,
|
|||
return -ENODEV;
|
||||
|
||||
type = (unsigned long) id->data;
|
||||
|
||||
voltage_select = !!of_get_property(dev->of_node,
|
||||
"active-semi,vsel-high",
|
||||
NULL);
|
||||
} else {
|
||||
type = i2c_id->driver_data;
|
||||
}
|
||||
|
@ -442,8 +457,13 @@ static int act8865_pmic_probe(struct i2c_client *client,
|
|||
off_mask = ACT8846_OFF_SYSMASK;
|
||||
break;
|
||||
case ACT8865:
|
||||
regulators = act8865_regulators;
|
||||
num_regulators = ARRAY_SIZE(act8865_regulators);
|
||||
if (voltage_select) {
|
||||
regulators = act8865_alt_regulators;
|
||||
num_regulators = ARRAY_SIZE(act8865_alt_regulators);
|
||||
} else {
|
||||
regulators = act8865_regulators;
|
||||
num_regulators = ARRAY_SIZE(act8865_regulators);
|
||||
}
|
||||
off_reg = ACT8865_SYS_CTRL;
|
||||
off_mask = ACT8865_MSTROFF;
|
||||
break;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */
|
||||
#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */
|
||||
|
@ -199,6 +200,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
|
|||
rdesc->owner = THIS_MODULE;
|
||||
|
||||
initdata = of_get_regulator_init_data(dev, np, rdesc);
|
||||
initdata->supply_regulator = "vin";
|
||||
sreg->initdata = initdata;
|
||||
|
||||
anatop_np = of_get_parent(np);
|
||||
|
@ -262,6 +264,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
|
|||
rdesc->vsel_reg = sreg->control_reg;
|
||||
rdesc->vsel_mask = ((1 << sreg->vol_bit_width) - 1) <<
|
||||
sreg->vol_bit_shift;
|
||||
rdesc->min_dropout_uV = 125000;
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.init_data = initdata;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
@ -189,13 +190,22 @@ static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
|
|||
{
|
||||
struct arizona_pdata *pdata = &arizona->pdata;
|
||||
struct arizona_ldo1 *ldo1 = config->driver_data;
|
||||
struct device_node *np = arizona->dev->of_node;
|
||||
struct device_node *init_node, *dcvdd_node;
|
||||
struct regulator_init_data *init_data;
|
||||
|
||||
pdata->ldoena = arizona_of_get_named_gpio(arizona, "wlf,ldoena", true);
|
||||
pdata->ldoena = of_get_named_gpio(np, "wlf,ldoena", 0);
|
||||
if (pdata->ldoena < 0) {
|
||||
dev_warn(arizona->dev,
|
||||
"LDOENA GPIO property missing/malformed: %d\n",
|
||||
pdata->ldoena);
|
||||
pdata->ldoena = 0;
|
||||
} else {
|
||||
config->ena_gpio_initialized = true;
|
||||
}
|
||||
|
||||
init_node = of_get_child_by_name(arizona->dev->of_node, "ldo1");
|
||||
dcvdd_node = of_parse_phandle(arizona->dev->of_node, "DCVDD-supply", 0);
|
||||
init_node = of_get_child_by_name(np, "ldo1");
|
||||
dcvdd_node = of_parse_phandle(np, "DCVDD-supply", 0);
|
||||
|
||||
if (init_node) {
|
||||
config->of_node = init_node;
|
||||
|
@ -245,6 +255,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
|
|||
switch (arizona->type) {
|
||||
case WM5102:
|
||||
case WM8997:
|
||||
case WM8998:
|
||||
case WM1814:
|
||||
desc = &arizona_ldo1_hc;
|
||||
ldo1->init_data = arizona_ldo1_dvfs;
|
||||
break;
|
||||
|
@ -272,8 +284,6 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
|
|||
ret = arizona_ldo1_of_get_pdata(arizona, &config, desc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
config.ena_gpio_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -196,10 +196,10 @@ static const struct regulator_desc axp22x_regulators[] = {
|
|||
AXP_DESC(AXP22X, DCDC5, "dcdc5", "vin5", 1000, 2550, 50,
|
||||
AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)),
|
||||
/* secondary switchable output of DCDC1 */
|
||||
AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", "dcdc1", 1600, 3400, 100,
|
||||
AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL, 1600, 3400, 100,
|
||||
AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(7)),
|
||||
/* LDO regulator internally chained to DCDC5 */
|
||||
AXP_DESC(AXP22X, DC5LDO, "dc5ldo", "dcdc5", 700, 1400, 100,
|
||||
AXP_DESC(AXP22X, DC5LDO, "dc5ldo", NULL, 700, 1400, 100,
|
||||
AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)),
|
||||
AXP_DESC(AXP22X, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
|
||||
AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)),
|
||||
|
@ -350,6 +350,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
|
|||
};
|
||||
int ret, i, nregulators;
|
||||
u32 workmode;
|
||||
const char *axp22x_dc1_name = axp22x_regulators[AXP22X_DCDC1].name;
|
||||
const char *axp22x_dc5_name = axp22x_regulators[AXP22X_DCDC5].name;
|
||||
|
||||
switch (axp20x->variant) {
|
||||
case AXP202_ID:
|
||||
|
@ -371,8 +373,37 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
|
|||
axp20x_regulator_parse_dt(pdev);
|
||||
|
||||
for (i = 0; i < nregulators; i++) {
|
||||
rdev = devm_regulator_register(&pdev->dev, ®ulators[i],
|
||||
&config);
|
||||
const struct regulator_desc *desc = ®ulators[i];
|
||||
struct regulator_desc *new_desc;
|
||||
|
||||
/*
|
||||
* Regulators DC1SW and DC5LDO are connected internally,
|
||||
* so we have to handle their supply names separately.
|
||||
*
|
||||
* We always register the regulators in proper sequence,
|
||||
* so the supply names are correctly read. See the last
|
||||
* part of this loop to see where we save the DT defined
|
||||
* name.
|
||||
*/
|
||||
if (regulators == axp22x_regulators) {
|
||||
if (i == AXP22X_DC1SW) {
|
||||
new_desc = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*desc),
|
||||
GFP_KERNEL);
|
||||
*new_desc = regulators[i];
|
||||
new_desc->supply_name = axp22x_dc1_name;
|
||||
desc = new_desc;
|
||||
} else if (i == AXP22X_DC5LDO) {
|
||||
new_desc = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*desc),
|
||||
GFP_KERNEL);
|
||||
*new_desc = regulators[i];
|
||||
new_desc->supply_name = axp22x_dc5_name;
|
||||
desc = new_desc;
|
||||
}
|
||||
}
|
||||
|
||||
rdev = devm_regulator_register(&pdev->dev, desc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(&pdev->dev, "Failed to register %s\n",
|
||||
regulators[i].name);
|
||||
|
@ -388,6 +419,21 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "Failed to set workmode on %s\n",
|
||||
rdev->desc->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save AXP22X DCDC1 / DCDC5 regulator names for later.
|
||||
*/
|
||||
if (regulators == axp22x_regulators) {
|
||||
/* Can we use rdev->constraints->name instead? */
|
||||
if (i == AXP22X_DCDC1)
|
||||
of_property_read_string(rdev->dev.of_node,
|
||||
"regulator-name",
|
||||
&axp22x_dc1_name);
|
||||
else if (i == AXP22X_DCDC5)
|
||||
of_property_read_string(rdev->dev.of_node,
|
||||
"regulator-name",
|
||||
&axp22x_dc5_name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -244,7 +244,7 @@ static int bcm590xx_get_enable_register(int id)
|
|||
break;
|
||||
case BCM590XX_REG_VBUS:
|
||||
reg = BCM590XX_OTG_CTRL;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return reg;
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
|
||||
|
||||
static DEFINE_MUTEX(regulator_list_mutex);
|
||||
static LIST_HEAD(regulator_list);
|
||||
static LIST_HEAD(regulator_map_list);
|
||||
static LIST_HEAD(regulator_ena_gpio_list);
|
||||
static LIST_HEAD(regulator_supply_alias_list);
|
||||
|
@ -59,6 +58,8 @@ static bool has_full_constraints;
|
|||
|
||||
static struct dentry *debugfs_root;
|
||||
|
||||
static struct class regulator_class;
|
||||
|
||||
/*
|
||||
* struct regulator_map
|
||||
*
|
||||
|
@ -131,6 +132,45 @@ static bool have_full_constraints(void)
|
|||
return has_full_constraints || of_have_populated_dt();
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_lock_supply - lock a regulator and its supplies
|
||||
* @rdev: regulator source
|
||||
*/
|
||||
static void regulator_lock_supply(struct regulator_dev *rdev)
|
||||
{
|
||||
struct regulator *supply;
|
||||
int i = 0;
|
||||
|
||||
while (1) {
|
||||
mutex_lock_nested(&rdev->mutex, i++);
|
||||
supply = rdev->supply;
|
||||
|
||||
if (!rdev->supply)
|
||||
return;
|
||||
|
||||
rdev = supply->rdev;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_unlock_supply - unlock a regulator and its supplies
|
||||
* @rdev: regulator source
|
||||
*/
|
||||
static void regulator_unlock_supply(struct regulator_dev *rdev)
|
||||
{
|
||||
struct regulator *supply;
|
||||
|
||||
while (1) {
|
||||
mutex_unlock(&rdev->mutex);
|
||||
supply = rdev->supply;
|
||||
|
||||
if (!rdev->supply)
|
||||
return;
|
||||
|
||||
rdev = supply->rdev;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* of_get_regulator - get a regulator device node based on supply name
|
||||
* @dev: Device pointer for the consumer (of regulator) device
|
||||
|
@ -180,7 +220,7 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
|
|||
return -ENODEV;
|
||||
}
|
||||
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
|
||||
rdev_err(rdev, "operation not allowed\n");
|
||||
rdev_err(rdev, "voltage operation not allowed\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
@ -240,7 +280,7 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
|
|||
return -ENODEV;
|
||||
}
|
||||
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
|
||||
rdev_err(rdev, "operation not allowed\n");
|
||||
rdev_err(rdev, "current operation not allowed\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
@ -277,7 +317,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
|
|||
return -ENODEV;
|
||||
}
|
||||
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
|
||||
rdev_err(rdev, "operation not allowed\n");
|
||||
rdev_err(rdev, "mode operation not allowed\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
@ -301,7 +341,7 @@ static int regulator_check_drms(struct regulator_dev *rdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
|
||||
rdev_dbg(rdev, "operation not allowed\n");
|
||||
rdev_dbg(rdev, "drms operation not allowed\n");
|
||||
return -EPERM;
|
||||
}
|
||||
return 0;
|
||||
|
@ -1325,6 +1365,47 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
|
|||
}
|
||||
}
|
||||
|
||||
static int of_node_match(struct device *dev, const void *data)
|
||||
{
|
||||
return dev->of_node == data;
|
||||
}
|
||||
|
||||
static struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = class_find_device(®ulator_class, NULL, np, of_node_match);
|
||||
|
||||
return dev ? dev_to_rdev(dev) : NULL;
|
||||
}
|
||||
|
||||
static int regulator_match(struct device *dev, const void *data)
|
||||
{
|
||||
struct regulator_dev *r = dev_to_rdev(dev);
|
||||
|
||||
return strcmp(rdev_get_name(r), data) == 0;
|
||||
}
|
||||
|
||||
static struct regulator_dev *regulator_lookup_by_name(const char *name)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = class_find_device(®ulator_class, NULL, name, regulator_match);
|
||||
|
||||
return dev ? dev_to_rdev(dev) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_dev_lookup - lookup a regulator device.
|
||||
* @dev: device for regulator "consumer".
|
||||
* @supply: Supply name or regulator ID.
|
||||
* @ret: 0 on success, -ENODEV if lookup fails permanently, -EPROBE_DEFER if
|
||||
* lookup could succeed in the future.
|
||||
*
|
||||
* If successful, returns a struct regulator_dev that corresponds to the name
|
||||
* @supply and with the embedded struct device refcount incremented by one,
|
||||
* or NULL on failure. The refcount must be dropped by calling put_device().
|
||||
*/
|
||||
static struct regulator_dev *regulator_dev_lookup(struct device *dev,
|
||||
const char *supply,
|
||||
int *ret)
|
||||
|
@ -1340,10 +1421,9 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
|
|||
if (dev && dev->of_node) {
|
||||
node = of_get_regulator(dev, supply);
|
||||
if (node) {
|
||||
list_for_each_entry(r, ®ulator_list, list)
|
||||
if (r->dev.parent &&
|
||||
node == r->dev.of_node)
|
||||
return r;
|
||||
r = of_find_regulator_by_node(node);
|
||||
if (r)
|
||||
return r;
|
||||
*ret = -EPROBE_DEFER;
|
||||
return NULL;
|
||||
} else {
|
||||
|
@ -1361,20 +1441,24 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
|
|||
if (dev)
|
||||
devname = dev_name(dev);
|
||||
|
||||
list_for_each_entry(r, ®ulator_list, list)
|
||||
if (strcmp(rdev_get_name(r), supply) == 0)
|
||||
return r;
|
||||
r = regulator_lookup_by_name(supply);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
list_for_each_entry(map, ®ulator_map_list, list) {
|
||||
/* If the mapping has a device set up it must match */
|
||||
if (map->dev_name &&
|
||||
(!devname || strcmp(map->dev_name, devname)))
|
||||
continue;
|
||||
|
||||
if (strcmp(map->supply, supply) == 0)
|
||||
if (strcmp(map->supply, supply) == 0 &&
|
||||
get_device(&map->regulator->dev)) {
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
return map->regulator;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1409,6 +1493,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
|
|||
|
||||
if (have_full_constraints()) {
|
||||
r = dummy_regulator_rdev;
|
||||
get_device(&r->dev);
|
||||
} else {
|
||||
dev_err(dev, "Failed to resolve %s-supply for %s\n",
|
||||
rdev->supply_name, rdev->desc->name);
|
||||
|
@ -1418,12 +1503,16 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
|
|||
|
||||
/* Recursively resolve the supply of the supply */
|
||||
ret = regulator_resolve_supply(r);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
put_device(&r->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = set_supply(rdev, r);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
put_device(&r->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Cascade always-on state to supply */
|
||||
if (_regulator_is_enabled(rdev) && rdev->supply) {
|
||||
|
@ -1459,8 +1548,6 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
|
|||
else
|
||||
ret = -EPROBE_DEFER;
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
|
||||
rdev = regulator_dev_lookup(dev, id, &ret);
|
||||
if (rdev)
|
||||
goto found;
|
||||
|
@ -1472,7 +1559,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
|
|||
* succeed, so, quit with appropriate error value
|
||||
*/
|
||||
if (ret && ret != -ENODEV)
|
||||
goto out;
|
||||
return regulator;
|
||||
|
||||
if (!devname)
|
||||
devname = "deviceless";
|
||||
|
@ -1486,40 +1573,46 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
|
|||
devname, id);
|
||||
|
||||
rdev = dummy_regulator_rdev;
|
||||
get_device(&rdev->dev);
|
||||
goto found;
|
||||
/* Don't log an error when called from regulator_get_optional() */
|
||||
} else if (!have_full_constraints() || exclusive) {
|
||||
dev_warn(dev, "dummy supplies not allowed\n");
|
||||
}
|
||||
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
return regulator;
|
||||
|
||||
found:
|
||||
if (rdev->exclusive) {
|
||||
regulator = ERR_PTR(-EPERM);
|
||||
goto out;
|
||||
put_device(&rdev->dev);
|
||||
return regulator;
|
||||
}
|
||||
|
||||
if (exclusive && rdev->open_count) {
|
||||
regulator = ERR_PTR(-EBUSY);
|
||||
goto out;
|
||||
put_device(&rdev->dev);
|
||||
return regulator;
|
||||
}
|
||||
|
||||
ret = regulator_resolve_supply(rdev);
|
||||
if (ret < 0) {
|
||||
regulator = ERR_PTR(ret);
|
||||
goto out;
|
||||
put_device(&rdev->dev);
|
||||
return regulator;
|
||||
}
|
||||
|
||||
if (!try_module_get(rdev->owner))
|
||||
goto out;
|
||||
if (!try_module_get(rdev->owner)) {
|
||||
put_device(&rdev->dev);
|
||||
return regulator;
|
||||
}
|
||||
|
||||
regulator = create_regulator(rdev, dev, id);
|
||||
if (regulator == NULL) {
|
||||
regulator = ERR_PTR(-ENOMEM);
|
||||
put_device(&rdev->dev);
|
||||
module_put(rdev->owner);
|
||||
goto out;
|
||||
return regulator;
|
||||
}
|
||||
|
||||
rdev->open_count++;
|
||||
|
@ -1533,9 +1626,6 @@ found:
|
|||
rdev->use_count = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
|
||||
return regulator;
|
||||
}
|
||||
|
||||
|
@ -1633,6 +1723,7 @@ static void _regulator_put(struct regulator *regulator)
|
|||
|
||||
rdev->open_count--;
|
||||
rdev->exclusive = 0;
|
||||
put_device(&rdev->dev);
|
||||
mutex_unlock(&rdev->mutex);
|
||||
|
||||
kfree(regulator->supply_name);
|
||||
|
@ -2312,6 +2403,40 @@ static int _regulator_is_enabled(struct regulator_dev *rdev)
|
|||
return rdev->desc->ops->is_enabled(rdev);
|
||||
}
|
||||
|
||||
static int _regulator_list_voltage(struct regulator *regulator,
|
||||
unsigned selector, int lock)
|
||||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
const struct regulator_ops *ops = rdev->desc->ops;
|
||||
int ret;
|
||||
|
||||
if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector)
|
||||
return rdev->desc->fixed_uV;
|
||||
|
||||
if (ops->list_voltage) {
|
||||
if (selector >= rdev->desc->n_voltages)
|
||||
return -EINVAL;
|
||||
if (lock)
|
||||
mutex_lock(&rdev->mutex);
|
||||
ret = ops->list_voltage(rdev, selector);
|
||||
if (lock)
|
||||
mutex_unlock(&rdev->mutex);
|
||||
} else if (rdev->supply) {
|
||||
ret = _regulator_list_voltage(rdev->supply, selector, lock);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
if (ret < rdev->constraints->min_uV)
|
||||
ret = 0;
|
||||
else if (ret > rdev->constraints->max_uV)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_is_enabled - is the regulator output enabled
|
||||
* @regulator: regulator source
|
||||
|
@ -2401,33 +2526,7 @@ EXPORT_SYMBOL_GPL(regulator_count_voltages);
|
|||
*/
|
||||
int regulator_list_voltage(struct regulator *regulator, unsigned selector)
|
||||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
const struct regulator_ops *ops = rdev->desc->ops;
|
||||
int ret;
|
||||
|
||||
if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector)
|
||||
return rdev->desc->fixed_uV;
|
||||
|
||||
if (ops->list_voltage) {
|
||||
if (selector >= rdev->desc->n_voltages)
|
||||
return -EINVAL;
|
||||
mutex_lock(&rdev->mutex);
|
||||
ret = ops->list_voltage(rdev, selector);
|
||||
mutex_unlock(&rdev->mutex);
|
||||
} else if (rdev->supply) {
|
||||
ret = regulator_list_voltage(rdev->supply, selector);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
if (ret < rdev->constraints->min_uV)
|
||||
ret = 0;
|
||||
else if (ret > rdev->constraints->max_uV)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return _regulator_list_voltage(regulator, selector, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_list_voltage);
|
||||
|
||||
|
@ -2562,6 +2661,23 @@ int regulator_is_supported_voltage(struct regulator *regulator,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_is_supported_voltage);
|
||||
|
||||
static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
|
||||
int max_uV)
|
||||
{
|
||||
const struct regulator_desc *desc = rdev->desc;
|
||||
|
||||
if (desc->ops->map_voltage)
|
||||
return desc->ops->map_voltage(rdev, min_uV, max_uV);
|
||||
|
||||
if (desc->ops->list_voltage == regulator_list_voltage_linear)
|
||||
return regulator_map_voltage_linear(rdev, min_uV, max_uV);
|
||||
|
||||
if (desc->ops->list_voltage == regulator_list_voltage_linear_range)
|
||||
return regulator_map_voltage_linear_range(rdev, min_uV, max_uV);
|
||||
|
||||
return regulator_map_voltage_iterate(rdev, min_uV, max_uV);
|
||||
}
|
||||
|
||||
static int _regulator_call_set_voltage(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV,
|
||||
unsigned *selector)
|
||||
|
@ -2650,23 +2766,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
|||
}
|
||||
|
||||
} else if (rdev->desc->ops->set_voltage_sel) {
|
||||
if (rdev->desc->ops->map_voltage) {
|
||||
ret = rdev->desc->ops->map_voltage(rdev, min_uV,
|
||||
max_uV);
|
||||
} else {
|
||||
if (rdev->desc->ops->list_voltage ==
|
||||
regulator_list_voltage_linear)
|
||||
ret = regulator_map_voltage_linear(rdev,
|
||||
min_uV, max_uV);
|
||||
else if (rdev->desc->ops->list_voltage ==
|
||||
regulator_list_voltage_linear_range)
|
||||
ret = regulator_map_voltage_linear_range(rdev,
|
||||
min_uV, max_uV);
|
||||
else
|
||||
ret = regulator_map_voltage_iterate(rdev,
|
||||
min_uV, max_uV);
|
||||
}
|
||||
|
||||
ret = regulator_map_voltage(rdev, min_uV, max_uV);
|
||||
if (ret >= 0) {
|
||||
best_val = rdev->desc->ops->list_voltage(rdev, ret);
|
||||
if (min_uV <= best_val && max_uV >= best_val) {
|
||||
|
@ -2717,32 +2817,15 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_set_voltage - set regulator output voltage
|
||||
* @regulator: regulator source
|
||||
* @min_uV: Minimum required voltage in uV
|
||||
* @max_uV: Maximum acceptable voltage in uV
|
||||
*
|
||||
* Sets a voltage regulator to the desired output voltage. This can be set
|
||||
* during any regulator state. IOW, regulator can be disabled or enabled.
|
||||
*
|
||||
* If the regulator is enabled then the voltage will change to the new value
|
||||
* immediately otherwise if the regulator is disabled the regulator will
|
||||
* output at the new voltage when enabled.
|
||||
*
|
||||
* NOTE: If the regulator is shared between several devices then the lowest
|
||||
* request voltage that meets the system constraints will be used.
|
||||
* Regulator system constraints must be set for this regulator before
|
||||
* calling this function otherwise this call will fail.
|
||||
*/
|
||||
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
|
||||
static int regulator_set_voltage_unlocked(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);
|
||||
int best_supply_uV = 0;
|
||||
int supply_change_uV = 0;
|
||||
|
||||
/* If we're setting the same range as last time the change
|
||||
* should be a noop (some cpufreq implementations use the same
|
||||
|
@ -2786,17 +2869,95 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
|
|||
if (ret < 0)
|
||||
goto out2;
|
||||
|
||||
if (rdev->supply && (rdev->desc->min_dropout_uV ||
|
||||
!rdev->desc->ops->get_voltage)) {
|
||||
int current_supply_uV;
|
||||
int selector;
|
||||
|
||||
selector = regulator_map_voltage(rdev, min_uV, max_uV);
|
||||
if (selector < 0) {
|
||||
ret = selector;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
best_supply_uV = _regulator_list_voltage(regulator, selector, 0);
|
||||
if (best_supply_uV < 0) {
|
||||
ret = best_supply_uV;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
best_supply_uV += rdev->desc->min_dropout_uV;
|
||||
|
||||
current_supply_uV = _regulator_get_voltage(rdev->supply->rdev);
|
||||
if (current_supply_uV < 0) {
|
||||
ret = current_supply_uV;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
supply_change_uV = best_supply_uV - current_supply_uV;
|
||||
}
|
||||
|
||||
if (supply_change_uV > 0) {
|
||||
ret = regulator_set_voltage_unlocked(rdev->supply,
|
||||
best_supply_uV, INT_MAX);
|
||||
if (ret) {
|
||||
dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n",
|
||||
ret);
|
||||
goto out2;
|
||||
}
|
||||
}
|
||||
|
||||
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
|
||||
if (ret < 0)
|
||||
goto out2;
|
||||
|
||||
if (supply_change_uV < 0) {
|
||||
ret = regulator_set_voltage_unlocked(rdev->supply,
|
||||
best_supply_uV, INT_MAX);
|
||||
if (ret)
|
||||
dev_warn(&rdev->dev, "Failed to decrease supply voltage: %d\n",
|
||||
ret);
|
||||
/* No need to fail here */
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&rdev->mutex);
|
||||
return ret;
|
||||
out2:
|
||||
regulator->min_uV = old_min_uV;
|
||||
regulator->max_uV = old_max_uV;
|
||||
mutex_unlock(&rdev->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_set_voltage - set regulator output voltage
|
||||
* @regulator: regulator source
|
||||
* @min_uV: Minimum required voltage in uV
|
||||
* @max_uV: Maximum acceptable voltage in uV
|
||||
*
|
||||
* Sets a voltage regulator to the desired output voltage. This can be set
|
||||
* during any regulator state. IOW, regulator can be disabled or enabled.
|
||||
*
|
||||
* If the regulator is enabled then the voltage will change to the new value
|
||||
* immediately otherwise if the regulator is disabled the regulator will
|
||||
* output at the new voltage when enabled.
|
||||
*
|
||||
* NOTE: If the regulator is shared between several devices then the lowest
|
||||
* request voltage that meets the system constraints will be used.
|
||||
* Regulator system constraints must be set for this regulator before
|
||||
* calling this function otherwise this call will fail.
|
||||
*/
|
||||
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
regulator_lock_supply(regulator->rdev);
|
||||
|
||||
ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV);
|
||||
|
||||
regulator_unlock_supply(regulator->rdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_set_voltage);
|
||||
|
@ -2949,7 +3110,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
|
|||
} else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) {
|
||||
ret = rdev->desc->fixed_uV;
|
||||
} else if (rdev->supply) {
|
||||
ret = regulator_get_voltage(rdev->supply);
|
||||
ret = _regulator_get_voltage(rdev->supply->rdev);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -2972,11 +3133,11 @@ int regulator_get_voltage(struct regulator *regulator)
|
|||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(®ulator->rdev->mutex);
|
||||
regulator_lock_supply(regulator->rdev);
|
||||
|
||||
ret = _regulator_get_voltage(regulator->rdev);
|
||||
|
||||
mutex_unlock(®ulator->rdev->mutex);
|
||||
regulator_unlock_supply(regulator->rdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -3810,8 +3971,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
|
|||
}
|
||||
}
|
||||
|
||||
list_add(&rdev->list, ®ulator_list);
|
||||
|
||||
rdev_init_debugfs(rdev);
|
||||
out:
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
|
@ -3865,6 +4024,19 @@ void regulator_unregister(struct regulator_dev *rdev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_unregister);
|
||||
|
||||
static int _regulator_suspend_prepare(struct device *dev, void *data)
|
||||
{
|
||||
struct regulator_dev *rdev = dev_to_rdev(dev);
|
||||
const suspend_state_t *state = data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
ret = suspend_prepare(rdev, *state);
|
||||
mutex_unlock(&rdev->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_suspend_prepare - prepare regulators for system wide suspend
|
||||
* @state: system suspend state
|
||||
|
@ -3874,31 +4046,46 @@ EXPORT_SYMBOL_GPL(regulator_unregister);
|
|||
*/
|
||||
int regulator_suspend_prepare(suspend_state_t state)
|
||||
{
|
||||
struct regulator_dev *rdev;
|
||||
int ret = 0;
|
||||
|
||||
/* ON is handled by regulator active state */
|
||||
if (state == PM_SUSPEND_ON)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
list_for_each_entry(rdev, ®ulator_list, list) {
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
ret = suspend_prepare(rdev, state);
|
||||
mutex_unlock(&rdev->mutex);
|
||||
|
||||
if (ret < 0) {
|
||||
rdev_err(rdev, "failed to prepare\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
return ret;
|
||||
return class_for_each_device(®ulator_class, NULL, &state,
|
||||
_regulator_suspend_prepare);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
|
||||
|
||||
static int _regulator_suspend_finish(struct device *dev, void *data)
|
||||
{
|
||||
struct regulator_dev *rdev = dev_to_rdev(dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
if (rdev->use_count > 0 || rdev->constraints->always_on) {
|
||||
if (!_regulator_is_enabled(rdev)) {
|
||||
ret = _regulator_do_enable(rdev);
|
||||
if (ret)
|
||||
dev_err(dev,
|
||||
"Failed to resume regulator %d\n",
|
||||
ret);
|
||||
}
|
||||
} else {
|
||||
if (!have_full_constraints())
|
||||
goto unlock;
|
||||
if (!_regulator_is_enabled(rdev))
|
||||
goto unlock;
|
||||
|
||||
ret = _regulator_do_disable(rdev);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to suspend regulator %d\n", ret);
|
||||
}
|
||||
unlock:
|
||||
mutex_unlock(&rdev->mutex);
|
||||
|
||||
/* Keep processing regulators in spite of any errors */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_suspend_finish - resume regulators from system wide suspend
|
||||
*
|
||||
|
@ -3907,33 +4094,8 @@ EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
|
|||
*/
|
||||
int regulator_suspend_finish(void)
|
||||
{
|
||||
struct regulator_dev *rdev;
|
||||
int ret = 0, error;
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
list_for_each_entry(rdev, ®ulator_list, list) {
|
||||
mutex_lock(&rdev->mutex);
|
||||
if (rdev->use_count > 0 || rdev->constraints->always_on) {
|
||||
if (!_regulator_is_enabled(rdev)) {
|
||||
error = _regulator_do_enable(rdev);
|
||||
if (error)
|
||||
ret = error;
|
||||
}
|
||||
} else {
|
||||
if (!have_full_constraints())
|
||||
goto unlock;
|
||||
if (!_regulator_is_enabled(rdev))
|
||||
goto unlock;
|
||||
|
||||
error = _regulator_do_disable(rdev);
|
||||
if (error)
|
||||
ret = error;
|
||||
}
|
||||
unlock:
|
||||
mutex_unlock(&rdev->mutex);
|
||||
}
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
return ret;
|
||||
return class_for_each_device(®ulator_class, NULL, NULL,
|
||||
_regulator_suspend_finish);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_suspend_finish);
|
||||
|
||||
|
@ -4053,14 +4215,35 @@ static const struct file_operations supply_map_fops = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct summary_data {
|
||||
struct seq_file *s;
|
||||
struct regulator_dev *parent;
|
||||
int level;
|
||||
};
|
||||
|
||||
static void regulator_summary_show_subtree(struct seq_file *s,
|
||||
struct regulator_dev *rdev,
|
||||
int level);
|
||||
|
||||
static int regulator_summary_show_children(struct device *dev, void *data)
|
||||
{
|
||||
struct regulator_dev *rdev = dev_to_rdev(dev);
|
||||
struct summary_data *summary_data = data;
|
||||
|
||||
if (rdev->supply && rdev->supply->rdev == summary_data->parent)
|
||||
regulator_summary_show_subtree(summary_data->s, rdev,
|
||||
summary_data->level + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void regulator_summary_show_subtree(struct seq_file *s,
|
||||
struct regulator_dev *rdev,
|
||||
int level)
|
||||
{
|
||||
struct list_head *list = s->private;
|
||||
struct regulator_dev *child;
|
||||
struct regulation_constraints *c;
|
||||
struct regulator *consumer;
|
||||
struct summary_data summary_data;
|
||||
|
||||
if (!rdev)
|
||||
return;
|
||||
|
@ -4110,33 +4293,32 @@ static void regulator_summary_show_subtree(struct seq_file *s,
|
|||
seq_puts(s, "\n");
|
||||
}
|
||||
|
||||
list_for_each_entry(child, list, list) {
|
||||
/* handle only non-root regulators supplied by current rdev */
|
||||
if (!child->supply || child->supply->rdev != rdev)
|
||||
continue;
|
||||
summary_data.s = s;
|
||||
summary_data.level = level;
|
||||
summary_data.parent = rdev;
|
||||
|
||||
regulator_summary_show_subtree(s, child, level + 1);
|
||||
}
|
||||
class_for_each_device(®ulator_class, NULL, &summary_data,
|
||||
regulator_summary_show_children);
|
||||
}
|
||||
|
||||
static int regulator_summary_show_roots(struct device *dev, void *data)
|
||||
{
|
||||
struct regulator_dev *rdev = dev_to_rdev(dev);
|
||||
struct seq_file *s = data;
|
||||
|
||||
if (!rdev->supply)
|
||||
regulator_summary_show_subtree(s, rdev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int regulator_summary_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct list_head *list = s->private;
|
||||
struct regulator_dev *rdev;
|
||||
|
||||
seq_puts(s, " regulator use open bypass voltage current min max\n");
|
||||
seq_puts(s, "-------------------------------------------------------------------------------\n");
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
|
||||
list_for_each_entry(rdev, list, list) {
|
||||
if (rdev->supply)
|
||||
continue;
|
||||
|
||||
regulator_summary_show_subtree(s, rdev, 0);
|
||||
}
|
||||
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
class_for_each_device(®ulator_class, NULL, s,
|
||||
regulator_summary_show_roots);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4170,7 +4352,7 @@ static int __init regulator_init(void)
|
|||
&supply_map_fops);
|
||||
|
||||
debugfs_create_file("regulator_summary", 0444, debugfs_root,
|
||||
®ulator_list, ®ulator_summary_fops);
|
||||
NULL, ®ulator_summary_fops);
|
||||
|
||||
regulator_dummy_init();
|
||||
|
||||
|
|
|
@ -381,6 +381,7 @@ static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id,
|
|||
case DA9053_AA:
|
||||
case DA9053_BA:
|
||||
case DA9053_BB:
|
||||
case DA9053_BC:
|
||||
for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) {
|
||||
info = &da9053_regulator_info[i];
|
||||
if (info->reg_desc.id == id)
|
||||
|
|
|
@ -698,7 +698,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
|
|||
rdata->initdata = da9063_matches[i].init_data;
|
||||
|
||||
n++;
|
||||
};
|
||||
}
|
||||
|
||||
*da9063_reg_matches = da9063_matches;
|
||||
return pdata;
|
||||
|
|
|
@ -76,6 +76,9 @@ static void of_get_regulation_constraints(struct device_node *np,
|
|||
if (of_property_read_bool(np, "regulator-allow-bypass"))
|
||||
constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
|
||||
|
||||
if (of_property_read_bool(np, "regulator-allow-set-load"))
|
||||
constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS;
|
||||
|
||||
ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
|
||||
if (!ret) {
|
||||
if (pval)
|
||||
|
|
|
@ -69,12 +69,6 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
|
|||
|
||||
drvdata->state = selector;
|
||||
|
||||
ret = pwm_enable(drvdata->pwm);
|
||||
if (ret) {
|
||||
dev_err(&rdev->dev, "Failed to enable PWM\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -89,6 +83,29 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev,
|
|||
return drvdata->duty_cycle_table[selector].uV;
|
||||
}
|
||||
|
||||
static int pwm_regulator_enable(struct regulator_dev *dev)
|
||||
{
|
||||
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
||||
|
||||
return pwm_enable(drvdata->pwm);
|
||||
}
|
||||
|
||||
static int pwm_regulator_disable(struct regulator_dev *dev)
|
||||
{
|
||||
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
||||
|
||||
pwm_disable(drvdata->pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwm_regulator_is_enabled(struct regulator_dev *dev)
|
||||
{
|
||||
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
||||
|
||||
return pwm_is_enabled(drvdata->pwm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continuous voltage call-backs
|
||||
*/
|
||||
|
@ -144,11 +161,17 @@ static struct regulator_ops pwm_regulator_voltage_table_ops = {
|
|||
.get_voltage_sel = pwm_regulator_get_voltage_sel,
|
||||
.list_voltage = pwm_regulator_list_voltage,
|
||||
.map_voltage = regulator_map_voltage_iterate,
|
||||
.enable = pwm_regulator_enable,
|
||||
.disable = pwm_regulator_disable,
|
||||
.is_enabled = pwm_regulator_is_enabled,
|
||||
};
|
||||
|
||||
static struct regulator_ops pwm_regulator_voltage_continuous_ops = {
|
||||
.get_voltage = pwm_regulator_get_voltage,
|
||||
.set_voltage = pwm_regulator_set_voltage,
|
||||
.enable = pwm_regulator_enable,
|
||||
.disable = pwm_regulator_disable,
|
||||
.is_enabled = pwm_regulator_is_enabled,
|
||||
};
|
||||
|
||||
static struct regulator_desc pwm_regulator_desc = {
|
||||
|
|
|
@ -36,9 +36,9 @@ struct qcom_rpm_reg {
|
|||
};
|
||||
|
||||
struct rpm_regulator_req {
|
||||
u32 key;
|
||||
u32 nbytes;
|
||||
u32 value;
|
||||
__le32 key;
|
||||
__le32 nbytes;
|
||||
__le32 value;
|
||||
};
|
||||
|
||||
#define RPM_KEY_SWEN 0x6e657773 /* "swen" */
|
||||
|
@ -62,9 +62,9 @@ static int rpm_reg_enable(struct regulator_dev *rdev)
|
|||
struct rpm_regulator_req req;
|
||||
int ret;
|
||||
|
||||
req.key = RPM_KEY_SWEN;
|
||||
req.nbytes = sizeof(u32);
|
||||
req.value = 1;
|
||||
req.key = cpu_to_le32(RPM_KEY_SWEN);
|
||||
req.nbytes = cpu_to_le32(sizeof(u32));
|
||||
req.value = cpu_to_le32(1);
|
||||
|
||||
ret = rpm_reg_write_active(vreg, &req, sizeof(req));
|
||||
if (!ret)
|
||||
|
@ -86,8 +86,8 @@ static int rpm_reg_disable(struct regulator_dev *rdev)
|
|||
struct rpm_regulator_req req;
|
||||
int ret;
|
||||
|
||||
req.key = RPM_KEY_SWEN;
|
||||
req.nbytes = sizeof(u32);
|
||||
req.key = cpu_to_le32(RPM_KEY_SWEN);
|
||||
req.nbytes = cpu_to_le32(sizeof(u32));
|
||||
req.value = 0;
|
||||
|
||||
ret = rpm_reg_write_active(vreg, &req, sizeof(req));
|
||||
|
@ -113,9 +113,9 @@ static int rpm_reg_set_voltage(struct regulator_dev *rdev,
|
|||
struct rpm_regulator_req req;
|
||||
int ret = 0;
|
||||
|
||||
req.key = RPM_KEY_UV;
|
||||
req.nbytes = sizeof(u32);
|
||||
req.value = min_uV;
|
||||
req.key = cpu_to_le32(RPM_KEY_UV);
|
||||
req.nbytes = cpu_to_le32(sizeof(u32));
|
||||
req.value = cpu_to_le32(min_uV);
|
||||
|
||||
ret = rpm_reg_write_active(vreg, &req, sizeof(req));
|
||||
if (!ret)
|
||||
|
@ -129,9 +129,9 @@ static int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA)
|
|||
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||
struct rpm_regulator_req req;
|
||||
|
||||
req.key = RPM_KEY_MA;
|
||||
req.nbytes = sizeof(u32);
|
||||
req.value = load_uA;
|
||||
req.key = cpu_to_le32(RPM_KEY_MA);
|
||||
req.nbytes = cpu_to_le32(sizeof(u32));
|
||||
req.value = cpu_to_le32(load_uA / 1000);
|
||||
|
||||
return rpm_reg_write_active(vreg, &req, sizeof(req));
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/mfd/core.h>
|
||||
|
@ -33,7 +33,7 @@ static int tps6105x_regulator_enable(struct regulator_dev *rdev)
|
|||
int ret;
|
||||
|
||||
/* Activate voltage mode */
|
||||
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
|
||||
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_MODE_MASK,
|
||||
TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT);
|
||||
if (ret)
|
||||
|
@ -48,7 +48,7 @@ static int tps6105x_regulator_disable(struct regulator_dev *rdev)
|
|||
int ret;
|
||||
|
||||
/* Set into shutdown mode */
|
||||
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
|
||||
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_MODE_MASK,
|
||||
TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
|
||||
if (ret)
|
||||
|
@ -60,10 +60,10 @@ static int tps6105x_regulator_disable(struct regulator_dev *rdev)
|
|||
static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
u8 regval;
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val);
|
||||
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
regval &= TPS6105X_REG0_MODE_MASK;
|
||||
|
@ -78,10 +78,10 @@ static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
|
|||
static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
u8 regval;
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val);
|
||||
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -96,7 +96,7 @@ static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
|
|||
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
|
||||
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
|
||||
TPS6105X_REG0_VOLTAGE_MASK,
|
||||
selector << TPS6105X_REG0_VOLTAGE_SHIFT);
|
||||
if (ret)
|
||||
|
|
|
@ -86,6 +86,42 @@
|
|||
|
||||
#define TPS65023_MAX_REG_ID TPS65023_LDO_2
|
||||
|
||||
#define TPS65023_REGULATOR_DCDC(_num, _t, _em) \
|
||||
{ \
|
||||
.name = "VDCDC"#_num, \
|
||||
.of_match = of_match_ptr("VDCDC"#_num), \
|
||||
.regulators_node = of_match_ptr("regulators"), \
|
||||
.id = TPS65023_DCDC_##_num, \
|
||||
.n_voltages = ARRAY_SIZE(_t), \
|
||||
.ops = &tps65023_dcdc_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.volt_table = _t, \
|
||||
.vsel_reg = TPS65023_REG_DEF_CORE, \
|
||||
.vsel_mask = ARRAY_SIZE(_t) - 1, \
|
||||
.enable_mask = _em, \
|
||||
.enable_reg = TPS65023_REG_REG_CTRL, \
|
||||
.apply_reg = TPS65023_REG_CON_CTRL2, \
|
||||
.apply_bit = TPS65023_REG_CTRL2_GO, \
|
||||
} \
|
||||
|
||||
#define TPS65023_REGULATOR_LDO(_num, _t, _vm) \
|
||||
{ \
|
||||
.name = "LDO"#_num, \
|
||||
.of_match = of_match_ptr("LDO"#_num), \
|
||||
.regulators_node = of_match_ptr("regulators"), \
|
||||
.id = TPS65023_LDO_##_num, \
|
||||
.n_voltages = ARRAY_SIZE(_t), \
|
||||
.ops = &tps65023_ldo_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.volt_table = _t, \
|
||||
.vsel_reg = TPS65023_REG_LDO_CTRL, \
|
||||
.vsel_mask = _vm, \
|
||||
.enable_mask = 1 << (_num), \
|
||||
.enable_reg = TPS65023_REG_REG_CTRL, \
|
||||
} \
|
||||
|
||||
/* Supported voltage values for regulators */
|
||||
static const unsigned int VCORE_VSEL_table[] = {
|
||||
800000, 825000, 850000, 875000,
|
||||
|
@ -124,25 +160,16 @@ static const unsigned int TPS65023_LDO2_VSEL_table[] = {
|
|||
2500000, 2800000, 3000000, 3300000,
|
||||
};
|
||||
|
||||
/* Regulator specific details */
|
||||
struct tps_info {
|
||||
const char *name;
|
||||
u8 table_len;
|
||||
const unsigned int *table;
|
||||
};
|
||||
|
||||
/* PMIC details */
|
||||
struct tps_pmic {
|
||||
struct regulator_desc desc[TPS65023_NUM_REGULATOR];
|
||||
struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
|
||||
const struct tps_info *info[TPS65023_NUM_REGULATOR];
|
||||
const struct tps_driver_data *driver_data;
|
||||
struct regmap *regmap;
|
||||
u8 core_regulator;
|
||||
};
|
||||
|
||||
/* Struct passed as driver data */
|
||||
struct tps_driver_data {
|
||||
const struct tps_info *info;
|
||||
const struct regulator_desc *desc;
|
||||
u8 core_regulator;
|
||||
};
|
||||
|
||||
|
@ -154,7 +181,7 @@ static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev)
|
|||
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
|
||||
return -EINVAL;
|
||||
|
||||
if (dcdc != tps->core_regulator)
|
||||
if (dcdc != tps->driver_data->core_regulator)
|
||||
return 0;
|
||||
|
||||
return regulator_get_voltage_sel_regmap(dev);
|
||||
|
@ -166,7 +193,7 @@ static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
|
|||
struct tps_pmic *tps = rdev_get_drvdata(dev);
|
||||
int dcdc = rdev_get_id(dev);
|
||||
|
||||
if (dcdc != tps->core_regulator)
|
||||
if (dcdc != tps->driver_data->core_regulator)
|
||||
return -EINVAL;
|
||||
|
||||
return regulator_set_voltage_sel_regmap(dev, selector);
|
||||
|
@ -199,30 +226,60 @@ static const struct regmap_config tps65023_regmap_config = {
|
|||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static const struct regulator_desc tps65020_regulators[] = {
|
||||
TPS65023_REGULATOR_DCDC(1, DCDC_FIXED_3300000_VSEL_table, 0x20),
|
||||
TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_1800000_VSEL_table, 0x10),
|
||||
TPS65023_REGULATOR_DCDC(3, VCORE_VSEL_table, 0x08),
|
||||
TPS65023_REGULATOR_LDO(1, TPS65020_LDO_VSEL_table, 0x07),
|
||||
TPS65023_REGULATOR_LDO(2, TPS65020_LDO_VSEL_table, 0x70),
|
||||
};
|
||||
|
||||
static const struct regulator_desc tps65021_regulators[] = {
|
||||
TPS65023_REGULATOR_DCDC(1, DCDC_FIXED_3300000_VSEL_table, 0x20),
|
||||
TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_1800000_VSEL_table, 0x10),
|
||||
TPS65023_REGULATOR_DCDC(3, VCORE_VSEL_table, 0x08),
|
||||
TPS65023_REGULATOR_LDO(1, TPS65023_LDO1_VSEL_table, 0x07),
|
||||
TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70),
|
||||
};
|
||||
|
||||
static const struct regulator_desc tps65023_regulators[] = {
|
||||
TPS65023_REGULATOR_DCDC(1, VCORE_VSEL_table, 0x20),
|
||||
TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_3300000_VSEL_table, 0x10),
|
||||
TPS65023_REGULATOR_DCDC(3, DCDC_FIXED_1800000_VSEL_table, 0x08),
|
||||
TPS65023_REGULATOR_LDO(1, TPS65023_LDO1_VSEL_table, 0x07),
|
||||
TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70),
|
||||
};
|
||||
|
||||
static struct tps_driver_data tps65020_drv_data = {
|
||||
.desc = tps65020_regulators,
|
||||
.core_regulator = TPS65023_DCDC_3,
|
||||
};
|
||||
|
||||
static struct tps_driver_data tps65021_drv_data = {
|
||||
.desc = tps65021_regulators,
|
||||
.core_regulator = TPS65023_DCDC_3,
|
||||
};
|
||||
|
||||
static struct tps_driver_data tps65023_drv_data = {
|
||||
.desc = tps65023_regulators,
|
||||
.core_regulator = TPS65023_DCDC_1,
|
||||
};
|
||||
|
||||
static int tps_65023_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
const struct tps_driver_data *drv_data = (void *)id->driver_data;
|
||||
const struct tps_info *info = drv_data->info;
|
||||
struct regulator_init_data *init_data = dev_get_platdata(&client->dev);
|
||||
struct regulator_config config = { };
|
||||
struct regulator_init_data *init_data;
|
||||
struct regulator_dev *rdev;
|
||||
struct tps_pmic *tps;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
/**
|
||||
* init_data points to array of regulator_init structures
|
||||
* coming from the board-evm file.
|
||||
*/
|
||||
init_data = dev_get_platdata(&client->dev);
|
||||
if (!init_data)
|
||||
return -EIO;
|
||||
|
||||
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
|
||||
if (!tps)
|
||||
return -ENOMEM;
|
||||
|
||||
tps->driver_data = (struct tps_driver_data *)id->driver_data;
|
||||
|
||||
tps->regmap = devm_regmap_init_i2c(client, &tps65023_regmap_config);
|
||||
if (IS_ERR(tps->regmap)) {
|
||||
error = PTR_ERR(tps->regmap);
|
||||
|
@ -232,58 +289,22 @@ static int tps_65023_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
/* common for all regulators */
|
||||
tps->core_regulator = drv_data->core_regulator;
|
||||
config.dev = &client->dev;
|
||||
config.driver_data = tps;
|
||||
config.regmap = tps->regmap;
|
||||
|
||||
for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
|
||||
/* Store regulator specific information */
|
||||
tps->info[i] = info;
|
||||
|
||||
tps->desc[i].name = info->name;
|
||||
tps->desc[i].id = i;
|
||||
tps->desc[i].n_voltages = info->table_len;
|
||||
tps->desc[i].volt_table = info->table;
|
||||
tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
|
||||
&tps65023_ldo_ops : &tps65023_dcdc_ops);
|
||||
tps->desc[i].type = REGULATOR_VOLTAGE;
|
||||
tps->desc[i].owner = THIS_MODULE;
|
||||
|
||||
tps->desc[i].enable_reg = TPS65023_REG_REG_CTRL;
|
||||
switch (i) {
|
||||
case TPS65023_LDO_1:
|
||||
tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
|
||||
tps->desc[i].vsel_mask = 0x07;
|
||||
tps->desc[i].enable_mask = 1 << 1;
|
||||
break;
|
||||
case TPS65023_LDO_2:
|
||||
tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
|
||||
tps->desc[i].vsel_mask = 0x70;
|
||||
tps->desc[i].enable_mask = 1 << 2;
|
||||
break;
|
||||
default: /* DCDCx */
|
||||
tps->desc[i].enable_mask =
|
||||
1 << (TPS65023_NUM_REGULATOR - i);
|
||||
tps->desc[i].vsel_reg = TPS65023_REG_DEF_CORE;
|
||||
tps->desc[i].vsel_mask = info->table_len - 1;
|
||||
tps->desc[i].apply_reg = TPS65023_REG_CON_CTRL2;
|
||||
tps->desc[i].apply_bit = TPS65023_REG_CTRL2_GO;
|
||||
}
|
||||
|
||||
config.dev = &client->dev;
|
||||
config.init_data = init_data;
|
||||
config.driver_data = tps;
|
||||
config.regmap = tps->regmap;
|
||||
for (i = 0; i < TPS65023_NUM_REGULATOR; i++) {
|
||||
if (init_data)
|
||||
config.init_data = &init_data[i];
|
||||
|
||||
/* Register the regulators */
|
||||
rdev = devm_regulator_register(&client->dev, &tps->desc[i],
|
||||
&config);
|
||||
if (IS_ERR(rdev)) {
|
||||
tps->rdev[i] = devm_regulator_register(&client->dev,
|
||||
&tps->driver_data->desc[i], &config);
|
||||
if (IS_ERR(tps->rdev[i])) {
|
||||
dev_err(&client->dev, "failed to register %s\n",
|
||||
id->name);
|
||||
return PTR_ERR(rdev);
|
||||
return PTR_ERR(tps->rdev[i]);
|
||||
}
|
||||
|
||||
/* Save regulator for cleanup */
|
||||
tps->rdev[i] = rdev;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, tps);
|
||||
|
@ -296,120 +317,33 @@ static int tps_65023_probe(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct tps_info tps65020_regs[] = {
|
||||
{
|
||||
.name = "VDCDC1",
|
||||
.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
|
||||
.table = DCDC_FIXED_3300000_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "VDCDC2",
|
||||
.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
|
||||
.table = DCDC_FIXED_1800000_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "VDCDC3",
|
||||
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
|
||||
.table = VCORE_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "LDO1",
|
||||
.table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table),
|
||||
.table = TPS65020_LDO_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "LDO2",
|
||||
.table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table),
|
||||
.table = TPS65020_LDO_VSEL_table,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct tps_info tps65021_regs[] = {
|
||||
{
|
||||
.name = "VDCDC1",
|
||||
.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
|
||||
.table = DCDC_FIXED_3300000_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "VDCDC2",
|
||||
.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
|
||||
.table = DCDC_FIXED_1800000_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "VDCDC3",
|
||||
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
|
||||
.table = VCORE_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "LDO1",
|
||||
.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
|
||||
.table = TPS65023_LDO1_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "LDO2",
|
||||
.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
|
||||
.table = TPS65023_LDO2_VSEL_table,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct tps_info tps65023_regs[] = {
|
||||
{
|
||||
.name = "VDCDC1",
|
||||
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
|
||||
.table = VCORE_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "VDCDC2",
|
||||
.table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
|
||||
.table = DCDC_FIXED_3300000_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "VDCDC3",
|
||||
.table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
|
||||
.table = DCDC_FIXED_1800000_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "LDO1",
|
||||
.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
|
||||
.table = TPS65023_LDO1_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "LDO2",
|
||||
.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
|
||||
.table = TPS65023_LDO2_VSEL_table,
|
||||
},
|
||||
};
|
||||
|
||||
static struct tps_driver_data tps65020_drv_data = {
|
||||
.info = tps65020_regs,
|
||||
.core_regulator = TPS65023_DCDC_3,
|
||||
};
|
||||
|
||||
static struct tps_driver_data tps65021_drv_data = {
|
||||
.info = tps65021_regs,
|
||||
.core_regulator = TPS65023_DCDC_3,
|
||||
};
|
||||
|
||||
static struct tps_driver_data tps65023_drv_data = {
|
||||
.info = tps65023_regs,
|
||||
.core_regulator = TPS65023_DCDC_1,
|
||||
static const struct of_device_id tps65023_of_match[] = {
|
||||
{ .compatible = "ti,tps65020", .data = &tps65020_drv_data},
|
||||
{ .compatible = "ti,tps65021", .data = &tps65021_drv_data},
|
||||
{ .compatible = "ti,tps65023", .data = &tps65023_drv_data},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tps65023_of_match);
|
||||
|
||||
static const struct i2c_device_id tps_65023_id[] = {
|
||||
{.name = "tps65023",
|
||||
.driver_data = (unsigned long) &tps65023_drv_data},
|
||||
{.name = "tps65021",
|
||||
.driver_data = (unsigned long) &tps65021_drv_data,},
|
||||
{.name = "tps65020",
|
||||
.driver_data = (unsigned long) &tps65020_drv_data},
|
||||
{
|
||||
.name = "tps65023",
|
||||
.driver_data = (kernel_ulong_t)&tps65023_drv_data
|
||||
}, {
|
||||
.name = "tps65021",
|
||||
.driver_data = (kernel_ulong_t)&tps65021_drv_data
|
||||
}, {
|
||||
.name = "tps65020",
|
||||
.driver_data = (kernel_ulong_t)&tps65020_drv_data
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, tps_65023_id);
|
||||
|
||||
static struct i2c_driver tps_65023_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tps65023",
|
||||
.of_match_table = of_match_ptr(tps65023_of_match),
|
||||
},
|
||||
.probe = tps_65023_probe,
|
||||
.id_table = tps_65023_id,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define MFD_TPS6105X_H
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
/*
|
||||
|
@ -82,20 +83,15 @@ struct tps6105x_platform_data {
|
|||
|
||||
/**
|
||||
* struct tps6105x - state holder for the TPS6105x drivers
|
||||
* @mutex: mutex to serialize I2C accesses
|
||||
* @i2c_client: corresponding I2C client
|
||||
* @regulator: regulator device if used in voltage mode
|
||||
* @regmap: used for i2c communcation on accessing registers
|
||||
*/
|
||||
struct tps6105x {
|
||||
struct tps6105x_platform_data *pdata;
|
||||
struct mutex lock;
|
||||
struct i2c_client *client;
|
||||
struct regulator_dev *regulator;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
extern int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value);
|
||||
extern int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf);
|
||||
extern int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg,
|
||||
u8 bitmask, u8 bitvalues);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -245,6 +245,7 @@ enum regulator_type {
|
|||
* @linear_min_sel: Minimal selector for starting linear mapping
|
||||
* @fixed_uV: Fixed voltage of rails.
|
||||
* @ramp_delay: Time to settle down after voltage change (unit: uV/us)
|
||||
* @min_dropout_uV: The minimum dropout voltage this regulator can handle
|
||||
* @linear_ranges: A constant table of possible voltage ranges.
|
||||
* @n_linear_ranges: Number of entries in the @linear_ranges table.
|
||||
* @volt_table: Voltage mapping table (if table based mapping)
|
||||
|
@ -292,6 +293,7 @@ struct regulator_desc {
|
|||
unsigned int linear_min_sel;
|
||||
int fixed_uV;
|
||||
unsigned int ramp_delay;
|
||||
int min_dropout_uV;
|
||||
|
||||
const struct regulator_linear_range *linear_ranges;
|
||||
int n_linear_ranges;
|
||||
|
|
Загрузка…
Ссылка в новой задаче