mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-07 04:09:21 +00:00
regulator: Updates for v3.9
A fairly quiet release for the regulator API, the bulk of the changes being lots of small cleanups and API updates contributed by Axel Lin with just a small set of larger changes: - New driver for LP8755 - DT support for S5M8767, TPS51632, TPS6507x and TPS65090 - Support for writing a "commit changes" bit in the regmap helper functions. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJRI3THAAoJELSic+t+oim9s74P/jrnSyHIE6soY4QjWb2N9Vgd QjbEYZFPwNMXgcYt7P3srJbHr0L/Jrwweo+AZDw1z9WDT9aPBAIW/r2cIQ4V/bRg KFvb77JAi/iwKXzjReJpk4lZvwmnb9O6ZLZFnq0FC7Wfu8SDkskzT5FOwkqNjnR2 6NzDGIgXddSxPYUH6gsZYiYw3b9DcW2HguT4C69XSjFssYeOtvHdEAEO+8drylAF AEqPylzkhWG44KuDOw3CioHrz9nHuWQor4GyeH1pm06YFdHss9uNe3oA5J75Vk5f 6ugNSHcq9kU/3o6TaHARkDJ/DbgjA5aAu/alXBrpEpSSKgEvnFOgEcb43QGWPeuz R0CK6KSAG4WzLFeVq+ped6470/YiihhUeyIgt5t+ug4g8a6xkw9L6K9NzypOVYD7 7fcUJnuzZz7v0MwVCJmHr7b9ESQac5vuwlGLE2iaNBIcsXI4S1uv6rrJI7mL5JbY f7YpPHCAytDhAW0myuI55L8bkCUK/EuL1c8ISKehGdfkY72ZFgYZbV5225u4Fuf4 J+s2UICtIacKAtL3VXM1sR7Q5I5QfXvF+F36yrZriZzw3r5mDcxVo8+nymcduxW7 h2qFQ11725qDaPcorI5WbHsL6yoePTJPJN/x8ewxkrqB05lLeTJetm5ncB9ZUTFh LdgLZROnRreFXXFMWpwZ =+3b2 -----END PGP SIGNATURE----- Merge tag 'regulator-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator Pull regulator updates from Mark Brown: "A fairly quiet release for the regulator API, the bulk of the changes being lots of small cleanups and API updates contributed by Axel Lin with just a small set of larger changes: - New driver for LP8755 - DT support for S5M8767, TPS51632, TPS6507x and TPS65090 - Support for writing a "commit changes" bit in the regmap helper functions." * tag 'regulator-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (60 commits) regulator: Fix memory garbage dev_err printout. regulator: max77686: Reuse rdev_get_id() function. regulator: tps51632: Use regulator_[get|set]_voltage_sel_regmap regulator: as3711: Fix checking if no platform initialization data regulator: s5m8767: Prevent possible NULL pointer dereference regulator: s5m8767: Fix dev argument for devm_kzalloc and of_get_regulator_init_data regulator: core: Optimize _regulator_do_set_voltage if voltage does not change regulator: max8998: Let regulator core handle the case selector == old_selector regulator: s5m8767: Use of_get_child_count() regulator: anatop: improve precision of delay time regulator: show state for GPIO-controlled regulators regulator: s5m8767: Fix build in non-DT case regulator: add device tree support for s5m8767 regulator: palmas: Remove a redundant setting for warm_reset regulator: mc13xxx: Use of_get_child_count() regulator: max8997: Use of_get_child_count() regulator: tps65090: Fix using wrong dev argument for calling of_regulator_match regulators: anatop: add set_voltage_time_sel interface regulator: Add missing of_node_put() regulator: tps6507x: Fix using wrong dev argument for calling of_regulator_match ...
This commit is contained in:
commit
8909ff652d
41 changed files with 1921 additions and 567 deletions
91
Documentation/devicetree/bindings/mfd/tps6507x.txt
Executable file
91
Documentation/devicetree/bindings/mfd/tps6507x.txt
Executable file
|
@ -0,0 +1,91 @@
|
|||
TPS6507x Power Management Integrated Circuit
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,tps6507x"
|
||||
- reg: I2C slave address
|
||||
- regulators: This is the list of child nodes that specify the regulator
|
||||
initialization data for defined regulators. Not all regulators for the
|
||||
given device need to be present. The definition for each of these nodes
|
||||
is defined using the standard binding for regulators found at
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt.
|
||||
The regulator is matched with the regulator-compatible.
|
||||
|
||||
The valid regulator-compatible values are:
|
||||
tps6507x: vdcdc1, vdcdc2, vdcdc3, vldo1, vldo2
|
||||
- xxx-supply: Input voltage supply regulator.
|
||||
These entries are required if regulators are enabled for a device.
|
||||
Missing of these properties can cause the regulator registration
|
||||
fails.
|
||||
If some of input supply is powered through battery or always-on
|
||||
supply then also it is require to have these parameters with proper
|
||||
node handle of always on power supply.
|
||||
tps6507x:
|
||||
vindcdc1_2-supply: VDCDC1 and VDCDC2 input.
|
||||
vindcdc3-supply : VDCDC3 input.
|
||||
vldo1_2-supply : VLDO1 and VLDO2 input.
|
||||
|
||||
Regulator Optional properties:
|
||||
- defdcdc_default: It's property of DCDC2 and DCDC3 regulators.
|
||||
0: If defdcdc pin of DCDC2/DCDC3 is pulled to GND.
|
||||
1: If defdcdc pin of DCDC2/DCDC3 is driven HIGH.
|
||||
If this property is not defined, it defaults to 0 (not enabled).
|
||||
|
||||
Example:
|
||||
|
||||
pmu: tps6507x@48 {
|
||||
compatible = "ti,tps6507x";
|
||||
reg = <0x48>;
|
||||
|
||||
vindcdc1_2-supply = <&vbat>;
|
||||
vindcdc3-supply = <...>;
|
||||
vinldo1_2-supply = <...>;
|
||||
|
||||
regulators {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
vdcdc1_reg: regulator@0 {
|
||||
regulator-compatible = "VDCDC1";
|
||||
reg = <0>;
|
||||
regulator-min-microvolt = <3150000>;
|
||||
regulator-max-microvolt = <3450000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
vdcdc2_reg: regulator@1 {
|
||||
regulator-compatible = "VDCDC2";
|
||||
reg = <1>;
|
||||
regulator-min-microvolt = <1710000>;
|
||||
regulator-max-microvolt = <3450000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
defdcdc_default = <1>;
|
||||
};
|
||||
vdcdc3_reg: regulator@2 {
|
||||
regulator-compatible = "VDCDC3";
|
||||
reg = <2>;
|
||||
regulator-min-microvolt = <950000>
|
||||
regulator-max-microvolt = <1350000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
defdcdc_default = <1>;
|
||||
};
|
||||
ldo1_reg: regulator@3 {
|
||||
regulator-compatible = "LDO1";
|
||||
reg = <3>;
|
||||
regulator-min-microvolt = <1710000>;
|
||||
regulator-max-microvolt = <1890000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
ldo2_reg: regulator@4 {
|
||||
regulator-compatible = "LDO2";
|
||||
reg = <4>;
|
||||
regulator-min-microvolt = <1140000>;
|
||||
regulator-max-microvolt = <1320000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
|
@ -9,6 +9,11 @@ Required properties:
|
|||
- anatop-min-voltage: Minimum voltage of this regulator
|
||||
- anatop-max-voltage: Maximum voltage of this regulator
|
||||
|
||||
Optional properties:
|
||||
- anatop-delay-reg-offset: Anatop MFD step time register offset
|
||||
- anatop-delay-bit-shift: Bit shift for the step time register
|
||||
- anatop-delay-bit-width: Number of bits used in the step time register
|
||||
|
||||
Any property defined as part of the core regulator
|
||||
binding, defined in regulator.txt, can also be used.
|
||||
|
||||
|
@ -23,6 +28,9 @@ Example:
|
|||
anatop-reg-offset = <0x140>;
|
||||
anatop-vol-bit-shift = <9>;
|
||||
anatop-vol-bit-width = <5>;
|
||||
anatop-delay-reg-offset = <0x170>;
|
||||
anatop-delay-bit-shift = <24>;
|
||||
anatop-delay-bit-width = <2>;
|
||||
anatop-min-bit-val = <1>;
|
||||
anatop-min-voltage = <725000>;
|
||||
anatop-max-voltage = <1300000>;
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
* Samsung S5M8767 Voltage and Current Regulator
|
||||
|
||||
The Samsung S5M8767 is a multi-function device which includes volatage and
|
||||
current regulators, rtc, charger controller and other sub-blocks. It is
|
||||
interfaced to the host controller using a i2c interface. Each sub-block is
|
||||
addressed by the host system using different i2c slave address. This document
|
||||
describes the bindings for 'pmic' sub-block of s5m8767.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "samsung,s5m8767-pmic".
|
||||
- reg: Specifies the i2c slave address of the pmic block. It should be 0x66.
|
||||
|
||||
- s5m8767,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
|
||||
units for buck2 when changing voltage using gpio dvs. Refer to [1] below
|
||||
for additional information.
|
||||
|
||||
- s5m8767,pmic-buck3-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
|
||||
units for buck3 when changing voltage using gpio dvs. Refer to [1] below
|
||||
for additional information.
|
||||
|
||||
- s5m8767,pmic-buck4-dvs-voltage: A set of 8 voltage values in micro-volt (uV)
|
||||
units for buck4 when changing voltage using gpio dvs. Refer to [1] below
|
||||
for additional information.
|
||||
|
||||
- s5m8767,pmic-buck-ds-gpios: GPIO specifiers for three host gpio's used
|
||||
for selecting GPIO DVS lines. It is one-to-one mapped to dvs gpio lines.
|
||||
|
||||
[1] If none of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
|
||||
property is specified, the 's5m8767,pmic-buck[2/3/4]-dvs-voltage'
|
||||
property should specify atleast one voltage level (which would be a
|
||||
safe operating voltage).
|
||||
|
||||
If either of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional
|
||||
property is specified, then all the eight voltage values for the
|
||||
's5m8767,pmic-buck[2/3/4]-dvs-voltage' should be specified.
|
||||
|
||||
Optional properties:
|
||||
- interrupt-parent: Specifies the phandle of the interrupt controller to which
|
||||
the interrupts from s5m8767 are delivered to.
|
||||
- interrupts: Interrupt specifiers for two interrupt sources.
|
||||
- First interrupt specifier is for 'irq1' interrupt.
|
||||
- Second interrupt specifier is for 'alert' interrupt.
|
||||
- s5m8767,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs.
|
||||
- s5m8767,pmic-buck3-uses-gpio-dvs: 'buck3' can be controlled by gpio dvs.
|
||||
- s5m8767,pmic-buck4-uses-gpio-dvs: 'buck4' can be controlled by gpio dvs.
|
||||
|
||||
Additional properties required if either of the optional properties are used:
|
||||
|
||||
- s5m8767,pmic-buck234-default-dvs-idx: Default voltage setting selected from
|
||||
the possible 8 options selectable by the dvs gpios. The value of this
|
||||
property should be between 0 and 7. If not specified or if out of range, the
|
||||
default value of this property is set to 0.
|
||||
|
||||
- s5m8767,pmic-buck-dvs-gpios: GPIO specifiers for three host gpio's used
|
||||
for dvs. The format of the gpio specifier depends in the gpio controller.
|
||||
|
||||
Regulators: The regulators of s5m8767 that have to be instantiated should be
|
||||
included in a sub-node named 'regulators'. Regulator nodes included in this
|
||||
sub-node should be of the format as listed below.
|
||||
|
||||
regulator_name {
|
||||
ldo1_reg: LDO1 {
|
||||
regulator-name = "VDD_ALIVE_1.0V";
|
||||
regulator-min-microvolt = <1100000>;
|
||||
regulator-max-microvolt = <1100000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
op_mode = <1>; /* Normal Mode */
|
||||
};
|
||||
};
|
||||
The above regulator entries are defined in regulator bindings documentation
|
||||
except op_mode description.
|
||||
- op_mode: describes the different operating modes of the LDO's with
|
||||
power mode change in SOC. The different possible values are,
|
||||
0 - always off mode
|
||||
1 - on in normal mode
|
||||
2 - low power mode
|
||||
3 - suspend mode
|
||||
|
||||
The following are the names of the regulators that the s5m8767 pmic block
|
||||
supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
|
||||
as per the datasheet of s5m8767.
|
||||
|
||||
- LDOn
|
||||
- valid values for n are 1 to 28
|
||||
- Example: LDO0, LD01, LDO28
|
||||
- BUCKn
|
||||
- valid values for n are 1 to 9.
|
||||
- Example: BUCK1, BUCK2, BUCK9
|
||||
|
||||
The bindings inside the regulator nodes use the standard regulator bindings
|
||||
which are documented elsewhere.
|
||||
|
||||
Example:
|
||||
|
||||
s5m8767_pmic@66 {
|
||||
compatible = "samsung,s5m8767-pmic";
|
||||
reg = <0x66>;
|
||||
|
||||
s5m8767,pmic-buck2-uses-gpio-dvs;
|
||||
s5m8767,pmic-buck3-uses-gpio-dvs;
|
||||
s5m8767,pmic-buck4-uses-gpio-dvs;
|
||||
|
||||
s5m8767,pmic-buck-default-dvs-idx = <0>;
|
||||
|
||||
s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 1 0 0>, /* DVS1 */
|
||||
<&gpx0 1 1 0 0>, /* DVS2 */
|
||||
<&gpx0 2 1 0 0>; /* DVS3 */
|
||||
|
||||
s5m8767,pmic-buck-ds-gpios = <&gpx2 3 1 0 0>, /* SET1 */
|
||||
<&gpx2 4 1 0 0>, /* SET2 */
|
||||
<&gpx2 5 1 0 0>; /* SET3 */
|
||||
|
||||
s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>,
|
||||
<1250000>, <1200000>,
|
||||
<1150000>, <1100000>,
|
||||
<1000000>, <950000>;
|
||||
|
||||
s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>,
|
||||
<1100000>, <1100000>,
|
||||
<1000000>, <1000000>,
|
||||
<1000000>, <1000000>;
|
||||
|
||||
s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>,
|
||||
<1200000>, <1200000>,
|
||||
<1200000>, <1200000>,
|
||||
<1200000>, <1200000>;
|
||||
|
||||
regulators {
|
||||
ldo1_reg: LDO1 {
|
||||
regulator-name = "VDD_ABB_3.3V";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
op_mode = <1>; /* Normal Mode */
|
||||
};
|
||||
|
||||
ldo2_reg: LDO2 {
|
||||
regulator-name = "VDD_ALIVE_1.1V";
|
||||
regulator-min-microvolt = <1100000>;
|
||||
regulator-max-microvolt = <1100000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
buck1_reg: BUCK1 {
|
||||
regulator-name = "VDD_MIF_1.2V";
|
||||
regulator-min-microvolt = <950000>;
|
||||
regulator-max-microvolt = <1350000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
TPS51632 Voltage regulators
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "ti,tps51632"
|
||||
- reg: I2C slave address
|
||||
|
||||
Optional properties:
|
||||
- ti,enable-pwm-dvfs: Enable the DVFS voltage control through the PWM interface.
|
||||
- ti,dvfs-step-20mV: The 20mV step voltage when PWM DVFS enabled. Missing this
|
||||
will set 10mV step voltage in PWM DVFS mode. In normal mode, the voltage
|
||||
step is 10mV as per datasheet.
|
||||
|
||||
Any property defined as part of the core regulator binding, defined in
|
||||
regulator.txt, can also be used.
|
||||
|
||||
Example:
|
||||
|
||||
tps51632 {
|
||||
compatible = "ti,tps51632";
|
||||
reg = <0x43>;
|
||||
regulator-name = "tps51632-vout";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1500000>;
|
||||
regulator-boot-on;
|
||||
ti,enable-pwm-dvfs;
|
||||
ti,dvfs-step-20mV;
|
||||
};
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -60,6 +61,15 @@ static struct mfd_cell s2mps11_devs[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id sec_dt_match[] = {
|
||||
{ .compatible = "samsung,s5m8767-pmic",
|
||||
.data = (void *)S5M8767X,
|
||||
},
|
||||
{},
|
||||
};
|
||||
#endif
|
||||
|
||||
int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest)
|
||||
{
|
||||
return regmap_read(sec_pmic->regmap, reg, dest);
|
||||
|
@ -95,6 +105,57 @@ static struct regmap_config sec_regmap_config = {
|
|||
.val_bits = 8,
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/*
|
||||
* Only the common platform data elements for s5m8767 are parsed here from the
|
||||
* device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and
|
||||
* others have to parse their own platform data elements from device tree.
|
||||
*
|
||||
* The s5m8767 platform data structure is instantiated here and the drivers for
|
||||
* the sub-modules need not instantiate another instance while parsing their
|
||||
* platform data.
|
||||
*/
|
||||
static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
|
||||
struct device *dev)
|
||||
{
|
||||
struct sec_platform_data *pd;
|
||||
|
||||
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
|
||||
if (!pd) {
|
||||
dev_err(dev, "could not allocate memory for pdata\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/*
|
||||
* ToDo: the 'wakeup' member in the platform data is more of a linux
|
||||
* specfic information. Hence, there is no binding for that yet and
|
||||
* not parsed here.
|
||||
*/
|
||||
|
||||
return pd;
|
||||
}
|
||||
#else
|
||||
static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
|
||||
struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
#ifdef CONFIG_OF
|
||||
if (i2c->dev.of_node) {
|
||||
const struct of_device_id *match;
|
||||
match = of_match_node(sec_dt_match, i2c->dev.of_node);
|
||||
return (int)match->data;
|
||||
}
|
||||
#endif
|
||||
return (int)id->driver_data;
|
||||
}
|
||||
|
||||
static int sec_pmic_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -111,13 +172,22 @@ static int sec_pmic_probe(struct i2c_client *i2c,
|
|||
sec_pmic->dev = &i2c->dev;
|
||||
sec_pmic->i2c = i2c;
|
||||
sec_pmic->irq = i2c->irq;
|
||||
sec_pmic->type = id->driver_data;
|
||||
sec_pmic->type = sec_i2c_get_driver_data(i2c, id);
|
||||
|
||||
if (sec_pmic->dev->of_node) {
|
||||
pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
|
||||
if (IS_ERR(pdata)) {
|
||||
ret = PTR_ERR(pdata);
|
||||
return ret;
|
||||
}
|
||||
pdata->device_type = sec_pmic->type;
|
||||
}
|
||||
if (pdata) {
|
||||
sec_pmic->device_type = pdata->device_type;
|
||||
sec_pmic->ono = pdata->ono;
|
||||
sec_pmic->irq_base = pdata->irq_base;
|
||||
sec_pmic->wakeup = pdata->wakeup;
|
||||
sec_pmic->pdata = pdata;
|
||||
}
|
||||
|
||||
sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config);
|
||||
|
@ -192,6 +262,7 @@ static struct i2c_driver sec_pmic_driver = {
|
|||
.driver = {
|
||||
.name = "sec_pmic",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(sec_dt_match),
|
||||
},
|
||||
.probe = sec_pmic_probe,
|
||||
.remove = sec_pmic_remove,
|
||||
|
|
|
@ -30,8 +30,6 @@ struct pm8607_regulator_info {
|
|||
unsigned int *vol_table;
|
||||
unsigned int *vol_suspend;
|
||||
|
||||
int update_reg;
|
||||
int update_bit;
|
||||
int slope_double;
|
||||
};
|
||||
|
||||
|
@ -222,29 +220,6 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
|
||||
{
|
||||
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1));
|
||||
|
||||
ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg,
|
||||
rdev->desc->vsel_mask, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
switch (info->desc.id) {
|
||||
case PM8607_ID_BUCK1:
|
||||
case PM8607_ID_BUCK3:
|
||||
ret = pm860x_set_bits(info->i2c, info->update_reg,
|
||||
1 << info->update_bit,
|
||||
1 << info->update_bit);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pm8606_preg_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
|
@ -276,7 +251,7 @@ static int pm8606_preg_is_enabled(struct regulator_dev *rdev)
|
|||
|
||||
static struct regulator_ops pm8607_regulator_ops = {
|
||||
.list_voltage = pm8607_list_voltage,
|
||||
.set_voltage_sel = pm8607_set_voltage_sel,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
|
@ -313,11 +288,11 @@ static struct regulator_ops pm8606_preg_ops = {
|
|||
.n_voltages = ARRAY_SIZE(vreg##_table), \
|
||||
.vsel_reg = PM8607_##vreg, \
|
||||
.vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \
|
||||
.apply_reg = PM8607_##ureg, \
|
||||
.apply_bit = (ubit), \
|
||||
.enable_reg = PM8607_##ereg, \
|
||||
.enable_mask = 1 << (ebit), \
|
||||
}, \
|
||||
.update_reg = PM8607_##ureg, \
|
||||
.update_bit = (ubit), \
|
||||
.slope_double = (0), \
|
||||
.vol_table = (unsigned int *)&vreg##_table, \
|
||||
.vol_suspend = (unsigned int *)&vreg##_suspend_table, \
|
||||
|
@ -343,9 +318,9 @@ static struct regulator_ops pm8606_preg_ops = {
|
|||
}
|
||||
|
||||
static struct pm8607_regulator_info pm8607_regulator_info[] = {
|
||||
PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0),
|
||||
PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1),
|
||||
PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2),
|
||||
PM8607_DVC(BUCK1, GO, BIT(0), SUPPLIES_EN11, 0),
|
||||
PM8607_DVC(BUCK2, GO, BIT(1), SUPPLIES_EN11, 1),
|
||||
PM8607_DVC(BUCK3, GO, BIT(2), SUPPLIES_EN11, 2),
|
||||
|
||||
PM8607_LDO(1, LDO1, 0, SUPPLIES_EN11, 3),
|
||||
PM8607_LDO(2, LDO2, 0, SUPPLIES_EN11, 4),
|
||||
|
@ -372,7 +347,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
|
|||
struct regulator_config *config)
|
||||
{
|
||||
struct device_node *nproot, *np;
|
||||
nproot = pdev->dev.parent->of_node;
|
||||
nproot = of_node_get(pdev->dev.parent->of_node);
|
||||
if (!nproot)
|
||||
return -ENODEV;
|
||||
nproot = of_find_node_by_name(nproot, "regulators");
|
||||
|
@ -388,6 +363,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
|
|||
break;
|
||||
}
|
||||
}
|
||||
of_node_put(nproot);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
|
|
@ -91,6 +91,7 @@ config REGULATOR_AAT2870
|
|||
config REGULATOR_ARIZONA
|
||||
tristate "Wolfson Arizona class devices"
|
||||
depends on MFD_ARIZONA
|
||||
depends on SND_SOC
|
||||
help
|
||||
Support for the regulators found on Wolfson Arizona class
|
||||
devices.
|
||||
|
@ -277,6 +278,15 @@ config REGULATOR_LP872X
|
|||
help
|
||||
This driver supports LP8720/LP8725 PMIC
|
||||
|
||||
config REGULATOR_LP8755
|
||||
tristate "TI LP8755 High Performance PMU driver"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
This driver supports LP8755 High Performance PMU driver. This
|
||||
chip contains six step-down DC/DC converters which can support
|
||||
9 mode multiphase configuration.
|
||||
|
||||
config REGULATOR_LP8788
|
||||
bool "TI LP8788 Power Regulators"
|
||||
depends on MFD_LP8788
|
||||
|
|
|
@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
|
|||
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
|
||||
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
|
||||
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
|
||||
obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
|
||||
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
|
||||
|
|
|
@ -31,12 +31,18 @@
|
|||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
|
||||
#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */
|
||||
#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */
|
||||
|
||||
struct anatop_regulator {
|
||||
const char *name;
|
||||
u32 control_reg;
|
||||
struct regmap *anatop;
|
||||
int vol_bit_shift;
|
||||
int vol_bit_width;
|
||||
u32 delay_reg;
|
||||
int delay_bit_shift;
|
||||
int delay_bit_width;
|
||||
int min_bit_val;
|
||||
int min_voltage;
|
||||
int max_voltage;
|
||||
|
@ -55,6 +61,32 @@ static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg,
|
|||
return regulator_set_voltage_sel_regmap(reg, selector);
|
||||
}
|
||||
|
||||
static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
|
||||
unsigned int old_sel,
|
||||
unsigned int new_sel)
|
||||
{
|
||||
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
/* check whether need to care about LDO ramp up speed */
|
||||
if (anatop_reg->delay_bit_width && new_sel > old_sel) {
|
||||
/*
|
||||
* the delay for LDO ramp up time is
|
||||
* based on the register setting, we need
|
||||
* to calculate how many steps LDO need to
|
||||
* ramp up, and how much delay needed. (us)
|
||||
*/
|
||||
regmap_read(anatop_reg->anatop, anatop_reg->delay_reg, &val);
|
||||
val = (val >> anatop_reg->delay_bit_shift) &
|
||||
((1 << anatop_reg->delay_bit_width) - 1);
|
||||
ret = (new_sel - old_sel) * (LDO_RAMP_UP_UNIT_IN_CYCLES <<
|
||||
val) / LDO_RAMP_UP_FREQ_IN_MHZ + 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
|
||||
{
|
||||
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
|
||||
|
@ -67,6 +99,7 @@ static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
|
|||
|
||||
static struct regulator_ops anatop_rops = {
|
||||
.set_voltage_sel = anatop_regmap_set_voltage_sel,
|
||||
.set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
|
||||
.get_voltage_sel = anatop_regmap_get_voltage_sel,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.map_voltage = regulator_map_voltage_linear,
|
||||
|
@ -143,6 +176,14 @@ static int anatop_regulator_probe(struct platform_device *pdev)
|
|||
goto anatop_probe_end;
|
||||
}
|
||||
|
||||
/* read LDO ramp up setting, only for core reg */
|
||||
of_property_read_u32(np, "anatop-delay-reg-offset",
|
||||
&sreg->delay_reg);
|
||||
of_property_read_u32(np, "anatop-delay-bit-width",
|
||||
&sreg->delay_bit_width);
|
||||
of_property_read_u32(np, "anatop-delay-bit-shift",
|
||||
&sreg->delay_bit_shift);
|
||||
|
||||
rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1
|
||||
+ sreg->min_bit_val;
|
||||
rdesc->min_uV = sreg->min_voltage;
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <linux/regulator/machine.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <linux/mfd/arizona/core.h>
|
||||
#include <linux/mfd/arizona/pdata.h>
|
||||
|
@ -34,6 +36,8 @@ struct arizona_micsupp {
|
|||
|
||||
struct regulator_consumer_supply supply;
|
||||
struct regulator_init_data init_data;
|
||||
|
||||
struct work_struct check_cp_work;
|
||||
};
|
||||
|
||||
static int arizona_micsupp_list_voltage(struct regulator_dev *rdev,
|
||||
|
@ -72,9 +76,73 @@ static int arizona_micsupp_map_voltage(struct regulator_dev *rdev,
|
|||
return selector;
|
||||
}
|
||||
|
||||
static void arizona_micsupp_check_cp(struct work_struct *work)
|
||||
{
|
||||
struct arizona_micsupp *micsupp =
|
||||
container_of(work, struct arizona_micsupp, check_cp_work);
|
||||
struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm;
|
||||
struct arizona *arizona = micsupp->arizona;
|
||||
struct regmap *regmap = arizona->regmap;
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, ARIZONA_MIC_CHARGE_PUMP_1, ®);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to read CP state: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dapm) {
|
||||
if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
|
||||
ARIZONA_CPMIC_ENA)
|
||||
snd_soc_dapm_force_enable_pin(dapm, "MICSUPP");
|
||||
else
|
||||
snd_soc_dapm_disable_pin(dapm, "MICSUPP");
|
||||
|
||||
snd_soc_dapm_sync(dapm);
|
||||
}
|
||||
}
|
||||
|
||||
static int arizona_micsupp_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable_regmap(rdev);
|
||||
|
||||
if (ret == 0)
|
||||
schedule_work(&micsupp->check_cp_work);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int arizona_micsupp_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
ret = regulator_disable_regmap(rdev);
|
||||
if (ret == 0)
|
||||
schedule_work(&micsupp->check_cp_work);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena)
|
||||
{
|
||||
struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
ret = regulator_set_bypass_regmap(rdev, ena);
|
||||
if (ret == 0)
|
||||
schedule_work(&micsupp->check_cp_work);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct regulator_ops arizona_micsupp_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.enable = arizona_micsupp_enable,
|
||||
.disable = arizona_micsupp_disable,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
|
||||
.list_voltage = arizona_micsupp_list_voltage,
|
||||
|
@ -84,7 +152,7 @@ static struct regulator_ops arizona_micsupp_ops = {
|
|||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
|
||||
.get_bypass = regulator_get_bypass_regmap,
|
||||
.set_bypass = regulator_set_bypass_regmap,
|
||||
.set_bypass = arizona_micsupp_set_bypass,
|
||||
};
|
||||
|
||||
static const struct regulator_desc arizona_micsupp = {
|
||||
|
@ -109,7 +177,8 @@ static const struct regulator_desc arizona_micsupp = {
|
|||
static const struct regulator_init_data arizona_micsupp_default = {
|
||||
.constraints = {
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS |
|
||||
REGULATOR_CHANGE_VOLTAGE,
|
||||
REGULATOR_CHANGE_VOLTAGE |
|
||||
REGULATOR_CHANGE_BYPASS,
|
||||
.min_uV = 1700000,
|
||||
.max_uV = 3300000,
|
||||
},
|
||||
|
@ -131,6 +200,7 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
micsupp->arizona = arizona;
|
||||
INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp);
|
||||
|
||||
/*
|
||||
* Since the chip usually supplies itself we provide some
|
||||
|
|
|
@ -303,7 +303,7 @@ static int as3711_regulator_probe(struct platform_device *pdev)
|
|||
reg_data = pdata ? pdata->init_data[id] : NULL;
|
||||
|
||||
/* No need to register if there is no regulator data */
|
||||
if (!ri->desc.name)
|
||||
if (!reg_data)
|
||||
continue;
|
||||
|
||||
reg = ®s[id];
|
||||
|
|
|
@ -200,8 +200,8 @@ static int regulator_check_consumers(struct regulator_dev *rdev,
|
|||
}
|
||||
|
||||
if (*min_uV > *max_uV) {
|
||||
dev_err(regulator->dev, "Restricting voltage, %u-%uuV\n",
|
||||
regulator->min_uV, regulator->max_uV);
|
||||
rdev_err(rdev, "Restricting voltage, %u-%uuV\n",
|
||||
*min_uV, *max_uV);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2080,10 +2080,20 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap);
|
|||
*/
|
||||
int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sel <<= ffs(rdev->desc->vsel_mask) - 1;
|
||||
|
||||
return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
|
||||
ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
|
||||
rdev->desc->vsel_mask, sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rdev->desc->apply_bit)
|
||||
ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
|
||||
rdev->desc->apply_bit,
|
||||
rdev->desc->apply_bit);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
|
||||
|
||||
|
@ -2229,8 +2239,11 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
|||
best_val = rdev->desc->ops->list_voltage(rdev, ret);
|
||||
if (min_uV <= best_val && max_uV >= best_val) {
|
||||
selector = ret;
|
||||
ret = rdev->desc->ops->set_voltage_sel(rdev,
|
||||
ret);
|
||||
if (old_selector == selector)
|
||||
ret = 0;
|
||||
else
|
||||
ret = rdev->desc->ops->set_voltage_sel(
|
||||
rdev, ret);
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
@ -2241,7 +2254,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
|||
|
||||
/* Call set_voltage_time_sel if successfully obtained old_selector */
|
||||
if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
|
||||
rdev->desc->ops->set_voltage_time_sel) {
|
||||
old_selector != selector && rdev->desc->ops->set_voltage_time_sel) {
|
||||
|
||||
delay = rdev->desc->ops->set_voltage_time_sel(rdev,
|
||||
old_selector, selector);
|
||||
|
@ -2294,6 +2307,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
|
|||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
int ret = 0;
|
||||
int old_min_uV, old_max_uV;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
|
||||
|
@ -2315,18 +2329,29 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
|
|||
ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* restore original values in case of error */
|
||||
old_min_uV = regulator->min_uV;
|
||||
old_max_uV = regulator->max_uV;
|
||||
regulator->min_uV = min_uV;
|
||||
regulator->max_uV = max_uV;
|
||||
|
||||
ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto out2;
|
||||
|
||||
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
|
||||
if (ret < 0)
|
||||
goto out2;
|
||||
|
||||
out:
|
||||
mutex_unlock(&rdev->mutex);
|
||||
return ret;
|
||||
out2:
|
||||
regulator->min_uV = old_min_uV;
|
||||
regulator->max_uV = old_max_uV;
|
||||
mutex_unlock(&rdev->mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_set_voltage);
|
||||
|
||||
|
@ -3208,7 +3233,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
|
|||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
if (ops->is_enabled) {
|
||||
if (rdev->ena_gpio || ops->is_enabled) {
|
||||
status = device_create_file(dev, &dev_attr_state);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
|
|
@ -70,7 +70,6 @@ struct da9052_regulator_info {
|
|||
int step_uV;
|
||||
int min_uV;
|
||||
int max_uV;
|
||||
unsigned char activate_bit;
|
||||
};
|
||||
|
||||
struct da9052_regulator {
|
||||
|
@ -210,36 +209,6 @@ static int da9052_map_voltage(struct regulator_dev *rdev,
|
|||
return sel;
|
||||
}
|
||||
|
||||
static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,
|
||||
unsigned int selector)
|
||||
{
|
||||
struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
|
||||
struct da9052_regulator_info *info = regulator->info;
|
||||
int id = rdev_get_id(rdev);
|
||||
int ret;
|
||||
|
||||
ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg,
|
||||
rdev->desc->vsel_mask, selector);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Some LDOs and DCDCs are DVC controlled which requires enabling of
|
||||
* the activate bit to implment the changes on the output.
|
||||
*/
|
||||
switch (id) {
|
||||
case DA9052_ID_BUCK1:
|
||||
case DA9052_ID_BUCK2:
|
||||
case DA9052_ID_BUCK3:
|
||||
case DA9052_ID_LDO2:
|
||||
case DA9052_ID_LDO3:
|
||||
ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
|
||||
info->activate_bit, info->activate_bit);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct regulator_ops da9052_dcdc_ops = {
|
||||
.get_current_limit = da9052_dcdc_get_current_limit,
|
||||
.set_current_limit = da9052_dcdc_set_current_limit,
|
||||
|
@ -247,7 +216,7 @@ static struct regulator_ops da9052_dcdc_ops = {
|
|||
.list_voltage = da9052_list_voltage,
|
||||
.map_voltage = da9052_map_voltage,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = da9052_regulator_set_voltage_sel,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
|
@ -257,7 +226,7 @@ static struct regulator_ops da9052_ldo_ops = {
|
|||
.list_voltage = da9052_list_voltage,
|
||||
.map_voltage = da9052_map_voltage,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = da9052_regulator_set_voltage_sel,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
|
@ -274,13 +243,14 @@ static struct regulator_ops da9052_ldo_ops = {
|
|||
.owner = THIS_MODULE,\
|
||||
.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
|
||||
.vsel_mask = (1 << (sbits)) - 1,\
|
||||
.apply_reg = DA9052_SUPPLY_REG, \
|
||||
.apply_bit = (abits), \
|
||||
.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
|
||||
.enable_mask = 1 << (ebits),\
|
||||
},\
|
||||
.min_uV = (min) * 1000,\
|
||||
.max_uV = (max) * 1000,\
|
||||
.step_uV = (step) * 1000,\
|
||||
.activate_bit = (abits),\
|
||||
}
|
||||
|
||||
#define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \
|
||||
|
@ -294,13 +264,14 @@ static struct regulator_ops da9052_ldo_ops = {
|
|||
.owner = THIS_MODULE,\
|
||||
.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
|
||||
.vsel_mask = (1 << (sbits)) - 1,\
|
||||
.apply_reg = DA9052_SUPPLY_REG, \
|
||||
.apply_bit = (abits), \
|
||||
.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \
|
||||
.enable_mask = 1 << (ebits),\
|
||||
},\
|
||||
.min_uV = (min) * 1000,\
|
||||
.max_uV = (max) * 1000,\
|
||||
.step_uV = (step) * 1000,\
|
||||
.activate_bit = (abits),\
|
||||
}
|
||||
|
||||
static struct da9052_regulator_info da9052_regulator_info[] = {
|
||||
|
@ -395,9 +366,9 @@ static int da9052_regulator_probe(struct platform_device *pdev)
|
|||
config.init_data = pdata->regulators[pdev->id];
|
||||
} else {
|
||||
#ifdef CONFIG_OF
|
||||
struct device_node *nproot = da9052->dev->of_node;
|
||||
struct device_node *np;
|
||||
struct device_node *nproot, *np;
|
||||
|
||||
nproot = of_node_get(da9052->dev->of_node);
|
||||
if (!nproot)
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -414,6 +385,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
|
|||
break;
|
||||
}
|
||||
}
|
||||
of_node_put(nproot);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ struct da9055_volt_reg {
|
|||
int reg_b;
|
||||
int sl_shift;
|
||||
int v_mask;
|
||||
int v_shift;
|
||||
};
|
||||
|
||||
struct da9055_mode_reg {
|
||||
|
@ -388,7 +387,6 @@ static struct regulator_ops da9055_ldo_ops = {
|
|||
.reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \
|
||||
.sl_shift = 7,\
|
||||
.v_mask = (1 << (vbits)) - 1,\
|
||||
.v_shift = (vbits),\
|
||||
},\
|
||||
}
|
||||
|
||||
|
@ -417,7 +415,6 @@ static struct regulator_ops da9055_ldo_ops = {
|
|||
.reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \
|
||||
.sl_shift = 7,\
|
||||
.v_mask = (1 << (vbits)) - 1,\
|
||||
.v_shift = (vbits),\
|
||||
},\
|
||||
.mode = {\
|
||||
.reg = DA9055_REG_BCORE_MODE,\
|
||||
|
|
|
@ -132,7 +132,7 @@ static struct regulator_ops gpio_regulator_voltage_ops = {
|
|||
.list_voltage = gpio_regulator_list_voltage,
|
||||
};
|
||||
|
||||
struct gpio_regulator_config *
|
||||
static struct gpio_regulator_config *
|
||||
of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
|
||||
{
|
||||
struct gpio_regulator_config *config;
|
||||
|
@ -163,10 +163,7 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
|
|||
config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0);
|
||||
|
||||
/* Fetch GPIOs. */
|
||||
for (i = 0; ; i++)
|
||||
if (of_get_named_gpio(np, "gpios", i) < 0)
|
||||
break;
|
||||
config->nr_gpios = i;
|
||||
config->nr_gpios = of_gpio_count(np);
|
||||
|
||||
config->gpios = devm_kzalloc(dev,
|
||||
sizeof(struct gpio) * config->nr_gpios,
|
||||
|
|
|
@ -73,8 +73,6 @@ static const unsigned int buck_voltage_map[] = {
|
|||
};
|
||||
|
||||
#define BUCK_TARGET_VOL_MASK 0x3f
|
||||
#define BUCK_TARGET_VOL_MIN_IDX 0x01
|
||||
#define BUCK_TARGET_VOL_MAX_IDX 0x19
|
||||
|
||||
#define LP3971_BUCK_RAMP_REG(x) (buck_base_addr[x]+2)
|
||||
|
||||
|
@ -140,7 +138,7 @@ static int lp3971_ldo_disable(struct regulator_dev *dev)
|
|||
return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0);
|
||||
}
|
||||
|
||||
static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
|
||||
static int lp3971_ldo_get_voltage_sel(struct regulator_dev *dev)
|
||||
{
|
||||
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
|
||||
int ldo = rdev_get_id(dev) - LP3971_LDO1;
|
||||
|
@ -149,7 +147,7 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
|
|||
reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
|
||||
val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
|
||||
|
||||
return dev->desc->volt_table[val];
|
||||
return val;
|
||||
}
|
||||
|
||||
static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
|
||||
|
@ -168,7 +166,7 @@ static struct regulator_ops lp3971_ldo_ops = {
|
|||
.is_enabled = lp3971_ldo_is_enabled,
|
||||
.enable = lp3971_ldo_enable,
|
||||
.disable = lp3971_ldo_disable,
|
||||
.get_voltage = lp3971_ldo_get_voltage,
|
||||
.get_voltage_sel = lp3971_ldo_get_voltage_sel,
|
||||
.set_voltage_sel = lp3971_ldo_set_voltage_sel,
|
||||
};
|
||||
|
||||
|
@ -201,24 +199,16 @@ static int lp3971_dcdc_disable(struct regulator_dev *dev)
|
|||
return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0);
|
||||
}
|
||||
|
||||
static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
|
||||
static int lp3971_dcdc_get_voltage_sel(struct regulator_dev *dev)
|
||||
{
|
||||
struct lp3971 *lp3971 = rdev_get_drvdata(dev);
|
||||
int buck = rdev_get_id(dev) - LP3971_DCDC1;
|
||||
u16 reg;
|
||||
int val;
|
||||
|
||||
reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck));
|
||||
reg &= BUCK_TARGET_VOL_MASK;
|
||||
|
||||
if (reg <= BUCK_TARGET_VOL_MAX_IDX)
|
||||
val = buck_voltage_map[reg];
|
||||
else {
|
||||
val = 0;
|
||||
dev_warn(&dev->dev, "chip reported incorrect voltage value.\n");
|
||||
}
|
||||
|
||||
return val;
|
||||
return reg;
|
||||
}
|
||||
|
||||
static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
|
||||
|
@ -249,7 +239,7 @@ static struct regulator_ops lp3971_dcdc_ops = {
|
|||
.is_enabled = lp3971_dcdc_is_enabled,
|
||||
.enable = lp3971_dcdc_enable,
|
||||
.disable = lp3971_dcdc_disable,
|
||||
.get_voltage = lp3971_dcdc_get_voltage,
|
||||
.get_voltage_sel = lp3971_dcdc_get_voltage_sel,
|
||||
.set_voltage_sel = lp3971_dcdc_set_voltage_sel,
|
||||
};
|
||||
|
||||
|
|
|
@ -165,8 +165,6 @@ static const int buck_base_addr[] = {
|
|||
#define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
|
||||
#define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
|
||||
#define LP3972_BUCK_VOL_MASK 0x1f
|
||||
#define LP3972_BUCK_VOL_MIN_IDX(x) ((x) ? 0x01 : 0x00)
|
||||
#define LP3972_BUCK_VOL_MAX_IDX(x) ((x) ? 0x19 : 0x1f)
|
||||
|
||||
static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count,
|
||||
u16 *dest)
|
||||
|
@ -257,7 +255,7 @@ static int lp3972_ldo_disable(struct regulator_dev *dev)
|
|||
mask, 0);
|
||||
}
|
||||
|
||||
static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
|
||||
static int lp3972_ldo_get_voltage_sel(struct regulator_dev *dev)
|
||||
{
|
||||
struct lp3972 *lp3972 = rdev_get_drvdata(dev);
|
||||
int ldo = rdev_get_id(dev) - LP3972_LDO1;
|
||||
|
@ -267,7 +265,7 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
|
|||
reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
|
||||
val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;
|
||||
|
||||
return dev->desc->volt_table[val];
|
||||
return val;
|
||||
}
|
||||
|
||||
static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
|
||||
|
@ -314,7 +312,7 @@ static struct regulator_ops lp3972_ldo_ops = {
|
|||
.is_enabled = lp3972_ldo_is_enabled,
|
||||
.enable = lp3972_ldo_enable,
|
||||
.disable = lp3972_ldo_disable,
|
||||
.get_voltage = lp3972_ldo_get_voltage,
|
||||
.get_voltage_sel = lp3972_ldo_get_voltage_sel,
|
||||
.set_voltage_sel = lp3972_ldo_set_voltage_sel,
|
||||
};
|
||||
|
||||
|
@ -353,24 +351,16 @@ static int lp3972_dcdc_disable(struct regulator_dev *dev)
|
|||
return val;
|
||||
}
|
||||
|
||||
static int lp3972_dcdc_get_voltage(struct regulator_dev *dev)
|
||||
static int lp3972_dcdc_get_voltage_sel(struct regulator_dev *dev)
|
||||
{
|
||||
struct lp3972 *lp3972 = rdev_get_drvdata(dev);
|
||||
int buck = rdev_get_id(dev) - LP3972_DCDC1;
|
||||
u16 reg;
|
||||
int val;
|
||||
|
||||
reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
|
||||
reg &= LP3972_BUCK_VOL_MASK;
|
||||
if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck))
|
||||
val = dev->desc->volt_table[reg];
|
||||
else {
|
||||
val = 0;
|
||||
dev_warn(&dev->dev, "chip reported incorrect voltage value."
|
||||
" reg = %d\n", reg);
|
||||
}
|
||||
|
||||
return val;
|
||||
return reg;
|
||||
}
|
||||
|
||||
static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev,
|
||||
|
@ -402,7 +392,7 @@ static struct regulator_ops lp3972_dcdc_ops = {
|
|||
.is_enabled = lp3972_dcdc_is_enabled,
|
||||
.enable = lp3972_dcdc_enable,
|
||||
.disable = lp3972_dcdc_disable,
|
||||
.get_voltage = lp3972_dcdc_get_voltage,
|
||||
.get_voltage_sel = lp3972_dcdc_get_voltage_sel,
|
||||
.set_voltage_sel = lp3972_dcdc_set_voltage_sel,
|
||||
};
|
||||
|
||||
|
|
|
@ -181,20 +181,6 @@ static inline int lp872x_update_bits(struct lp872x *lp, u8 addr,
|
|||
return regmap_update_bits(lp->regmap, addr, mask, data);
|
||||
}
|
||||
|
||||
static int _rdev_to_offset(struct regulator_dev *rdev)
|
||||
{
|
||||
enum lp872x_regulator_id id = rdev_get_id(rdev);
|
||||
|
||||
switch (id) {
|
||||
case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
|
||||
return id;
|
||||
case LP8725_ID_LDO1 ... LP8725_ID_BUCK2:
|
||||
return id - LP8725_ID_BASE;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int lp872x_get_timestep_usec(struct lp872x *lp)
|
||||
{
|
||||
enum lp872x_id chip = lp->chipid;
|
||||
|
@ -234,28 +220,20 @@ static int lp872x_get_timestep_usec(struct lp872x *lp)
|
|||
static int lp872x_regulator_enable_time(struct regulator_dev *rdev)
|
||||
{
|
||||
struct lp872x *lp = rdev_get_drvdata(rdev);
|
||||
enum lp872x_regulator_id regulator = rdev_get_id(rdev);
|
||||
enum lp872x_regulator_id rid = rdev_get_id(rdev);
|
||||
int time_step_us = lp872x_get_timestep_usec(lp);
|
||||
int ret, offset;
|
||||
int ret;
|
||||
u8 addr, val;
|
||||
|
||||
if (time_step_us < 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (regulator) {
|
||||
case LP8720_ID_LDO1 ... LP8720_ID_LDO5:
|
||||
case LP8725_ID_LDO1 ... LP8725_ID_LILO2:
|
||||
offset = _rdev_to_offset(rdev);
|
||||
if (offset < 0)
|
||||
return -EINVAL;
|
||||
|
||||
addr = LP872X_LDO1_VOUT + offset;
|
||||
switch (rid) {
|
||||
case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
|
||||
addr = LP872X_LDO1_VOUT + rid;
|
||||
break;
|
||||
case LP8720_ID_BUCK:
|
||||
addr = LP8720_BUCK_VOUT1;
|
||||
break;
|
||||
case LP8725_ID_BUCK1:
|
||||
addr = LP8725_BUCK1_VOUT1;
|
||||
case LP8725_ID_LDO1 ... LP8725_ID_BUCK1:
|
||||
addr = LP872X_LDO1_VOUT + rid - LP8725_ID_BASE;
|
||||
break;
|
||||
case LP8725_ID_BUCK2:
|
||||
addr = LP8725_BUCK2_VOUT1;
|
||||
|
|
566
drivers/regulator/lp8755.c
Normal file
566
drivers/regulator/lp8755.c
Normal file
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
* LP8755 High Performance Power Management Unit : System Interface Driver
|
||||
* (based on rev. 0.26)
|
||||
* Copyright 2012 Texas Instruments
|
||||
*
|
||||
* Author: Daniel(Geon Si) Jeong <daniel.jeong@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/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/platform_data/lp8755.h>
|
||||
|
||||
#define LP8755_REG_BUCK0 0x00
|
||||
#define LP8755_REG_BUCK1 0x03
|
||||
#define LP8755_REG_BUCK2 0x04
|
||||
#define LP8755_REG_BUCK3 0x01
|
||||
#define LP8755_REG_BUCK4 0x05
|
||||
#define LP8755_REG_BUCK5 0x02
|
||||
#define LP8755_REG_MAX 0xFF
|
||||
|
||||
#define LP8755_BUCK_EN_M BIT(7)
|
||||
#define LP8755_BUCK_LINEAR_OUT_MAX 0x76
|
||||
#define LP8755_BUCK_VOUT_M 0x7F
|
||||
|
||||
struct lp8755_mphase {
|
||||
int nreg;
|
||||
int buck_num[LP8755_BUCK_MAX];
|
||||
};
|
||||
|
||||
struct lp8755_chip {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct lp8755_platform_data *pdata;
|
||||
|
||||
int irq;
|
||||
unsigned int irqmask;
|
||||
|
||||
int mphase;
|
||||
struct regulator_dev *rdev[LP8755_BUCK_MAX];
|
||||
};
|
||||
|
||||
/**
|
||||
*lp8755_read : read a single register value from lp8755.
|
||||
*@pchip : device to read from
|
||||
*@reg : register to read from
|
||||
*@val : pointer to store read value
|
||||
*/
|
||||
static int lp8755_read(struct lp8755_chip *pchip, unsigned int reg,
|
||||
unsigned int *val)
|
||||
{
|
||||
return regmap_read(pchip->regmap, reg, val);
|
||||
}
|
||||
|
||||
/**
|
||||
*lp8755_write : write a single register value to lp8755.
|
||||
*@pchip : device to write to
|
||||
*@reg : register to write to
|
||||
*@val : value to be written
|
||||
*/
|
||||
static int lp8755_write(struct lp8755_chip *pchip, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
return regmap_write(pchip->regmap, reg, val);
|
||||
}
|
||||
|
||||
/**
|
||||
*lp8755_update_bits : set the values of bit fields in lp8755 register.
|
||||
*@pchip : device to read from
|
||||
*@reg : register to update
|
||||
*@mask : bitmask to be changed
|
||||
*@val : value for bitmask
|
||||
*/
|
||||
static int lp8755_update_bits(struct lp8755_chip *pchip, unsigned int reg,
|
||||
unsigned int mask, unsigned int val)
|
||||
{
|
||||
return regmap_update_bits(pchip->regmap, reg, mask, val);
|
||||
}
|
||||
|
||||
static int lp8755_buck_enable_time(struct regulator_dev *rdev)
|
||||
{
|
||||
int ret;
|
||||
unsigned int regval;
|
||||
enum lp8755_bucks id = rdev_get_id(rdev);
|
||||
struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
|
||||
|
||||
ret = lp8755_read(pchip, 0x12 + id, ®val);
|
||||
if (ret < 0) {
|
||||
dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
return (regval & 0xff) * 100;
|
||||
}
|
||||
|
||||
static int lp8755_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
|
||||
{
|
||||
int ret;
|
||||
unsigned int regbval = 0x0;
|
||||
enum lp8755_bucks id = rdev_get_id(rdev);
|
||||
struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
|
||||
|
||||
switch (mode) {
|
||||
case REGULATOR_MODE_FAST:
|
||||
/* forced pwm mode */
|
||||
regbval = (0x01 << id);
|
||||
break;
|
||||
case REGULATOR_MODE_NORMAL:
|
||||
/* enable automatic pwm/pfm mode */
|
||||
ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x00);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
break;
|
||||
case REGULATOR_MODE_IDLE:
|
||||
/* enable automatic pwm/pfm/lppfm mode */
|
||||
ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x20);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
|
||||
ret = lp8755_update_bits(pchip, 0x10, 0x01, 0x01);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
break;
|
||||
default:
|
||||
dev_err(pchip->dev, "Not supported buck mode %s\n", __func__);
|
||||
/* forced pwm mode */
|
||||
regbval = (0x01 << id);
|
||||
}
|
||||
|
||||
ret = lp8755_update_bits(pchip, 0x06, 0x01 << id, regbval);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
return ret;
|
||||
err_i2c:
|
||||
dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int lp8755_buck_get_mode(struct regulator_dev *rdev)
|
||||
{
|
||||
int ret;
|
||||
unsigned int regval;
|
||||
enum lp8755_bucks id = rdev_get_id(rdev);
|
||||
struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
|
||||
|
||||
ret = lp8755_read(pchip, 0x06, ®val);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
|
||||
/* mode fast means forced pwm mode */
|
||||
if (regval & (0x01 << id))
|
||||
return REGULATOR_MODE_FAST;
|
||||
|
||||
ret = lp8755_read(pchip, 0x08 + id, ®val);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
|
||||
/* mode idle means automatic pwm/pfm/lppfm mode */
|
||||
if (regval & 0x20)
|
||||
return REGULATOR_MODE_IDLE;
|
||||
|
||||
/* mode normal means automatic pwm/pfm mode */
|
||||
return REGULATOR_MODE_NORMAL;
|
||||
|
||||
err_i2c:
|
||||
dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp)
|
||||
{
|
||||
int ret;
|
||||
unsigned int regval = 0x00;
|
||||
enum lp8755_bucks id = rdev_get_id(rdev);
|
||||
struct lp8755_chip *pchip = rdev_get_drvdata(rdev);
|
||||
|
||||
/* uV/us */
|
||||
switch (ramp) {
|
||||
case 0 ... 230:
|
||||
regval = 0x07;
|
||||
break;
|
||||
case 231 ... 470:
|
||||
regval = 0x06;
|
||||
break;
|
||||
case 471 ... 940:
|
||||
regval = 0x05;
|
||||
break;
|
||||
case 941 ... 1900:
|
||||
regval = 0x04;
|
||||
break;
|
||||
case 1901 ... 3800:
|
||||
regval = 0x03;
|
||||
break;
|
||||
case 3801 ... 7500:
|
||||
regval = 0x02;
|
||||
break;
|
||||
case 7501 ... 15000:
|
||||
regval = 0x01;
|
||||
break;
|
||||
case 15001 ... 30000:
|
||||
regval = 0x00;
|
||||
break;
|
||||
default:
|
||||
dev_err(pchip->dev,
|
||||
"Not supported ramp value %d %s\n", ramp, __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = lp8755_update_bits(pchip, 0x07 + id, 0x07, regval);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
return ret;
|
||||
err_i2c:
|
||||
dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct regulator_ops lp8755_buck_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 = lp8755_buck_enable_time,
|
||||
.set_mode = lp8755_buck_set_mode,
|
||||
.get_mode = lp8755_buck_get_mode,
|
||||
.set_ramp_delay = lp8755_buck_set_ramp,
|
||||
};
|
||||
|
||||
#define lp8755_rail(_id) "lp8755_buck"#_id
|
||||
#define lp8755_buck_init(_id)\
|
||||
{\
|
||||
.constraints = {\
|
||||
.name = lp8755_rail(_id),\
|
||||
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,\
|
||||
.min_uV = 500000,\
|
||||
.max_uV = 1675000,\
|
||||
},\
|
||||
}
|
||||
|
||||
static struct regulator_init_data lp8755_reg_default[LP8755_BUCK_MAX] = {
|
||||
[LP8755_BUCK0] = lp8755_buck_init(0),
|
||||
[LP8755_BUCK1] = lp8755_buck_init(1),
|
||||
[LP8755_BUCK2] = lp8755_buck_init(2),
|
||||
[LP8755_BUCK3] = lp8755_buck_init(3),
|
||||
[LP8755_BUCK4] = lp8755_buck_init(4),
|
||||
[LP8755_BUCK5] = lp8755_buck_init(5),
|
||||
};
|
||||
|
||||
static const struct lp8755_mphase mphase_buck[MPHASE_CONF_MAX] = {
|
||||
{ 3, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK5 } },
|
||||
{ 6, { LP8755_BUCK0, LP8755_BUCK1, LP8755_BUCK2, LP8755_BUCK3,
|
||||
LP8755_BUCK4, LP8755_BUCK5 } },
|
||||
{ 5, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK4,
|
||||
LP8755_BUCK5} },
|
||||
{ 4, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK4, LP8755_BUCK5} },
|
||||
{ 3, { LP8755_BUCK0, LP8755_BUCK4, LP8755_BUCK5} },
|
||||
{ 2, { LP8755_BUCK0, LP8755_BUCK5} },
|
||||
{ 1, { LP8755_BUCK0} },
|
||||
{ 2, { LP8755_BUCK0, LP8755_BUCK3} },
|
||||
{ 4, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK5} },
|
||||
};
|
||||
|
||||
static int lp8755_init_data(struct lp8755_chip *pchip)
|
||||
{
|
||||
unsigned int regval;
|
||||
int ret, icnt, buck_num;
|
||||
struct lp8755_platform_data *pdata = pchip->pdata;
|
||||
|
||||
/* read back muti-phase configuration */
|
||||
ret = lp8755_read(pchip, 0x3D, ®val);
|
||||
if (ret < 0)
|
||||
goto out_i2c_error;
|
||||
pchip->mphase = regval & 0x0F;
|
||||
|
||||
/* set default data based on multi-phase config */
|
||||
for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) {
|
||||
buck_num = mphase_buck[pchip->mphase].buck_num[icnt];
|
||||
pdata->buck_data[buck_num] = &lp8755_reg_default[buck_num];
|
||||
}
|
||||
return ret;
|
||||
|
||||
out_i2c_error:
|
||||
dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define lp8755_buck_desc(_id)\
|
||||
{\
|
||||
.name = lp8755_rail(_id),\
|
||||
.id = LP8755_BUCK##_id,\
|
||||
.ops = &lp8755_buck_ops,\
|
||||
.n_voltages = LP8755_BUCK_LINEAR_OUT_MAX+1,\
|
||||
.uV_step = 10000,\
|
||||
.min_uV = 500000,\
|
||||
.type = REGULATOR_VOLTAGE,\
|
||||
.owner = THIS_MODULE,\
|
||||
.enable_reg = LP8755_REG_BUCK##_id,\
|
||||
.enable_mask = LP8755_BUCK_EN_M,\
|
||||
.vsel_reg = LP8755_REG_BUCK##_id,\
|
||||
.vsel_mask = LP8755_BUCK_VOUT_M,\
|
||||
}
|
||||
|
||||
static struct regulator_desc lp8755_regulators[] = {
|
||||
lp8755_buck_desc(0),
|
||||
lp8755_buck_desc(1),
|
||||
lp8755_buck_desc(2),
|
||||
lp8755_buck_desc(3),
|
||||
lp8755_buck_desc(4),
|
||||
lp8755_buck_desc(5),
|
||||
};
|
||||
|
||||
static int lp8755_regulator_init(struct lp8755_chip *pchip)
|
||||
{
|
||||
int ret, icnt, buck_num;
|
||||
struct lp8755_platform_data *pdata = pchip->pdata;
|
||||
struct regulator_config rconfig = { };
|
||||
|
||||
rconfig.regmap = pchip->regmap;
|
||||
rconfig.dev = pchip->dev;
|
||||
rconfig.driver_data = pchip;
|
||||
|
||||
for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) {
|
||||
buck_num = mphase_buck[pchip->mphase].buck_num[icnt];
|
||||
rconfig.init_data = pdata->buck_data[buck_num];
|
||||
rconfig.of_node = pchip->dev->of_node;
|
||||
pchip->rdev[buck_num] =
|
||||
regulator_register(&lp8755_regulators[buck_num], &rconfig);
|
||||
if (IS_ERR(pchip->rdev[buck_num])) {
|
||||
ret = PTR_ERR(pchip->rdev[buck_num]);
|
||||
pchip->rdev[buck_num] = NULL;
|
||||
dev_err(pchip->dev, "regulator init failed: buck %d\n",
|
||||
buck_num);
|
||||
goto err_buck;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_buck:
|
||||
for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
|
||||
regulator_unregister(pchip->rdev[icnt]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t lp8755_irq_handler(int irq, void *data)
|
||||
{
|
||||
int ret, icnt;
|
||||
unsigned int flag0, flag1;
|
||||
struct lp8755_chip *pchip = data;
|
||||
|
||||
/* read flag0 register */
|
||||
ret = lp8755_read(pchip, 0x0D, &flag0);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
/* clear flag register to pull up int. pin */
|
||||
ret = lp8755_write(pchip, 0x0D, 0x00);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
|
||||
/* sent power fault detection event to specific regulator */
|
||||
for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
|
||||
if ((flag0 & (0x4 << icnt))
|
||||
&& (pchip->irqmask & (0x04 << icnt))
|
||||
&& (pchip->rdev[icnt] != NULL))
|
||||
regulator_notifier_call_chain(pchip->rdev[icnt],
|
||||
LP8755_EVENT_PWR_FAULT,
|
||||
NULL);
|
||||
|
||||
/* read flag1 register */
|
||||
ret = lp8755_read(pchip, 0x0E, &flag1);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
/* clear flag register to pull up int. pin */
|
||||
ret = lp8755_write(pchip, 0x0E, 0x00);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
|
||||
/* send OCP event to all regualtor devices */
|
||||
if ((flag1 & 0x01) && (pchip->irqmask & 0x01))
|
||||
for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
|
||||
if (pchip->rdev[icnt] != NULL)
|
||||
regulator_notifier_call_chain(pchip->rdev[icnt],
|
||||
LP8755_EVENT_OCP,
|
||||
NULL);
|
||||
|
||||
/* send OVP event to all regualtor devices */
|
||||
if ((flag1 & 0x02) && (pchip->irqmask & 0x02))
|
||||
for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
|
||||
if (pchip->rdev[icnt] != NULL)
|
||||
regulator_notifier_call_chain(pchip->rdev[icnt],
|
||||
LP8755_EVENT_OVP,
|
||||
NULL);
|
||||
return IRQ_HANDLED;
|
||||
|
||||
err_i2c:
|
||||
dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int lp8755_int_config(struct lp8755_chip *pchip)
|
||||
{
|
||||
int ret;
|
||||
unsigned int regval;
|
||||
|
||||
if (pchip->irq == 0) {
|
||||
dev_warn(pchip->dev, "not use interrupt : %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = lp8755_read(pchip, 0x0F, ®val);
|
||||
if (ret < 0)
|
||||
goto err_i2c;
|
||||
pchip->irqmask = regval;
|
||||
ret = request_threaded_irq(pchip->irq, NULL, lp8755_irq_handler,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"lp8755-irq", pchip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
|
||||
err_i2c:
|
||||
dev_err(pchip->dev, "i2c acceess error %s\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct regmap_config lp8755_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = LP8755_REG_MAX,
|
||||
};
|
||||
|
||||
static int lp8755_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int ret, icnt;
|
||||
struct lp8755_chip *pchip;
|
||||
struct lp8755_platform_data *pdata = client->dev.platform_data;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "i2c functionality check fail.\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
pchip = devm_kzalloc(&client->dev,
|
||||
sizeof(struct lp8755_chip), GFP_KERNEL);
|
||||
if (!pchip)
|
||||
return -ENOMEM;
|
||||
|
||||
pchip->dev = &client->dev;
|
||||
pchip->regmap = devm_regmap_init_i2c(client, &lp8755_regmap);
|
||||
if (IS_ERR(pchip->regmap)) {
|
||||
ret = PTR_ERR(pchip->regmap);
|
||||
dev_err(&client->dev, "fail to allocate regmap %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
i2c_set_clientdata(client, pchip);
|
||||
|
||||
if (pdata != NULL) {
|
||||
pchip->pdata = pdata;
|
||||
pchip->mphase = pdata->mphase;
|
||||
} else {
|
||||
pchip->pdata = devm_kzalloc(pchip->dev,
|
||||
sizeof(struct lp8755_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pchip->pdata)
|
||||
return -ENOMEM;
|
||||
ret = lp8755_init_data(pchip);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "fail to initialize chip\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = lp8755_regulator_init(pchip);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "fail to initialize regulators\n");
|
||||
goto err_regulator;
|
||||
}
|
||||
|
||||
pchip->irq = client->irq;
|
||||
ret = lp8755_int_config(pchip);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "fail to irq config\n");
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_irq:
|
||||
for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++)
|
||||
regulator_unregister(pchip->rdev[icnt]);
|
||||
|
||||
err_regulator:
|
||||
/* output disable */
|
||||
for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
|
||||
lp8755_write(pchip, icnt, 0x00);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lp8755_remove(struct i2c_client *client)
|
||||
{
|
||||
int icnt;
|
||||
struct lp8755_chip *pchip = i2c_get_clientdata(client);
|
||||
|
||||
for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++)
|
||||
regulator_unregister(pchip->rdev[icnt]);
|
||||
|
||||
for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++)
|
||||
lp8755_write(pchip, icnt, 0x00);
|
||||
|
||||
if (pchip->irq != 0)
|
||||
free_irq(pchip->irq, pchip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id lp8755_id[] = {
|
||||
{LP8755_NAME, 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, lp8755_id);
|
||||
|
||||
static struct i2c_driver lp8755_i2c_driver = {
|
||||
.driver = {
|
||||
.name = LP8755_NAME,
|
||||
},
|
||||
.probe = lp8755_probe,
|
||||
.remove = lp8755_remove,
|
||||
.id_table = lp8755_id,
|
||||
};
|
||||
|
||||
static int __init lp8755_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lp8755_i2c_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(lp8755_init);
|
||||
|
||||
static void __exit lp8755_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lp8755_i2c_driver);
|
||||
}
|
||||
|
||||
module_exit(lp8755_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Texas Instruments lp8755 driver");
|
||||
MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -103,16 +103,6 @@ static const int lp8788_buck_vtbl[] = {
|
|||
1950000, 2000000,
|
||||
};
|
||||
|
||||
static const u8 buck1_vout_addr[] = {
|
||||
LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
|
||||
LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
|
||||
};
|
||||
|
||||
static const u8 buck2_vout_addr[] = {
|
||||
LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1,
|
||||
LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3,
|
||||
};
|
||||
|
||||
static void lp8788_buck1_set_dvs(struct lp8788_buck *buck)
|
||||
{
|
||||
struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;
|
||||
|
@ -235,7 +225,7 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
|
|||
lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
|
||||
idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;
|
||||
}
|
||||
addr = buck1_vout_addr[idx];
|
||||
addr = LP8788_BUCK1_VOUT0 + idx;
|
||||
break;
|
||||
case BUCK2:
|
||||
if (mode == EXTPIN) {
|
||||
|
@ -258,7 +248,7 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
|
|||
lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
|
||||
idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;
|
||||
}
|
||||
addr = buck2_vout_addr[idx];
|
||||
addr = LP8788_BUCK2_VOUT0 + idx;
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
|
@ -429,7 +419,8 @@ static struct regulator_desc lp8788_buck_desc[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
|
||||
static int lp8788_dvs_gpio_request(struct platform_device *pdev,
|
||||
struct lp8788_buck *buck,
|
||||
enum lp8788_buck_id id)
|
||||
{
|
||||
struct lp8788_platform_data *pdata = buck->lp->pdata;
|
||||
|
@ -440,7 +431,7 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
|
|||
switch (id) {
|
||||
case BUCK1:
|
||||
gpio = pdata->buck1_dvs->gpio;
|
||||
ret = devm_gpio_request_one(buck->lp->dev, gpio, DVS_LOW,
|
||||
ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW,
|
||||
b1_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -448,9 +439,9 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
|
|||
buck->dvs = pdata->buck1_dvs;
|
||||
break;
|
||||
case BUCK2:
|
||||
for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) {
|
||||
for (i = 0; i < LP8788_NUM_BUCK2_DVS; i++) {
|
||||
gpio = pdata->buck2_dvs->gpio[i];
|
||||
ret = devm_gpio_request_one(buck->lp->dev, gpio,
|
||||
ret = devm_gpio_request_one(&pdev->dev, gpio,
|
||||
DVS_LOW, b2_name[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -464,7 +455,8 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
|
||||
static int lp8788_init_dvs(struct platform_device *pdev,
|
||||
struct lp8788_buck *buck, enum lp8788_buck_id id)
|
||||
{
|
||||
struct lp8788_platform_data *pdata = buck->lp->pdata;
|
||||
u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
|
||||
|
@ -472,7 +464,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
|
|||
u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };
|
||||
|
||||
/* no dvs for buck3, 4 */
|
||||
if (id == BUCK3 || id == BUCK4)
|
||||
if (id > BUCK2)
|
||||
return 0;
|
||||
|
||||
/* no dvs platform data, then dvs will be selected by I2C registers */
|
||||
|
@ -483,7 +475,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
|
|||
(id == BUCK2 && !pdata->buck2_dvs))
|
||||
goto set_default_dvs_mode;
|
||||
|
||||
if (lp8788_dvs_gpio_request(buck, id))
|
||||
if (lp8788_dvs_gpio_request(pdev, buck, id))
|
||||
goto set_default_dvs_mode;
|
||||
|
||||
return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
|
||||
|
@ -503,17 +495,20 @@ static int lp8788_buck_probe(struct platform_device *pdev)
|
|||
struct regulator_dev *rdev;
|
||||
int ret;
|
||||
|
||||
buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
|
||||
if (id >= LP8788_NUM_BUCKS)
|
||||
return -EINVAL;
|
||||
|
||||
buck = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
|
||||
if (!buck)
|
||||
return -ENOMEM;
|
||||
|
||||
buck->lp = lp;
|
||||
|
||||
ret = lp8788_init_dvs(buck, id);
|
||||
ret = lp8788_init_dvs(pdev, buck, id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cfg.dev = lp->dev;
|
||||
cfg.dev = pdev->dev.parent;
|
||||
cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;
|
||||
cfg.driver_data = buck;
|
||||
cfg.regmap = lp->regmap;
|
||||
|
@ -521,7 +516,7 @@ static int lp8788_buck_probe(struct platform_device *pdev)
|
|||
rdev = regulator_register(&lp8788_buck_desc[id], &cfg);
|
||||
if (IS_ERR(rdev)) {
|
||||
ret = PTR_ERR(rdev);
|
||||
dev_err(lp->dev, "BUCK%d regulator register err = %d\n",
|
||||
dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n",
|
||||
id + 1, ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -88,11 +88,6 @@
|
|||
#define ENABLE GPIOF_OUT_INIT_HIGH
|
||||
#define DISABLE GPIOF_OUT_INIT_LOW
|
||||
|
||||
enum lp8788_enable_mode {
|
||||
REGISTER,
|
||||
EXTPIN,
|
||||
};
|
||||
|
||||
enum lp8788_ldo_id {
|
||||
DLDO1,
|
||||
DLDO2,
|
||||
|
@ -189,114 +184,38 @@ static enum lp8788_ldo_id lp8788_aldo_id[] = {
|
|||
ALDO10,
|
||||
};
|
||||
|
||||
/* DLDO 7, 9 and 11, ALDO 1 ~ 5 and 7
|
||||
: can be enabled either by external pin or by i2c register */
|
||||
static enum lp8788_enable_mode
|
||||
lp8788_get_ldo_enable_mode(struct lp8788_ldo *ldo, enum lp8788_ldo_id id)
|
||||
{
|
||||
int ret;
|
||||
u8 val, mask;
|
||||
|
||||
ret = lp8788_read_byte(ldo->lp, LP8788_EN_SEL, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (id) {
|
||||
case DLDO7:
|
||||
mask = LP8788_EN_SEL_DLDO7_M;
|
||||
break;
|
||||
case DLDO9:
|
||||
case DLDO11:
|
||||
mask = LP8788_EN_SEL_DLDO911_M;
|
||||
break;
|
||||
case ALDO1:
|
||||
mask = LP8788_EN_SEL_ALDO1_M;
|
||||
break;
|
||||
case ALDO2 ... ALDO4:
|
||||
mask = LP8788_EN_SEL_ALDO234_M;
|
||||
break;
|
||||
case ALDO5:
|
||||
mask = LP8788_EN_SEL_ALDO5_M;
|
||||
break;
|
||||
case ALDO7:
|
||||
mask = LP8788_EN_SEL_ALDO7_M;
|
||||
break;
|
||||
default:
|
||||
return REGISTER;
|
||||
}
|
||||
|
||||
return val & mask ? EXTPIN : REGISTER;
|
||||
}
|
||||
|
||||
static int lp8788_ldo_ctrl_by_extern_pin(struct lp8788_ldo *ldo, int pinstate)
|
||||
{
|
||||
struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
|
||||
|
||||
if (!pin)
|
||||
return -EINVAL;
|
||||
|
||||
if (gpio_is_valid(pin->gpio))
|
||||
gpio_set_value(pin->gpio, pinstate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lp8788_ldo_is_enabled_by_extern_pin(struct lp8788_ldo *ldo)
|
||||
{
|
||||
struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
|
||||
|
||||
if (!pin)
|
||||
return -EINVAL;
|
||||
|
||||
return gpio_get_value(pin->gpio) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int lp8788_ldo_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
|
||||
enum lp8788_ldo_id id = rdev_get_id(rdev);
|
||||
enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
|
||||
|
||||
switch (mode) {
|
||||
case EXTPIN:
|
||||
return lp8788_ldo_ctrl_by_extern_pin(ldo, ENABLE);
|
||||
case REGISTER:
|
||||
if (ldo->en_pin) {
|
||||
gpio_set_value(ldo->en_pin->gpio, ENABLE);
|
||||
return 0;
|
||||
} else {
|
||||
return regulator_enable_regmap(rdev);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int lp8788_ldo_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
|
||||
enum lp8788_ldo_id id = rdev_get_id(rdev);
|
||||
enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
|
||||
|
||||
switch (mode) {
|
||||
case EXTPIN:
|
||||
return lp8788_ldo_ctrl_by_extern_pin(ldo, DISABLE);
|
||||
case REGISTER:
|
||||
if (ldo->en_pin) {
|
||||
gpio_set_value(ldo->en_pin->gpio, DISABLE);
|
||||
return 0;
|
||||
} else {
|
||||
return regulator_disable_regmap(rdev);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int lp8788_ldo_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
|
||||
enum lp8788_ldo_id id = rdev_get_id(rdev);
|
||||
enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
|
||||
|
||||
switch (mode) {
|
||||
case EXTPIN:
|
||||
return lp8788_ldo_is_enabled_by_extern_pin(ldo);
|
||||
case REGISTER:
|
||||
if (ldo->en_pin)
|
||||
return gpio_get_value(ldo->en_pin->gpio) ? 1 : 0;
|
||||
else
|
||||
return regulator_is_enabled_regmap(rdev);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
|
||||
|
@ -616,10 +535,11 @@ static struct regulator_desc lp8788_aldo_desc[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo,
|
||||
static int lp8788_gpio_request_ldo_en(struct platform_device *pdev,
|
||||
struct lp8788_ldo *ldo,
|
||||
enum lp8788_ext_ldo_en_id id)
|
||||
{
|
||||
struct device *dev = ldo->lp->dev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
|
||||
int ret, gpio, pinstate;
|
||||
char *name[] = {
|
||||
|
@ -647,7 +567,8 @@ static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo,
|
||||
static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
|
||||
struct lp8788_ldo *ldo,
|
||||
enum lp8788_ldo_id id)
|
||||
{
|
||||
int ret;
|
||||
|
@ -693,9 +614,11 @@ static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo,
|
|||
|
||||
ldo->en_pin = pdata->ldo_pin[enable_id];
|
||||
|
||||
ret = lp8788_gpio_request_ldo_en(ldo, enable_id);
|
||||
if (ret)
|
||||
ret = lp8788_gpio_request_ldo_en(pdev, ldo, enable_id);
|
||||
if (ret) {
|
||||
ldo->en_pin = NULL;
|
||||
goto set_default_ldo_enable_mode;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
|
@ -712,16 +635,16 @@ static int lp8788_dldo_probe(struct platform_device *pdev)
|
|||
struct regulator_dev *rdev;
|
||||
int ret;
|
||||
|
||||
ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
|
||||
ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
|
||||
if (!ldo)
|
||||
return -ENOMEM;
|
||||
|
||||
ldo->lp = lp;
|
||||
ret = lp8788_config_ldo_enable_mode(ldo, lp8788_dldo_id[id]);
|
||||
ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_dldo_id[id]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cfg.dev = lp->dev;
|
||||
cfg.dev = pdev->dev.parent;
|
||||
cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL;
|
||||
cfg.driver_data = ldo;
|
||||
cfg.regmap = lp->regmap;
|
||||
|
@ -729,7 +652,7 @@ static int lp8788_dldo_probe(struct platform_device *pdev)
|
|||
rdev = regulator_register(&lp8788_dldo_desc[id], &cfg);
|
||||
if (IS_ERR(rdev)) {
|
||||
ret = PTR_ERR(rdev);
|
||||
dev_err(lp->dev, "DLDO%d regulator register err = %d\n",
|
||||
dev_err(&pdev->dev, "DLDO%d regulator register err = %d\n",
|
||||
id + 1, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -768,16 +691,16 @@ static int lp8788_aldo_probe(struct platform_device *pdev)
|
|||
struct regulator_dev *rdev;
|
||||
int ret;
|
||||
|
||||
ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
|
||||
ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
|
||||
if (!ldo)
|
||||
return -ENOMEM;
|
||||
|
||||
ldo->lp = lp;
|
||||
ret = lp8788_config_ldo_enable_mode(ldo, lp8788_aldo_id[id]);
|
||||
ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_aldo_id[id]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cfg.dev = lp->dev;
|
||||
cfg.dev = pdev->dev.parent;
|
||||
cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL;
|
||||
cfg.driver_data = ldo;
|
||||
cfg.regmap = lp->regmap;
|
||||
|
@ -785,7 +708,7 @@ static int lp8788_aldo_probe(struct platform_device *pdev)
|
|||
rdev = regulator_register(&lp8788_aldo_desc[id], &cfg);
|
||||
if (IS_ERR(rdev)) {
|
||||
ret = PTR_ERR(rdev);
|
||||
dev_err(lp->dev, "ALDO%d regulator register err = %d\n",
|
||||
dev_err(&pdev->dev, "ALDO%d regulator register err = %d\n",
|
||||
id + 1, ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -75,13 +75,14 @@ static int max77686_buck_set_suspend_disable(struct regulator_dev *rdev)
|
|||
{
|
||||
unsigned int val;
|
||||
struct max77686_data *max77686 = rdev_get_drvdata(rdev);
|
||||
int id = rdev_get_id(rdev);
|
||||
|
||||
if (rdev->desc->id == MAX77686_BUCK1)
|
||||
if (id == MAX77686_BUCK1)
|
||||
val = 0x1;
|
||||
else
|
||||
val = 0x1 << MAX77686_OPMODE_BUCK234_SHIFT;
|
||||
|
||||
max77686->opmode[rdev->desc->id] = val;
|
||||
max77686->opmode[id] = val;
|
||||
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
|
||||
rdev->desc->enable_mask,
|
||||
val);
|
||||
|
@ -93,9 +94,10 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
|
|||
{
|
||||
struct max77686_data *max77686 = rdev_get_drvdata(rdev);
|
||||
unsigned int val;
|
||||
int id = rdev_get_id(rdev);
|
||||
|
||||
/* BUCK[5-9] doesn't support this feature */
|
||||
if (rdev->desc->id >= MAX77686_BUCK5)
|
||||
if (id >= MAX77686_BUCK5)
|
||||
return 0;
|
||||
|
||||
switch (mode) {
|
||||
|
@ -111,7 +113,7 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
max77686->opmode[rdev->desc->id] = val;
|
||||
max77686->opmode[id] = val;
|
||||
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
|
||||
rdev->desc->enable_mask,
|
||||
val);
|
||||
|
@ -140,7 +142,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
max77686->opmode[rdev->desc->id] = val;
|
||||
max77686->opmode[rdev_get_id(rdev)] = val;
|
||||
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
|
||||
rdev->desc->enable_mask,
|
||||
val);
|
||||
|
@ -152,7 +154,7 @@ static int max77686_enable(struct regulator_dev *rdev)
|
|||
|
||||
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
|
||||
rdev->desc->enable_mask,
|
||||
max77686->opmode[rdev->desc->id]);
|
||||
max77686->opmode[rdev_get_id(rdev)]);
|
||||
}
|
||||
|
||||
static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
|
||||
|
|
|
@ -224,11 +224,11 @@ static struct of_regulator_match max8907_matches[] = {
|
|||
|
||||
static int max8907_regulator_parse_dt(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.parent->of_node;
|
||||
struct device_node *regulators;
|
||||
struct device_node *np, *regulators;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.parent->of_node)
|
||||
np = of_node_get(pdev->dev.parent->of_node);
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
regulators = of_find_node_by_name(np, "regulators");
|
||||
|
@ -239,6 +239,7 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev)
|
|||
|
||||
ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
|
||||
ARRAY_SIZE(max8907_matches));
|
||||
of_node_put(regulators);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
|
||||
ret);
|
||||
|
|
|
@ -252,7 +252,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
|
|||
{
|
||||
struct device_node *nproot, *np;
|
||||
int rcount;
|
||||
nproot = pdev->dev.parent->of_node;
|
||||
nproot = of_node_get(pdev->dev.parent->of_node);
|
||||
if (!nproot)
|
||||
return -ENODEV;
|
||||
np = of_find_node_by_name(nproot, "regulators");
|
||||
|
@ -263,6 +263,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
|
|||
|
||||
rcount = of_regulator_match(&pdev->dev, np,
|
||||
&max8925_regulator_matches[ridx], 1);
|
||||
of_node_put(np);
|
||||
if (rcount < 0)
|
||||
return -ENODEV;
|
||||
config->init_data = max8925_regulator_matches[ridx].init_data;
|
||||
|
|
|
@ -54,6 +54,13 @@ struct max8997_data {
|
|||
u8 saved_states[MAX8997_REG_MAX];
|
||||
};
|
||||
|
||||
static const unsigned int safeoutvolt[] = {
|
||||
4850000,
|
||||
4900000,
|
||||
4950000,
|
||||
3300000,
|
||||
};
|
||||
|
||||
static inline void max8997_set_gpio(struct max8997_data *max8997)
|
||||
{
|
||||
int set3 = (max8997->buck125_gpioindex) & 0x1;
|
||||
|
@ -130,29 +137,6 @@ static const struct voltage_map_desc *reg_voltage_map[] = {
|
|||
[MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc,
|
||||
};
|
||||
|
||||
static int max8997_list_voltage_safeout(struct regulator_dev *rdev,
|
||||
unsigned int selector)
|
||||
{
|
||||
int rid = rdev_get_id(rdev);
|
||||
|
||||
if (rid == MAX8997_ESAFEOUT1 || rid == MAX8997_ESAFEOUT2) {
|
||||
switch (selector) {
|
||||
case 0:
|
||||
return 4850000;
|
||||
case 1:
|
||||
return 4900000;
|
||||
case 2:
|
||||
return 4950000;
|
||||
case 3:
|
||||
return 3300000;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev,
|
||||
unsigned int selector)
|
||||
{
|
||||
|
@ -522,7 +506,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev,
|
||||
static int max8997_set_voltage_buck_time_sel(struct regulator_dev *rdev,
|
||||
unsigned int old_selector,
|
||||
unsigned int new_selector)
|
||||
{
|
||||
|
@ -720,49 +704,23 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const int safeoutvolt[] = {
|
||||
3300000,
|
||||
4850000,
|
||||
4900000,
|
||||
4950000,
|
||||
};
|
||||
|
||||
/* For SAFEOUT1 and SAFEOUT2 */
|
||||
static int max8997_set_voltage_safeout(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV, unsigned *selector)
|
||||
static int max8997_set_voltage_safeout_sel(struct regulator_dev *rdev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct max8997_data *max8997 = rdev_get_drvdata(rdev);
|
||||
struct i2c_client *i2c = max8997->iodev->i2c;
|
||||
int rid = rdev_get_id(rdev);
|
||||
int reg, shift = 0, mask, ret;
|
||||
int i = 0;
|
||||
u8 val;
|
||||
|
||||
if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(safeoutvolt); i++) {
|
||||
if (min_uV <= safeoutvolt[i] &&
|
||||
max_uV >= safeoutvolt[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= ARRAY_SIZE(safeoutvolt))
|
||||
return -EINVAL;
|
||||
|
||||
if (i == 0)
|
||||
val = 0x3;
|
||||
else
|
||||
val = i - 1;
|
||||
|
||||
ret = max8997_get_voltage_register(rdev, ®, &shift, &mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = max8997_update_reg(i2c, reg, val << shift, mask << shift);
|
||||
*selector = val;
|
||||
|
||||
return ret;
|
||||
return max8997_update_reg(i2c, reg, selector << shift, mask << shift);
|
||||
}
|
||||
|
||||
static int max8997_reg_disable_suspend(struct regulator_dev *rdev)
|
||||
|
@ -799,7 +757,6 @@ static struct regulator_ops max8997_ldo_ops = {
|
|||
.disable = max8997_reg_disable,
|
||||
.get_voltage_sel = max8997_get_voltage_sel,
|
||||
.set_voltage = max8997_set_voltage_ldobuck,
|
||||
.set_voltage_time_sel = max8997_set_voltage_ldobuck_time_sel,
|
||||
.set_suspend_disable = max8997_reg_disable_suspend,
|
||||
};
|
||||
|
||||
|
@ -810,7 +767,7 @@ static struct regulator_ops max8997_buck_ops = {
|
|||
.disable = max8997_reg_disable,
|
||||
.get_voltage_sel = max8997_get_voltage_sel,
|
||||
.set_voltage = max8997_set_voltage_buck,
|
||||
.set_voltage_time_sel = max8997_set_voltage_ldobuck_time_sel,
|
||||
.set_voltage_time_sel = max8997_set_voltage_buck_time_sel,
|
||||
.set_suspend_disable = max8997_reg_disable_suspend,
|
||||
};
|
||||
|
||||
|
@ -823,12 +780,12 @@ static struct regulator_ops max8997_fixedvolt_ops = {
|
|||
};
|
||||
|
||||
static struct regulator_ops max8997_safeout_ops = {
|
||||
.list_voltage = max8997_list_voltage_safeout,
|
||||
.list_voltage = regulator_list_voltage_table,
|
||||
.is_enabled = max8997_reg_is_enabled,
|
||||
.enable = max8997_reg_enable,
|
||||
.disable = max8997_reg_disable,
|
||||
.get_voltage_sel = max8997_get_voltage_sel,
|
||||
.set_voltage = max8997_set_voltage_safeout,
|
||||
.set_voltage_sel = max8997_set_voltage_safeout_sel,
|
||||
.set_suspend_disable = max8997_reg_disable_suspend,
|
||||
};
|
||||
|
||||
|
@ -960,7 +917,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
|
|||
struct max8997_regulator_data *rdata;
|
||||
unsigned int i, dvs_voltage_nr = 1, ret;
|
||||
|
||||
pmic_np = iodev->dev->of_node;
|
||||
pmic_np = of_node_get(iodev->dev->of_node);
|
||||
if (!pmic_np) {
|
||||
dev_err(&pdev->dev, "could not find pmic sub-node\n");
|
||||
return -ENODEV;
|
||||
|
@ -973,13 +930,12 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
|
|||
}
|
||||
|
||||
/* count the number of regulators to be supported in pmic */
|
||||
pdata->num_regulators = 0;
|
||||
for_each_child_of_node(regulators_np, reg_np)
|
||||
pdata->num_regulators++;
|
||||
pdata->num_regulators = of_get_child_count(regulators_np);
|
||||
|
||||
rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
|
||||
pdata->num_regulators, GFP_KERNEL);
|
||||
if (!rdata) {
|
||||
of_node_put(regulators_np);
|
||||
dev_err(&pdev->dev, "could not allocate memory for regulator data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -1002,6 +958,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
|
|||
rdata->reg_node = reg_np;
|
||||
rdata++;
|
||||
}
|
||||
of_node_put(regulators_np);
|
||||
|
||||
if (of_get_property(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs", NULL))
|
||||
pdata->buck1_gpiodvs = true;
|
||||
|
@ -1233,13 +1190,15 @@ static int max8997_pmic_probe(struct platform_device *pdev)
|
|||
int id = pdata->regulators[i].id;
|
||||
|
||||
desc = reg_voltage_map[id];
|
||||
if (desc)
|
||||
if (desc) {
|
||||
regulators[id].n_voltages =
|
||||
(desc->max - desc->min) / desc->step + 1;
|
||||
else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2)
|
||||
regulators[id].n_voltages = 4;
|
||||
else if (id == MAX8997_CHARGER_CV)
|
||||
} else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) {
|
||||
regulators[id].volt_table = safeoutvolt;
|
||||
regulators[id].n_voltages = ARRAY_SIZE(safeoutvolt);
|
||||
} else if (id == MAX8997_CHARGER_CV) {
|
||||
regulators[id].n_voltages = 16;
|
||||
}
|
||||
|
||||
config.dev = max8997->dev;
|
||||
config.init_data = pdata->regulators[i].initdata;
|
||||
|
|
|
@ -311,25 +311,13 @@ static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev,
|
|||
dev_get_platdata(max8998->iodev->dev);
|
||||
struct i2c_client *i2c = max8998->iodev->i2c;
|
||||
int buck = rdev_get_id(rdev);
|
||||
int reg, shift = 0, mask, ret;
|
||||
int j, previous_sel;
|
||||
int reg, shift = 0, mask, ret, j;
|
||||
static u8 buck1_last_val;
|
||||
|
||||
ret = max8998_get_voltage_register(rdev, ®, &shift, &mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
previous_sel = max8998_get_voltage_sel(rdev);
|
||||
|
||||
/* Check if voltage needs to be changed */
|
||||
/* if previous_voltage equal new voltage, return */
|
||||
if (previous_sel == selector) {
|
||||
dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n",
|
||||
regulator_list_voltage_linear(rdev, previous_sel),
|
||||
regulator_list_voltage_linear(rdev, selector));
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (buck) {
|
||||
case MAX8998_BUCK1:
|
||||
dev_dbg(max8998->dev,
|
||||
|
|
|
@ -164,6 +164,14 @@ static const unsigned int mc13892_sw1[] = {
|
|||
1350000, 1375000
|
||||
};
|
||||
|
||||
/*
|
||||
* Note: this table is used to derive SWxVSEL by index into
|
||||
* the array. Offset the values by the index of 1100000uV
|
||||
* to get the actual register value for that voltage selector
|
||||
* if the HI bit is to be set as well.
|
||||
*/
|
||||
#define MC13892_SWxHI_SEL_OFFSET 20
|
||||
|
||||
static const unsigned int mc13892_sw[] = {
|
||||
600000, 625000, 650000, 675000, 700000, 725000,
|
||||
750000, 775000, 800000, 825000, 850000, 875000,
|
||||
|
@ -239,7 +247,6 @@ static const unsigned int mc13892_pwgtdrv[] = {
|
|||
};
|
||||
|
||||
static struct regulator_ops mc13892_gpo_regulator_ops;
|
||||
/* sw regulators need special care due to the "hi bit" */
|
||||
static struct regulator_ops mc13892_sw_regulator_ops;
|
||||
|
||||
|
||||
|
@ -396,7 +403,7 @@ static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev)
|
|||
{
|
||||
struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
|
||||
int ret, id = rdev_get_id(rdev);
|
||||
unsigned int val;
|
||||
unsigned int val, selector;
|
||||
|
||||
dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
|
||||
|
||||
|
@ -407,12 +414,28 @@ static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = (val & mc13892_regulators[id].vsel_mask)
|
||||
>> mc13892_regulators[id].vsel_shift;
|
||||
/*
|
||||
* Figure out if the HI bit is set inside the switcher mode register
|
||||
* since this means the selector value we return is at a different
|
||||
* offset into the selector table.
|
||||
*
|
||||
* According to the MC13892 documentation note 59 (Table 47) the SW1
|
||||
* buck switcher does not support output range programming therefore
|
||||
* the HI bit must always remain 0. So do not do anything strange if
|
||||
* our register is MC13892_SWITCHERS0.
|
||||
*/
|
||||
|
||||
dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
|
||||
selector = val & mc13892_regulators[id].vsel_mask;
|
||||
|
||||
return val;
|
||||
if ((mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) &&
|
||||
(val & MC13892_SWITCHERS0_SWxHI)) {
|
||||
selector += MC13892_SWxHI_SEL_OFFSET;
|
||||
}
|
||||
|
||||
dev_dbg(rdev_get_dev(rdev), "%s id: %d val: 0x%08x selector: %d\n",
|
||||
__func__, id, val, selector);
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
|
||||
|
@ -425,18 +448,35 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
|
|||
|
||||
volt = rdev->desc->volt_table[selector];
|
||||
mask = mc13892_regulators[id].vsel_mask;
|
||||
reg_value = selector << mc13892_regulators[id].vsel_shift;
|
||||
reg_value = selector;
|
||||
|
||||
/*
|
||||
* Don't mess with the HI bit or support HI voltage offsets for SW1.
|
||||
*
|
||||
* Since the get_voltage_sel callback has given a fudged value for
|
||||
* the selector offset, we need to back out that offset if HI is
|
||||
* to be set so we write the correct value to the register.
|
||||
*
|
||||
* The HI bit addition and selector offset handling COULD be more
|
||||
* complicated by shifting and masking off the voltage selector part
|
||||
* of the register then logical OR it back in, but since the selector
|
||||
* is at bits 4:0 there is very little point. This makes the whole
|
||||
* thing more readable and we do far less work.
|
||||
*/
|
||||
|
||||
if (mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) {
|
||||
if (volt > 1375000) {
|
||||
mask |= MC13892_SWITCHERS0_SWxHI;
|
||||
reg_value -= MC13892_SWxHI_SEL_OFFSET;
|
||||
reg_value |= MC13892_SWITCHERS0_SWxHI;
|
||||
} else if (volt < 1100000) {
|
||||
mask |= MC13892_SWITCHERS0_SWxHI;
|
||||
} else if (volt < 1100000) {
|
||||
reg_value &= ~MC13892_SWITCHERS0_SWxHI;
|
||||
mask |= MC13892_SWITCHERS0_SWxHI;
|
||||
}
|
||||
}
|
||||
|
||||
mc13xxx_lock(priv->mc13xxx);
|
||||
ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, mask,
|
||||
ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg, mask,
|
||||
reg_value);
|
||||
mc13xxx_unlock(priv->mc13xxx);
|
||||
|
||||
|
@ -495,15 +535,18 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
|
|||
struct mc13xxx_regulator_init_data *mc13xxx_data;
|
||||
struct regulator_config config = { };
|
||||
int i, ret;
|
||||
int num_regulators = 0;
|
||||
int num_regulators = 0, num_parsed;
|
||||
u32 val;
|
||||
|
||||
num_regulators = mc13xxx_get_num_regulators_dt(pdev);
|
||||
|
||||
if (num_regulators <= 0 && pdata)
|
||||
num_regulators = pdata->num_regulators;
|
||||
if (num_regulators <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
num_parsed = num_regulators;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv) +
|
||||
num_regulators * sizeof(priv->regulators[0]),
|
||||
GFP_KERNEL);
|
||||
|
@ -520,7 +563,7 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
/* enable switch auto mode */
|
||||
/* enable switch auto mode (on 2.0A silicon only) */
|
||||
if ((val & 0x0000FFFF) == 0x45d0) {
|
||||
ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
|
||||
MC13892_SWITCHERS4_SW1MODE_M |
|
||||
|
@ -546,7 +589,39 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
|
|||
= mc13892_vcam_get_mode;
|
||||
|
||||
mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators,
|
||||
ARRAY_SIZE(mc13892_regulators));
|
||||
ARRAY_SIZE(mc13892_regulators),
|
||||
&num_parsed);
|
||||
|
||||
/*
|
||||
* Perform a little sanity check on the regulator tree - if we found
|
||||
* a number of regulators from mc13xxx_get_num_regulators_dt and
|
||||
* then parsed a smaller number in mc13xxx_parse_regulators_dt then
|
||||
* there is a regulator defined in the regulators node which has
|
||||
* not matched any usable regulator in the driver. In this case,
|
||||
* there is one missing and what will happen is the first regulator
|
||||
* will get registered again.
|
||||
*
|
||||
* Fix this by basically making our number of registerable regulators
|
||||
* equal to the number of regulators we parsed. We are allocating
|
||||
* too much memory for priv, but this is unavoidable at this point.
|
||||
*
|
||||
* As an example of how this can happen, try making a typo in your
|
||||
* regulators node (vviohi {} instead of viohi {}) so that the name
|
||||
* does not match..
|
||||
*
|
||||
* The check will basically pass for platform data (non-DT) because
|
||||
* mc13xxx_parse_regulators_dt for !CONFIG_OF will not touch num_parsed.
|
||||
*
|
||||
*/
|
||||
if (num_parsed != num_regulators) {
|
||||
dev_warn(&pdev->dev,
|
||||
"parsed %d != regulators %d - check your device tree!\n",
|
||||
num_parsed, num_regulators);
|
||||
|
||||
num_regulators = num_parsed;
|
||||
priv->num_regulators = num_regulators;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_regulators; i++) {
|
||||
struct regulator_init_data *init_data;
|
||||
struct regulator_desc *desc;
|
||||
|
|
|
@ -164,29 +164,30 @@ EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops);
|
|||
#ifdef CONFIG_OF
|
||||
int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *parent, *child;
|
||||
int num = 0;
|
||||
struct device_node *parent;
|
||||
int num;
|
||||
|
||||
of_node_get(pdev->dev.parent->of_node);
|
||||
parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
|
||||
if (!parent)
|
||||
return -ENODEV;
|
||||
|
||||
for_each_child_of_node(parent, child)
|
||||
num++;
|
||||
|
||||
num = of_get_child_count(parent);
|
||||
of_node_put(parent);
|
||||
return num;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt);
|
||||
|
||||
struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
|
||||
struct platform_device *pdev, struct mc13xxx_regulator *regulators,
|
||||
int num_regulators)
|
||||
int num_regulators, int *num_parsed)
|
||||
{
|
||||
struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
|
||||
struct mc13xxx_regulator_init_data *data, *p;
|
||||
struct device_node *parent, *child;
|
||||
int i;
|
||||
int i, parsed = 0;
|
||||
|
||||
*num_parsed = 0;
|
||||
|
||||
of_node_get(pdev->dev.parent->of_node);
|
||||
parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
|
||||
|
@ -195,24 +196,32 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
|
|||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data) * priv->num_regulators,
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
if (!data) {
|
||||
of_node_put(parent);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = data;
|
||||
|
||||
for_each_child_of_node(parent, child) {
|
||||
for (i = 0; i < num_regulators; i++) {
|
||||
if (!of_node_cmp(child->name,
|
||||
regulators[i].desc.name)) {
|
||||
|
||||
p->id = i;
|
||||
p->init_data = of_get_regulator_init_data(
|
||||
&pdev->dev, child);
|
||||
p->node = child;
|
||||
p++;
|
||||
|
||||
parsed++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
of_node_put(parent);
|
||||
|
||||
*num_parsed = parsed;
|
||||
return data;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt);
|
||||
|
|
|
@ -39,7 +39,7 @@ extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
|
|||
extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev);
|
||||
extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
|
||||
struct platform_device *pdev, struct mc13xxx_regulator *regulators,
|
||||
int num_regulators);
|
||||
int num_regulators, int *num_parsed);
|
||||
#else
|
||||
static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
|
|||
|
||||
static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
|
||||
struct platform_device *pdev, struct mc13xxx_regulator *regulators,
|
||||
int num_regulators)
|
||||
int num_regulators, int *num_parsed)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -527,6 +527,7 @@ static void palmas_dt_to_pdata(struct device *dev,
|
|||
u32 prop;
|
||||
int idx, ret;
|
||||
|
||||
node = of_node_get(node);
|
||||
regulators = of_find_node_by_name(node, "regulators");
|
||||
if (!regulators) {
|
||||
dev_info(dev, "regulator node not found\n");
|
||||
|
@ -535,6 +536,7 @@ static void palmas_dt_to_pdata(struct device *dev,
|
|||
|
||||
ret = of_regulator_match(dev, regulators, palmas_matches,
|
||||
PALMAS_NUM_REGS);
|
||||
of_node_put(regulators);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error parsing regulator init data: %d\n", ret);
|
||||
return;
|
||||
|
@ -565,11 +567,6 @@ static void palmas_dt_to_pdata(struct device *dev,
|
|||
if (!ret)
|
||||
pdata->reg_init[idx]->mode_sleep = prop;
|
||||
|
||||
ret = of_property_read_u32(palmas_matches[idx].of_node,
|
||||
"ti,warm_reset", &prop);
|
||||
if (!ret)
|
||||
pdata->reg_init[idx]->warm_reset = prop;
|
||||
|
||||
ret = of_property_read_u32(palmas_matches[idx].of_node,
|
||||
"ti,tstep", &prop);
|
||||
if (!ret)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/bug.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -21,6 +22,9 @@
|
|||
#include <linux/regulator/machine.h>
|
||||
#include <linux/mfd/samsung/core.h>
|
||||
#include <linux/mfd/samsung/s5m8767.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
|
||||
#define S5M8767_OPMODE_NORMAL_MODE 0x1
|
||||
|
||||
struct s5m8767_info {
|
||||
struct device *dev;
|
||||
|
@ -255,10 +259,8 @@ static int s5m8767_reg_disable(struct regulator_dev *rdev)
|
|||
return sec_reg_update(s5m8767->iodev, reg, ~mask, mask);
|
||||
}
|
||||
|
||||
static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
|
||||
static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767)
|
||||
{
|
||||
struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
|
||||
int reg_id = rdev_get_id(rdev);
|
||||
int reg;
|
||||
|
||||
switch (reg_id) {
|
||||
|
@ -296,43 +298,18 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
*_reg = reg;
|
||||
|
||||
return 0;
|
||||
return reg;
|
||||
}
|
||||
|
||||
static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
|
||||
{
|
||||
struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
|
||||
int reg, mask, ret;
|
||||
int reg_id = rdev_get_id(rdev);
|
||||
unsigned int val;
|
||||
|
||||
ret = s5m8767_get_voltage_register(rdev, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff;
|
||||
|
||||
ret = sec_reg_read(s5m8767->iodev, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val &= mask;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int s5m8767_convert_voltage_to_sel(
|
||||
const struct sec_voltage_desc *desc,
|
||||
int min_vol, int max_vol)
|
||||
static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc,
|
||||
int min_vol)
|
||||
{
|
||||
int selector = 0;
|
||||
|
||||
if (desc == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (max_vol < desc->min || min_vol > desc->max)
|
||||
if (min_vol > desc->max)
|
||||
return -EINVAL;
|
||||
|
||||
if (min_vol < desc->min)
|
||||
|
@ -340,7 +317,7 @@ static int s5m8767_convert_voltage_to_sel(
|
|||
|
||||
selector = DIV_ROUND_UP(min_vol - desc->min, desc->step);
|
||||
|
||||
if (desc->min + desc->step * selector > max_vol)
|
||||
if (desc->min + desc->step * selector > desc->max)
|
||||
return -EINVAL;
|
||||
|
||||
return selector;
|
||||
|
@ -373,15 +350,13 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
|
|||
{
|
||||
struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
|
||||
int reg_id = rdev_get_id(rdev);
|
||||
int reg, mask, ret = 0, old_index, index = 0;
|
||||
int old_index, index = 0;
|
||||
u8 *buck234_vol = NULL;
|
||||
|
||||
switch (reg_id) {
|
||||
case S5M8767_LDO1 ... S5M8767_LDO28:
|
||||
mask = 0x3f;
|
||||
break;
|
||||
case S5M8767_BUCK1 ... S5M8767_BUCK6:
|
||||
mask = 0xff;
|
||||
if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs)
|
||||
buck234_vol = &s5m8767->buck2_vol[0];
|
||||
else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs)
|
||||
|
@ -392,7 +367,6 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
|
|||
case S5M8767_BUCK7 ... S5M8767_BUCK8:
|
||||
return -EINVAL;
|
||||
case S5M8767_BUCK9:
|
||||
mask = 0xff;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -412,11 +386,7 @@ static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
|
|||
else
|
||||
return s5m8767_set_low(s5m8767);
|
||||
} else {
|
||||
ret = s5m8767_get_voltage_register(rdev, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sec_reg_update(s5m8767->iodev, reg, selector, mask);
|
||||
return regulator_set_voltage_sel_regmap(rdev, selector);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,7 +411,7 @@ static struct regulator_ops s5m8767_ops = {
|
|||
.is_enabled = s5m8767_reg_is_enabled,
|
||||
.enable = s5m8767_reg_enable,
|
||||
.disable = s5m8767_reg_disable,
|
||||
.get_voltage_sel = s5m8767_get_voltage_sel,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = s5m8767_set_voltage_sel,
|
||||
.set_voltage_time_sel = s5m8767_set_voltage_time_sel,
|
||||
};
|
||||
|
@ -508,10 +478,182 @@ static struct regulator_desc regulators[] = {
|
|||
s5m8767_regulator_desc(BUCK9),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,
|
||||
struct sec_platform_data *pdata,
|
||||
struct device_node *pmic_np)
|
||||
{
|
||||
int i, gpio;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
gpio = of_get_named_gpio(pmic_np,
|
||||
"s5m8767,pmic-buck-dvs-gpios", i);
|
||||
if (!gpio_is_valid(gpio)) {
|
||||
dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
|
||||
return -EINVAL;
|
||||
}
|
||||
pdata->buck_gpios[i] = gpio;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev,
|
||||
struct sec_platform_data *pdata,
|
||||
struct device_node *pmic_np)
|
||||
{
|
||||
int i, gpio;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
gpio = of_get_named_gpio(pmic_np,
|
||||
"s5m8767,pmic-buck-ds-gpios", i);
|
||||
if (!gpio_is_valid(gpio)) {
|
||||
dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
|
||||
return -EINVAL;
|
||||
}
|
||||
pdata->buck_ds[i] = gpio;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
|
||||
struct sec_platform_data *pdata)
|
||||
{
|
||||
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device_node *pmic_np, *regulators_np, *reg_np;
|
||||
struct sec_regulator_data *rdata;
|
||||
struct sec_opmode_data *rmode;
|
||||
unsigned int i, dvs_voltage_nr = 1, ret;
|
||||
|
||||
pmic_np = iodev->dev->of_node;
|
||||
if (!pmic_np) {
|
||||
dev_err(iodev->dev, "could not find pmic sub-node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
regulators_np = of_find_node_by_name(pmic_np, "regulators");
|
||||
if (!regulators_np) {
|
||||
dev_err(iodev->dev, "could not find regulators sub-node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* count the number of regulators to be supported in pmic */
|
||||
pdata->num_regulators = of_get_child_count(regulators_np);
|
||||
|
||||
rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
|
||||
pdata->num_regulators, GFP_KERNEL);
|
||||
if (!rdata) {
|
||||
dev_err(iodev->dev,
|
||||
"could not allocate memory for regulator data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) *
|
||||
pdata->num_regulators, GFP_KERNEL);
|
||||
if (!rdata) {
|
||||
dev_err(iodev->dev,
|
||||
"could not allocate memory for regulator mode\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pdata->regulators = rdata;
|
||||
pdata->opmode = rmode;
|
||||
for_each_child_of_node(regulators_np, reg_np) {
|
||||
for (i = 0; i < ARRAY_SIZE(regulators); i++)
|
||||
if (!of_node_cmp(reg_np->name, regulators[i].name))
|
||||
break;
|
||||
|
||||
if (i == ARRAY_SIZE(regulators)) {
|
||||
dev_warn(iodev->dev,
|
||||
"don't know how to configure regulator %s\n",
|
||||
reg_np->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
rdata->id = i;
|
||||
rdata->initdata = of_get_regulator_init_data(
|
||||
&pdev->dev, reg_np);
|
||||
rdata->reg_node = reg_np;
|
||||
rdata++;
|
||||
rmode->id = i;
|
||||
if (of_property_read_u32(reg_np, "op_mode",
|
||||
&rmode->mode)) {
|
||||
dev_warn(iodev->dev,
|
||||
"no op_mode property property at %s\n",
|
||||
reg_np->full_name);
|
||||
|
||||
rmode->mode = S5M8767_OPMODE_NORMAL_MODE;
|
||||
}
|
||||
rmode++;
|
||||
}
|
||||
|
||||
if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL))
|
||||
pdata->buck2_gpiodvs = true;
|
||||
|
||||
if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL))
|
||||
pdata->buck3_gpiodvs = true;
|
||||
|
||||
if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL))
|
||||
pdata->buck4_gpiodvs = true;
|
||||
|
||||
if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
|
||||
pdata->buck4_gpiodvs) {
|
||||
ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (of_property_read_u32(pmic_np,
|
||||
"s5m8767,pmic-buck-default-dvs-idx",
|
||||
&pdata->buck_default_idx)) {
|
||||
pdata->buck_default_idx = 0;
|
||||
} else {
|
||||
if (pdata->buck_default_idx >= 8) {
|
||||
pdata->buck_default_idx = 0;
|
||||
dev_info(iodev->dev,
|
||||
"invalid value for default dvs index, use 0\n");
|
||||
}
|
||||
}
|
||||
dvs_voltage_nr = 8;
|
||||
}
|
||||
|
||||
ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (of_property_read_u32_array(pmic_np,
|
||||
"s5m8767,pmic-buck2-dvs-voltage",
|
||||
pdata->buck2_voltage, dvs_voltage_nr)) {
|
||||
dev_err(iodev->dev, "buck2 voltages not specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_array(pmic_np,
|
||||
"s5m8767,pmic-buck3-dvs-voltage",
|
||||
pdata->buck3_voltage, dvs_voltage_nr)) {
|
||||
dev_err(iodev->dev, "buck3 voltages not specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_array(pmic_np,
|
||||
"s5m8767,pmic-buck4-dvs-voltage",
|
||||
pdata->buck4_voltage, dvs_voltage_nr)) {
|
||||
dev_err(iodev->dev, "buck4 voltages not specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
|
||||
struct sec_platform_data *pdata)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int s5m8767_pmic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
|
||||
struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
|
||||
struct sec_platform_data *pdata = iodev->pdata;
|
||||
struct regulator_config config = { };
|
||||
struct regulator_dev **rdev;
|
||||
struct s5m8767_info *s5m8767;
|
||||
|
@ -522,6 +664,12 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (iodev->dev->of_node) {
|
||||
ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata->buck2_gpiodvs) {
|
||||
if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
|
||||
dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
|
||||
|
@ -577,23 +725,17 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
|
|||
s5m8767->opmode = pdata->opmode;
|
||||
|
||||
buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
|
||||
pdata->buck2_init,
|
||||
pdata->buck2_init +
|
||||
buck_voltage_val2.step);
|
||||
pdata->buck2_init);
|
||||
|
||||
sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
|
||||
|
||||
buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
|
||||
pdata->buck3_init,
|
||||
pdata->buck3_init +
|
||||
buck_voltage_val2.step);
|
||||
pdata->buck3_init);
|
||||
|
||||
sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
|
||||
|
||||
buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
|
||||
pdata->buck4_init,
|
||||
pdata->buck4_init +
|
||||
buck_voltage_val2.step);
|
||||
pdata->buck4_init);
|
||||
|
||||
sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
|
||||
|
||||
|
@ -602,27 +744,21 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
|
|||
s5m8767->buck2_vol[i] =
|
||||
s5m8767_convert_voltage_to_sel(
|
||||
&buck_voltage_val2,
|
||||
pdata->buck2_voltage[i],
|
||||
pdata->buck2_voltage[i] +
|
||||
buck_voltage_val2.step);
|
||||
pdata->buck2_voltage[i]);
|
||||
}
|
||||
|
||||
if (s5m8767->buck3_gpiodvs) {
|
||||
s5m8767->buck3_vol[i] =
|
||||
s5m8767_convert_voltage_to_sel(
|
||||
&buck_voltage_val2,
|
||||
pdata->buck3_voltage[i],
|
||||
pdata->buck3_voltage[i] +
|
||||
buck_voltage_val2.step);
|
||||
pdata->buck3_voltage[i]);
|
||||
}
|
||||
|
||||
if (s5m8767->buck4_gpiodvs) {
|
||||
s5m8767->buck4_vol[i] =
|
||||
s5m8767_convert_voltage_to_sel(
|
||||
&buck_voltage_val2,
|
||||
pdata->buck4_voltage[i],
|
||||
pdata->buck4_voltage[i] +
|
||||
buck_voltage_val2.step);
|
||||
pdata->buck4_voltage[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -760,11 +896,19 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
|
|||
(desc->max - desc->min) / desc->step + 1;
|
||||
regulators[id].min_uV = desc->min;
|
||||
regulators[id].uV_step = desc->step;
|
||||
regulators[id].vsel_reg =
|
||||
s5m8767_get_vsel_reg(id, s5m8767);
|
||||
if (id < S5M8767_BUCK1)
|
||||
regulators[id].vsel_mask = 0x3f;
|
||||
else
|
||||
regulators[id].vsel_mask = 0xff;
|
||||
}
|
||||
|
||||
config.dev = s5m8767->dev;
|
||||
config.init_data = pdata->regulators[i].initdata;
|
||||
config.driver_data = s5m8767;
|
||||
config.regmap = iodev->regmap;
|
||||
config.of_node = pdata->regulators[i].reg_node;
|
||||
|
||||
rdev[i] = regulator_register(®ulators[id], &config);
|
||||
if (IS_ERR(rdev[i])) {
|
||||
|
|
|
@ -28,10 +28,13 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/regulator/tps51632-regulator.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -85,49 +88,8 @@ struct tps51632_chip {
|
|||
struct regulator_desc desc;
|
||||
struct regulator_dev *rdev;
|
||||
struct regmap *regmap;
|
||||
bool enable_pwm_dvfs;
|
||||
};
|
||||
|
||||
static int tps51632_dcdc_get_voltage_sel(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps51632_chip *tps = rdev_get_drvdata(rdev);
|
||||
unsigned int data;
|
||||
int ret;
|
||||
unsigned int reg = TPS51632_VOLTAGE_SELECT_REG;
|
||||
int vsel;
|
||||
|
||||
if (tps->enable_pwm_dvfs)
|
||||
reg = TPS51632_VOLTAGE_BASE_REG;
|
||||
|
||||
ret = regmap_read(tps->regmap, reg, &data);
|
||||
if (ret < 0) {
|
||||
dev_err(tps->dev, "reg read failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
vsel = data & TPS51632_VOUT_MASK;
|
||||
return vsel;
|
||||
}
|
||||
|
||||
static int tps51632_dcdc_set_voltage_sel(struct regulator_dev *rdev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct tps51632_chip *tps = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
unsigned int reg = TPS51632_VOLTAGE_SELECT_REG;
|
||||
|
||||
if (tps->enable_pwm_dvfs)
|
||||
reg = TPS51632_VOLTAGE_BASE_REG;
|
||||
|
||||
if (selector > TPS51632_MAX_VSEL)
|
||||
return -EINVAL;
|
||||
|
||||
ret = regmap_write(tps->regmap, reg, selector);
|
||||
if (ret < 0)
|
||||
dev_err(tps->dev, "reg write failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev,
|
||||
int ramp_delay)
|
||||
{
|
||||
|
@ -144,8 +106,8 @@ static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev,
|
|||
}
|
||||
|
||||
static struct regulator_ops tps51632_dcdc_ops = {
|
||||
.get_voltage_sel = tps51632_dcdc_get_voltage_sel,
|
||||
.set_voltage_sel = tps51632_dcdc_set_voltage_sel,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||
.set_ramp_delay = tps51632_dcdc_set_ramp_delay,
|
||||
|
@ -162,7 +124,6 @@ static int tps51632_init_dcdc(struct tps51632_chip *tps,
|
|||
goto skip_pwm_config;
|
||||
|
||||
control |= TPS51632_DVFS_PWMEN;
|
||||
tps->enable_pwm_dvfs = pdata->enable_pwm_dvfs;
|
||||
vsel = TPS51632_VOLT_VSEL(pdata->base_voltage_uV);
|
||||
ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG, vsel);
|
||||
if (ret < 0) {
|
||||
|
@ -205,22 +166,96 @@ skip_pwm_config:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool rd_wr_reg(struct device *dev, unsigned int reg)
|
||||
static bool is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
if ((reg >= 0x8) && (reg <= 0x10))
|
||||
return false;
|
||||
switch (reg) {
|
||||
case TPS51632_OFFSET_REG:
|
||||
case TPS51632_FAULT_REG:
|
||||
case TPS51632_IMON_REG:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_read_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case 0x08 ... 0x0F:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_write_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case TPS51632_VOLTAGE_SELECT_REG:
|
||||
case TPS51632_VOLTAGE_BASE_REG:
|
||||
case TPS51632_VMAX_REG:
|
||||
case TPS51632_DVFS_CONTROL_REG:
|
||||
case TPS51632_POWER_STATE_REG:
|
||||
case TPS51632_SLEW_REGS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config tps51632_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.writeable_reg = rd_wr_reg,
|
||||
.readable_reg = rd_wr_reg,
|
||||
.writeable_reg = is_write_reg,
|
||||
.readable_reg = is_read_reg,
|
||||
.volatile_reg = is_volatile_reg,
|
||||
.max_register = TPS51632_MAX_REG - 1,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id tps51632_of_match[] = {
|
||||
{ .compatible = "ti,tps51632",},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tps51632_of_match);
|
||||
|
||||
static struct tps51632_regulator_platform_data *
|
||||
of_get_tps51632_platform_data(struct device *dev)
|
||||
{
|
||||
struct tps51632_regulator_platform_data *pdata;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
dev_err(dev, "Memory alloc failed for platform data\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
|
||||
if (!pdata->reg_init_data) {
|
||||
dev_err(dev, "Not able to get OF regulator init data\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdata->enable_pwm_dvfs =
|
||||
of_property_read_bool(np, "ti,enable-pwm-dvfs");
|
||||
pdata->dvfs_step_20mV = of_property_read_bool(np, "ti,dvfs-step-20mV");
|
||||
|
||||
pdata->base_voltage_uV = pdata->reg_init_data->constraints.min_uV ? :
|
||||
TPS51632_MIN_VOLATGE;
|
||||
pdata->max_voltage_uV = pdata->reg_init_data->constraints.max_uV ? :
|
||||
TPS51632_MAX_VOLATGE;
|
||||
return pdata;
|
||||
}
|
||||
#else
|
||||
static struct tps51632_regulator_platform_data *
|
||||
of_get_tps51632_platform_data(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tps51632_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -230,7 +265,19 @@ static int tps51632_probe(struct i2c_client *client,
|
|||
int ret;
|
||||
struct regulator_config config = { };
|
||||
|
||||
if (client->dev.of_node) {
|
||||
const struct of_device_id *match;
|
||||
match = of_match_device(of_match_ptr(tps51632_of_match),
|
||||
&client->dev);
|
||||
if (!match) {
|
||||
dev_err(&client->dev, "Error: No device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
if (!pdata && client->dev.of_node)
|
||||
pdata = of_get_tps51632_platform_data(&client->dev);
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "No Platform data\n");
|
||||
return -EINVAL;
|
||||
|
@ -269,6 +316,12 @@ static int tps51632_probe(struct i2c_client *client,
|
|||
tps->desc.type = REGULATOR_VOLTAGE;
|
||||
tps->desc.owner = THIS_MODULE;
|
||||
|
||||
if (pdata->enable_pwm_dvfs)
|
||||
tps->desc.vsel_reg = TPS51632_VOLTAGE_BASE_REG;
|
||||
else
|
||||
tps->desc.vsel_reg = TPS51632_VOLTAGE_SELECT_REG;
|
||||
tps->desc.vsel_mask = TPS51632_VOUT_MASK;
|
||||
|
||||
tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config);
|
||||
if (IS_ERR(tps->regmap)) {
|
||||
ret = PTR_ERR(tps->regmap);
|
||||
|
@ -319,6 +372,7 @@ static struct i2c_driver tps51632_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "tps51632",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(tps51632_of_match),
|
||||
},
|
||||
.probe = tps51632_probe,
|
||||
.remove = tps51632_remove,
|
||||
|
|
|
@ -23,8 +23,10 @@
|
|||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/tps6507x.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mfd/tps6507x.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
|
||||
/* DCDC's */
|
||||
#define TPS6507X_DCDC_1 0
|
||||
|
@ -356,6 +358,80 @@ static struct regulator_ops tps6507x_pmic_ops = {
|
|||
.list_voltage = regulator_list_voltage_table,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_regulator_match tps6507x_matches[] = {
|
||||
{ .name = "VDCDC1"},
|
||||
{ .name = "VDCDC2"},
|
||||
{ .name = "VDCDC3"},
|
||||
{ .name = "LDO1"},
|
||||
{ .name = "LDO2"},
|
||||
};
|
||||
|
||||
static struct tps6507x_board *tps6507x_parse_dt_reg_data(
|
||||
struct platform_device *pdev,
|
||||
struct of_regulator_match **tps6507x_reg_matches)
|
||||
{
|
||||
struct tps6507x_board *tps_board;
|
||||
struct device_node *np = pdev->dev.parent->of_node;
|
||||
struct device_node *regulators;
|
||||
struct of_regulator_match *matches;
|
||||
static struct regulator_init_data *reg_data;
|
||||
int idx = 0, count, ret;
|
||||
|
||||
tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board),
|
||||
GFP_KERNEL);
|
||||
if (!tps_board) {
|
||||
dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
regulators = of_find_node_by_name(np, "regulators");
|
||||
if (!regulators) {
|
||||
dev_err(&pdev->dev, "regulator node not found\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = ARRAY_SIZE(tps6507x_matches);
|
||||
matches = tps6507x_matches;
|
||||
|
||||
ret = of_regulator_match(&pdev->dev, regulators, matches, count);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
|
||||
ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*tps6507x_reg_matches = matches;
|
||||
|
||||
reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data)
|
||||
* TPS6507X_NUM_REGULATOR), GFP_KERNEL);
|
||||
if (!reg_data) {
|
||||
dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tps_board->tps6507x_pmic_init_data = reg_data;
|
||||
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
if (!matches[idx].init_data || !matches[idx].of_node)
|
||||
continue;
|
||||
|
||||
memcpy(®_data[idx], matches[idx].init_data,
|
||||
sizeof(struct regulator_init_data));
|
||||
|
||||
}
|
||||
|
||||
return tps_board;
|
||||
}
|
||||
#else
|
||||
static inline struct tps6507x_board *tps6507x_parse_dt_reg_data(
|
||||
struct platform_device *pdev,
|
||||
struct of_regulator_match **tps6507x_reg_matches)
|
||||
{
|
||||
*tps6507x_reg_matches = NULL;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
static int tps6507x_pmic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
|
||||
|
@ -365,8 +441,10 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
|
|||
struct regulator_dev *rdev;
|
||||
struct tps6507x_pmic *tps;
|
||||
struct tps6507x_board *tps_board;
|
||||
struct of_regulator_match *tps6507x_reg_matches = NULL;
|
||||
int i;
|
||||
int error;
|
||||
unsigned int prop;
|
||||
|
||||
/**
|
||||
* tps_board points to pmic related constants
|
||||
|
@ -374,6 +452,9 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
|
|||
*/
|
||||
|
||||
tps_board = dev_get_platdata(tps6507x_dev->dev);
|
||||
if (!tps_board && tps6507x_dev->dev->of_node)
|
||||
tps_board = tps6507x_parse_dt_reg_data(pdev,
|
||||
&tps6507x_reg_matches);
|
||||
if (!tps_board)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -415,6 +496,17 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)
|
|||
config.init_data = init_data;
|
||||
config.driver_data = tps;
|
||||
|
||||
if (tps6507x_reg_matches) {
|
||||
error = of_property_read_u32(
|
||||
tps6507x_reg_matches[i].of_node,
|
||||
"ti,defdcdc_default", &prop);
|
||||
|
||||
if (!error)
|
||||
tps->info[i]->defdcdc_default = prop;
|
||||
|
||||
config.of_node = tps6507x_reg_matches[i].of_node;
|
||||
}
|
||||
|
||||
rdev = regulator_register(&tps->desc[i], &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(tps6507x_dev->dev,
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/mfd/tps65090.h>
|
||||
|
||||
struct tps65090_regulator {
|
||||
|
@ -67,8 +69,8 @@ static struct regulator_desc tps65090_regulator_desc[] = {
|
|||
tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_reg_contol_ops),
|
||||
tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_reg_contol_ops),
|
||||
tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_reg_contol_ops),
|
||||
tps65090_REG_DESC(LDO1, "vsys_l1", 0, tps65090_ldo_ops),
|
||||
tps65090_REG_DESC(LDO2, "vsys_l2", 0, tps65090_ldo_ops),
|
||||
tps65090_REG_DESC(LDO1, "vsys-l1", 0, tps65090_ldo_ops),
|
||||
tps65090_REG_DESC(LDO2, "vsys-l2", 0, tps65090_ldo_ops),
|
||||
};
|
||||
|
||||
static inline bool is_dcdc(int id)
|
||||
|
@ -138,6 +140,92 @@ static void tps65090_configure_regulator_config(
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_regulator_match tps65090_matches[] = {
|
||||
{ .name = "dcdc1", },
|
||||
{ .name = "dcdc2", },
|
||||
{ .name = "dcdc3", },
|
||||
{ .name = "fet1", },
|
||||
{ .name = "fet2", },
|
||||
{ .name = "fet3", },
|
||||
{ .name = "fet4", },
|
||||
{ .name = "fet5", },
|
||||
{ .name = "fet6", },
|
||||
{ .name = "fet7", },
|
||||
{ .name = "ldo1", },
|
||||
{ .name = "ldo2", },
|
||||
};
|
||||
|
||||
static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
|
||||
struct platform_device *pdev,
|
||||
struct of_regulator_match **tps65090_reg_matches)
|
||||
{
|
||||
struct tps65090_platform_data *tps65090_pdata;
|
||||
struct device_node *np = pdev->dev.parent->of_node;
|
||||
struct device_node *regulators;
|
||||
int idx = 0, ret;
|
||||
struct tps65090_regulator_plat_data *reg_pdata;
|
||||
|
||||
tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata),
|
||||
GFP_KERNEL);
|
||||
if (!tps65090_pdata) {
|
||||
dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX *
|
||||
sizeof(*reg_pdata), GFP_KERNEL);
|
||||
if (!reg_pdata) {
|
||||
dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
regulators = of_find_node_by_name(np, "regulators");
|
||||
if (!regulators) {
|
||||
dev_err(&pdev->dev, "regulator node not found\n");
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches,
|
||||
ARRAY_SIZE(tps65090_matches));
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Error parsing regulator init data: %d\n", ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
*tps65090_reg_matches = tps65090_matches;
|
||||
for (idx = 0; idx < ARRAY_SIZE(tps65090_matches); idx++) {
|
||||
struct regulator_init_data *ri_data;
|
||||
struct tps65090_regulator_plat_data *rpdata;
|
||||
|
||||
rpdata = ®_pdata[idx];
|
||||
ri_data = tps65090_matches[idx].init_data;
|
||||
if (!ri_data || !tps65090_matches[idx].of_node)
|
||||
continue;
|
||||
|
||||
rpdata->reg_init_data = ri_data;
|
||||
rpdata->enable_ext_control = of_property_read_bool(
|
||||
tps65090_matches[idx].of_node,
|
||||
"ti,enable-ext-control");
|
||||
if (rpdata->enable_ext_control)
|
||||
rpdata->gpio = of_get_named_gpio(np,
|
||||
"dcdc-ext-control-gpios", 0);
|
||||
|
||||
tps65090_pdata->reg_pdata[idx] = rpdata;
|
||||
}
|
||||
return tps65090_pdata;
|
||||
}
|
||||
#else
|
||||
static inline struct tps65090_platform_data *tps65090_parse_dt_reg_data(
|
||||
struct platform_device *pdev,
|
||||
struct of_regulator_match **tps65090_reg_matches)
|
||||
{
|
||||
*tps65090_reg_matches = NULL;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tps65090_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent);
|
||||
|
@ -147,15 +235,19 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
|
|||
struct tps65090_regulator_plat_data *tps_pdata;
|
||||
struct tps65090_regulator *pmic;
|
||||
struct tps65090_platform_data *tps65090_pdata;
|
||||
struct of_regulator_match *tps65090_reg_matches = NULL;
|
||||
int num;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&pdev->dev, "Probing regulator\n");
|
||||
|
||||
tps65090_pdata = dev_get_platdata(pdev->dev.parent);
|
||||
if (!tps65090_pdata) {
|
||||
if (!tps65090_pdata && tps65090_mfd->dev->of_node)
|
||||
tps65090_pdata = tps65090_parse_dt_reg_data(pdev,
|
||||
&tps65090_reg_matches);
|
||||
if (IS_ERR_OR_NULL(tps65090_pdata)) {
|
||||
dev_err(&pdev->dev, "Platform data missing\n");
|
||||
return -EINVAL;
|
||||
return tps65090_pdata ? PTR_ERR(tps65090_pdata) : -EINVAL;
|
||||
}
|
||||
|
||||
pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
|
||||
|
@ -192,13 +284,17 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.dev = pdev->dev.parent;
|
||||
config.driver_data = ri;
|
||||
config.regmap = tps65090_mfd->rmap;
|
||||
if (tps_pdata)
|
||||
config.init_data = tps_pdata->reg_init_data;
|
||||
else
|
||||
config.init_data = NULL;
|
||||
if (tps65090_reg_matches)
|
||||
config.of_node = tps65090_reg_matches[num].of_node;
|
||||
else
|
||||
config.of_node = NULL;
|
||||
|
||||
rdev = regulator_register(ri->desc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
|
|
|
@ -61,10 +61,6 @@ struct tps6586x_regulator {
|
|||
|
||||
int enable_bit[2];
|
||||
int enable_reg[2];
|
||||
|
||||
/* for DVM regulators */
|
||||
int go_reg;
|
||||
int go_bit;
|
||||
};
|
||||
|
||||
static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
|
||||
|
@ -72,37 +68,10 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
|
|||
return rdev_get_dev(rdev)->parent;
|
||||
}
|
||||
|
||||
static int tps6586x_set_voltage_sel(struct regulator_dev *rdev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
|
||||
struct device *parent = to_tps6586x_dev(rdev);
|
||||
int ret, val, rid = rdev_get_id(rdev);
|
||||
uint8_t mask;
|
||||
|
||||
val = selector << (ffs(rdev->desc->vsel_mask) - 1);
|
||||
mask = rdev->desc->vsel_mask;
|
||||
|
||||
ret = tps6586x_update(parent, rdev->desc->vsel_reg, val, mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Update go bit for DVM regulators */
|
||||
switch (rid) {
|
||||
case TPS6586X_ID_LDO_2:
|
||||
case TPS6586X_ID_LDO_4:
|
||||
case TPS6586X_ID_SM_0:
|
||||
case TPS6586X_ID_SM_1:
|
||||
ret = tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct regulator_ops tps6586x_regulator_ops = {
|
||||
.list_voltage = regulator_list_voltage_table,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = tps6586x_set_voltage_sel,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
|
@ -142,7 +111,7 @@ static const unsigned int tps6586x_dvm_voltages[] = {
|
|||
};
|
||||
|
||||
#define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits, \
|
||||
ereg0, ebit0, ereg1, ebit1) \
|
||||
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
|
||||
.desc = { \
|
||||
.supply_name = _pin_name, \
|
||||
.name = "REG-" #_id, \
|
||||
|
@ -156,29 +125,26 @@ static const unsigned int tps6586x_dvm_voltages[] = {
|
|||
.enable_mask = 1 << (ebit0), \
|
||||
.vsel_reg = TPS6586X_##vreg, \
|
||||
.vsel_mask = ((1 << (nbits)) - 1) << (shift), \
|
||||
.apply_reg = (goreg), \
|
||||
.apply_bit = (gobit), \
|
||||
}, \
|
||||
.enable_reg[0] = TPS6586X_SUPPLY##ereg0, \
|
||||
.enable_bit[0] = (ebit0), \
|
||||
.enable_reg[1] = TPS6586X_SUPPLY##ereg1, \
|
||||
.enable_bit[1] = (ebit1),
|
||||
|
||||
#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
|
||||
.go_reg = TPS6586X_##goreg, \
|
||||
.go_bit = (gobit),
|
||||
|
||||
#define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits, \
|
||||
ereg0, ebit0, ereg1, ebit1) \
|
||||
{ \
|
||||
TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
|
||||
ereg0, ebit0, ereg1, ebit1) \
|
||||
ereg0, ebit0, ereg1, ebit1, 0, 0) \
|
||||
}
|
||||
|
||||
#define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \
|
||||
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
|
||||
{ \
|
||||
TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \
|
||||
ereg0, ebit0, ereg1, ebit1) \
|
||||
TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
|
||||
ereg0, ebit0, ereg1, ebit1, goreg, gobit) \
|
||||
}
|
||||
|
||||
#define TPS6586X_SYS_REGULATOR() \
|
||||
|
@ -207,13 +173,13 @@ static struct tps6586x_regulator tps6586x_regulator[] = {
|
|||
TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
|
||||
|
||||
TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3,
|
||||
ENB, 3, VCC2, 6),
|
||||
ENB, 3, TPS6586X_VCC2, BIT(6)),
|
||||
TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3,
|
||||
END, 3, VCC1, 6),
|
||||
END, 3, TPS6586X_VCC1, BIT(6)),
|
||||
TPS6586X_DVM(SM_0, "vin-sm0", dvm, SM0V1, 0, 5, ENA, 1,
|
||||
ENB, 1, VCC1, 2),
|
||||
ENB, 1, TPS6586X_VCC1, BIT(2)),
|
||||
TPS6586X_DVM(SM_1, "vin-sm1", dvm, SM1V1, 0, 5, ENA, 0,
|
||||
ENB, 0, VCC1, 0),
|
||||
ENB, 0, TPS6586X_VCC1, BIT(0)),
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -964,8 +964,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
|
|||
{
|
||||
struct tps65910_board *pmic_plat_data;
|
||||
struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device_node *np = pdev->dev.parent->of_node;
|
||||
struct device_node *regulators;
|
||||
struct device_node *np, *regulators;
|
||||
struct of_regulator_match *matches;
|
||||
unsigned int prop;
|
||||
int idx = 0, ret, count;
|
||||
|
@ -978,6 +977,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
np = of_node_get(pdev->dev.parent->of_node);
|
||||
regulators = of_find_node_by_name(np, "regulators");
|
||||
if (!regulators) {
|
||||
dev_err(&pdev->dev, "regulator node not found\n");
|
||||
|
@ -994,11 +994,13 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
|
|||
matches = tps65911_matches;
|
||||
break;
|
||||
default:
|
||||
of_node_put(regulators);
|
||||
dev_err(&pdev->dev, "Invalid tps chip version\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = of_regulator_match(&pdev->dev, regulators, matches, count);
|
||||
of_node_put(regulators);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
|
||||
ret);
|
||||
|
|
|
@ -26,6 +26,7 @@ enum sec_device_type {
|
|||
/**
|
||||
* struct sec_pmic_dev - s5m87xx master device for sub-drivers
|
||||
* @dev: master device of the chip (can be used to access platform data)
|
||||
* @pdata: pointer to private data used to pass platform data to child
|
||||
* @i2c: i2c client private data for regulator
|
||||
* @rtc: i2c client private data for rtc
|
||||
* @iolock: mutex for serializing io access
|
||||
|
@ -39,6 +40,7 @@ enum sec_device_type {
|
|||
*/
|
||||
struct sec_pmic_dev {
|
||||
struct device *dev;
|
||||
struct sec_platform_data *pdata;
|
||||
struct regmap *regmap;
|
||||
struct i2c_client *i2c;
|
||||
struct i2c_client *rtc;
|
||||
|
@ -82,11 +84,11 @@ struct sec_platform_data {
|
|||
|
||||
int buck_gpios[3];
|
||||
int buck_ds[3];
|
||||
int buck2_voltage[8];
|
||||
unsigned int buck2_voltage[8];
|
||||
bool buck2_gpiodvs;
|
||||
int buck3_voltage[8];
|
||||
unsigned int buck3_voltage[8];
|
||||
bool buck3_gpiodvs;
|
||||
int buck4_voltage[8];
|
||||
unsigned int buck4_voltage[8];
|
||||
bool buck4_gpiodvs;
|
||||
|
||||
int buck_set1;
|
||||
|
@ -127,6 +129,7 @@ struct sec_platform_data {
|
|||
struct sec_regulator_data {
|
||||
int id;
|
||||
struct regulator_init_data *initdata;
|
||||
struct device_node *reg_node;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -136,7 +139,7 @@ struct sec_regulator_data {
|
|||
*/
|
||||
struct sec_opmode_data {
|
||||
int id;
|
||||
int mode;
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
71
include/linux/platform_data/lp8755.h
Normal file
71
include/linux/platform_data/lp8755.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* LP8755 High Performance Power Management Unit Driver:System Interface Driver
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments
|
||||
*
|
||||
* Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.com>
|
||||
* G.Shark Jeong <gshark.jeong@gmail.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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LP8755_H
|
||||
#define _LP8755_H
|
||||
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#define LP8755_NAME "lp8755-regulator"
|
||||
/*
|
||||
*PWR FAULT : power fault detected
|
||||
*OCP : over current protect activated
|
||||
*OVP : over voltage protect activated
|
||||
*TEMP_WARN : thermal warning
|
||||
*TEMP_SHDN : thermal shutdonw detected
|
||||
*I_LOAD : current measured
|
||||
*/
|
||||
#define LP8755_EVENT_PWR_FAULT REGULATOR_EVENT_FAIL
|
||||
#define LP8755_EVENT_OCP REGULATOR_EVENT_OVER_CURRENT
|
||||
#define LP8755_EVENT_OVP 0x10000
|
||||
#define LP8755_EVENT_TEMP_WARN 0x2000
|
||||
#define LP8755_EVENT_TEMP_SHDN REGULATOR_EVENT_OVER_TEMP
|
||||
#define LP8755_EVENT_I_LOAD 0x40000
|
||||
|
||||
enum lp8755_bucks {
|
||||
LP8755_BUCK0 = 0,
|
||||
LP8755_BUCK1,
|
||||
LP8755_BUCK2,
|
||||
LP8755_BUCK3,
|
||||
LP8755_BUCK4,
|
||||
LP8755_BUCK5,
|
||||
LP8755_BUCK_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* multiphase configuration options
|
||||
*/
|
||||
enum lp8755_mphase_config {
|
||||
MPHASE_CONF0,
|
||||
MPHASE_CONF1,
|
||||
MPHASE_CONF2,
|
||||
MPHASE_CONF3,
|
||||
MPHASE_CONF4,
|
||||
MPHASE_CONF5,
|
||||
MPHASE_CONF6,
|
||||
MPHASE_CONF7,
|
||||
MPHASE_CONF8,
|
||||
MPHASE_CONF_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* struct lp8755_platform_data
|
||||
* @mphase_type : Multiphase Switcher Configurations.
|
||||
* @buck_data : buck0~6 init voltage in uV
|
||||
*/
|
||||
struct lp8755_platform_data {
|
||||
int mphase;
|
||||
struct regulator_init_data *buck_data[LP8755_BUCK_MAX];
|
||||
};
|
||||
#endif
|
|
@ -193,6 +193,10 @@ enum regulator_type {
|
|||
*
|
||||
* @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
|
||||
* @vsel_mask: Mask for register bitfield used for selector
|
||||
* @apply_reg: Register for initiate voltage change on the output when
|
||||
* using regulator_set_voltage_sel_regmap
|
||||
* @apply_bit: Register bitfield used for initiate voltage change on the
|
||||
* output when using regulator_set_voltage_sel_regmap
|
||||
* @enable_reg: Register for control when using regmap enable/disable ops
|
||||
* @enable_mask: Mask for control when using regmap enable/disable ops
|
||||
*
|
||||
|
@ -218,6 +222,8 @@ struct regulator_desc {
|
|||
|
||||
unsigned int vsel_reg;
|
||||
unsigned int vsel_mask;
|
||||
unsigned int apply_reg;
|
||||
unsigned int apply_bit;
|
||||
unsigned int enable_reg;
|
||||
unsigned int enable_mask;
|
||||
unsigned int bypass_reg;
|
||||
|
|
|
@ -1152,6 +1152,8 @@ SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
|
|||
SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
|
||||
SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
|
||||
SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("MICSUPP"),
|
||||
};
|
||||
|
||||
#define ARIZONA_MIXER_INPUT_ROUTES(name) \
|
||||
|
@ -1364,6 +1366,8 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
|
|||
{ "AEC Loopback", "SPKDAT1R", "OUT5R" },
|
||||
{ "SPKDAT1L", NULL, "OUT5L" },
|
||||
{ "SPKDAT1R", NULL, "OUT5R" },
|
||||
|
||||
{ "MICSUPP", NULL, "SYSCLK" },
|
||||
};
|
||||
|
||||
static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
|
||||
|
|
|
@ -624,6 +624,8 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
|
|||
SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
|
||||
SND_SOC_DAPM_OUTPUT("SPKDAT2L"),
|
||||
SND_SOC_DAPM_OUTPUT("SPKDAT2R"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("MICSUPP"),
|
||||
};
|
||||
|
||||
#define ARIZONA_MIXER_INPUT_ROUTES(name) \
|
||||
|
@ -832,6 +834,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
|
|||
|
||||
{ "SPKDAT2L", NULL, "OUT6L" },
|
||||
{ "SPKDAT2R", NULL, "OUT6R" },
|
||||
|
||||
{ "MICSUPP", NULL, "SYSCLK" },
|
||||
};
|
||||
|
||||
static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
|
||||
|
|
Loading…
Reference in a new issue