regulator: Update for v4.5

Aside from a fix for a spurious warning (which caused more problems than
 it fixed in the fixing really) this is all driver updates, including new
 drivers for Dialog PV88060/90 and TI LM363x and TPS65086 devices.  The
 qcom_smd driver has had PM8916 and PMA8084 support added.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJWlUWiAAoJECTWi3JdVIfQtywH/0joibyUbL34arXcPNCUUhlo
 UnhTgT1kfOoS01ODt9gU49X4/8SRL9HdjcrIV8yTz4Ldb8by8Rd3ZrkO//9zs7BF
 5PIqIzEw6FT/Ovsj8Tc35irccMSrwtTIGRrA8zrM/WtWQWcIUWFxMw+j/lewIvvH
 jHZNTTLL5XemObSTfvzhbS6PZ8RcvRVXLNJjZYYO5xAEHNg3i5Hxao5p3QKzVJ8m
 P5n4jSiTY/pVePcs9dzzQTGjlzkE11KX7DBxnmXOSPZsArSaRIC53DCmqu/JoG+o
 3JJBkmRx7IJb0651hclFaUl8Wl56FSst+zigeAj82b301xpVR30iG3xiwYK/AT8=
 =NQ6n
 -----END PGP SIGNATURE-----

Merge tag 'regulator-v4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator

Pull regulator updates from Mark Brown:
 "Aside from a fix for a spurious warning (which caused more problems
  than it fixed in the fixing really) this is all driver updates,
  including new drivers for Dialog PV88060/90 and TI LM363x and TPS65086
  devices.  The qcom_smd driver has had PM8916 and PMA8084 support
  added"

* tag 'regulator-v4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (36 commits)
  regulator: core: remove some dead code
  regulator: core: use dev_to_rdev
  regulator: lp872x: Get rid of duplicate reference to DVS GPIO
  regulator: lp872x: Add missing of_match in regulators descriptions
  regulator: axp20x: Fix GPIO LDO enable value for AXP22x
  regulator: lp8788: constify regulator_ops structures
  regulator: wm8*: constify regulator_ops structures
  regulator: da9*: constify regulator_ops structures
  regulator: mt6311: Use REGCACHE_RBTREE
  regulator: tps65917/palmas: Add bypass ops for LDOs with bypass capability
  regulator: qcom-smd: Add support for PMA8084
  regulator: qcom-smd: Add PM8916 support
  soc: qcom: documentation: Update SMD/RPM Docs
  regulator: pv88090: logical vs bitwise AND typo
  regulator: pv88090: Fix irq leak
  regulator: pv88090: new regulator driver
  regulator: wm831x-ldo: Use platform_register/unregister_drivers()
  regulator: wm831x-dcdc: Use platform_register/unregister_drivers()
  regulator: lp8788-ldo: Use platform_register/unregister_drivers()
  regulator: core: Fix nested locking of supplies
  ...
This commit is contained in:
Linus Torvalds 2016-01-15 12:14:47 -08:00
commit 4b43ea2a7c
40 changed files with 2414 additions and 248 deletions

View File

@ -0,0 +1,34 @@
TI LMU LM363x regulator device tree bindings
LM363x regulator driver supports LM3631 and LM3632.
LM3631 has five regulators and LM3632 supports three regulators.
Required property:
- compatible: "ti,lm363x-regulator"
Optional properties:
LM3632 has external enable pins for two LDOs.
- ti,lcm-en1-gpio: A GPIO specifier for Vpos control pin.
- ti,lcm-en2-gpio: A GPIO specifier for Vneg control pin.
Child nodes:
LM3631
- vboost
- vcont
- voref
- vpos
- vneg
LM3632
- vboost
- vpos
- vneg
Optional properties of a child node:
Each sub-node should contain the constraints and initialization.
Please refer to [1].
Examples: Please refer to ti-lmu dt-bindings [2].
[1] ../regulator/regulator.txt
[2] ../mfd/ti-lmu.txt

View File

@ -0,0 +1,124 @@
* Powerventure Semiconductor PV88060 Voltage Regulator
Required properties:
- compatible: "pvs,pv88060".
- reg: I2C slave address, usually 0x49.
- interrupts: the interrupt outputs of the controller
- regulators: A node that houses a sub-node for each regulator within the
device. Each sub-node is identified using the node's name, with valid
values listed below. The content of each sub-node is defined by the
standard binding for regulators; see regulator.txt.
BUCK1, LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7, SW1, SW2, SW3, SW4,
SW5, and SW6.
Optional properties:
- Any optional property defined in regulator.txt
Example
pmic: pv88060@49 {
compatible = "pvs,pv88060";
reg = <0x49>;
interrupt-parent = <&gpio>;
interrupts = <24 24>;
regulators {
BUCK1 {
regulator-name = "buck1";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <4387500>;
regulator-min-microamp = <1496000>;
regulator-max-microamp = <4189000>;
regulator-boot-on;
};
LDO1 {
regulator-name = "ldo1";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3350000>;
regulator-boot-on;
};
LDO2 {
regulator-name = "ldo2";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3350000>;
regulator-boot-on;
};
LDO3 {
regulator-name = "ldo3";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3350000>;
regulator-boot-on;
};
LDO4 {
regulator-name = "ldo4";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3350000>;
regulator-boot-on;
};
LDO5 {
regulator-name = "ldo5";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3350000>;
regulator-boot-on;
};
LDO6 {
regulator-name = "ldo6";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3350000>;
regulator-boot-on;
};
LDO7 {
regulator-name = "ldo7";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3350000>;
regulator-boot-on;
};
SW1 {
regulator-name = "sw1";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
};
SW2 {
regulator-name = "sw2";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-boot-on;
};
SW3 {
regulator-name = "sw3";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-boot-on;
};
SW4 {
regulator-name = "sw4";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-boot-on;
};
SW5 {
regulator-name = "sw5";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-boot-on;
};
SW6 {
regulator-name = "sw6";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
};
};
};

View File

@ -0,0 +1,65 @@
* Powerventure Semiconductor PV88090 Voltage Regulator
Required properties:
- compatible: "pvs,pv88090".
- reg: I2C slave address, usually 0x48.
- interrupts: the interrupt outputs of the controller
- regulators: A node that houses a sub-node for each regulator within the
device. Each sub-node is identified using the node's name, with valid
values listed below. The content of each sub-node is defined by the
standard binding for regulators; see regulator.txt.
BUCK1, BUCK2, BUCK3, LDO1, and LDO2.
Optional properties:
- Any optional property defined in regulator.txt
Example
pmic: pv88090@48 {
compatible = "pvs,pv88090";
reg = <0x48>;
interrupt-parent = <&gpio>;
interrupts = <24 24>;
regulators {
BUCK1 {
regulator-name = "buck1";
regulator-min-microvolt = < 600000>;
regulator-max-microvolt = <1393750>;
regulator-min-microamp = < 220000>;
regulator-max-microamp = <7040000>;
regulator-boot-on;
};
BUCK2 {
regulator-name = "buck2";
regulator-min-microvolt = < 600000>;
regulator-max-microvolt = <1393750>;
regulator-min-microamp = <1496000>;
regulator-max-microamp = <4189000>;
};
BUCK3 {
regulator-name = "buck3";
regulator-min-microvolt = <600000>;
regulator-max-microvolt = <1393750>;
regulator-min-microamp = <1496000>;
regulator-max-microamp = <4189000>;
regulator-boot-on;
};
LDO1 {
regulator-name = "ldo1";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <4350000>;
regulator-boot-on;
};
LDO2 {
regulator-name = "ldo2";
regulator-min-microvolt = < 650000>;
regulator-max-microvolt = <2225000>;
regulator-boot-on;
};
};
};

View File

@ -1,27 +1,17 @@
Qualcomm Resource Power Manager (RPM) over SMD
QCOM SMD RPM REGULATOR
This driver is used to interface with the Resource Power Manager (RPM) found in
various Qualcomm platforms. The RPM allows each component in the system to vote
for state of the system resources, such as clocks, regulators and bus
frequencies.
The Qualcomm RPM over SMD regulator is modelled as a subdevice of the RPM.
Because SMD is used as the communication transport mechanism, the RPM resides as
a subnode of the SMD. As such, the SMD-RPM regulator requires that the SMD and
RPM nodes be present.
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,rpm-msm8974"
Please refer to Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt for
information pertaining to the SMD node.
- qcom,smd-channels:
Usage: required
Value type: <stringlist>
Definition: Shared Memory channel used for communication with the RPM
Please refer to Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt for
information regarding the RPM node.
= SUBDEVICES
The RPM exposes resources to its subnodes. The below bindings specify the set
of valid subnodes that can operate on these resources.
== Regulators
== Regulator
Regulator nodes are identified by their compatible:
@ -30,7 +20,9 @@ Regulator nodes are identified by their compatible:
Value type: <string>
Definition: must be one of:
"qcom,rpm-pm8841-regulators"
"qcom,rpm-pm8916-regulators"
"qcom,rpm-pm8941-regulators"
"qcom,rpm-pma8084-regulators"
- vdd_s1-supply:
- vdd_s2-supply:
@ -45,6 +37,19 @@ Regulator nodes are identified by their compatible:
Definition: reference to regulator supplying the input pin, as
described in the data sheet
- vdd_s1-supply:
- vdd_s2-supply:
- vdd_s3-supply:
- vdd_s4-supply:
- vdd_l1_l2_l3-supply:
- vdd_l4_l5_l6-supply:
- vdd_l7-supply:
- vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18-supply:
Usage: optional (pm8916 only)
Value type: <phandle>
Definition: reference to regulator supplying the input pin, as
described in the data sheet
- vdd_s1-supply:
- vdd_s2-supply:
- vdd_s3-supply:
@ -63,6 +68,35 @@ Regulator nodes are identified by their compatible:
Definition: reference to regulator supplying the input pin, as
described in the data sheet
- vdd_s1-supply:
- vdd_s2-supply:
- vdd_s3-supply:
- vdd_s4-supply:
- vdd_s5-supply:
- vdd_s6-supply:
- vdd_s7-supply:
- vdd_s8-supply:
- vdd_s9-supply:
- vdd_s10-supply:
- vdd_s11-supply:
- vdd_s12-supply:
- vdd_l1_l11-supply:
- vdd_l2_l3_l4_l27-supply:
- vdd_l5_l7-supply:
- vdd_l6_l12_l14_l15_l26-supply:
- vdd_l8-supply:
- vdd_l9_l10_l13_l20_l23_l24-supply:
- vdd_l16_l25-supply:
- vdd_l17-supply:
- vdd_l18-supply:
- vdd_l19-supply:
- vdd_l21-supply:
- vdd_l22-supply:
Usage: optional (pma8084 only)
Value type: <phandle>
Definition: reference to regulator supplying the input pin, as
described in the data sheet
The regulator node houses sub-nodes for each regulator within the device. Each
sub-node is identified using the node's name, with valid values listed for each
of the pmics below.
@ -70,11 +104,20 @@ of the pmics below.
pm8841:
s1, s2, s3, s4, s5, s6, s7, s8
pm8916:
s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
l14, l15, l16, l17, l18
pm8941:
s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13,
l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2,
lvs3, 5vs1, 5vs2
pma8084:
s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5,
l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
l21, l22, l23, l24, l25, l26, l27, lvs1, lvs2, lvs3, lvs4, 5vs1
The content of each sub-node is defined by the standard binding for regulators -
see regulator.txt.
@ -114,4 +157,3 @@ see regulator.txt.
};
};
};

View File

@ -0,0 +1,58 @@
Qualcomm Resource Power Manager (RPM) over SMD
This driver is used to interface with the Resource Power Manager (RPM) found in
various Qualcomm platforms. The RPM allows each component in the system to vote
for state of the system resources, such as clocks, regulators and bus
frequencies.
The SMD information for the RPM edge should be filled out. See qcom,smd.txt for
the required edge properties. All SMD related properties will reside within the
RPM node itself.
= SUBDEVICES
The RPM exposes resources to its subnodes. The rpm_requests node must be
present and this subnode may contain children that designate regulator
resources.
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,rpm-apq8084"
"qcom,rpm-msm8916"
"qcom,rpm-msm8974"
- qcom,smd-channels:
Usage: required
Value type: <string>
Definition: must be "rpm_requests"
Refer to Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
for information on the regulator subnodes that can exist under the rpm_requests.
Example:
soc {
apcs: syscon@f9011000 {
compatible = "syscon";
reg = <0xf9011000 0x1000>;
};
};
smd {
compatible = "qcom,smd";
rpm {
interrupts = <0 168 1>;
qcom,ipc = <&apcs 8 0>;
qcom,smd-edge = <15>;
rpm_requests {
compatible = "qcom,rpm-msm8974";
qcom,smd-channels = "rpm_requests";
...
};
};
};

View File

