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:
Linus Torvalds 2013-02-20 09:22:19 -08:00
commit 8909ff652d
41 changed files with 1921 additions and 567 deletions

View 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;
};
};
};

View File

@ -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>;

View File

@ -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;
};
};
};

View File

@ -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;
};

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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, &reg);
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

View File

@ -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 = &regs[id];

View File

@ -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;

View File

@ -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
}

View File

@ -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,\

View File

@ -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,

View File

@ -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,
};

View File

@ -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,
};

View File

@ -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
View 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, &regval);
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, &regval);
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, &regval);
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, &regval);
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, &regval);
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");

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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, &reg, &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;

View File

@ -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, &reg, &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,

View File

@ -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;
if (volt > 1375000) {
mask |= MC13892_SWITCHERS0_SWxHI;
reg_value |= MC13892_SWITCHERS0_SWxHI;
} else if (volt < 1100000) {
mask |= MC13892_SWITCHERS0_SWxHI;
reg_value &= ~MC13892_SWITCHERS0_SWxHI;
/*
* 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) {
reg_value -= MC13892_SWxHI_SEL_OFFSET;
reg_value |= MC13892_SWITCHERS0_SWxHI;
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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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)

View File

@ -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, &reg);
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, &reg);
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(&regulators[id], &config);
if (IS_ERR(rdev[i])) {

View File

@ -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))
switch (reg) {
case TPS51632_OFFSET_REG:
case TPS51632_FAULT_REG:
case TPS51632_IMON_REG:
return true;
default:
return false;
return true;
}
}
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,

View File

@ -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(&reg_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,

View File

@ -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 = &reg_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)) {

View File

@ -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)),
};
/*

View File

@ -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);

View File

@ -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;
};
/*

View 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

View File

@ -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;

View File

@ -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,

View File

@ -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,