@ -274,6 +274,15 @@ config REGULATOR_ISL6271A
help
This driver supports ISL6271A voltage regulator chip.
config REGULATOR_LM363X
tristate "TI LM363X voltage regulators"
depends on MFD_TI_LMU
help
This driver supports LM3631 and LM3632 voltage regulators for
the LCD bias.
One boost output voltage is configurable and always on.
Other LDOs are used for the display module.
config REGULATOR_LP3971
tristate "National Semiconductors LP3971 PMIC regulator driver"
depends on I2C
@ -446,6 +455,7 @@ config REGULATOR_MC13892
config REGULATOR_MT6311
tristate "MediaTek MT6311 PMIC"
depends on I2C
select REGMAP_I2C
help
Say y here to select this option to enable the power regulator of
MediaTek MT6311 PMIC.
@ -504,6 +514,22 @@ config REGULATOR_PFUZE100
Say y here to support the regulators found on the Freescale
PFUZE100/PFUZE200 PMIC.
config REGULATOR_PV88060
tristate "Powerventure Semiconductor PV88060 regulator"
depends on I2C
select REGMAP_I2C
help
Say y here to support the voltage regulators and convertors
PV88060
config REGULATOR_PV88090
tristate "Powerventure Semiconductor PV88090 regulator"
depends on I2C
select REGMAP_I2C
help
Say y here to support the voltage regulators and convertors
on PV88090
config REGULATOR_PWM
tristate "PWM voltage regulator"
depends on PWM
@ -680,6 +706,13 @@ config REGULATOR_TPS6507X
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
config REGULATOR_TPS65086
tristate "TI TPS65086 Power regulators"
depends on MFD_TPS65086
help
This driver provides support for the voltage regulators on
TI TPS65086 PMICs.
config REGULATOR_TPS65090
tristate "TI TPS65090 Power regulator"
depends on MFD_TPS65090

View File

@ -36,6 +36,7 @@ obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
@ -66,6 +67,8 @@ obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
obj-$(CONFIG_REGULATOR_PV88090) += pv88090-regulator.o
obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
@ -85,6 +88,7 @@ obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65086) += tps65086-regulator.o
obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o
obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o
obj-$(CONFIG_REGULATOR_TPS65218) += tps65218-regulator.o

View File

@ -27,8 +27,8 @@
#define AXP20X_IO_ENABLED 0x03
#define AXP20X_IO_DISABLED 0x07
#define AXP22X_IO_ENABLED 0x04
#define AXP22X_IO_DISABLED 0x03
#define AXP22X_IO_ENABLED 0x03
#define AXP22X_IO_DISABLED 0x04
#define AXP20X_WORKMODE_DCDC2_MASK BIT(2)
#define AXP20X_WORKMODE_DCDC3_MASK BIT(1)

View File

@ -132,24 +132,24 @@ static bool have_full_constraints(void)
return has_full_constraints || of_have_populated_dt();
}
static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
{
if (rdev && rdev->supply)
return rdev->supply->rdev;
return NULL;
}
/**
* 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;
int i;
while (1) {
mutex_lock_nested(&rdev->mutex, i++);
supply = rdev->supply;
if (!rdev->supply)
return;
rdev = supply->rdev;
}
for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++)
mutex_lock_nested(&rdev->mutex, i);
}
/**
@ -2368,7 +2368,6 @@ static void regulator_disable_work(struct work_struct *work)
int regulator_disable_deferred(struct regulator *regulator, int ms)
{
struct regulator_dev *rdev = regulator->rdev;
int ret;
if (regulator->always_on)
return 0;
@ -2380,13 +2379,9 @@ int regulator_disable_deferred(struct regulator *regulator, int ms)
rdev->deferred_disables++;
mutex_unlock(&rdev->mutex);
ret = queue_delayed_work(system_power_efficient_wq,
&rdev->disable_work,
msecs_to_jiffies(ms));
if (ret < 0)
return ret;
else
return 0;
queue_delayed_work(system_power_efficient_wq, &rdev->disable_work,
msecs_to_jiffies(ms));
return 0;
}
EXPORT_SYMBOL_GPL(regulator_disable_deferred);
@ -3451,8 +3446,10 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
consumers[i].consumer = NULL;
for (i = 0; i < num_consumers; i++) {
consumers[i].consumer = regulator_get(dev,
consumers[i].supply);
consumers[i].consumer = _regulator_get(dev,
consumers[i].supply,
false,
!consumers[i].optional);
if (IS_ERR(consumers[i].consumer)) {
ret = PTR_ERR(consumers[i].consumer);
dev_err(dev, "Failed to get supply '%s': %d\n",
@ -3708,7 +3705,7 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
{
struct device *dev = kobj_to_dev(kobj);
struct regulator_dev *rdev = container_of(dev, struct regulator_dev, dev);
struct regulator_dev *rdev = dev_to_rdev(dev);
const struct regulator_ops *ops = rdev->desc->ops;
umode_t mode = attr->mode;

View File

@ -257,7 +257,7 @@ static const struct regulator_linear_range da9034_ldo12_ranges[] = {
REGULATOR_LINEAR_RANGE(2700000, 8, 15, 50000),
};
static struct regulator_ops da903x_regulator_ldo_ops = {
static const struct regulator_ops da903x_regulator_ldo_ops = {
.set_voltage_sel = da903x_set_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
@ -268,7 +268,7 @@ static struct regulator_ops da903x_regulator_ldo_ops = {
};
/* NOTE: this is dedicated for the insane DA9030 LDO14 */
static struct regulator_ops da9030_regulator_ldo14_ops = {
static const struct regulator_ops da9030_regulator_ldo14_ops = {
.set_voltage_sel = da903x_set_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = da9030_list_ldo14_voltage,
@ -279,7 +279,7 @@ static struct regulator_ops da9030_regulator_ldo14_ops = {
};
/* NOTE: this is dedicated for the DA9030 LDO1 and LDO15 that have locks */
static struct regulator_ops da9030_regulator_ldo1_15_ops = {
static const struct regulator_ops da9030_regulator_ldo1_15_ops = {
.set_voltage_sel = da9030_set_ldo1_15_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
@ -289,7 +289,7 @@ static struct regulator_ops da9030_regulator_ldo1_15_ops = {
.is_enabled = da903x_is_enabled,
};
static struct regulator_ops da9034_regulator_dvc_ops = {
static const struct regulator_ops da9034_regulator_dvc_ops = {
.set_voltage_sel = da9034_set_dvc_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
@ -300,7 +300,7 @@ static struct regulator_ops da9034_regulator_dvc_ops = {
};
/* NOTE: this is dedicated for the insane LDO12 */
static struct regulator_ops da9034_regulator_ldo12_ops = {
static const struct regulator_ops da9034_regulator_ldo12_ops = {
.set_voltage_sel = da903x_set_voltage_sel,
.get_voltage_sel = da903x_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear_range,

View File

@ -265,7 +265,7 @@ static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
return ret;
}
static struct regulator_ops da9052_dcdc_ops = {
static const struct regulator_ops da9052_dcdc_ops = {
.get_current_limit = da9052_dcdc_get_current_limit,
.set_current_limit = da9052_dcdc_set_current_limit,
@ -279,7 +279,7 @@ static struct regulator_ops da9052_dcdc_ops = {
.disable = regulator_disable_regmap,
};
static struct regulator_ops da9052_ldo_ops = {
static const struct regulator_ops da9052_ldo_ops = {
.list_voltage = da9052_list_voltage,
.map_voltage = da9052_map_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,

View File

@ -324,7 +324,7 @@ static int da9055_suspend_disable(struct regulator_dev *rdev)
return 0;
}
static struct regulator_ops da9055_buck_ops = {
static const struct regulator_ops da9055_buck_ops = {
.get_mode = da9055_buck_get_mode,
.set_mode = da9055_buck_set_mode,
@ -345,7 +345,7 @@ static struct regulator_ops da9055_buck_ops = {
.set_suspend_mode = da9055_buck_set_mode,
};
static struct regulator_ops da9055_ldo_ops = {
static const struct regulator_ops da9055_ldo_ops = {
.get_mode = da9055_ldo_get_mode,
.set_mode = da9055_ldo_set_mode,

View File

@ -371,7 +371,7 @@ static int da9062_ldo_set_suspend_mode(struct regulator_dev *rdev,
return regmap_field_write(regl->suspend_sleep, val);
}
static struct regulator_ops da9062_buck_ops = {
static const struct regulator_ops da9062_buck_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
@ -389,7 +389,7 @@ static struct regulator_ops da9062_buck_ops = {
.set_suspend_mode = da9062_buck_set_suspend_mode,
};
static struct regulator_ops da9062_ldo_ops = {
static const struct regulator_ops da9062_ldo_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,

View File

@ -427,7 +427,7 @@ static int da9063_ldo_set_suspend_mode(struct regulator_dev *rdev, unsigned mode
return regmap_field_write(regl->suspend_sleep, val);
}
static struct regulator_ops da9063_buck_ops = {
static const struct regulator_ops da9063_buck_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
@ -445,7 +445,7 @@ static struct regulator_ops da9063_buck_ops = {
.set_suspend_mode = da9063_buck_set_suspend_mode,
};
static struct regulator_ops da9063_ldo_ops = {
static const struct regulator_ops da9063_ldo_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,

View File

@ -46,7 +46,7 @@ static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA,
int max_uA);
static int da9210_get_current_limit(struct regulator_dev *rdev);
static struct regulator_ops da9210_buck_ops = {
static const struct regulator_ops da9210_buck_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,

View File

@ -219,7 +219,7 @@ static int da9211_get_current_limit(struct regulator_dev *rdev)
return current_limits[data];
}
static struct regulator_ops da9211_buck_ops = {
static const struct regulator_ops da9211_buck_ops = {
.get_mode = da9211_buck_get_mode,
.set_mode = da9211_buck_set_mode,
.enable = regulator_enable_regmap,

View File

@ -164,8 +164,11 @@ int devm_regulator_bulk_get(struct device *dev, int num_consumers,
consumers[i].consumer = NULL;
for (i = 0; i < num_consumers; i++) {
consumers[i].consumer = devm_regulator_get(dev,
consumers[i].supply);
consumers[i].consumer = _devm_regulator_get(dev,
consumers[i].supply,
consumers[i].optional ?
OPTIONAL_GET :
NORMAL_GET);
if (IS_ERR(consumers[i].consumer)) {
ret = PTR_ERR(consumers[i].consumer);
dev_err(dev, "Failed to get supply '%s': %d\n",

View File

@ -0,0 +1,291 @@
/*
* TI LM363X Regulator Driver
*
* Copyright 2015 Texas Instruments
*
* Author: Milo Kim <milo.kim@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/mfd/ti-lmu.h>
#include <linux/mfd/ti-lmu-register.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
/* LM3631 */
#define LM3631_BOOST_VSEL_MAX 0x25
#define LM3631_LDO_VSEL_MAX 0x28
#define LM3631_CONT_VSEL_MAX 0x03
#define LM3631_VBOOST_MIN 4500000
#define LM3631_VCONT_MIN 1800000
#define LM3631_VLDO_MIN 4000000
#define ENABLE_TIME_USEC 1000
/* LM3632 */
#define LM3632_BOOST_VSEL_MAX 0x26
#define LM3632_LDO_VSEL_MAX 0x29
#define LM3632_VBOOST_MIN 4500000
#define LM3632_VLDO_MIN 4000000
/* Common */
#define LM363X_STEP_50mV 50000
#define LM363X_STEP_500mV 500000
static const int ldo_cont_enable_time[] = {
0, 2000, 5000, 10000, 20000, 50000, 100000, 200000,
};
static int lm363x_regulator_enable_time(struct regulator_dev *rdev)
{
enum lm363x_regulator_id id = rdev_get_id(rdev);
u8 val, addr, mask;
switch (id) {
case LM3631_LDO_CONT:
addr = LM3631_REG_ENTIME_VCONT;
mask = LM3631_ENTIME_CONT_MASK;
break;
case LM3631_LDO_OREF:
addr = LM3631_REG_ENTIME_VOREF;
mask = LM3631_ENTIME_MASK;
break;
case LM3631_LDO_POS:
addr = LM3631_REG_ENTIME_VPOS;
mask = LM3631_ENTIME_MASK;
break;
case LM3631_LDO_NEG:
addr = LM3631_REG_ENTIME_VNEG;
mask = LM3631_ENTIME_MASK;
break;
default:
return 0;
}
if (regmap_read(rdev->regmap, addr, (unsigned int *)&val))
return -EINVAL;
val = (val & mask) >> LM3631_ENTIME_SHIFT;
if (id == LM3631_LDO_CONT)
return ldo_cont_enable_time[val];
else
return ENABLE_TIME_USEC * val;
}
static struct regulator_ops lm363x_boost_voltage_table_ops = {
.list_voltage = regulator_list_voltage_linear,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
static struct regulator_ops lm363x_regulator_voltage_table_ops = {
.list_voltage = regulator_list_voltage_linear,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.enable_time = lm363x_regulator_enable_time,
};
static const struct regulator_desc lm363x_regulator_desc[] = {
/* LM3631 */
{
.name = "vboost",
.of_match = "vboost",
.id = LM3631_BOOST,
.ops = &lm363x_boost_voltage_table_ops,
.n_voltages = LM3631_BOOST_VSEL_MAX + 1,
.min_uV = LM3631_VBOOST_MIN,
.uV_step = LM363X_STEP_50mV,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.vsel_reg = LM3631_REG_VOUT_BOOST,
.vsel_mask = LM3631_VOUT_MASK,
},
{
.name = "ldo_cont",
.of_match = "vcont",
.id = LM3631_LDO_CONT,
.ops = &lm363x_regulator_voltage_table_ops,
.n_voltages = LM3631_CONT_VSEL_MAX + 1,
.min_uV = LM3631_VCONT_MIN,
.uV_step = LM363X_STEP_500mV,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.vsel_reg = LM3631_REG_VOUT_CONT,
.vsel_mask = LM3631_VOUT_CONT_MASK,
.enable_reg = LM3631_REG_LDO_CTRL2,
.enable_mask = LM3631_EN_CONT_MASK,
},
{
.name = "ldo_oref",
.of_match = "voref",
.id = LM3631_LDO_OREF,
.ops = &lm363x_regulator_voltage_table_ops,
.n_voltages = LM3631_LDO_VSEL_MAX + 1,
.min_uV = LM3631_VLDO_MIN,
.uV_step = LM363X_STEP_50mV,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.vsel_reg = LM3631_REG_VOUT_OREF,
.vsel_mask = LM3631_VOUT_MASK,
.enable_reg = LM3631_REG_LDO_CTRL1,
.enable_mask = LM3631_EN_OREF_MASK,
},
{
.name = "ldo_vpos",
.of_match = "vpos",
.id = LM3631_LDO_POS,
.ops = &lm363x_regulator_voltage_table_ops,
.n_voltages = LM3631_LDO_VSEL_MAX + 1,
.min_uV = LM3631_VLDO_MIN,
.uV_step = LM363X_STEP_50mV,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.vsel_reg = LM3631_REG_VOUT_POS,
.vsel_mask = LM3631_VOUT_MASK,
.enable_reg = LM3631_REG_LDO_CTRL1,
.enable_mask = LM3631_EN_VPOS_MASK,
},
{
.name = "ldo_vneg",
.of_match = "vneg",
.id = LM3631_LDO_NEG,
.ops = &lm363x_regulator_voltage_table_ops,
.n_voltages = LM3631_LDO_VSEL_MAX + 1,
.min_uV = LM3631_VLDO_MIN,
.uV_step = LM363X_STEP_50mV,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.vsel_reg = LM3631_REG_VOUT_NEG,
.vsel_mask = LM3631_VOUT_MASK,
.enable_reg = LM3631_REG_LDO_CTRL1,
.enable_mask = LM3631_EN_VNEG_MASK,
},
/* LM3632 */
{
.name = "vboost",
.of_match = "vboost",
.id = LM3632_BOOST,
.ops = &lm363x_boost_voltage_table_ops,
.n_voltages = LM3632_BOOST_VSEL_MAX + 1,
.min_uV = LM3632_VBOOST_MIN,
.uV_step = LM363X_STEP_50mV,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.vsel_reg = LM3632_REG_VOUT_BOOST,
.vsel_mask = LM3632_VOUT_MASK,
},
{
.name = "ldo_vpos",
.of_match = "vpos",
.id = LM3632_LDO_POS,
.ops = &lm363x_regulator_voltage_table_ops,
.n_voltages = LM3632_LDO_VSEL_MAX + 1,
.min_uV = LM3632_VLDO_MIN,
.uV_step = LM363X_STEP_50mV,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.vsel_reg = LM3632_REG_VOUT_POS,
.vsel_mask = LM3632_VOUT_MASK,
.enable_reg = LM3632_REG_BIAS_CONFIG,
.enable_mask = LM3632_EN_VPOS_MASK,
},
{
.name = "ldo_vneg",
.of_match = "vneg",
.id = LM3632_LDO_NEG,
.ops = &lm363x_regulator_voltage_table_ops,
.n_voltages = LM3632_LDO_VSEL_MAX + 1,
.min_uV = LM3632_VLDO_MIN,
.uV_step = LM363X_STEP_50mV,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.vsel_reg = LM3632_REG_VOUT_NEG,
.vsel_mask = LM3632_VOUT_MASK,
.enable_reg = LM3632_REG_BIAS_CONFIG,
.enable_mask = LM3632_EN_VNEG_MASK,
},
};
static int lm363x_regulator_of_get_enable_gpio(struct device_node *np, int id)
{
/*
* Check LCM_EN1/2_GPIO is configured.
* Those pins are used for enabling VPOS/VNEG LDOs.
*/
switch (id) {
case LM3632_LDO_POS:
return of_get_named_gpio(np, "ti,lcm-en1-gpio", 0);
case LM3632_LDO_NEG:
return of_get_named_gpio(np, "ti,lcm-en2-gpio", 0);
default:
return -EINVAL;
}
}
static int lm363x_regulator_probe(struct platform_device *pdev)
{
struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
struct regmap *regmap = lmu->regmap;
struct regulator_config cfg = { };
struct regulator_dev *rdev;
struct device *dev = &pdev->dev;
int id = pdev->id;
int ret, ena_gpio;
cfg.dev = dev;
cfg.regmap = regmap;
/*
* LM3632 LDOs can be controlled by external pin.
* Register update is required if the pin is used.
*/
ena_gpio = lm363x_regulator_of_get_enable_gpio(dev->of_node, id);
if (gpio_is_valid(ena_gpio)) {
cfg.ena_gpio = ena_gpio;
cfg.ena_gpio_flags = GPIOF_OUT_INIT_LOW;
ret = regmap_update_bits(regmap, LM3632_REG_BIAS_CONFIG,
LM3632_EXT_EN_MASK,
LM3632_EXT_EN_MASK);
if (ret) {
dev_err(dev, "External pin err: %d\n", ret);
return ret;
}
}
rdev = devm_regulator_register(dev, &lm363x_regulator_desc[id], &cfg);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
dev_err(dev, "[%d] regulator register err: %d\n", id, ret);
return ret;
}
return 0;
}
static struct platform_driver lm363x_regulator_driver = {
.probe = lm363x_regulator_probe,
.driver = {
.name = "lm363x-regulator",
},
};
module_platform_driver(lm363x_regulator_driver);
MODULE_DESCRIPTION("TI LM363X Regulator Driver");
MODULE_AUTHOR("Milo Kim");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:lm363x-regulator");

View File

@ -108,7 +108,6 @@ struct lp872x {
struct lp872x_platform_data *pdata;
int num_regulators;
enum lp872x_dvs_state dvs_pin;
int dvs_gpio;
};
/* LP8720/LP8725 shared voltage table for LDOs */
@ -520,6 +519,7 @@ static struct regulator_ops lp8725_buck_ops = {
static struct regulator_desc lp8720_regulator_desc[] = {
{
.name = "ldo1",
.of_match = of_match_ptr("ldo1"),
.id = LP8720_ID_LDO1,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@ -533,6 +533,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
},
{
.name = "ldo2",
.of_match = of_match_ptr("ldo2"),
.id = LP8720_ID_LDO2,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@ -546,6 +547,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
},
{
.name = "ldo3",
.of_match = of_match_ptr("ldo3"),
.id = LP8720_ID_LDO3,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@ -559,6 +561,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
},
{
.name = "ldo4",
.of_match = of_match_ptr("ldo4"),
.id = LP8720_ID_LDO4,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp8720_ldo4_vtbl),
@ -572,6 +575,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
},
{
.name = "ldo5",
.of_match = of_match_ptr("ldo5"),
.id = LP8720_ID_LDO5,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@ -585,6 +589,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
},
{
.name = "buck",
.of_match = of_match_ptr("buck"),
.id = LP8720_ID_BUCK,
.ops = &lp8720_buck_ops,
.n_voltages = ARRAY_SIZE(lp8720_buck_vtbl),
@ -599,6 +604,7 @@ static struct regulator_desc lp8720_regulator_desc[] = {
static struct regulator_desc lp8725_regulator_desc[] = {
{
.name = "ldo1",
.of_match = of_match_ptr("ldo1"),
.id = LP8725_ID_LDO1,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@ -612,6 +618,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "ldo2",
.of_match = of_match_ptr("ldo2"),
.id = LP8725_ID_LDO2,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@ -625,6 +632,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "ldo3",
.of_match = of_match_ptr("ldo3"),
.id = LP8725_ID_LDO3,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@ -638,6 +646,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "ldo4",
.of_match = of_match_ptr("ldo4"),
.id = LP8725_ID_LDO4,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@ -651,6 +660,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "ldo5",
.of_match = of_match_ptr("ldo5"),
.id = LP8725_ID_LDO5,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
@ -664,6 +674,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "lilo1",
.of_match = of_match_ptr("lilo1"),
.id = LP8725_ID_LILO1,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl),
@ -677,6 +688,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "lilo2",
.of_match = of_match_ptr("lilo2"),
.id = LP8725_ID_LILO2,
.ops = &lp872x_ldo_ops,
.n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl),
@ -690,6 +702,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "buck1",
.of_match = of_match_ptr("buck1"),
.id = LP8725_ID_BUCK1,
.ops = &lp8725_buck_ops,
.n_voltages = ARRAY_SIZE(lp8725_buck_vtbl),
@ -701,6 +714,7 @@ static struct regulator_desc lp8725_regulator_desc[] = {
},
{
.name = "buck2",
.of_match = of_match_ptr("buck2"),
.id = LP8725_ID_BUCK2,
.ops = &lp8725_buck_ops,
.n_voltages = ARRAY_SIZE(lp8725_buck_vtbl),
@ -737,7 +751,6 @@ static int lp872x_init_dvs(struct lp872x *lp)
}
lp->dvs_pin = pinstate;
lp->dvs_gpio = gpio;
return 0;

View File

@ -344,7 +344,7 @@ static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
}
static struct regulator_ops lp8788_buck12_ops = {
static const struct regulator_ops lp8788_buck12_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = lp8788_buck12_set_voltage_sel,
@ -357,7 +357,7 @@ static struct regulator_ops lp8788_buck12_ops = {
.get_mode = lp8788_buck_get_mode,
};
static struct regulator_ops lp8788_buck34_ops = {
static const struct regulator_ops lp8788_buck34_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = regulator_set_voltage_sel_regmap,

View File

@ -170,7 +170,7 @@ static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
return ENABLE_TIME_USEC * val;
}
static struct regulator_ops lp8788_ldo_voltage_table_ops = {
static const struct regulator_ops lp8788_ldo_voltage_table_ops = {
.list_voltage = regulator_list_voltage_table,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@ -180,7 +180,7 @@ static struct regulator_ops lp8788_ldo_voltage_table_ops = {
.enable_time = lp8788_ldo_enable_time,
};
static struct regulator_ops lp8788_ldo_voltage_fixed_ops = {
static const struct regulator_ops lp8788_ldo_voltage_fixed_ops = {
.list_voltage = regulator_list_voltage_linear,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@ -613,22 +613,20 @@ static struct platform_driver lp8788_aldo_driver = {
},
};
static struct platform_driver * const drivers[] = {
&lp8788_dldo_driver,
&lp8788_aldo_driver,
};
static int __init lp8788_ldo_init(void)
{
int ret;
ret = platform_driver_register(&lp8788_dldo_driver);
if (ret)
return ret;
return platform_driver_register(&lp8788_aldo_driver);
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
subsys_initcall(lp8788_ldo_init);
static void __exit lp8788_ldo_exit(void)
{
platform_driver_unregister(&lp8788_aldo_driver);
platform_driver_unregister(&lp8788_dldo_driver);
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(lp8788_ldo_exit);

View File

@ -30,6 +30,7 @@ static const struct regmap_config mt6311_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = MT6311_FQMTR_CON4,
.cache_type = REGCACHE_RBTREE,
};
/* Default limits measured in millivolts and milliamps */

View File

@ -612,6 +612,18 @@ static struct regulator_ops palmas_ops_ldo = {
.map_voltage = regulator_map_voltage_linear,
};
static struct regulator_ops palmas_ops_ldo9 = {
.is_enabled = palmas_is_enabled_ldo,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.set_bypass = regulator_set_bypass_regmap,
.get_bypass = regulator_get_bypass_regmap,
};
static struct regulator_ops palmas_ops_ext_control_ldo = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
@ -639,6 +651,19 @@ static struct regulator_ops tps65917_ops_ldo = {
.set_voltage_time_sel = regulator_set_voltage_time_sel,
};
static struct regulator_ops tps65917_ops_ldo_1_2 = {
.is_enabled = palmas_is_enabled_ldo,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_bypass = regulator_set_bypass_regmap,
.get_bypass = regulator_get_bypass_regmap,
};
static int palmas_regulator_config_external(struct palmas *palmas, int id,
struct palmas_reg_init *reg_init)
{
@ -915,6 +940,13 @@ static int palmas_ldo_registration(struct palmas_pmic *pmic,
if (pdata && pdata->ldo6_vibrator &&
(id == PALMAS_REG_LDO6))
desc->enable_time = 2000;
if (id == PALMAS_REG_LDO9) {
desc->ops = &palmas_ops_ldo9;
desc->bypass_reg = desc->enable_reg;
desc->bypass_mask =
PALMAS_LDO9_CTRL_LDO_BYPASS_EN;
}
} else {
if (!ddata->has_regen3 && id == PALMAS_REG_REGEN3)
continue;
@ -1019,6 +1051,13 @@ static int tps65917_ldo_registration(struct palmas_pmic *pmic,
* It is of the order of ~60mV/uS.
*/
desc->ramp_delay = 2500;
if (id == TPS65917_REG_LDO1 ||
id == TPS65917_REG_LDO2) {
desc->ops = &tps65917_ops_ldo_1_2;
desc->bypass_reg = desc->enable_reg;
desc->bypass_mask =
TPS65917_LDO1_CTRL_BYPASS_EN;
}
} else {
desc->n_voltages = 1;
if (reg_init && reg_init->roof_floor)

View File

@ -0,0 +1,437 @@
/*
* pv88060-regulator.c - Regulator device driver for PV88060
* Copyright (C) 2015 Powerventure Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regmap.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/regulator/of_regulator.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include "pv88060-regulator.h"
#define PV88060_MAX_REGULATORS 14
/* PV88060 REGULATOR IDs */
enum {
/* BUCKs */
PV88060_ID_BUCK1,
/* LDOs */
PV88060_ID_LDO1,
PV88060_ID_LDO2,
PV88060_ID_LDO3,
PV88060_ID_LDO4,
PV88060_ID_LDO5,
PV88060_ID_LDO6,
PV88060_ID_LDO7,
/* SWTs */
PV88060_ID_SW1,
PV88060_ID_SW2,
PV88060_ID_SW3,
PV88060_ID_SW4,
PV88060_ID_SW5,
PV88060_ID_SW6,
};
struct pv88060_regulator {
struct regulator_desc desc;
/* Current limiting */
unsigned n_current_limits;
const int *current_limits;
unsigned int limit_mask;
unsigned int conf; /* buck configuration register */
};
struct pv88060 {
struct device *dev;
struct regmap *regmap;
struct regulator_dev *rdev[PV88060_MAX_REGULATORS];
};
static const struct regmap_config pv88060_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
/* Current limits array (in uA) for BUCK1
* Entry indexes corresponds to register values.
*/
static const int pv88060_buck1_limits[] = {
1496000, 2393000, 3291000, 4189000
};
static unsigned int pv88060_buck_get_mode(struct regulator_dev *rdev)
{
struct pv88060_regulator *info = rdev_get_drvdata(rdev);
unsigned int data;
int ret, mode = 0;
ret = regmap_read(rdev->regmap, info->conf, &data);
if (ret < 0)
return ret;
switch (data & PV88060_BUCK_MODE_MASK) {
case PV88060_BUCK_MODE_SYNC:
mode = REGULATOR_MODE_FAST;
break;
case PV88060_BUCK_MODE_AUTO:
mode = REGULATOR_MODE_NORMAL;
break;
case PV88060_BUCK_MODE_SLEEP:
mode = REGULATOR_MODE_STANDBY;
break;
}
return mode;
}
static int pv88060_buck_set_mode(struct regulator_dev *rdev,
unsigned int mode)
{
struct pv88060_regulator *info = rdev_get_drvdata(rdev);
int val = 0;
switch (mode) {
case REGULATOR_MODE_FAST:
val = PV88060_BUCK_MODE_SYNC;
break;
case REGULATOR_MODE_NORMAL:
val = PV88060_BUCK_MODE_AUTO;
break;
case REGULATOR_MODE_STANDBY:
val = PV88060_BUCK_MODE_SLEEP;
break;
default:
return -EINVAL;
}
return regmap_update_bits(rdev->regmap, info->conf,
PV88060_BUCK_MODE_MASK, val);
}
static int pv88060_set_current_limit(struct regulator_dev *rdev, int min,
int max)
{
struct pv88060_regulator *info = rdev_get_drvdata(rdev);
int i;
/* search for closest to maximum */
for (i = info->n_current_limits; i >= 0; i--) {
if (min <= info->current_limits[i]
&& max >= info->current_limits[i]) {
return regmap_update_bits(rdev->regmap,
info->conf,
info->limit_mask,
i << PV88060_BUCK_ILIM_SHIFT);
}
}
return -EINVAL;
}
static int pv88060_get_current_limit(struct regulator_dev *rdev)
{
struct pv88060_regulator *info = rdev_get_drvdata(rdev);
unsigned int data;
int ret;
ret = regmap_read(rdev->regmap, info->conf, &data);
if (ret < 0)
return ret;
data = (data & info->limit_mask) >> PV88060_BUCK_ILIM_SHIFT;
return info->current_limits[data];
}
static struct regulator_ops pv88060_buck_ops = {
.get_mode = pv88060_buck_get_mode,
.set_mode = pv88060_buck_set_mode,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
.set_current_limit = pv88060_set_current_limit,
.get_current_limit = pv88060_get_current_limit,
};
static struct regulator_ops pv88060_ldo_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
};
#define PV88060_BUCK(chip, regl_name, min, step, max, limits_array) \
{\
.desc = {\
.id = chip##_ID_##regl_name,\
.name = __stringify(chip##_##regl_name),\
.of_match = of_match_ptr(#regl_name),\
.regulators_node = of_match_ptr("regulators"),\
.type = REGULATOR_VOLTAGE,\
.owner = THIS_MODULE,\
.ops = &pv88060_buck_ops,\
.min_uV = min,\
.uV_step = step,\
.n_voltages = ((max) - (min))/(step) + 1,\
.enable_reg = PV88060_REG_##regl_name##_CONF0,\
.enable_mask = PV88060_BUCK_EN, \
.vsel_reg = PV88060_REG_##regl_name##_CONF0,\
.vsel_mask = PV88060_VBUCK_MASK,\
},\
.current_limits = limits_array,\
.n_current_limits = ARRAY_SIZE(limits_array),\
.limit_mask = PV88060_BUCK_ILIM_MASK, \
.conf = PV88060_REG_##regl_name##_CONF1,\
}
#define PV88060_LDO(chip, regl_name, min, step, max) \
{\
.desc = {\
.id = chip##_ID_##regl_name,\
.name = __stringify(chip##_##regl_name),\
.of_match = of_match_ptr(#regl_name),\
.regulators_node = of_match_ptr("regulators"),\
.type = REGULATOR_VOLTAGE,\
.owner = THIS_MODULE,\
.ops = &pv88060_ldo_ops,\
.min_uV = min, \
.uV_step = step, \
.n_voltages = (step) ? ((max - min) / step + 1) : 1, \
.enable_reg = PV88060_REG_##regl_name##_CONF, \
.enable_mask = PV88060_LDO_EN, \
.vsel_reg = PV88060_REG_##regl_name##_CONF, \
.vsel_mask = PV88060_VLDO_MASK, \
},\
}
#define PV88060_SW(chip, regl_name, max) \
{\
.desc = {\
.id = chip##_ID_##regl_name,\
.name = __stringify(chip##_##regl_name),\
.of_match = of_match_ptr(#regl_name),\
.regulators_node = of_match_ptr("regulators"),\
.type = REGULATOR_VOLTAGE,\
.owner = THIS_MODULE,\
.ops = &pv88060_ldo_ops,\
.min_uV = max,\
.uV_step = 0,\
.n_voltages = 1,\
.enable_reg = PV88060_REG_##regl_name##_CONF,\
.enable_mask = PV88060_SW_EN,\
},\
}
static const struct pv88060_regulator pv88060_regulator_info[] = {
PV88060_BUCK(PV88060, BUCK1, 2800000, 12500, 4387500,
pv88060_buck1_limits),
PV88060_LDO(PV88060, LDO1, 1200000, 50000, 3350000),
PV88060_LDO(PV88060, LDO2, 1200000, 50000, 3350000),
PV88060_LDO(PV88060, LDO3, 1200000, 50000, 3350000),
PV88060_LDO(PV88060, LDO4, 1200000, 50000, 3350000),
PV88060_LDO(PV88060, LDO5, 1200000, 50000, 3350000),
PV88060_LDO(PV88060, LDO6, 1200000, 50000, 3350000),
PV88060_LDO(PV88060, LDO7, 1200000, 50000, 3350000),
PV88060_SW(PV88060, SW1, 5000000),
PV88060_SW(PV88060, SW2, 5000000),
PV88060_SW(PV88060, SW3, 5000000),
PV88060_SW(PV88060, SW4, 5000000),
PV88060_SW(PV88060, SW5, 5000000),
PV88060_SW(PV88060, SW6, 5000000),
};
static irqreturn_t pv88060_irq_handler(int irq, void *data)
{
struct pv88060 *chip = data;
int i, reg_val, err, ret = IRQ_NONE;
err = regmap_read(chip->regmap, PV88060_REG_EVENT_A, &reg_val);
if (err < 0)
goto error_i2c;
if (reg_val & PV88060_E_VDD_FLT) {
for (i = 0; i < PV88060_MAX_REGULATORS; i++) {
if (chip->rdev[i] != NULL) {
regulator_notifier_call_chain(chip->rdev[i],
REGULATOR_EVENT_UNDER_VOLTAGE,
NULL);
}
}
err = regmap_update_bits(chip->regmap, PV88060_REG_EVENT_A,
PV88060_E_VDD_FLT, PV88060_E_VDD_FLT);
if (err < 0)
goto error_i2c;
ret = IRQ_HANDLED;
}
if (reg_val & PV88060_E_OVER_TEMP) {
for (i = 0; i < PV88060_MAX_REGULATORS; i++) {
if (chip->rdev[i] != NULL) {
regulator_notifier_call_chain(chip->rdev[i],
REGULATOR_EVENT_OVER_TEMP,
NULL);
}
}
err = regmap_update_bits(chip->regmap, PV88060_REG_EVENT_A,
PV88060_E_OVER_TEMP, PV88060_E_OVER_TEMP);
if (err < 0)
goto error_i2c;
ret = IRQ_HANDLED;
}
return ret;
error_i2c:
dev_err(chip->dev, "I2C error : %d\n", err);
return IRQ_NONE;
}
/*
* I2C driver interface functions
*/
static int pv88060_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
struct pv88060 *chip;
struct regulator_config config = { };
int error, i, ret = 0;
chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88060), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->dev = &i2c->dev;
chip->regmap = devm_regmap_init_i2c(i2c, &pv88060_regmap_config);
if (IS_ERR(chip->regmap)) {
error = PTR_ERR(chip->regmap);
dev_err(chip->dev, "Failed to allocate register map: %d\n",
error);
return error;
}
i2c_set_clientdata(i2c, chip);
if (i2c->irq != 0) {
ret = regmap_write(chip->regmap, PV88060_REG_MASK_A, 0xFF);
if (ret < 0) {
dev_err(chip->dev,
"Failed to mask A reg: %d\n", ret);
return ret;
}
ret = regmap_write(chip->regmap, PV88060_REG_MASK_B, 0xFF);
if (ret < 0) {
dev_err(chip->dev,
"Failed to mask B reg: %d\n", ret);
return ret;
}
ret = regmap_write(chip->regmap, PV88060_REG_MASK_C, 0xFF);
if (ret < 0) {
dev_err(chip->dev,
"Failed to mask C reg: %d\n", ret);
return ret;
}
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
pv88060_irq_handler,
IRQF_TRIGGER_LOW|IRQF_ONESHOT,
"pv88060", chip);
if (ret != 0) {
dev_err(chip->dev, "Failed to request IRQ: %d\n",
i2c->irq);
return ret;
}
ret = regmap_update_bits(chip->regmap, PV88060_REG_MASK_A,
PV88060_M_VDD_FLT | PV88060_M_OVER_TEMP, 0);
if (ret < 0) {
dev_err(chip->dev,
"Failed to update mask reg: %d\n", ret);
return ret;
}
} else {
dev_warn(chip->dev, "No IRQ configured\n");
}
config.dev = chip->dev;
config.regmap = chip->regmap;
for (i = 0; i < PV88060_MAX_REGULATORS; i++) {
if (init_data)
config.init_data = &init_data[i];
config.driver_data = (void *)&pv88060_regulator_info[i];
chip->rdev[i] = devm_regulator_register(chip->dev,
&pv88060_regulator_info[i].desc, &config);
if (IS_ERR(chip->rdev[i])) {
dev_err(chip->dev,
"Failed to register PV88060 regulator\n");
return PTR_ERR(chip->rdev[i]);
}
}
return 0;
}
static const struct i2c_device_id pv88060_i2c_id[] = {
{"pv88060", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, pv88060_i2c_id);
#ifdef CONFIG_OF
static const struct of_device_id pv88060_dt_ids[] = {
{ .compatible = "pvs,pv88060", .data = &pv88060_i2c_id[0] },
{},
};
MODULE_DEVICE_TABLE(of, pv88060_dt_ids);
#endif
static struct i2c_driver pv88060_regulator_driver = {
.driver = {
.name = "pv88060",
.of_match_table = of_match_ptr(pv88060_dt_ids),
},
.probe = pv88060_i2c_probe,
.id_table = pv88060_i2c_id,
};
module_i2c_driver(pv88060_regulator_driver);
MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88060");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,69 @@
/*
* pv88060-regulator.h - Regulator definitions for PV88060
* Copyright (C) 2015 Powerventure Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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 __PV88060_REGISTERS_H__
#define __PV88060_REGISTERS_H__
/* System Control and Event Registers */
#define PV88060_REG_EVENT_A 0x04
#define PV88060_REG_MASK_A 0x08
#define PV88060_REG_MASK_B 0x09
#define PV88060_REG_MASK_C 0x0A
/* Regulator Registers */
#define PV88060_REG_BUCK1_CONF0 0x1B
#define PV88060_REG_BUCK1_CONF1 0x1C
#define PV88060_REG_LDO1_CONF 0x1D
#define PV88060_REG_LDO2_CONF 0x1E
#define PV88060_REG_LDO3_CONF 0x1F
#define PV88060_REG_LDO4_CONF 0x20
#define PV88060_REG_LDO5_CONF 0x21
#define PV88060_REG_LDO6_CONF 0x22
#define PV88060_REG_LDO7_CONF 0x23
#define PV88060_REG_SW1_CONF 0x3B
#define PV88060_REG_SW2_CONF 0x3C
#define PV88060_REG_SW3_CONF 0x3D
#define PV88060_REG_SW4_CONF 0x3E
#define PV88060_REG_SW5_CONF 0x3F
#define PV88060_REG_SW6_CONF 0x40
/* PV88060_REG_EVENT_A (addr=0x04) */
#define PV88060_E_VDD_FLT 0x01
#define PV88060_E_OVER_TEMP 0x02
/* PV88060_REG_MASK_A (addr=0x08) */
#define PV88060_M_VDD_FLT 0x01
#define PV88060_M_OVER_TEMP 0x02
/* PV88060_REG_BUCK1_CONF0 (addr=0x1B) */
#define PV88060_BUCK_EN 0x80
#define PV88060_VBUCK_MASK 0x7F
/* PV88060_REG_LDO1/2/3/4/5/6/7_CONT */
#define PV88060_LDO_EN 0x40
#define PV88060_VLDO_MASK 0x3F
/* PV88060_REG_SW1/2/3/4/5_CONF */
#define PV88060_SW_EN 0x80
/* PV88060_REG_BUCK1_CONF1 (addr=0x1C) */
#define PV88060_BUCK_ILIM_SHIFT 2
#define PV88060_BUCK_ILIM_MASK 0x0C
#define PV88060_BUCK_MODE_SHIFT 0
#define PV88060_BUCK_MODE_MASK 0x03
#define PV88060_BUCK_MODE_SLEEP 0x00
#define PV88060_BUCK_MODE_AUTO 0x01
#define PV88060_BUCK_MODE_SYNC 0x02
#endif /* __PV88060_REGISTERS_H__ */

View File

@ -0,0 +1,458 @@
/*
* pv88090-regulator.c - Regulator device driver for PV88090
* Copyright (C) 2015 Powerventure Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*/
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regmap.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/regulator/of_regulator.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include "pv88090-regulator.h"
#define PV88090_MAX_REGULATORS 5
/* PV88090 REGULATOR IDs */
enum {
/* BUCKs */
PV88090_ID_BUCK1,
PV88090_ID_BUCK2,
PV88090_ID_BUCK3,
/* LDOs */
PV88090_ID_LDO1,
PV88090_ID_LDO2,
};
struct pv88090_regulator {
struct regulator_desc desc;
/* Current limiting */
unsigned n_current_limits;
const int *current_limits;
unsigned int limit_mask;
unsigned int conf;
unsigned int conf2;
};
struct pv88090 {
struct device *dev;
struct regmap *regmap;
struct regulator_dev *rdev[PV88090_MAX_REGULATORS];
};
struct pv88090_buck_voltage {
int min_uV;
int max_uV;
int uV_step;
};
static const struct regmap_config pv88090_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3.
* Entry indexes corresponds to register values.
*/
static const int pv88090_buck1_limits[] = {
220000, 440000, 660000, 880000, 1100000, 1320000, 1540000, 1760000,
1980000, 2200000, 2420000, 2640000, 2860000, 3080000, 3300000, 3520000,
3740000, 3960000, 4180000, 4400000, 4620000, 4840000, 5060000, 5280000,
5500000, 5720000, 5940000, 6160000, 6380000, 6600000, 6820000, 7040000
};
static const int pv88090_buck23_limits[] = {
1496000, 2393000, 3291000, 4189000
};
static const struct pv88090_buck_voltage pv88090_buck_vol[3] = {
{
.min_uV = 600000,
.max_uV = 1393750,
.uV_step = 6250,
},
{
.min_uV = 1400000,
.max_uV = 2193750,
.uV_step = 6250,
},
{
.min_uV = 1250000,
.max_uV = 2837500,
.uV_step = 12500,
},
};
static unsigned int pv88090_buck_get_mode(struct regulator_dev *rdev)
{
struct pv88090_regulator *info = rdev_get_drvdata(rdev);
unsigned int data;
int ret, mode = 0;
ret = regmap_read(rdev->regmap, info->conf, &data);
if (ret < 0)
return ret;
switch (data & PV88090_BUCK1_MODE_MASK) {
case PV88090_BUCK_MODE_SYNC:
mode = REGULATOR_MODE_FAST;
break;
case PV88090_BUCK_MODE_AUTO:
mode = REGULATOR_MODE_NORMAL;
break;
case PV88090_BUCK_MODE_SLEEP:
mode = REGULATOR_MODE_STANDBY;
break;
}
return mode;
}
static int pv88090_buck_set_mode(struct regulator_dev *rdev,
unsigned int mode)
{
struct pv88090_regulator *info = rdev_get_drvdata(rdev);
int val = 0;
switch (mode) {
case REGULATOR_MODE_FAST:
val = PV88090_BUCK_MODE_SYNC;
break;
case REGULATOR_MODE_NORMAL:
val = PV88090_BUCK_MODE_AUTO;
break;
case REGULATOR_MODE_STANDBY:
val = PV88090_BUCK_MODE_SLEEP;
break;
default:
return -EINVAL;
}
return regmap_update_bits(rdev->regmap, info->conf,
PV88090_BUCK1_MODE_MASK, val);
}
static int pv88090_set_current_limit(struct regulator_dev *rdev, int min,
int max)
{
struct pv88090_regulator *info = rdev_get_drvdata(rdev);
int i;
/* search for closest to maximum */
for (i = info->n_current_limits; i >= 0; i--) {
if (min <= info->current_limits[i]
&& max >= info->current_limits[i]) {
return regmap_update_bits(rdev->regmap,
info->conf,
info->limit_mask,
i << PV88090_BUCK1_ILIM_SHIFT);
}
}
return -EINVAL;
}
static int pv88090_get_current_limit(struct regulator_dev *rdev)
{
struct pv88090_regulator *info = rdev_get_drvdata(rdev);
unsigned int data;
int ret;
ret = regmap_read(rdev->regmap, info->conf, &data);
if (ret < 0)
return ret;
data = (data & info->limit_mask) >> PV88090_BUCK1_ILIM_SHIFT;
return info->current_limits[data];
}
static struct regulator_ops pv88090_buck_ops = {
.get_mode = pv88090_buck_get_mode,
.set_mode = pv88090_buck_set_mode,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
.set_current_limit = pv88090_set_current_limit,
.get_current_limit = pv88090_get_current_limit,
};
static struct regulator_ops pv88090_ldo_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
};
#define PV88090_BUCK(chip, regl_name, min, step, max, limits_array) \
{\
.desc = {\
.id = chip##_ID_##regl_name,\
.name = __stringify(chip##_##regl_name),\
.of_match = of_match_ptr(#regl_name),\
.regulators_node = of_match_ptr("regulators"),\
.type = REGULATOR_VOLTAGE,\
.owner = THIS_MODULE,\
.ops = &pv88090_buck_ops,\
.min_uV = min, \
.uV_step = step, \
.n_voltages = ((max) - (min))/(step) + 1, \
.enable_reg = PV88090_REG_##regl_name##_CONF0, \
.enable_mask = PV88090_##regl_name##_EN, \
.vsel_reg = PV88090_REG_##regl_name##_CONF0, \
.vsel_mask = PV88090_V##regl_name##_MASK, \
},\
.current_limits = limits_array, \
.n_current_limits = ARRAY_SIZE(limits_array), \
.limit_mask = PV88090_##regl_name##_ILIM_MASK, \
.conf = PV88090_REG_##regl_name##_CONF1, \
.conf2 = PV88090_REG_##regl_name##_CONF2, \
}
#define PV88090_LDO(chip, regl_name, min, step, max) \
{\
.desc = {\
.id = chip##_ID_##regl_name,\
.name = __stringify(chip##_##regl_name),\
.of_match = of_match_ptr(#regl_name),\
.regulators_node = of_match_ptr("regulators"),\
.type = REGULATOR_VOLTAGE,\
.owner = THIS_MODULE,\
.ops = &pv88090_ldo_ops,\
.min_uV = min, \
.uV_step = step, \
.n_voltages = ((max) - (min))/(step) + 1, \
.enable_reg = PV88090_REG_##regl_name##_CONT, \
.enable_mask = PV88090_##regl_name##_EN, \
.vsel_reg = PV88090_REG_##regl_name##_CONT, \
.vsel_mask = PV88090_V##regl_name##_MASK, \
},\
}
static struct pv88090_regulator pv88090_regulator_info[] = {
PV88090_BUCK(PV88090, BUCK1, 600000, 6250, 1393750,
pv88090_buck1_limits),
PV88090_BUCK(PV88090, BUCK2, 600000, 6250, 1393750,
pv88090_buck23_limits),
PV88090_BUCK(PV88090, BUCK3, 600000, 6250, 1393750,
pv88090_buck23_limits),
PV88090_LDO(PV88090, LDO1, 1200000, 50000, 4350000),
PV88090_LDO(PV88090, LDO2, 650000, 25000, 2225000),
};
static irqreturn_t pv88090_irq_handler(int irq, void *data)
{
struct pv88090 *chip = data;
int i, reg_val, err, ret = IRQ_NONE;
err = regmap_read(chip->regmap, PV88090_REG_EVENT_A, &reg_val);
if (err < 0)
goto error_i2c;
if (reg_val & PV88090_E_VDD_FLT) {
for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
if (chip->rdev[i] != NULL) {
regulator_notifier_call_chain(chip->rdev[i],
REGULATOR_EVENT_UNDER_VOLTAGE,
NULL);
}
}
err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
PV88090_E_VDD_FLT, PV88090_E_VDD_FLT);
if (err < 0)
goto error_i2c;
ret = IRQ_HANDLED;
}
if (reg_val & PV88090_E_OVER_TEMP) {
for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
if (chip->rdev[i] != NULL) {
regulator_notifier_call_chain(chip->rdev[i],
REGULATOR_EVENT_OVER_TEMP,
NULL);
}
}
err = regmap_update_bits(chip->regmap, PV88090_REG_EVENT_A,
PV88090_E_OVER_TEMP, PV88090_E_OVER_TEMP);
if (err < 0)
goto error_i2c;
ret = IRQ_HANDLED;
}
return ret;
error_i2c:
dev_err(chip->dev, "I2C error : %d\n", err);
return IRQ_NONE;
}
/*
* I2C driver interface functions
*/
static int pv88090_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
struct pv88090 *chip;
struct regulator_config config = { };
int error, i, ret = 0;
unsigned int conf2, range, index;
chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88090), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->dev = &i2c->dev;
chip->regmap = devm_regmap_init_i2c(i2c, &pv88090_regmap_config);
if (IS_ERR(chip->regmap)) {
error = PTR_ERR(chip->regmap);
dev_err(chip->dev, "Failed to allocate register map: %d\n",
error);
return error;
}
i2c_set_clientdata(i2c, chip);
if (i2c->irq != 0) {
ret = regmap_write(chip->regmap, PV88090_REG_MASK_A, 0xFF);
if (ret < 0) {
dev_err(chip->dev,
"Failed to mask A reg: %d\n", ret);
return ret;
}
ret = regmap_write(chip->regmap, PV88090_REG_MASK_B, 0xFF);
if (ret < 0) {
dev_err(chip->dev,
"Failed to mask B reg: %d\n", ret);
return ret;
}
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
pv88090_irq_handler,
IRQF_TRIGGER_LOW|IRQF_ONESHOT,
"pv88090", chip);
if (ret != 0) {
dev_err(chip->dev, "Failed to request IRQ: %d\n",
i2c->irq);
return ret;
}
ret = regmap_update_bits(chip->regmap, PV88090_REG_MASK_A,
PV88090_M_VDD_FLT | PV88090_M_OVER_TEMP, 0);
if (ret < 0) {
dev_err(chip->dev,
"Failed to update mask reg: %d\n", ret);
return ret;
}
} else {
dev_warn(chip->dev, "No IRQ configured\n");
}
config.dev = chip->dev;
config.regmap = chip->regmap;
for (i = 0; i < PV88090_MAX_REGULATORS; i++) {
if (init_data)
config.init_data = &init_data[i];
if (i == PV88090_ID_BUCK2 || i == PV88090_ID_BUCK3) {
ret = regmap_read(chip->regmap,
pv88090_regulator_info[i].conf2, &conf2);
if (ret < 0)
return ret;
conf2 = (conf2 >> PV88090_BUCK_VDAC_RANGE_SHIFT) &
PV88090_BUCK_VDAC_RANGE_MASK;
ret = regmap_read(chip->regmap,
PV88090_REG_BUCK_FOLD_RANGE, &range);
if (ret < 0)
return ret;
range = (range >>
(PV88080_BUCK_VRANGE_GAIN_SHIFT + i - 1)) &
PV88080_BUCK_VRANGE_GAIN_MASK;
index = ((range << 1) | conf2);
pv88090_regulator_info[i].desc.min_uV
= pv88090_buck_vol[index].min_uV;
pv88090_regulator_info[i].desc.uV_step
= pv88090_buck_vol[index].uV_step;
pv88090_regulator_info[i].desc.n_voltages
= ((pv88090_buck_vol[index].max_uV)
- (pv88090_buck_vol[index].min_uV))
/(pv88090_buck_vol[index].uV_step) + 1;
}
config.driver_data = (void *)&pv88090_regulator_info[i];
chip->rdev[i] = devm_regulator_register(chip->dev,
&pv88090_regulator_info[i].desc, &config);
if (IS_ERR(chip->rdev[i])) {
dev_err(chip->dev,
"Failed to register PV88090 regulator\n");
return PTR_ERR(chip->rdev[i]);
}
}
return 0;
}
static const struct i2c_device_id pv88090_i2c_id[] = {
{"pv88090", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, pv88090_i2c_id);
#ifdef CONFIG_OF
static const struct of_device_id pv88090_dt_ids[] = {
{ .compatible = "pvs,pv88090", .data = &pv88090_i2c_id[0] },
{},
};
MODULE_DEVICE_TABLE(of, pv88090_dt_ids);
#endif
static struct i2c_driver pv88090_regulator_driver = {
.driver = {
.name = "pv88090",
.of_match_table = of_match_ptr(pv88090_dt_ids),
},
.probe = pv88090_i2c_probe,
.id_table = pv88090_i2c_id,
};
module_i2c_driver(pv88090_regulator_driver);
MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88090");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,98 @@
/*
* pv88090-regulator.h - Regulator definitions for PV88090
* Copyright (C) 2015 Powerventure Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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 __PV88090_REGISTERS_H__
#define __PV88090_REGISTERS_H__
/* System Control and Event Registers */
#define PV88090_REG_EVENT_A 0x03
#define PV88090_REG_MASK_A 0x06
#define PV88090_REG_MASK_B 0x07
/* Regulator Registers */
#define PV88090_REG_BUCK1_CONF0 0x18
#define PV88090_REG_BUCK1_CONF1 0x19
#define PV88090_REG_BUCK1_CONF2 0x1a
#define PV88090_REG_BUCK2_CONF0 0x1b
#define PV88090_REG_BUCK2_CONF1 0x1c
#define PV88090_REG_BUCK2_CONF2 0x58
#define PV88090_REG_BUCK3_CONF0 0x1d
#define PV88090_REG_BUCK3_CONF1 0x1e
#define PV88090_REG_BUCK3_CONF2 0x5c
#define PV88090_REG_LDO1_CONT 0x1f
#define PV88090_REG_LDO2_CONT 0x20
#define PV88090_REG_LDO3_CONT 0x21
#define PV88090_REG_BUCK_FOLD_RANGE 0x61
/* PV88090_REG_EVENT_A (addr=0x03) */
#define PV88090_E_VDD_FLT 0x01
#define PV88090_E_OVER_TEMP 0x02
/* PV88090_REG_MASK_A (addr=0x06) */
#define PV88090_M_VDD_FLT 0x01
#define PV88090_M_OVER_TEMP 0x02
/* PV88090_REG_BUCK1_CONF0 (addr=0x18) */
#define PV88090_BUCK1_EN 0x80
#define PV88090_VBUCK1_MASK 0x7F
/* PV88090_REG_BUCK2_CONF0 (addr=0x1b) */
#define PV88090_BUCK2_EN 0x80
#define PV88090_VBUCK2_MASK 0x7F
/* PV88090_REG_BUCK3_CONF0 (addr=0x1d) */
#define PV88090_BUCK3_EN 0x80
#define PV88090_VBUCK3_MASK 0x7F
/* PV88090_REG_LDO1_CONT (addr=0x1f) */
#define PV88090_LDO1_EN 0x40
#define PV88090_VLDO1_MASK 0x3F
/* PV88090_REG_LDO2_CONT (addr=0x20) */
#define PV88090_LDO2_EN 0x40
#define PV88090_VLDO2_MASK 0x3F
/* PV88090_REG_BUCK1_CONF1 (addr=0x19) */
#define PV88090_BUCK1_ILIM_SHIFT 2
#define PV88090_BUCK1_ILIM_MASK 0x7C
#define PV88090_BUCK1_MODE_MASK 0x03
/* PV88090_REG_BUCK2_CONF1 (addr=0x1c) */
#define PV88090_BUCK2_ILIM_SHIFT 2
#define PV88090_BUCK2_ILIM_MASK 0x0C
#define PV88090_BUCK2_MODE_MASK 0x03
/* PV88090_REG_BUCK3_CONF1 (addr=0x1e) */
#define PV88090_BUCK3_ILIM_SHIFT 2
#define PV88090_BUCK3_ILIM_MASK 0x0C
#define PV88090_BUCK3_MODE_MASK 0x03
#define PV88090_BUCK_MODE_SLEEP 0x00
#define PV88090_BUCK_MODE_AUTO 0x01
#define PV88090_BUCK_MODE_SYNC 0x02
/* PV88090_REG_BUCK2_CONF2 (addr=0x58) */
/* PV88090_REG_BUCK3_CONF2 (addr=0x5c) */
#define PV88090_BUCK_VDAC_RANGE_SHIFT 7
#define PV88090_BUCK_VDAC_RANGE_MASK 0x01
#define PV88090_BUCK_VDAC_RANGE_1 0x00
#define PV88090_BUCK_VDAC_RANGE_2 0x01
/* PV88090_REG_BUCK_FOLD_RANGE (addr=0x61) */
#define PV88080_BUCK_VRANGE_GAIN_SHIFT 3
#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01
#define PV88080_BUCK_VRANGE_GAIN_1 0x00
#define PV88080_BUCK_VRANGE_GAIN_2 0x01
#endif /* __PV88090_REGISTERS_H__ */

View File

@ -153,6 +153,49 @@ static const struct regulator_ops rpm_switch_ops = {
.is_enabled = rpm_reg_is_enabled,
};
static const struct regulator_desc pma8084_hfsmps = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(375000, 0, 95, 12500),
REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000),
},
.n_linear_ranges = 2,
.n_voltages = 159,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pma8084_ftsmps = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000),
REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000),
},
.n_linear_ranges = 2,
.n_voltages = 340,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pma8084_pldo = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(750000, 0, 30, 25000),
REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000),
},
.n_linear_ranges = 2,
.n_voltages = 100,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pma8084_nldo = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500),
},
.n_linear_ranges = 1,
.n_voltages = 64,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pma8084_switch = {
.ops = &rpm_switch_ops,
};
static const struct regulator_desc pm8x41_hfsmps = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500),
@ -211,6 +254,43 @@ static const struct regulator_desc pm8941_switch = {
.ops = &rpm_switch_ops,
};
static const struct regulator_desc pm8916_pldo = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(750000, 0, 208, 12500),
},
.n_linear_ranges = 1,
.n_voltages = 209,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pm8916_nldo = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(375000, 0, 93, 12500),
},
.n_linear_ranges = 1,
.n_voltages = 94,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pm8916_buck_lvo_smps = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(375000, 0, 95, 12500),
REGULATOR_LINEAR_RANGE(750000, 96, 127, 25000),
},
.n_linear_ranges = 2,
.n_voltages = 128,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pm8916_buck_hvo_smps = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(1550000, 0, 31, 25000),
},
.n_linear_ranges = 1,
.n_voltages = 32,
.ops = &rpm_smps_ldo_ops,
};
struct rpm_regulator_data {
const char *name;
u32 type;
@ -231,6 +311,32 @@ static const struct rpm_regulator_data rpm_pm8841_regulators[] = {
{}
};
static const struct rpm_regulator_data rpm_pm8916_regulators[] = {
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pm8916_buck_lvo_smps, "vdd_s1" },
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pm8916_buck_lvo_smps, "vdd_s2" },
{ "s3", QCOM_SMD_RPM_SMPA, 3, &pm8916_buck_lvo_smps, "vdd_s3" },
{ "s4", QCOM_SMD_RPM_SMPA, 4, &pm8916_buck_hvo_smps, "vdd_s4" },
{ "l1", QCOM_SMD_RPM_LDOA, 1, &pm8916_nldo, "vdd_l1_l2_l3" },
{ "l2", QCOM_SMD_RPM_LDOA, 2, &pm8916_nldo, "vdd_l1_l2_l3" },
{ "l3", QCOM_SMD_RPM_LDOA, 3, &pm8916_nldo, "vdd_l1_l2_l3" },
{ "l4", QCOM_SMD_RPM_LDOA, 4, &pm8916_pldo, "vdd_l4_l5_l6" },
{ "l5", QCOM_SMD_RPM_LDOA, 5, &pm8916_pldo, "vdd_l4_l5_l6" },
{ "l6", QCOM_SMD_RPM_LDOA, 6, &pm8916_pldo, "vdd_l4_l5_l6" },
{ "l7", QCOM_SMD_RPM_LDOA, 7, &pm8916_pldo, "vdd_l7" },
{ "l8", QCOM_SMD_RPM_LDOA, 8, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18" },
{ "l9", QCOM_SMD_RPM_LDOA, 9, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18" },
{ "l10", QCOM_SMD_RPM_LDOA, 10, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
{ "l11", QCOM_SMD_RPM_LDOA, 11, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
{ "l12", QCOM_SMD_RPM_LDOA, 12, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
{ "l13", QCOM_SMD_RPM_LDOA, 13, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
{ "l14", QCOM_SMD_RPM_LDOA, 14, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
{ "l15", QCOM_SMD_RPM_LDOA, 15, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
{ "l16", QCOM_SMD_RPM_LDOA, 16, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
{ "l17", QCOM_SMD_RPM_LDOA, 17, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
{ "l18", QCOM_SMD_RPM_LDOA, 18, &pm8916_pldo, "vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18"},
{}
};
static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pm8x41_hfsmps, "vdd_s1" },
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pm8x41_hfsmps, "vdd_s2" },
@ -272,9 +378,62 @@ static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
{}
};
static const struct rpm_regulator_data rpm_pma8084_regulators[] = {
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pma8084_ftsmps, "vdd_s1" },
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pma8084_ftsmps, "vdd_s2" },
{ "s3", QCOM_SMD_RPM_SMPA, 3, &pma8084_hfsmps, "vdd_s3" },
{ "s4", QCOM_SMD_RPM_SMPA, 4, &pma8084_hfsmps, "vdd_s4" },
{ "s5", QCOM_SMD_RPM_SMPA, 5, &pma8084_hfsmps, "vdd_s5" },
{ "s6", QCOM_SMD_RPM_SMPA, 6, &pma8084_ftsmps, "vdd_s6" },
{ "s7", QCOM_SMD_RPM_SMPA, 7, &pma8084_ftsmps, "vdd_s7" },
{ "s8", QCOM_SMD_RPM_SMPA, 8, &pma8084_ftsmps, "vdd_s8" },
{ "s9", QCOM_SMD_RPM_SMPA, 9, &pma8084_ftsmps, "vdd_s9" },
{ "s10", QCOM_SMD_RPM_SMPA, 10, &pma8084_ftsmps, "vdd_s10" },
{ "s11", QCOM_SMD_RPM_SMPA, 11, &pma8084_ftsmps, "vdd_s11" },
{ "s12", QCOM_SMD_RPM_SMPA, 12, &pma8084_ftsmps, "vdd_s12" },
{ "l1", QCOM_SMD_RPM_LDOA, 1, &pma8084_nldo, "vdd_l1_l11" },
{ "l2", QCOM_SMD_RPM_LDOA, 2, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
{ "l3", QCOM_SMD_RPM_LDOA, 3, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
{ "l4", QCOM_SMD_RPM_LDOA, 4, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
{ "l5", QCOM_SMD_RPM_LDOA, 5, &pma8084_pldo, "vdd_l5_l7" },
{ "l6", QCOM_SMD_RPM_LDOA, 6, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
{ "l7", QCOM_SMD_RPM_LDOA, 7, &pma8084_pldo, "vdd_l5_l7" },
{ "l8", QCOM_SMD_RPM_LDOA, 8, &pma8084_pldo, "vdd_l8" },
{ "l9", QCOM_SMD_RPM_LDOA, 9, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
{ "l10", QCOM_SMD_RPM_LDOA, 10, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
{ "l11", QCOM_SMD_RPM_LDOA, 11, &pma8084_nldo, "vdd_l1_l11" },
{ "l12", QCOM_SMD_RPM_LDOA, 12, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
{ "l13", QCOM_SMD_RPM_LDOA, 13, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
{ "l14", QCOM_SMD_RPM_LDOA, 14, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
{ "l15", QCOM_SMD_RPM_LDOA, 15, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
{ "l16", QCOM_SMD_RPM_LDOA, 16, &pma8084_pldo, "vdd_l16_l25" },
{ "l17", QCOM_SMD_RPM_LDOA, 17, &pma8084_pldo, "vdd_l17" },
{ "l18", QCOM_SMD_RPM_LDOA, 18, &pma8084_pldo, "vdd_l18" },
{ "l19", QCOM_SMD_RPM_LDOA, 19, &pma8084_pldo, "vdd_l19" },
{ "l20", QCOM_SMD_RPM_LDOA, 20, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
{ "l21", QCOM_SMD_RPM_LDOA, 21, &pma8084_pldo, "vdd_l21" },
{ "l22", QCOM_SMD_RPM_LDOA, 22, &pma8084_pldo, "vdd_l22" },
{ "l23", QCOM_SMD_RPM_LDOA, 23, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
{ "l24", QCOM_SMD_RPM_LDOA, 24, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
{ "l25", QCOM_SMD_RPM_LDOA, 25, &pma8084_pldo, "vdd_l16_l25" },
{ "l26", QCOM_SMD_RPM_LDOA, 26, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
{ "l27", QCOM_SMD_RPM_LDOA, 27, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
{ "lvs1", QCOM_SMD_RPM_VSA, 1, &pma8084_switch },
{ "lvs2", QCOM_SMD_RPM_VSA, 2, &pma8084_switch },
{ "lvs3", QCOM_SMD_RPM_VSA, 3, &pma8084_switch },
{ "lvs4", QCOM_SMD_RPM_VSA, 4, &pma8084_switch },
{ "5vs1", QCOM_SMD_RPM_VSA, 5, &pma8084_switch },
{}
};
static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
{ .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
{ .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
{ .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
{}
};
MODULE_DEVICE_TABLE(of, rpm_of_match);

View File

@ -27,90 +27,12 @@ static const unsigned int tps6105x_voltages[] = {
5000000, /* There is an additional 5V */
};
static int tps6105x_regulator_enable(struct regulator_dev *rdev)
{
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
int ret;
/* Activate voltage mode */
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_MODE_MASK,
TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT);
if (ret)
return ret;
return 0;
}
static int tps6105x_regulator_disable(struct regulator_dev *rdev)
{
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
int ret;
/* Set into shutdown mode */
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_MODE_MASK,
TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
if (ret)
return ret;
return 0;
}
static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
{
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
unsigned int regval;
int ret;
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
if (ret)
return ret;
regval &= TPS6105X_REG0_MODE_MASK;
regval >>= TPS6105X_REG0_MODE_SHIFT;
if (regval == TPS6105X_REG0_MODE_VOLTAGE)
return 1;
return 0;
}
static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
unsigned int regval;
int ret;
ret = regmap_read(tps6105x->regmap, TPS6105X_REG_0, &regval);
if (ret)
return ret;
regval &= TPS6105X_REG0_VOLTAGE_MASK;
regval >>= TPS6105X_REG0_VOLTAGE_SHIFT;
return (int) regval;
}
static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
unsigned selector)
{
struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
int ret;
ret = regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0,
TPS6105X_REG0_VOLTAGE_MASK,
selector << TPS6105X_REG0_VOLTAGE_SHIFT);
if (ret)
return ret;
return 0;
}
static struct regulator_ops tps6105x_regulator_ops = {
.enable = tps6105x_regulator_enable,
.disable = tps6105x_regulator_disable,
.is_enabled = tps6105x_regulator_is_enabled,
.get_voltage_sel = tps6105x_regulator_get_voltage_sel,
.set_voltage_sel = tps6105x_regulator_set_voltage_sel,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_table,
};
@ -122,6 +44,12 @@ static const struct regulator_desc tps6105x_regulator_desc = {
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(tps6105x_voltages),
.volt_table = tps6105x_voltages,
.vsel_reg = TPS6105X_REG_0,
.vsel_mask = TPS6105X_REG0_VOLTAGE_MASK,
.enable_reg = TPS6105X_REG_0,
.enable_mask = TPS6105X_REG0_MODE_MASK,
.enable_val = TPS6105X_REG0_MODE_VOLTAGE <<
TPS6105X_REG0_MODE_SHIFT,
};
/*
@ -144,6 +72,7 @@ static int tps6105x_regulator_probe(struct platform_device *pdev)
config.dev = &tps6105x->client->dev;
config.init_data = pdata->regulator_data;
config.driver_data = tps6105x;
config.regmap = tps6105x->regmap;
/* Register regulator with framework */
tps6105x->regulator = devm_regulator_register(&pdev->dev,

View File

@ -0,0 +1,251 @@
/*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
*
* Author: Andrew F. Davis <afd@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.
*
* Based on the TPS65912 driver
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/mfd/tps65086.h>
enum tps65086_regulators { BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, LDOA1,
LDOA2, LDOA3, SWA1, SWB1, SWB2, VTT };
#define TPS65086_REGULATOR(_name, _of, _id, _nv, _vr, _vm, _er, _em, _lr, _dr, _dm) \
[_id] = { \
.desc = { \
.name = _name, \
.of_match = of_match_ptr(_of), \
.regulators_node = "regulators", \
.of_parse_cb = tps65086_of_parse_cb, \
.id = _id, \
.ops = &reg_ops, \
.n_voltages = _nv, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.vsel_reg = _vr, \
.vsel_mask = _vm, \
.enable_reg = _er, \
.enable_mask = _em, \
.volt_table = NULL, \
.linear_ranges = _lr, \
.n_linear_ranges = ARRAY_SIZE(_lr), \
}, \
.decay_reg = _dr, \
.decay_mask = _dm, \
}
#define TPS65086_SWITCH(_name, _of, _id, _er, _em) \
[_id] = { \
.desc = { \
.name = _name, \
.of_match = of_match_ptr(_of), \
.regulators_node = "regulators", \
.of_parse_cb = tps65086_of_parse_cb, \
.id = _id, \
.ops = &switch_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.enable_reg = _er, \
.enable_mask = _em, \
}, \
}
struct tps65086_regulator {
struct regulator_desc desc;
unsigned int decay_reg;
unsigned int decay_mask;
};
static const struct regulator_linear_range tps65086_buck126_10mv_ranges[] = {
REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
REGULATOR_LINEAR_RANGE(410000, 0x1, 0x7F, 10000),
};
static const struct regulator_linear_range tps65086_buck126_25mv_ranges[] = {
REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x18, 0),
REGULATOR_LINEAR_RANGE(1025000, 0x19, 0x7F, 25000),
};
static const struct regulator_linear_range tps65086_buck345_ranges[] = {
REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
REGULATOR_LINEAR_RANGE(425000, 0x1, 0x7F, 25000),
};
static const struct regulator_linear_range tps65086_ldoa1_ranges[] = {
REGULATOR_LINEAR_RANGE(1350000, 0x0, 0x0, 0),
REGULATOR_LINEAR_RANGE(1500000, 0x1, 0x7, 100000),
REGULATOR_LINEAR_RANGE(2300000, 0x8, 0xA, 100000),
REGULATOR_LINEAR_RANGE(2700000, 0xB, 0xD, 150000),
REGULATOR_LINEAR_RANGE(3300000, 0xE, 0xE, 0),
};
static const struct regulator_linear_range tps65086_ldoa23_ranges[] = {
REGULATOR_LINEAR_RANGE(700000, 0x0, 0xD, 50000),
REGULATOR_LINEAR_RANGE(1400000, 0xE, 0xF, 100000),
};
/* Operations permitted on regulators */
static struct regulator_ops reg_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear_range,
};
/* Operations permitted on load switches */
static struct regulator_ops switch_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
};
static int tps65086_of_parse_cb(struct device_node *dev,
const struct regulator_desc *desc,
struct regulator_config *config);
static struct tps65086_regulator regulators[] = {
TPS65086_REGULATOR("BUCK1", "buck1", BUCK1, 0x80, TPS65086_BUCK1CTRL,
BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(0),
tps65086_buck126_10mv_ranges, TPS65086_BUCK1CTRL,
BIT(0)),
TPS65086_REGULATOR("BUCK2", "buck2", BUCK2, 0x80, TPS65086_BUCK2CTRL,
BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(1),
tps65086_buck126_10mv_ranges, TPS65086_BUCK2CTRL,
BIT(0)),
TPS65086_REGULATOR("BUCK3", "buck3", BUCK3, 0x80, TPS65086_BUCK3VID,
BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(2),
tps65086_buck345_ranges, TPS65086_BUCK3DECAY,
BIT(0)),
TPS65086_REGULATOR("BUCK4", "buck4", BUCK4, 0x80, TPS65086_BUCK4VID,
BUCK_VID_MASK, TPS65086_BUCK4CTRL, BIT(0),
tps65086_buck345_ranges, TPS65086_BUCK4VID,
BIT(0)),
TPS65086_REGULATOR("BUCK5", "buck5", BUCK5, 0x80, TPS65086_BUCK5VID,
BUCK_VID_MASK, TPS65086_BUCK5CTRL, BIT(0),
tps65086_buck345_ranges, TPS65086_BUCK5CTRL,
BIT(0)),
TPS65086_REGULATOR("BUCK6", "buck6", BUCK6, 0x80, TPS65086_BUCK6VID,
BUCK_VID_MASK, TPS65086_BUCK6CTRL, BIT(0),
tps65086_buck126_10mv_ranges, TPS65086_BUCK6CTRL,
BIT(0)),
TPS65086_REGULATOR("LDOA1", "ldoa1", LDOA1, 0xF, TPS65086_LDOA1CTRL,
VDOA1_VID_MASK, TPS65086_LDOA1CTRL, BIT(0),
tps65086_ldoa1_ranges, 0, 0),
TPS65086_REGULATOR("LDOA2", "ldoa2", LDOA2, 0x10, TPS65086_LDOA2VID,
VDOA23_VID_MASK, TPS65086_LDOA2CTRL, BIT(0),
tps65086_ldoa23_ranges, 0, 0),
TPS65086_REGULATOR("LDOA3", "ldoa3", LDOA3, 0x10, TPS65086_LDOA3VID,
VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0),
tps65086_ldoa23_ranges, 0, 0),
TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)),
TPS65086_SWITCH("SWB1", "swa2", SWB1, TPS65086_SWVTT_EN, BIT(6)),
TPS65086_SWITCH("SWB2", "swa3", SWB2, TPS65086_SWVTT_EN, BIT(7)),
TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
};
static inline bool has_25mv_mode(int id)
{
switch (id) {
case BUCK1:
case BUCK2:
case BUCK6:
return true;
default:
return false;
}
}
static int tps65086_of_parse_cb(struct device_node *dev,
const struct regulator_desc *desc,
struct regulator_config *config)
{
int ret;
/* Check for 25mV step mode */
if (has_25mv_mode(desc->id) &&
of_property_read_bool(config->of_node, "ti,regulator-step-size-25mv")) {
regulators[desc->id].desc.linear_ranges =
tps65086_buck126_25mv_ranges;
regulators[desc->id].desc.n_linear_ranges =
ARRAY_SIZE(tps65086_buck126_25mv_ranges);
}
/* Check for decay mode */
if (desc->id <= BUCK6 && of_property_read_bool(config->of_node, "ti,regulator-decay")) {
ret = regmap_write_bits(config->regmap,
regulators[desc->id].decay_reg,
regulators[desc->id].decay_mask,
regulators[desc->id].decay_mask);
if (ret) {
dev_err(config->dev, "Error setting decay\n");
return ret;
}
}
return 0;
}
static int tps65086_regulator_probe(struct platform_device *pdev)
{
struct tps65086 *tps = dev_get_drvdata(pdev->dev.parent);
struct regulator_config config = { };
struct regulator_dev *rdev;
int i;
platform_set_drvdata(pdev, tps);
config.dev = &pdev->dev;
config.dev->of_node = tps->dev->of_node;
config.driver_data = tps;
config.regmap = tps->regmap;
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
rdev = devm_regulator_register(&pdev->dev, &regulators[i].desc,
&config);
if (IS_ERR(rdev)) {
dev_err(tps->dev, "failed to register %s regulator\n",
pdev->name);
return PTR_ERR(rdev);
}
}
return 0;
}
static const struct platform_device_id tps65086_regulator_id_table[] = {
{ "tps65086-regulator", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps65086_regulator_id_table);
static struct platform_driver tps65086_regulator_driver = {
.driver = {
.name = "tps65086-regulator",
},
.probe = tps65086_regulator_probe,
.id_table = tps65086_regulator_id_table,
};
module_platform_driver(tps65086_regulator_driver);
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
MODULE_DESCRIPTION("TPS65086 Regulator driver");
MODULE_LICENSE("GPL v2");

View File

@ -27,19 +27,22 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65218.h>
enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 };
enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
DCDC5, DCDC6, LDO1, LS3 };
#define TPS65218_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _er, _em, \
_lr, _nlr, _delay, _fuv) \
#define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \
_cr, _cm, _lr, _nlr, _delay, _fuv) \
{ \
.name = _name, \
.id = _id, \
.ops = &_ops, \
.n_voltages = _n, \
.type = REGULATOR_VOLTAGE, \
.type = _type, \
.owner = THIS_MODULE, \
.vsel_reg = _vr, \
.vsel_mask = _vm, \
.csel_reg = _cr, \
.csel_mask = _cm, \
.enable_reg = _er, \
.enable_mask = _em, \
.volt_table = NULL, \
@ -80,6 +83,7 @@ static struct tps_info tps65218_pmic_regs[] = {
TPS65218_INFO(DCDC5, "DCDC5", 1000000, 1000000),
TPS65218_INFO(DCDC6, "DCDC6", 1800000, 1800000),
TPS65218_INFO(LDO1, "LDO1", 900000, 3400000),
TPS65218_INFO(LS3, "LS3", -1, -1),
};
#define TPS65218_OF_MATCH(comp, label) \
@ -96,6 +100,7 @@ static const struct of_device_id tps65218_of_match[] = {
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]),
TPS65218_OF_MATCH("ti,tps65218-ls3", tps65218_pmic_regs[LS3]),
{ }
};
MODULE_DEVICE_TABLE(of, tps65218_of_match);
@ -175,6 +180,68 @@ static struct regulator_ops tps65218_ldo1_dcdc34_ops = {
.map_voltage = regulator_map_voltage_linear_range,
};
static const int ls3_currents[] = { 100, 200, 500, 1000 };
static int tps65218_pmic_set_input_current_lim(struct regulator_dev *dev,
int lim_uA)
{
unsigned int index = 0;
unsigned int num_currents = ARRAY_SIZE(ls3_currents);
struct tps65218 *tps = rdev_get_drvdata(dev);
while (index < num_currents && ls3_currents[index] != lim_uA)
index++;
if (index == num_currents)
return -EINVAL;
return tps65218_set_bits(tps, dev->desc->csel_reg, dev->desc->csel_mask,
index << 2, TPS65218_PROTECT_L1);
}
static int tps65218_pmic_set_current_limit(struct regulator_dev *dev,
int min_uA, int max_uA)
{
int index = 0;
unsigned int num_currents = ARRAY_SIZE(ls3_currents);
struct tps65218 *tps = rdev_get_drvdata(dev);
while (index < num_currents && ls3_currents[index] < max_uA)
index++;
index--;
if (index < 0 || ls3_currents[index] < min_uA)
return -EINVAL;
return tps65218_set_bits(tps, dev->desc->csel_reg, dev->desc->csel_mask,
index << 2, TPS65218_PROTECT_L1);
}
static int tps65218_pmic_get_current_limit(struct regulator_dev *dev)
{
int retval;
unsigned int index;
struct tps65218 *tps = rdev_get_drvdata(dev);
retval = tps65218_reg_read(tps, dev->desc->csel_reg, &index);
if (retval < 0)
return retval;
index = (index & dev->desc->csel_mask) >> 2;
return ls3_currents[index];
}
static struct regulator_ops tps65218_ls3_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = tps65218_pmic_enable,
.disable = tps65218_pmic_disable,
.set_input_current_limit = tps65218_pmic_set_input_current_lim,
.set_current_limit = tps65218_pmic_set_current_limit,
.get_current_limit = tps65218_pmic_get_current_limit,
};
/* Operations permitted on DCDC5, DCDC6 */
static struct regulator_ops tps65218_dcdc56_pmic_ops = {
.is_enabled = regulator_is_enabled_regmap,
@ -183,36 +250,46 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = {
};
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,
dcdc1_dcdc2_ranges, 2, 4000, 0),
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,
dcdc1_dcdc2_ranges, 2, 4000, 0),
TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, tps65218_ldo1_dcdc34_ops,
64, TPS65218_REG_CONTROL_DCDC3,
TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, REGULATOR_VOLTAGE,
tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1,
TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges,
2, 4000, 0),
TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE,
tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2,
TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges,
2, 4000, 0),
TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE,
tps65218_ldo1_dcdc34_ops, 64,
TPS65218_REG_CONTROL_DCDC3,
TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC3_EN, ldo1_dcdc3_ranges, 2, 0, 0),
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,
dcdc4_ranges, 2, 0, 0),
TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, tps65218_dcdc56_pmic_ops,
1, -1, -1, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC5_EN, NULL, 0, 0, 1000000),
TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, tps65218_dcdc56_pmic_ops,
1, -1, -1, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC6_EN, NULL, 0, 0, 1800000),
TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64,
TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2,
0, 0),
TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE,
tps65218_ldo1_dcdc34_ops, 53,
TPS65218_REG_CONTROL_DCDC4,
TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2,
0, 0),
TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE,
tps65218_dcdc56_pmic_ops, 1, -1, -1,
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0,
NULL, 0, 0, 1000000),
TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE,
tps65218_dcdc56_pmic_ops, 1, -1, -1,
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0,
NULL, 0, 0, 1800000),
TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE,
tps65218_ldo1_dcdc34_ops, 64,
TPS65218_REG_CONTROL_LDO1,
TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
TPS65218_ENABLE2_LDO1_EN, ldo1_dcdc3_ranges,
TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges,
2, 0, 0),
TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT,
tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2,
TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2,
TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0),
};
static int tps65218_regulator_probe(struct platform_device *pdev)

View File

@ -365,7 +365,7 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev)
return wm831x_dcdc_ilim[val];
}
static struct regulator_ops wm831x_buckv_ops = {
static const struct regulator_ops wm831x_buckv_ops = {
.set_voltage_sel = wm831x_buckv_set_voltage_sel,
.get_voltage_sel = wm831x_buckv_get_voltage_sel,
.list_voltage = wm831x_buckv_list_voltage,
@ -585,7 +585,7 @@ static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, int uV)
return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, sel);
}
static struct regulator_ops wm831x_buckp_ops = {
static const struct regulator_ops wm831x_buckp_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
@ -725,7 +725,7 @@ static int wm831x_boostp_get_status(struct regulator_dev *rdev)
return REGULATOR_STATUS_OFF;
}
static struct regulator_ops wm831x_boostp_ops = {
static const struct regulator_ops wm831x_boostp_ops = {
.get_status = wm831x_boostp_get_status,
.is_enabled = regulator_is_enabled_regmap,
@ -818,7 +818,7 @@ static struct platform_driver wm831x_boostp_driver = {
#define WM831X_EPE_BASE 6
static struct regulator_ops wm831x_epe_ops = {
static const struct regulator_ops wm831x_epe_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@ -884,35 +884,22 @@ static struct platform_driver wm831x_epe_driver = {
},
};
static struct platform_driver * const drivers[] = {
&wm831x_buckv_driver,
&wm831x_buckp_driver,
&wm831x_boostp_driver,
&wm831x_epe_driver,
};
static int __init wm831x_dcdc_init(void)
{
int ret;
ret = platform_driver_register(&wm831x_buckv_driver);
if (ret != 0)
pr_err("Failed to register WM831x BUCKV driver: %d\n", ret);
ret = platform_driver_register(&wm831x_buckp_driver);
if (ret != 0)
pr_err("Failed to register WM831x BUCKP driver: %d\n", ret);
ret = platform_driver_register(&wm831x_boostp_driver);
if (ret != 0)
pr_err("Failed to register WM831x BOOST driver: %d\n", ret);
ret = platform_driver_register(&wm831x_epe_driver);
if (ret != 0)
pr_err("Failed to register WM831x EPE driver: %d\n", ret);
return 0;
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
subsys_initcall(wm831x_dcdc_init);
static void __exit wm831x_dcdc_exit(void)
{
platform_driver_unregister(&wm831x_epe_driver);
platform_driver_unregister(&wm831x_boostp_driver);
platform_driver_unregister(&wm831x_buckp_driver);
platform_driver_unregister(&wm831x_buckv_driver);
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(wm831x_dcdc_exit);

View File

@ -128,7 +128,7 @@ static int wm831x_isink_get_current(struct regulator_dev *rdev)
return wm831x_isinkv_values[ret];
}
static struct regulator_ops wm831x_isink_ops = {
static const struct regulator_ops wm831x_isink_ops = {
.is_enabled = wm831x_isink_is_enabled,
.enable = wm831x_isink_enable,
.disable = wm831x_isink_disable,

View File

@ -198,7 +198,7 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
}
static struct regulator_ops wm831x_gp_ldo_ops = {
static const struct regulator_ops wm831x_gp_ldo_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@ -409,7 +409,7 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev)
return regulator_mode_to_status(ret);
}
static struct regulator_ops wm831x_aldo_ops = {
static const struct regulator_ops wm831x_aldo_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@ -557,7 +557,7 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
return REGULATOR_STATUS_OFF;
}
static struct regulator_ops wm831x_alive_ldo_ops = {
static const struct regulator_ops wm831x_alive_ldo_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@ -653,32 +653,21 @@ static struct platform_driver wm831x_alive_ldo_driver = {
},
};
static struct platform_driver * const drivers[] = {
&wm831x_gp_ldo_driver,
&wm831x_aldo_driver,
&wm831x_alive_ldo_driver,
};
static int __init wm831x_ldo_init(void)
{
int ret;
ret = platform_driver_register(&wm831x_gp_ldo_driver);
if (ret != 0)
pr_err("Failed to register WM831x GP LDO driver: %d\n", ret);
ret = platform_driver_register(&wm831x_aldo_driver);
if (ret != 0)
pr_err("Failed to register WM831x ALDO driver: %d\n", ret);
ret = platform_driver_register(&wm831x_alive_ldo_driver);
if (ret != 0)
pr_err("Failed to register WM831x alive LDO driver: %d\n",
ret);
return 0;
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
subsys_initcall(wm831x_ldo_init);
static void __exit wm831x_ldo_exit(void)
{
platform_driver_unregister(&wm831x_alive_ldo_driver);
platform_driver_unregister(&wm831x_aldo_driver);
platform_driver_unregister(&wm831x_gp_ldo_driver);
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(wm831x_ldo_exit);

View File

@ -941,7 +941,7 @@ static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
return mode;
}
static struct regulator_ops wm8350_dcdc_ops = {
static const struct regulator_ops wm8350_dcdc_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
@ -958,7 +958,7 @@ static struct regulator_ops wm8350_dcdc_ops = {
.set_suspend_mode = wm8350_dcdc_set_suspend_mode,
};
static struct regulator_ops wm8350_dcdc2_5_ops = {
static const struct regulator_ops wm8350_dcdc2_5_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
@ -966,7 +966,7 @@ static struct regulator_ops wm8350_dcdc2_5_ops = {
.set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
};
static struct regulator_ops wm8350_ldo_ops = {
static const struct regulator_ops wm8350_ldo_ops = {
.map_voltage = regulator_map_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@ -980,7 +980,7 @@ static struct regulator_ops wm8350_ldo_ops = {
.set_suspend_disable = wm8350_ldo_set_suspend_disable,
};
static struct regulator_ops wm8350_isink_ops = {
static const struct regulator_ops wm8350_isink_ops = {
.set_current_limit = wm8350_isink_set_current,
.get_current_limit = wm8350_isink_get_current,
.enable = wm8350_isink_enable,

View File

@ -24,7 +24,7 @@ static const struct regulator_linear_range wm8400_ldo_ranges[] = {
REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000),
};
static struct regulator_ops wm8400_ldo_ops = {
static const struct regulator_ops wm8400_ldo_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@ -106,7 +106,7 @@ static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev,
return REGULATOR_MODE_NORMAL;
}
static struct regulator_ops wm8400_dcdc_ops = {
static const struct regulator_ops wm8400_dcdc_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,

View File

@ -36,7 +36,7 @@ struct wm8994_ldo {
#define WM8994_LDO1_MAX_SELECTOR 0x7
#define WM8994_LDO2_MAX_SELECTOR 0x3
static struct regulator_ops wm8994_ldo1_ops = {
static const struct regulator_ops wm8994_ldo1_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@ -69,7 +69,7 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
}
}
static struct regulator_ops wm8994_ldo2_ops = {
static const struct regulator_ops wm8994_ldo2_ops = {
.list_voltage = wm8994_ldo2_list_voltage,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,

View File

@ -200,6 +200,8 @@ enum tps65218_regulator_id {
TPS65218_DCDC_4,
TPS65218_DCDC_5,
TPS65218_DCDC_6,
/* LS's */
TPS65218_LS_3,
/* LDOs */
TPS65218_LDO_1,
};
@ -210,8 +212,11 @@ enum tps65218_regulator_id {
#define TPS65218_NUM_DCDC 6
/* Number of LDO voltage regulators available */
#define TPS65218_NUM_LDO 1
/* Number of total LS current regulators available */
#define TPS65218_NUM_LS 1
/* Number of total regulators available */
#define TPS65218_NUM_REGULATOR (TPS65218_NUM_DCDC + TPS65218_NUM_LDO)
#define TPS65218_NUM_REGULATOR (TPS65218_NUM_DCDC + TPS65218_NUM_LDO \
+ TPS65218_NUM_LS)
/* Define the TPS65218 IRQ numbers */
enum tps65218_irqs {

View File

@ -140,6 +140,8 @@ struct regulator;
*
* @supply: The name of the supply. Initialised by the user before
* using the bulk regulator APIs.
* @optional: The supply should be considered optional. Initialised by the user
* before using the bulk regulator APIs.
* @consumer: The regulator consumer for the supply. This will be managed
* by the bulk API.
*
@ -149,6 +151,7 @@ struct regulator;
*/
struct regulator_bulk_data {
const char *supply;
bool optional;
struct regulator *consumer;
/* private: Internal use */

View File

@ -302,6 +302,8 @@ struct regulator_desc {
unsigned int vsel_reg;
unsigned int vsel_mask;
unsigned int csel_reg;
unsigned int csel_mask;
unsigned int apply_reg;
unsigned int apply_bit;
unsigned int enable_reg;