mirror of https://gitee.com/openkylin/linux.git
Merge remote-tracking branches 'regulator/topic/drivers', 'regulator/topic/enable', 'regulator/topic/fan53555', 'regulator/topic/hi6421' and 'regulator/topic/isl9305' into regulator-next
This commit is contained in:
commit
a81bf3c4fc
|
@ -0,0 +1,23 @@
|
||||||
|
Binding for Fairchild FAN53555 regulators
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828"
|
||||||
|
- reg: I2C address
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- fcs,suspend-voltage-selector: declare which of the two available
|
||||||
|
voltage selector registers should be used for the suspend
|
||||||
|
voltage. The other one is used for the runtime voltage setting
|
||||||
|
Possible values are either <0> or <1>
|
||||||
|
- vin-supply: regulator supplying the vin pin
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
regulator@40 {
|
||||||
|
compatible = "fcs,fan53555";
|
||||||
|
regulator-name = "fan53555";
|
||||||
|
regulator-min-microvolt = <1000000>;
|
||||||
|
regulator-max-microvolt = <1800000>;
|
||||||
|
vin-supply = <&parent_reg>;
|
||||||
|
fcs,suspend-voltage-selector = <1>;
|
||||||
|
};
|
|
@ -0,0 +1,36 @@
|
||||||
|
Intersil ISL9305/ISL9305H voltage regulator
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- compatible: "isl,isl9305" or "isl,isl9305h"
|
||||||
|
- reg: I2C slave address, usually 0x68.
|
||||||
|
- regulators: A node that houses a sub-node for each regulator within the
|
||||||
|
device. Each sub-node is identified using the node's name, with valid
|
||||||
|
values being "dcd1", "dcd2", "ldo1" and "ldo2". The content of each sub-node
|
||||||
|
is defined by the standard binding for regulators; see regulator.txt.
|
||||||
|
- VINDCD1-supply: A phandle to a regulator node supplying VINDCD1.
|
||||||
|
VINDCD2-supply: A phandle to a regulator node supplying VINDCD2.
|
||||||
|
VINLDO1-supply: A phandle to a regulator node supplying VINLDO1.
|
||||||
|
VINLDO2-supply: A phandle to a regulator node supplying VINLDO2.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- Per-regulator optional properties are defined in regulator.txt
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
pmic: isl9305@68 {
|
||||||
|
compatible = "isl,isl9305";
|
||||||
|
reg = <0x68>;
|
||||||
|
|
||||||
|
VINDCD1-supply = <&system_power>;
|
||||||
|
VINDCD2-supply = <&system_power>;
|
||||||
|
VINLDO1-supply = <&system_power>;
|
||||||
|
VINLDO2-supply = <&system_power>;
|
||||||
|
|
||||||
|
regulators {
|
||||||
|
dcd1 {
|
||||||
|
regulator-name = "VDD_DSP";
|
||||||
|
regulator-always-on;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,27 @@
|
||||||
|
pwm regulator bindings
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should be "pwm-regulator"
|
||||||
|
- pwms: OF device-tree PWM specification (see PWM binding pwm.txt)
|
||||||
|
- voltage-table: voltage and duty table, include 2 members in each set of
|
||||||
|
brackets, first one is voltage(unit: uv), the next is duty(unit: percent)
|
||||||
|
|
||||||
|
Any property defined as part of the core regulator binding defined in
|
||||||
|
regulator.txt can also be used.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
pwm_regulator {
|
||||||
|
compatible = "pwm-regulator;
|
||||||
|
pwms = <&pwm1 0 8448 0>;
|
||||||
|
|
||||||
|
voltage-table = <1114000 0>,
|
||||||
|
<1095000 10>,
|
||||||
|
<1076000 20>,
|
||||||
|
<1056000 30>,
|
||||||
|
<1036000 40>,
|
||||||
|
<1016000 50>;
|
||||||
|
|
||||||
|
regulator-min-microvolt = <1016000>;
|
||||||
|
regulator-max-microvolt = <1114000>;
|
||||||
|
regulator-name = "vdd_logic";
|
||||||
|
};
|
|
@ -0,0 +1,16 @@
|
||||||
|
SKY81452 voltage regulator
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- any required generic properties defined in regulator.txt
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- any available generic properties defined in regulator.txt
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
regulator {
|
||||||
|
/* generic regulator properties */
|
||||||
|
regulator-name = "touch_en";
|
||||||
|
regulator-min-microvolt = <4500000>;
|
||||||
|
regulator-max-microvolt = <8000000>;
|
||||||
|
};
|
|
@ -49,6 +49,7 @@ epson Seiko Epson Corp.
|
||||||
est ESTeem Wireless Modems
|
est ESTeem Wireless Modems
|
||||||
eukrea Eukréa Electromatique
|
eukrea Eukréa Electromatique
|
||||||
excito Excito
|
excito Excito
|
||||||
|
fcs Fairchild Semiconductor
|
||||||
fsl Freescale Semiconductor
|
fsl Freescale Semiconductor
|
||||||
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
||||||
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
||||||
|
@ -124,6 +125,7 @@ sil Silicon Image
|
||||||
silabs Silicon Laboratories
|
silabs Silicon Laboratories
|
||||||
simtek
|
simtek
|
||||||
sii Seiko Instruments, Inc.
|
sii Seiko Instruments, Inc.
|
||||||
|
silergy Silergy Corp.
|
||||||
sirf SiRF Technology, Inc.
|
sirf SiRF Technology, Inc.
|
||||||
smsc Standard Microsystems Corporation
|
smsc Standard Microsystems Corporation
|
||||||
snps Synopsys, Inc.
|
snps Synopsys, Inc.
|
||||||
|
|
|
@ -241,6 +241,23 @@ config REGULATOR_GPIO
|
||||||
and the platform has to provide a mapping of GPIO-states
|
and the platform has to provide a mapping of GPIO-states
|
||||||
to target volts/amps.
|
to target volts/amps.
|
||||||
|
|
||||||
|
config REGULATOR_HI6421
|
||||||
|
tristate "HiSilicon Hi6421 PMIC voltage regulator support"
|
||||||
|
depends on MFD_HI6421_PMIC && OF
|
||||||
|
help
|
||||||
|
This driver provides support for the voltage regulators on the
|
||||||
|
HiSilicon Hi6421 PMU / Codec IC.
|
||||||
|
Hi6421 is a multi-function device which, on regulator part, provides
|
||||||
|
21 general purpose LDOs, 3 dedicated LDOs, and 5 BUCKs. All
|
||||||
|
of them come with support to either ECO (idle) or sleep mode.
|
||||||
|
|
||||||
|
config REGULATOR_ISL9305
|
||||||
|
tristate "Intersil ISL9305 regulator"
|
||||||
|
depends on I2C
|
||||||
|
select REGMAP_I2C
|
||||||
|
help
|
||||||
|
This driver supports ISL9305 voltage regulator chip.
|
||||||
|
|
||||||
config REGULATOR_ISL6271A
|
config REGULATOR_ISL6271A
|
||||||
tristate "Intersil ISL6271A Power regulator"
|
tristate "Intersil ISL6271A Power regulator"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
|
@ -450,6 +467,25 @@ config REGULATOR_PFUZE100
|
||||||
Say y here to support the regulators found on the Freescale
|
Say y here to support the regulators found on the Freescale
|
||||||
PFUZE100/PFUZE200 PMIC.
|
PFUZE100/PFUZE200 PMIC.
|
||||||
|
|
||||||
|
config REGULATOR_PWM
|
||||||
|
tristate "PWM voltage regulator"
|
||||||
|
depends on PWM
|
||||||
|
help
|
||||||
|
This driver supports PWM controlled voltage regulators. PWM
|
||||||
|
duty cycle can increase or decrease the voltage.
|
||||||
|
|
||||||
|
config REGULATOR_QCOM_RPM
|
||||||
|
tristate "Qualcomm RPM regulator driver"
|
||||||
|
depends on MFD_QCOM_RPM
|
||||||
|
help
|
||||||
|
If you say yes to this option, support will be included for the
|
||||||
|
regulators exposed by the Resource Power Manager found in Qualcomm
|
||||||
|
8660, 8960 and 8064 based devices.
|
||||||
|
|
||||||
|
Say M here if you want to include support for the regulators on the
|
||||||
|
Qualcomm RPM as a module. The module will be named
|
||||||
|
"qcom_rpm-regulator".
|
||||||
|
|
||||||
config REGULATOR_RC5T583
|
config REGULATOR_RC5T583
|
||||||
tristate "RICOH RC5T583 Power regulators"
|
tristate "RICOH RC5T583 Power regulators"
|
||||||
depends on MFD_RC5T583
|
depends on MFD_RC5T583
|
||||||
|
@ -484,11 +520,16 @@ config REGULATOR_S5M8767
|
||||||
via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
|
via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
|
||||||
supports DVS mode with 8bits of output voltage control.
|
supports DVS mode with 8bits of output voltage control.
|
||||||
|
|
||||||
config REGULATOR_ST_PWM
|
config REGULATOR_SKY81452
|
||||||
tristate "STMicroelectronics PWM voltage regulator"
|
tristate "Skyworks Solutions SKY81452 voltage regulator"
|
||||||
depends on ARCH_STI
|
depends on SKY81452
|
||||||
help
|
help
|
||||||
This driver supports ST's PWM controlled voltage regulators.
|
This driver supports Skyworks SKY81452 voltage output regulator
|
||||||
|
via I2C bus. SKY81452 has one voltage linear regulator can be
|
||||||
|
programmed from 4.5V to 20V.
|
||||||
|
|
||||||
|
This driver can also be built as a module. If so, the module
|
||||||
|
will be called sky81452-regulator.
|
||||||
|
|
||||||
config REGULATOR_TI_ABB
|
config REGULATOR_TI_ABB
|
||||||
tristate "TI Adaptive Body Bias on-chip LDO"
|
tristate "TI Adaptive Body Bias on-chip LDO"
|
||||||
|
|
|
@ -32,7 +32,9 @@ obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
|
||||||
obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
|
obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
|
||||||
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
|
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
|
||||||
obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
|
obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
|
||||||
|
obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
|
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
|
||||||
|
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
|
||||||
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
|
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
|
||||||
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
|
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
|
||||||
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
|
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
|
||||||
|
@ -55,8 +57,10 @@ obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
|
||||||
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
|
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
|
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
|
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
|
||||||
|
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
|
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
|
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
|
||||||
|
obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
|
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
|
obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
|
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
|
||||||
|
@ -65,7 +69,7 @@ obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
|
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
|
||||||
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
|
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
|
||||||
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
|
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
|
||||||
obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o
|
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
|
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
|
||||||
obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
|
obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
|
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
|
||||||
|
|
|
@ -839,7 +839,7 @@ static void print_constraints(struct regulator_dev *rdev)
|
||||||
static int machine_constraints_voltage(struct regulator_dev *rdev,
|
static int machine_constraints_voltage(struct regulator_dev *rdev,
|
||||||
struct regulation_constraints *constraints)
|
struct regulation_constraints *constraints)
|
||||||
{
|
{
|
||||||
struct regulator_ops *ops = rdev->desc->ops;
|
const struct regulator_ops *ops = rdev->desc->ops;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* do we need to apply the constraint voltage */
|
/* do we need to apply the constraint voltage */
|
||||||
|
@ -938,7 +938,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
|
||||||
static int machine_constraints_current(struct regulator_dev *rdev,
|
static int machine_constraints_current(struct regulator_dev *rdev,
|
||||||
struct regulation_constraints *constraints)
|
struct regulation_constraints *constraints)
|
||||||
{
|
{
|
||||||
struct regulator_ops *ops = rdev->desc->ops;
|
const struct regulator_ops *ops = rdev->desc->ops;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!constraints->min_uA && !constraints->max_uA)
|
if (!constraints->min_uA && !constraints->max_uA)
|
||||||
|
@ -982,7 +982,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
|
||||||
const struct regulation_constraints *constraints)
|
const struct regulation_constraints *constraints)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct regulator_ops *ops = rdev->desc->ops;
|
const struct regulator_ops *ops = rdev->desc->ops;
|
||||||
|
|
||||||
if (constraints)
|
if (constraints)
|
||||||
rdev->constraints = kmemdup(constraints, sizeof(*constraints),
|
rdev->constraints = kmemdup(constraints, sizeof(*constraints),
|
||||||
|
@ -1759,6 +1759,45 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _regulator_enable_delay - a delay helper function
|
||||||
|
* @delay: time to delay in microseconds
|
||||||
|
*
|
||||||
|
* Delay for the requested amount of time as per the guidelines in:
|
||||||
|
*
|
||||||
|
* Documentation/timers/timers-howto.txt
|
||||||
|
*
|
||||||
|
* The assumption here is that regulators will never be enabled in
|
||||||
|
* atomic context and therefore sleeping functions can be used.
|
||||||
|
*/
|
||||||
|
static void _regulator_enable_delay(unsigned int delay)
|
||||||
|
{
|
||||||
|
unsigned int ms = delay / 1000;
|
||||||
|
unsigned int us = delay % 1000;
|
||||||
|
|
||||||
|
if (ms > 0) {
|
||||||
|
/*
|
||||||
|
* For small enough values, handle super-millisecond
|
||||||
|
* delays in the usleep_range() call below.
|
||||||
|
*/
|
||||||
|
if (ms < 20)
|
||||||
|
us += ms * 1000;
|
||||||
|
else
|
||||||
|
msleep(ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Give the scheduler some room to coalesce with any other
|
||||||
|
* wakeup sources. For delays shorter than 10 us, don't even
|
||||||
|
* bother setting up high-resolution timers and just busy-
|
||||||
|
* loop.
|
||||||
|
*/
|
||||||
|
if (us >= 10)
|
||||||
|
usleep_range(us, us + 100);
|
||||||
|
else
|
||||||
|
udelay(us);
|
||||||
|
}
|
||||||
|
|
||||||
static int _regulator_do_enable(struct regulator_dev *rdev)
|
static int _regulator_do_enable(struct regulator_dev *rdev)
|
||||||
{
|
{
|
||||||
int ret, delay;
|
int ret, delay;
|
||||||
|
@ -1774,6 +1813,31 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
|
||||||
|
|
||||||
trace_regulator_enable(rdev_get_name(rdev));
|
trace_regulator_enable(rdev_get_name(rdev));
|
||||||
|
|
||||||
|
if (rdev->desc->off_on_delay) {
|
||||||
|
/* if needed, keep a distance of off_on_delay from last time
|
||||||
|
* this regulator was disabled.
|
||||||
|
*/
|
||||||
|
unsigned long start_jiffy = jiffies;
|
||||||
|
unsigned long intended, max_delay, remaining;
|
||||||
|
|
||||||
|
max_delay = usecs_to_jiffies(rdev->desc->off_on_delay);
|
||||||
|
intended = rdev->last_off_jiffy + max_delay;
|
||||||
|
|
||||||
|
if (time_before(start_jiffy, intended)) {
|
||||||
|
/* calc remaining jiffies to deal with one-time
|
||||||
|
* timer wrapping.
|
||||||
|
* in case of multiple timer wrapping, either it can be
|
||||||
|
* detected by out-of-range remaining, or it cannot be
|
||||||
|
* detected and we gets a panelty of
|
||||||
|
* _regulator_enable_delay().
|
||||||
|
*/
|
||||||
|
remaining = intended - start_jiffy;
|
||||||
|
if (remaining <= max_delay)
|
||||||
|
_regulator_enable_delay(
|
||||||
|
jiffies_to_usecs(remaining));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rdev->ena_pin) {
|
if (rdev->ena_pin) {
|
||||||
ret = regulator_ena_gpio_ctrl(rdev, true);
|
ret = regulator_ena_gpio_ctrl(rdev, true);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -1792,40 +1856,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
|
||||||
* together. */
|
* together. */
|
||||||
trace_regulator_enable_delay(rdev_get_name(rdev));
|
trace_regulator_enable_delay(rdev_get_name(rdev));
|
||||||
|
|
||||||
/*
|
_regulator_enable_delay(delay);
|
||||||
* Delay for the requested amount of time as per the guidelines in:
|
|
||||||
*
|
|
||||||
* Documentation/timers/timers-howto.txt
|
|
||||||
*
|
|
||||||
* The assumption here is that regulators will never be enabled in
|
|
||||||
* atomic context and therefore sleeping functions can be used.
|
|
||||||
*/
|
|
||||||
if (delay) {
|
|
||||||
unsigned int ms = delay / 1000;
|
|
||||||
unsigned int us = delay % 1000;
|
|
||||||
|
|
||||||
if (ms > 0) {
|
|
||||||
/*
|
|
||||||
* For small enough values, handle super-millisecond
|
|
||||||
* delays in the usleep_range() call below.
|
|
||||||
*/
|
|
||||||
if (ms < 20)
|
|
||||||
us += ms * 1000;
|
|
||||||
else
|
|
||||||
msleep(ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Give the scheduler some room to coalesce with any other
|
|
||||||
* wakeup sources. For delays shorter than 10 us, don't even
|
|
||||||
* bother setting up high-resolution timers and just busy-
|
|
||||||
* loop.
|
|
||||||
*/
|
|
||||||
if (us >= 10)
|
|
||||||
usleep_range(us, us + 100);
|
|
||||||
else
|
|
||||||
udelay(us);
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_regulator_enable_complete(rdev_get_name(rdev));
|
trace_regulator_enable_complete(rdev_get_name(rdev));
|
||||||
|
|
||||||
|
@ -1919,6 +1950,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* cares about last_off_jiffy only if off_on_delay is required by
|
||||||
|
* device.
|
||||||
|
*/
|
||||||
|
if (rdev->desc->off_on_delay)
|
||||||
|
rdev->last_off_jiffy = jiffies;
|
||||||
|
|
||||||
trace_regulator_disable_complete(rdev_get_name(rdev));
|
trace_regulator_disable_complete(rdev_get_name(rdev));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2208,9 +2245,9 @@ EXPORT_SYMBOL_GPL(regulator_count_voltages);
|
||||||
*/
|
*/
|
||||||
int regulator_list_voltage(struct regulator *regulator, unsigned selector)
|
int regulator_list_voltage(struct regulator *regulator, unsigned selector)
|
||||||
{
|
{
|
||||||
struct regulator_dev *rdev = regulator->rdev;
|
struct regulator_dev *rdev = regulator->rdev;
|
||||||
struct regulator_ops *ops = rdev->desc->ops;
|
const struct regulator_ops *ops = rdev->desc->ops;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector)
|
if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector)
|
||||||
return rdev->desc->fixed_uV;
|
return rdev->desc->fixed_uV;
|
||||||
|
@ -2270,8 +2307,8 @@ int regulator_get_hardware_vsel_register(struct regulator *regulator,
|
||||||
unsigned *vsel_reg,
|
unsigned *vsel_reg,
|
||||||
unsigned *vsel_mask)
|
unsigned *vsel_mask)
|
||||||
{
|
{
|
||||||
struct regulator_dev *rdev = regulator->rdev;
|
struct regulator_dev *rdev = regulator->rdev;
|
||||||
struct regulator_ops *ops = rdev->desc->ops;
|
const struct regulator_ops *ops = rdev->desc->ops;
|
||||||
|
|
||||||
if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap)
|
if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -2297,8 +2334,8 @@ EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register);
|
||||||
int regulator_list_hardware_vsel(struct regulator *regulator,
|
int regulator_list_hardware_vsel(struct regulator *regulator,
|
||||||
unsigned selector)
|
unsigned selector)
|
||||||
{
|
{
|
||||||
struct regulator_dev *rdev = regulator->rdev;
|
struct regulator_dev *rdev = regulator->rdev;
|
||||||
struct regulator_ops *ops = rdev->desc->ops;
|
const struct regulator_ops *ops = rdev->desc->ops;
|
||||||
|
|
||||||
if (selector >= rdev->desc->n_voltages)
|
if (selector >= rdev->desc->n_voltages)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -2572,8 +2609,8 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage);
|
||||||
int regulator_set_voltage_time(struct regulator *regulator,
|
int regulator_set_voltage_time(struct regulator *regulator,
|
||||||
int old_uV, int new_uV)
|
int old_uV, int new_uV)
|
||||||
{
|
{
|
||||||
struct regulator_dev *rdev = regulator->rdev;
|
struct regulator_dev *rdev = regulator->rdev;
|
||||||
struct regulator_ops *ops = rdev->desc->ops;
|
const struct regulator_ops *ops = rdev->desc->ops;
|
||||||
int old_sel = -1;
|
int old_sel = -1;
|
||||||
int new_sel = -1;
|
int new_sel = -1;
|
||||||
int voltage;
|
int voltage;
|
||||||
|
@ -3336,9 +3373,9 @@ EXPORT_SYMBOL_GPL(regulator_mode_to_status);
|
||||||
*/
|
*/
|
||||||
static int add_regulator_attributes(struct regulator_dev *rdev)
|
static int add_regulator_attributes(struct regulator_dev *rdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &rdev->dev;
|
struct device *dev = &rdev->dev;
|
||||||
struct regulator_ops *ops = rdev->desc->ops;
|
const struct regulator_ops *ops = rdev->desc->ops;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
/* some attributes need specific methods to be displayed */
|
/* some attributes need specific methods to be displayed */
|
||||||
if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
|
if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
|
||||||
|
@ -3516,12 +3553,17 @@ regulator_register(const struct regulator_desc *regulator_desc,
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
init_data = config->init_data;
|
|
||||||
|
|
||||||
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
|
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
|
||||||
if (rdev == NULL)
|
if (rdev == NULL)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
init_data = regulator_of_get_init_data(dev, regulator_desc,
|
||||||
|
&rdev->dev.of_node);
|
||||||
|
if (!init_data) {
|
||||||
|
init_data = config->init_data;
|
||||||
|
rdev->dev.of_node = of_node_get(config->of_node);
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(®ulator_list_mutex);
|
mutex_lock(®ulator_list_mutex);
|
||||||
|
|
||||||
mutex_init(&rdev->mutex);
|
mutex_init(&rdev->mutex);
|
||||||
|
@ -3548,7 +3590,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
|
||||||
|
|
||||||
/* register with sysfs */
|
/* register with sysfs */
|
||||||
rdev->dev.class = ®ulator_class;
|
rdev->dev.class = ®ulator_class;
|
||||||
rdev->dev.of_node = of_node_get(config->of_node);
|
|
||||||
rdev->dev.parent = dev;
|
rdev->dev.parent = dev;
|
||||||
dev_set_name(&rdev->dev, "regulator.%d",
|
dev_set_name(&rdev->dev, "regulator.%d",
|
||||||
atomic_inc_return(®ulator_no) - 1);
|
atomic_inc_return(®ulator_no) - 1);
|
||||||
|
@ -3905,7 +3946,7 @@ core_initcall(regulator_init);
|
||||||
static int __init regulator_init_complete(void)
|
static int __init regulator_init_complete(void)
|
||||||
{
|
{
|
||||||
struct regulator_dev *rdev;
|
struct regulator_dev *rdev;
|
||||||
struct regulator_ops *ops;
|
const struct regulator_ops *ops;
|
||||||
struct regulation_constraints *c;
|
struct regulation_constraints *c;
|
||||||
int enabled, ret;
|
int enabled, ret;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regulator/driver.h>
|
#include <linux/regulator/driver.h>
|
||||||
#include <linux/regulator/machine.h>
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <linux/regulator/of_regulator.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
|
@ -50,6 +52,11 @@
|
||||||
|
|
||||||
#define FAN53555_NVOLTAGES 64 /* Numbers of voltages */
|
#define FAN53555_NVOLTAGES 64 /* Numbers of voltages */
|
||||||
|
|
||||||
|
enum fan53555_vendor {
|
||||||
|
FAN53555_VENDOR_FAIRCHILD = 0,
|
||||||
|
FAN53555_VENDOR_SILERGY,
|
||||||
|
};
|
||||||
|
|
||||||
/* IC Type */
|
/* IC Type */
|
||||||
enum {
|
enum {
|
||||||
FAN53555_CHIP_ID_00 = 0,
|
FAN53555_CHIP_ID_00 = 0,
|
||||||
|
@ -60,7 +67,12 @@ enum {
|
||||||
FAN53555_CHIP_ID_05,
|
FAN53555_CHIP_ID_05,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SILERGY_SYR82X = 8,
|
||||||
|
};
|
||||||
|
|
||||||
struct fan53555_device_info {
|
struct fan53555_device_info {
|
||||||
|
enum fan53555_vendor vendor;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct regulator_desc desc;
|
struct regulator_desc desc;
|
||||||
|
@ -135,6 +147,38 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
|
||||||
return REGULATOR_MODE_NORMAL;
|
return REGULATOR_MODE_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int slew_rates[] = {
|
||||||
|
64000,
|
||||||
|
32000,
|
||||||
|
16000,
|
||||||
|
8000,
|
||||||
|
4000,
|
||||||
|
2000,
|
||||||
|
1000,
|
||||||
|
500,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp)
|
||||||
|
{
|
||||||
|
struct fan53555_device_info *di = rdev_get_drvdata(rdev);
|
||||||
|
int regval = -1, i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(slew_rates); i++) {
|
||||||
|
if (ramp <= slew_rates[i])
|
||||||
|
regval = i;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regval < 0) {
|
||||||
|
dev_err(di->dev, "unsupported ramp value %d\n", ramp);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return regmap_update_bits(di->regmap, FAN53555_CONTROL,
|
||||||
|
CTL_SLEW_MASK, regval << CTL_SLEW_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
static struct regulator_ops fan53555_regulator_ops = {
|
static struct regulator_ops fan53555_regulator_ops = {
|
||||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
@ -146,32 +190,11 @@ static struct regulator_ops fan53555_regulator_ops = {
|
||||||
.is_enabled = regulator_is_enabled_regmap,
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
.set_mode = fan53555_set_mode,
|
.set_mode = fan53555_set_mode,
|
||||||
.get_mode = fan53555_get_mode,
|
.get_mode = fan53555_get_mode,
|
||||||
|
.set_ramp_delay = fan53555_set_ramp,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For 00,01,03,05 options:
|
static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
|
||||||
* VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V.
|
|
||||||
* For 04 option:
|
|
||||||
* VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V.
|
|
||||||
* */
|
|
||||||
static int fan53555_device_setup(struct fan53555_device_info *di,
|
|
||||||
struct fan53555_platform_data *pdata)
|
|
||||||
{
|
{
|
||||||
unsigned int reg, data, mask;
|
|
||||||
|
|
||||||
/* Setup voltage control register */
|
|
||||||
switch (pdata->sleep_vsel_id) {
|
|
||||||
case FAN53555_VSEL_ID_0:
|
|
||||||
di->sleep_reg = FAN53555_VSEL0;
|
|
||||||
di->vol_reg = FAN53555_VSEL1;
|
|
||||||
break;
|
|
||||||
case FAN53555_VSEL_ID_1:
|
|
||||||
di->sleep_reg = FAN53555_VSEL1;
|
|
||||||
di->vol_reg = FAN53555_VSEL0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dev_err(di->dev, "Invalid VSEL ID!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
/* Init voltage range and step */
|
/* Init voltage range and step */
|
||||||
switch (di->chip_id) {
|
switch (di->chip_id) {
|
||||||
case FAN53555_CHIP_ID_00:
|
case FAN53555_CHIP_ID_00:
|
||||||
|
@ -187,18 +210,68 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(di->dev,
|
dev_err(di->dev,
|
||||||
"Chip ID[%d]\n not supported!\n", di->chip_id);
|
"Chip ID %d not supported!\n", di->chip_id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
/* Init slew rate */
|
|
||||||
if (pdata->slew_rate & 0x7)
|
return 0;
|
||||||
di->slew_rate = pdata->slew_rate;
|
}
|
||||||
else
|
|
||||||
di->slew_rate = FAN53555_SLEW_RATE_64MV;
|
static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di)
|
||||||
reg = FAN53555_CONTROL;
|
{
|
||||||
data = di->slew_rate << CTL_SLEW_SHIFT;
|
/* Init voltage range and step */
|
||||||
mask = CTL_SLEW_MASK;
|
switch (di->chip_id) {
|
||||||
return regmap_update_bits(di->regmap, reg, mask, data);
|
case SILERGY_SYR82X:
|
||||||
|
di->vsel_min = 712500;
|
||||||
|
di->vsel_step = 12500;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(di->dev,
|
||||||
|
"Chip ID %d not supported!\n", di->chip_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For 00,01,03,05 options:
|
||||||
|
* VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V.
|
||||||
|
* For 04 option:
|
||||||
|
* VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V.
|
||||||
|
* */
|
||||||
|
static int fan53555_device_setup(struct fan53555_device_info *di,
|
||||||
|
struct fan53555_platform_data *pdata)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Setup voltage control register */
|
||||||
|
switch (pdata->sleep_vsel_id) {
|
||||||
|
case FAN53555_VSEL_ID_0:
|
||||||
|
di->sleep_reg = FAN53555_VSEL0;
|
||||||
|
di->vol_reg = FAN53555_VSEL1;
|
||||||
|
break;
|
||||||
|
case FAN53555_VSEL_ID_1:
|
||||||
|
di->sleep_reg = FAN53555_VSEL1;
|
||||||
|
di->vol_reg = FAN53555_VSEL0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(di->dev, "Invalid VSEL ID!\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (di->vendor) {
|
||||||
|
case FAN53555_VENDOR_FAIRCHILD:
|
||||||
|
ret = fan53555_voltages_setup_fairchild(di);
|
||||||
|
break;
|
||||||
|
case FAN53555_VENDOR_SILERGY:
|
||||||
|
ret = fan53555_voltages_setup_silergy(di);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fan53555_regulator_register(struct fan53555_device_info *di,
|
static int fan53555_regulator_register(struct fan53555_device_info *di,
|
||||||
|
@ -207,6 +280,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di,
|
||||||
struct regulator_desc *rdesc = &di->desc;
|
struct regulator_desc *rdesc = &di->desc;
|
||||||
|
|
||||||
rdesc->name = "fan53555-reg";
|
rdesc->name = "fan53555-reg";
|
||||||
|
rdesc->supply_name = "vin";
|
||||||
rdesc->ops = &fan53555_regulator_ops;
|
rdesc->ops = &fan53555_regulator_ops;
|
||||||
rdesc->type = REGULATOR_VOLTAGE;
|
rdesc->type = REGULATOR_VOLTAGE;
|
||||||
rdesc->n_voltages = FAN53555_NVOLTAGES;
|
rdesc->n_voltages = FAN53555_NVOLTAGES;
|
||||||
|
@ -227,9 +301,46 @@ static struct regmap_config fan53555_regmap_config = {
|
||||||
.val_bits = 8,
|
.val_bits = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev,
|
||||||
|
struct device_node *np)
|
||||||
|
{
|
||||||
|
struct fan53555_platform_data *pdata;
|
||||||
|
int ret;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||||
|
if (!pdata)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pdata->regulator = of_get_regulator_init_data(dev, np);
|
||||||
|
|
||||||
|
ret = of_property_read_u32(np, "fcs,suspend-voltage-selector",
|
||||||
|
&tmp);
|
||||||
|
if (!ret)
|
||||||
|
pdata->sleep_vsel_id = tmp;
|
||||||
|
|
||||||
|
return pdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id fan53555_dt_ids[] = {
|
||||||
|
{
|
||||||
|
.compatible = "fcs,fan53555",
|
||||||
|
.data = (void *)FAN53555_VENDOR_FAIRCHILD
|
||||||
|
}, {
|
||||||
|
.compatible = "silergy,syr827",
|
||||||
|
.data = (void *)FAN53555_VENDOR_SILERGY,
|
||||||
|
}, {
|
||||||
|
.compatible = "silergy,syr828",
|
||||||
|
.data = (void *)FAN53555_VENDOR_SILERGY,
|
||||||
|
},
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, fan53555_dt_ids);
|
||||||
|
|
||||||
static int fan53555_regulator_probe(struct i2c_client *client,
|
static int fan53555_regulator_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
|
struct device_node *np = client->dev.of_node;
|
||||||
struct fan53555_device_info *di;
|
struct fan53555_device_info *di;
|
||||||
struct fan53555_platform_data *pdata;
|
struct fan53555_platform_data *pdata;
|
||||||
struct regulator_config config = { };
|
struct regulator_config config = { };
|
||||||
|
@ -237,6 +348,9 @@ static int fan53555_regulator_probe(struct i2c_client *client,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pdata = dev_get_platdata(&client->dev);
|
pdata = dev_get_platdata(&client->dev);
|
||||||
|
if (!pdata)
|
||||||
|
pdata = fan53555_parse_dt(&client->dev, np);
|
||||||
|
|
||||||
if (!pdata || !pdata->regulator) {
|
if (!pdata || !pdata->regulator) {
|
||||||
dev_err(&client->dev, "Platform data not found!\n");
|
dev_err(&client->dev, "Platform data not found!\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -247,13 +361,35 @@ static int fan53555_regulator_probe(struct i2c_client *client,
|
||||||
if (!di)
|
if (!di)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
di->regulator = pdata->regulator;
|
||||||
|
if (client->dev.of_node) {
|
||||||
|
const struct of_device_id *match;
|
||||||
|
|
||||||
|
match = of_match_device(of_match_ptr(fan53555_dt_ids),
|
||||||
|
&client->dev);
|
||||||
|
if (!match)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
di->vendor = (unsigned long) match->data;
|
||||||
|
} else {
|
||||||
|
/* if no ramp constraint set, get the pdata ramp_delay */
|
||||||
|
if (!di->regulator->constraints.ramp_delay) {
|
||||||
|
int slew_idx = (pdata->slew_rate & 0x7)
|
||||||
|
? pdata->slew_rate : 0;
|
||||||
|
|
||||||
|
di->regulator->constraints.ramp_delay
|
||||||
|
= slew_rates[slew_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
di->vendor = id->driver_data;
|
||||||
|
}
|
||||||
|
|
||||||
di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config);
|
di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config);
|
||||||
if (IS_ERR(di->regmap)) {
|
if (IS_ERR(di->regmap)) {
|
||||||
dev_err(&client->dev, "Failed to allocate regmap!\n");
|
dev_err(&client->dev, "Failed to allocate regmap!\n");
|
||||||
return PTR_ERR(di->regmap);
|
return PTR_ERR(di->regmap);
|
||||||
}
|
}
|
||||||
di->dev = &client->dev;
|
di->dev = &client->dev;
|
||||||
di->regulator = pdata->regulator;
|
|
||||||
i2c_set_clientdata(client, di);
|
i2c_set_clientdata(client, di);
|
||||||
/* Get chip ID */
|
/* Get chip ID */
|
||||||
ret = regmap_read(di->regmap, FAN53555_ID1, &val);
|
ret = regmap_read(di->regmap, FAN53555_ID1, &val);
|
||||||
|
@ -282,6 +418,8 @@ static int fan53555_regulator_probe(struct i2c_client *client,
|
||||||
config.init_data = di->regulator;
|
config.init_data = di->regulator;
|
||||||
config.regmap = di->regmap;
|
config.regmap = di->regmap;
|
||||||
config.driver_data = di;
|
config.driver_data = di;
|
||||||
|
config.of_node = np;
|
||||||
|
|
||||||
ret = fan53555_regulator_register(di, &config);
|
ret = fan53555_regulator_register(di, &config);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
dev_err(&client->dev, "Failed to register regulator!\n");
|
dev_err(&client->dev, "Failed to register regulator!\n");
|
||||||
|
@ -290,13 +428,20 @@ static int fan53555_regulator_probe(struct i2c_client *client,
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id fan53555_id[] = {
|
static const struct i2c_device_id fan53555_id[] = {
|
||||||
{"fan53555", -1},
|
{
|
||||||
|
.name = "fan53555",
|
||||||
|
.driver_data = FAN53555_VENDOR_FAIRCHILD
|
||||||
|
}, {
|
||||||
|
.name = "syr82x",
|
||||||
|
.driver_data = FAN53555_VENDOR_SILERGY
|
||||||
|
},
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct i2c_driver fan53555_regulator_driver = {
|
static struct i2c_driver fan53555_regulator_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "fan53555-regulator",
|
.name = "fan53555-regulator",
|
||||||
|
.of_match_table = of_match_ptr(fan53555_dt_ids),
|
||||||
},
|
},
|
||||||
.probe = fan53555_regulator_probe,
|
.probe = fan53555_regulator_probe,
|
||||||
.id_table = fan53555_id,
|
.id_table = fan53555_id,
|
||||||
|
|
|
@ -0,0 +1,634 @@
|
||||||
|
/*
|
||||||
|
* Device driver for regulators in Hi6421 IC
|
||||||
|
*
|
||||||
|
* Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd.
|
||||||
|
* http://www.hisilicon.com
|
||||||
|
* Copyright (c) <2013-2014> Linaro Ltd.
|
||||||
|
* http://www.linaro.org
|
||||||
|
*
|
||||||
|
* Author: Guodong Xu <guodong.xu@linaro.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/regulator/driver.h>
|
||||||
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <linux/regulator/of_regulator.h>
|
||||||
|
#include <linux/mfd/hi6421-pmic.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct hi6421_regulator_pdata - Hi6421 regulator data of platform device
|
||||||
|
* @lock: mutex to serialize regulator enable
|
||||||
|
*/
|
||||||
|
struct hi6421_regulator_pdata {
|
||||||
|
struct mutex lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct hi6421_regulator_info - hi6421 regulator information
|
||||||
|
* @desc: regulator description
|
||||||
|
* @mode_mask: ECO mode bitmask of LDOs; for BUCKs, this masks sleep
|
||||||
|
* @eco_microamp: eco mode load upper limit (in uA), valid for LDOs only
|
||||||
|
*/
|
||||||
|
struct hi6421_regulator_info {
|
||||||
|
struct regulator_desc desc;
|
||||||
|
u8 mode_mask;
|
||||||
|
u32 eco_microamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* HI6421 regulators */
|
||||||
|
enum hi6421_regulator_id {
|
||||||
|
HI6421_LDO0,
|
||||||
|
HI6421_LDO1,
|
||||||
|
HI6421_LDO2,
|
||||||
|
HI6421_LDO3,
|
||||||
|
HI6421_LDO4,
|
||||||
|
HI6421_LDO5,
|
||||||
|
HI6421_LDO6,
|
||||||
|
HI6421_LDO7,
|
||||||
|
HI6421_LDO8,
|
||||||
|
HI6421_LDO9,
|
||||||
|
HI6421_LDO10,
|
||||||
|
HI6421_LDO11,
|
||||||
|
HI6421_LDO12,
|
||||||
|
HI6421_LDO13,
|
||||||
|
HI6421_LDO14,
|
||||||
|
HI6421_LDO15,
|
||||||
|
HI6421_LDO16,
|
||||||
|
HI6421_LDO17,
|
||||||
|
HI6421_LDO18,
|
||||||
|
HI6421_LDO19,
|
||||||
|
HI6421_LDO20,
|
||||||
|
HI6421_LDOAUDIO,
|
||||||
|
HI6421_BUCK0,
|
||||||
|
HI6421_BUCK1,
|
||||||
|
HI6421_BUCK2,
|
||||||
|
HI6421_BUCK3,
|
||||||
|
HI6421_BUCK4,
|
||||||
|
HI6421_BUCK5,
|
||||||
|
HI6421_NUM_REGULATORS,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HI6421_REGULATOR_OF_MATCH(_name, id) \
|
||||||
|
{ \
|
||||||
|
.name = #_name, \
|
||||||
|
.driver_data = (void *) HI6421_##id, \
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct of_regulator_match hi6421_regulator_match[] = {
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout0, LDO0),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout1, LDO1),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout2, LDO2),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout3, LDO3),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout4, LDO4),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout5, LDO5),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout6, LDO6),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout7, LDO7),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout8, LDO8),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout9, LDO9),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout10, LDO10),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout11, LDO11),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout12, LDO12),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout13, LDO13),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout14, LDO14),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout15, LDO15),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout16, LDO16),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout17, LDO17),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout18, LDO18),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout19, LDO19),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout20, LDO20),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_vout_audio, LDOAUDIO),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_buck0, BUCK0),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_buck1, BUCK1),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_buck2, BUCK2),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_buck3, BUCK3),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_buck4, BUCK4),
|
||||||
|
HI6421_REGULATOR_OF_MATCH(hi6421_buck5, BUCK5),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* LDO 0, 4~7, 9~14, 16~20 have same voltage table. */
|
||||||
|
static const unsigned int ldo_0_voltages[] = {
|
||||||
|
1500000, 1800000, 2400000, 2500000,
|
||||||
|
2600000, 2700000, 2850000, 3000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* LDO 8, 15 have same voltage table. */
|
||||||
|
static const unsigned int ldo_8_voltages[] = {
|
||||||
|
1500000, 1800000, 2400000, 2600000,
|
||||||
|
2700000, 2850000, 3000000, 3300000,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Ranges are sorted in ascending order. */
|
||||||
|
static const struct regulator_linear_range ldo_audio_volt_range[] = {
|
||||||
|
REGULATOR_LINEAR_RANGE(2800000, 0, 3, 50000),
|
||||||
|
REGULATOR_LINEAR_RANGE(3000000, 4, 7, 100000),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned int buck_3_voltages[] = {
|
||||||
|
950000, 1050000, 1100000, 1117000,
|
||||||
|
1134000, 1150000, 1167000, 1200000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned int buck_4_voltages[] = {
|
||||||
|
1150000, 1200000, 1250000, 1350000,
|
||||||
|
1700000, 1800000, 1900000, 2000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned int buck_5_voltages[] = {
|
||||||
|
1150000, 1200000, 1250000, 1350000,
|
||||||
|
1600000, 1700000, 1800000, 1900000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_ops hi6421_ldo_ops;
|
||||||
|
static const struct regulator_ops hi6421_ldo_linear_ops;
|
||||||
|
static const struct regulator_ops hi6421_ldo_linear_range_ops;
|
||||||
|
static const struct regulator_ops hi6421_buck012_ops;
|
||||||
|
static const struct regulator_ops hi6421_buck345_ops;
|
||||||
|
|
||||||
|
#define HI6421_LDO_ENABLE_TIME (350)
|
||||||
|
/*
|
||||||
|
* _id - LDO id name string
|
||||||
|
* v_table - voltage table
|
||||||
|
* vreg - voltage select register
|
||||||
|
* vmask - voltage select mask
|
||||||
|
* ereg - enable register
|
||||||
|
* emask - enable mask
|
||||||
|
* odelay - off/on delay time in uS
|
||||||
|
* ecomask - eco mode mask
|
||||||
|
* ecoamp - eco mode load uppler limit in uA
|
||||||
|
*/
|
||||||
|
#define HI6421_LDO(_id, v_table, vreg, vmask, ereg, emask, \
|
||||||
|
odelay, ecomask, ecoamp) \
|
||||||
|
[HI6421_##_id] = { \
|
||||||
|
.desc = { \
|
||||||
|
.name = #_id, \
|
||||||
|
.ops = &hi6421_ldo_ops, \
|
||||||
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
.id = HI6421_##_id, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.n_voltages = ARRAY_SIZE(v_table), \
|
||||||
|
.volt_table = v_table, \
|
||||||
|
.vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \
|
||||||
|
.vsel_mask = vmask, \
|
||||||
|
.enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \
|
||||||
|
.enable_mask = emask, \
|
||||||
|
.enable_time = HI6421_LDO_ENABLE_TIME, \
|
||||||
|
.off_on_delay = odelay, \
|
||||||
|
}, \
|
||||||
|
.mode_mask = ecomask, \
|
||||||
|
.eco_microamp = ecoamp, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HI6421 LDO1~3 are linear voltage regulators at fixed uV_step
|
||||||
|
*
|
||||||
|
* _id - LDO id name string
|
||||||
|
* _min_uV - minimum voltage supported in uV
|
||||||
|
* n_volt - number of votages available
|
||||||
|
* vstep - voltage increase in each linear step in uV
|
||||||
|
* vreg - voltage select register
|
||||||
|
* vmask - voltage select mask
|
||||||
|
* ereg - enable register
|
||||||
|
* emask - enable mask
|
||||||
|
* odelay - off/on delay time in uS
|
||||||
|
* ecomask - eco mode mask
|
||||||
|
* ecoamp - eco mode load uppler limit in uA
|
||||||
|
*/
|
||||||
|
#define HI6421_LDO_LINEAR(_id, _min_uV, n_volt, vstep, vreg, vmask, \
|
||||||
|
ereg, emask, odelay, ecomask, ecoamp) \
|
||||||
|
[HI6421_##_id] = { \
|
||||||
|
.desc = { \
|
||||||
|
.name = #_id, \
|
||||||
|
.ops = &hi6421_ldo_linear_ops, \
|
||||||
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
.id = HI6421_##_id, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.min_uV = _min_uV, \
|
||||||
|
.n_voltages = n_volt, \
|
||||||
|
.uV_step = vstep, \
|
||||||
|
.vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \
|
||||||
|
.vsel_mask = vmask, \
|
||||||
|
.enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \
|
||||||
|
.enable_mask = emask, \
|
||||||
|
.enable_time = HI6421_LDO_ENABLE_TIME, \
|
||||||
|
.off_on_delay = odelay, \
|
||||||
|
}, \
|
||||||
|
.mode_mask = ecomask, \
|
||||||
|
.eco_microamp = ecoamp, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HI6421 LDOAUDIO is a linear voltage regulator with two 4-step ranges
|
||||||
|
*
|
||||||
|
* _id - LDO id name string
|
||||||
|
* n_volt - number of votages available
|
||||||
|
* volt_ranges - array of regulator_linear_range
|
||||||
|
* vstep - voltage increase in each linear step in uV
|
||||||
|
* vreg - voltage select register
|
||||||
|
* vmask - voltage select mask
|
||||||
|
* ereg - enable register
|
||||||
|
* emask - enable mask
|
||||||
|
* odelay - off/on delay time in uS
|
||||||
|
* ecomask - eco mode mask
|
||||||
|
* ecoamp - eco mode load uppler limit in uA
|
||||||
|
*/
|
||||||
|
#define HI6421_LDO_LINEAR_RANGE(_id, n_volt, volt_ranges, vreg, vmask, \
|
||||||
|
ereg, emask, odelay, ecomask, ecoamp) \
|
||||||
|
[HI6421_##_id] = { \
|
||||||
|
.desc = { \
|
||||||
|
.name = #_id, \
|
||||||
|
.ops = &hi6421_ldo_linear_range_ops, \
|
||||||
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
.id = HI6421_##_id, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.n_voltages = n_volt, \
|
||||||
|
.linear_ranges = volt_ranges, \
|
||||||
|
.n_linear_ranges = ARRAY_SIZE(volt_ranges), \
|
||||||
|
.vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \
|
||||||
|
.vsel_mask = vmask, \
|
||||||
|
.enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \
|
||||||
|
.enable_mask = emask, \
|
||||||
|
.enable_time = HI6421_LDO_ENABLE_TIME, \
|
||||||
|
.off_on_delay = odelay, \
|
||||||
|
}, \
|
||||||
|
.mode_mask = ecomask, \
|
||||||
|
.eco_microamp = ecoamp, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HI6421 BUCK0/1/2 are linear voltage regulators at fixed uV_step
|
||||||
|
*
|
||||||
|
* _id - BUCK0/1/2 id name string
|
||||||
|
* vreg - voltage select register
|
||||||
|
* vmask - voltage select mask
|
||||||
|
* ereg - enable register
|
||||||
|
* emask - enable mask
|
||||||
|
* sleepmask - mask of sleep mode
|
||||||
|
* etime - enable time
|
||||||
|
* odelay - off/on delay time in uS
|
||||||
|
*/
|
||||||
|
#define HI6421_BUCK012(_id, vreg, vmask, ereg, emask, sleepmask, \
|
||||||
|
etime, odelay) \
|
||||||
|
[HI6421_##_id] = { \
|
||||||
|
.desc = { \
|
||||||
|
.name = #_id, \
|
||||||
|
.ops = &hi6421_buck012_ops, \
|
||||||
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
.id = HI6421_##_id, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.min_uV = 700000, \
|
||||||
|
.n_voltages = 128, \
|
||||||
|
.uV_step = 7086, \
|
||||||
|
.vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \
|
||||||
|
.vsel_mask = vmask, \
|
||||||
|
.enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \
|
||||||
|
.enable_mask = emask, \
|
||||||
|
.enable_time = etime, \
|
||||||
|
.off_on_delay = odelay, \
|
||||||
|
}, \
|
||||||
|
.mode_mask = sleepmask, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HI6421 BUCK3/4/5 share similar configurations as LDOs, with exception
|
||||||
|
* that it supports SLEEP mode, so has different .ops.
|
||||||
|
*
|
||||||
|
* _id - LDO id name string
|
||||||
|
* v_table - voltage table
|
||||||
|
* vreg - voltage select register
|
||||||
|
* vmask - voltage select mask
|
||||||
|
* ereg - enable register
|
||||||
|
* emask - enable mask
|
||||||
|
* odelay - off/on delay time in uS
|
||||||
|
* sleepmask - mask of sleep mode
|
||||||
|
*/
|
||||||
|
#define HI6421_BUCK345(_id, v_table, vreg, vmask, ereg, emask, \
|
||||||
|
odelay, sleepmask) \
|
||||||
|
[HI6421_##_id] = { \
|
||||||
|
.desc = { \
|
||||||
|
.name = #_id, \
|
||||||
|
.ops = &hi6421_buck345_ops, \
|
||||||
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
.id = HI6421_##_id, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.n_voltages = ARRAY_SIZE(v_table), \
|
||||||
|
.volt_table = v_table, \
|
||||||
|
.vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \
|
||||||
|
.vsel_mask = vmask, \
|
||||||
|
.enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \
|
||||||
|
.enable_mask = emask, \
|
||||||
|
.enable_time = HI6421_LDO_ENABLE_TIME, \
|
||||||
|
.off_on_delay = odelay, \
|
||||||
|
}, \
|
||||||
|
.mode_mask = sleepmask, \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HI6421 regulator information */
|
||||||
|
static struct hi6421_regulator_info
|
||||||
|
hi6421_regulator_info[HI6421_NUM_REGULATORS] = {
|
||||||
|
HI6421_LDO(LDO0, ldo_0_voltages, 0x20, 0x07, 0x20, 0x10,
|
||||||
|
10000, 0x20, 8000),
|
||||||
|
HI6421_LDO_LINEAR(LDO1, 1700000, 4, 100000, 0x21, 0x03, 0x21, 0x10,
|
||||||
|
10000, 0x20, 5000),
|
||||||
|
HI6421_LDO_LINEAR(LDO2, 1050000, 8, 50000, 0x22, 0x07, 0x22, 0x10,
|
||||||
|
20000, 0x20, 8000),
|
||||||
|
HI6421_LDO_LINEAR(LDO3, 1050000, 8, 50000, 0x23, 0x07, 0x23, 0x10,
|
||||||
|
20000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO4, ldo_0_voltages, 0x24, 0x07, 0x24, 0x10,
|
||||||
|
20000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO5, ldo_0_voltages, 0x25, 0x07, 0x25, 0x10,
|
||||||
|
20000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO6, ldo_0_voltages, 0x26, 0x07, 0x26, 0x10,
|
||||||
|
20000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO7, ldo_0_voltages, 0x27, 0x07, 0x27, 0x10,
|
||||||
|
20000, 0x20, 5000),
|
||||||
|
HI6421_LDO(LDO8, ldo_8_voltages, 0x28, 0x07, 0x28, 0x10,
|
||||||
|
20000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO9, ldo_0_voltages, 0x29, 0x07, 0x29, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO10, ldo_0_voltages, 0x2a, 0x07, 0x2a, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO11, ldo_0_voltages, 0x2b, 0x07, 0x2b, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO12, ldo_0_voltages, 0x2c, 0x07, 0x2c, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO13, ldo_0_voltages, 0x2d, 0x07, 0x2d, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO14, ldo_0_voltages, 0x2e, 0x07, 0x2e, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO15, ldo_8_voltages, 0x2f, 0x07, 0x2f, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO16, ldo_0_voltages, 0x30, 0x07, 0x30, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO17, ldo_0_voltages, 0x31, 0x07, 0x31, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO18, ldo_0_voltages, 0x32, 0x07, 0x32, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO19, ldo_0_voltages, 0x33, 0x07, 0x33, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO(LDO20, ldo_0_voltages, 0x34, 0x07, 0x34, 0x10,
|
||||||
|
40000, 0x20, 8000),
|
||||||
|
HI6421_LDO_LINEAR_RANGE(LDOAUDIO, 8, ldo_audio_volt_range, 0x36,
|
||||||
|
0x70, 0x36, 0x01, 40000, 0x02, 5000),
|
||||||
|
HI6421_BUCK012(BUCK0, 0x0d, 0x7f, 0x0c, 0x01, 0x10, 400, 20000),
|
||||||
|
HI6421_BUCK012(BUCK1, 0x0f, 0x7f, 0x0e, 0x01, 0x10, 400, 20000),
|
||||||
|
HI6421_BUCK012(BUCK2, 0x11, 0x7f, 0x10, 0x01, 0x10, 350, 100),
|
||||||
|
HI6421_BUCK345(BUCK3, buck_3_voltages, 0x13, 0x07, 0x12, 0x01,
|
||||||
|
20000, 0x10),
|
||||||
|
HI6421_BUCK345(BUCK4, buck_4_voltages, 0x15, 0x07, 0x14, 0x01,
|
||||||
|
20000, 0x10),
|
||||||
|
HI6421_BUCK345(BUCK5, buck_5_voltages, 0x17, 0x07, 0x16, 0x01,
|
||||||
|
20000, 0x10),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hi6421_regulator_enable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct hi6421_regulator_pdata *pdata;
|
||||||
|
|
||||||
|
pdata = dev_get_drvdata(rdev->dev.parent);
|
||||||
|
/* hi6421 spec requires regulator enablement must be serialized:
|
||||||
|
* - Because when BUCK, LDO switching from off to on, it will have
|
||||||
|
* a huge instantaneous current; so you can not turn on two or
|
||||||
|
* more LDO or BUCKs simultaneously, or it may burn the chip.
|
||||||
|
*/
|
||||||
|
mutex_lock(&pdata->lock);
|
||||||
|
|
||||||
|
/* call regulator regmap helper */
|
||||||
|
regulator_enable_regmap(rdev);
|
||||||
|
|
||||||
|
mutex_unlock(&pdata->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
|
||||||
|
u32 reg_val;
|
||||||
|
|
||||||
|
regmap_read(rdev->regmap, rdev->desc->enable_reg, ®_val);
|
||||||
|
if (reg_val & info->mode_mask)
|
||||||
|
return REGULATOR_MODE_IDLE;
|
||||||
|
|
||||||
|
return REGULATOR_MODE_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
|
||||||
|
u32 reg_val;
|
||||||
|
|
||||||
|
regmap_read(rdev->regmap, rdev->desc->enable_reg, ®_val);
|
||||||
|
if (reg_val & info->mode_mask)
|
||||||
|
return REGULATOR_MODE_STANDBY;
|
||||||
|
|
||||||
|
return REGULATOR_MODE_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev,
|
||||||
|
unsigned int mode)
|
||||||
|
{
|
||||||
|
struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
|
||||||
|
u32 new_mode;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case REGULATOR_MODE_NORMAL:
|
||||||
|
new_mode = 0;
|
||||||
|
break;
|
||||||
|
case REGULATOR_MODE_IDLE:
|
||||||
|
new_mode = info->mode_mask;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set mode */
|
||||||
|
regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
|
||||||
|
info->mode_mask, new_mode);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev,
|
||||||
|
unsigned int mode)
|
||||||
|
{
|
||||||
|
struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
|
||||||
|
u32 new_mode;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case REGULATOR_MODE_NORMAL:
|
||||||
|
new_mode = 0;
|
||||||
|
break;
|
||||||
|
case REGULATOR_MODE_STANDBY:
|
||||||
|
new_mode = info->mode_mask;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set mode */
|
||||||
|
regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
|
||||||
|
info->mode_mask, new_mode);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int hi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev,
|
||||||
|
int input_uV, int output_uV, int load_uA)
|
||||||
|
{
|
||||||
|
struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
|
||||||
|
|
||||||
|
if (load_uA > info->eco_microamp)
|
||||||
|
return REGULATOR_MODE_NORMAL;
|
||||||
|
|
||||||
|
return REGULATOR_MODE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct regulator_ops hi6421_ldo_ops = {
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.enable = hi6421_regulator_enable,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_table,
|
||||||
|
.map_voltage = regulator_map_voltage_ascend,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.get_mode = hi6421_regulator_ldo_get_mode,
|
||||||
|
.set_mode = hi6421_regulator_ldo_set_mode,
|
||||||
|
.get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_ops hi6421_ldo_linear_ops = {
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.enable = hi6421_regulator_enable,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_linear,
|
||||||
|
.map_voltage = regulator_map_voltage_linear,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.get_mode = hi6421_regulator_ldo_get_mode,
|
||||||
|
.set_mode = hi6421_regulator_ldo_set_mode,
|
||||||
|
.get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_ops hi6421_ldo_linear_range_ops = {
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.enable = hi6421_regulator_enable,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_linear_range,
|
||||||
|
.map_voltage = regulator_map_voltage_linear_range,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.get_mode = hi6421_regulator_ldo_get_mode,
|
||||||
|
.set_mode = hi6421_regulator_ldo_set_mode,
|
||||||
|
.get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_ops hi6421_buck012_ops = {
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.enable = hi6421_regulator_enable,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_linear,
|
||||||
|
.map_voltage = regulator_map_voltage_linear,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.get_mode = hi6421_regulator_buck_get_mode,
|
||||||
|
.set_mode = hi6421_regulator_buck_set_mode,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_ops hi6421_buck345_ops = {
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.enable = hi6421_regulator_enable,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_table,
|
||||||
|
.map_voltage = regulator_map_voltage_ascend,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.get_mode = hi6421_regulator_buck_get_mode,
|
||||||
|
.set_mode = hi6421_regulator_buck_set_mode,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hi6421_regulator_register(struct platform_device *pdev,
|
||||||
|
struct regmap *rmap,
|
||||||
|
struct regulator_init_data *init_data,
|
||||||
|
int id, struct device_node *np)
|
||||||
|
{
|
||||||
|
struct hi6421_regulator_info *info = NULL;
|
||||||
|
struct regulator_config config = { };
|
||||||
|
struct regulator_dev *rdev;
|
||||||
|
|
||||||
|
/* assign per-regulator data */
|
||||||
|
info = &hi6421_regulator_info[id];
|
||||||
|
|
||||||
|
config.dev = &pdev->dev;
|
||||||
|
config.init_data = init_data;
|
||||||
|
config.driver_data = info;
|
||||||
|
config.regmap = rmap;
|
||||||
|
config.of_node = np;
|
||||||
|
|
||||||
|
/* register regulator with framework */
|
||||||
|
rdev = devm_regulator_register(&pdev->dev, &info->desc, &config);
|
||||||
|
if (IS_ERR(rdev)) {
|
||||||
|
dev_err(&pdev->dev, "failed to register regulator %s\n",
|
||||||
|
info->desc.name);
|
||||||
|
return PTR_ERR(rdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi6421_regulator_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct device_node *np;
|
||||||
|
struct hi6421_pmic *pmic;
|
||||||
|
struct hi6421_regulator_pdata *pdata;
|
||||||
|
int i, ret = 0;
|
||||||
|
|
||||||
|
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||||
|
if (!pdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
mutex_init(&pdata->lock);
|
||||||
|
platform_set_drvdata(pdev, pdata);
|
||||||
|
|
||||||
|
np = of_get_child_by_name(dev->parent->of_node, "regulators");
|
||||||
|
if (!np)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = of_regulator_match(dev, np,
|
||||||
|
hi6421_regulator_match,
|
||||||
|
ARRAY_SIZE(hi6421_regulator_match));
|
||||||
|
of_node_put(np);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "Error parsing regulator init data: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
pmic = dev_get_drvdata(dev->parent);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(hi6421_regulator_info); i++) {
|
||||||
|
ret = hi6421_regulator_register(pdev, pmic->regmap,
|
||||||
|
hi6421_regulator_match[i].init_data, i,
|
||||||
|
hi6421_regulator_match[i].of_node);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver hi6421_regulator_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "hi6421-regulator",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
.probe = hi6421_regulator_probe,
|
||||||
|
};
|
||||||
|
module_platform_driver(hi6421_regulator_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>");
|
||||||
|
MODULE_DESCRIPTION("Hi6421 regulator driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -35,4 +35,8 @@ struct regulator {
|
||||||
struct dentry *debugfs;
|
struct dentry *debugfs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
|
||||||
|
const struct regulator_desc *desc,
|
||||||
|
struct device_node **node);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
/*
|
||||||
|
* isl9305 - Intersil ISL9305 DCDC regulator
|
||||||
|
*
|
||||||
|
* Copyright 2014 Linaro Ltd
|
||||||
|
*
|
||||||
|
* Author: Mark Brown <broonie@kernel.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/platform_data/isl9305.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/regulator/driver.h>
|
||||||
|
#include <linux/regulator/of_regulator.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Registers
|
||||||
|
*/
|
||||||
|
#define ISL9305_DCD1OUT 0x0
|
||||||
|
#define ISL9305_DCD2OUT 0x1
|
||||||
|
#define ISL9305_LDO1OUT 0x2
|
||||||
|
#define ISL9305_LDO2OUT 0x3
|
||||||
|
#define ISL9305_DCD_PARAMETER 0x4
|
||||||
|
#define ISL9305_SYSTEM_PARAMETER 0x5
|
||||||
|
#define ISL9305_DCD_SRCTL 0x6
|
||||||
|
|
||||||
|
#define ISL9305_MAX_REG ISL9305_DCD_SRCTL
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DCD_PARAMETER
|
||||||
|
*/
|
||||||
|
#define ISL9305_DCD_PHASE 0x40
|
||||||
|
#define ISL9305_DCD2_ULTRA 0x20
|
||||||
|
#define ISL9305_DCD1_ULTRA 0x10
|
||||||
|
#define ISL9305_DCD2_BLD 0x08
|
||||||
|
#define ISL9305_DCD1_BLD 0x04
|
||||||
|
#define ISL9305_DCD2_MODE 0x02
|
||||||
|
#define ISL9305_DCD1_MODE 0x01
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SYSTEM_PARAMETER
|
||||||
|
*/
|
||||||
|
#define ISL9305_I2C_EN 0x40
|
||||||
|
#define ISL9305_DCDPOR_MASK 0x30
|
||||||
|
#define ISL9305_LDO2_EN 0x08
|
||||||
|
#define ISL9305_LDO1_EN 0x04
|
||||||
|
#define ISL9305_DCD2_EN 0x02
|
||||||
|
#define ISL9305_DCD1_EN 0x01
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DCD_SRCTL
|
||||||
|
*/
|
||||||
|
#define ISL9305_DCD2SR_MASK 0xc0
|
||||||
|
#define ISL9305_DCD1SR_MASK 0x07
|
||||||
|
|
||||||
|
static const struct regulator_ops isl9305_ops = {
|
||||||
|
.enable = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_linear,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_desc isl9305_regulators[] = {
|
||||||
|
[ISL9305_DCD1] = {
|
||||||
|
.name = "DCD1",
|
||||||
|
.of_match = of_match_ptr("dcd1"),
|
||||||
|
.regulators_node = of_match_ptr("regulators"),
|
||||||
|
.n_voltages = 0x70,
|
||||||
|
.min_uV = 825000,
|
||||||
|
.uV_step = 25000,
|
||||||
|
.vsel_reg = ISL9305_DCD1OUT,
|
||||||
|
.vsel_mask = 0x7f,
|
||||||
|
.enable_reg = ISL9305_SYSTEM_PARAMETER,
|
||||||
|
.enable_mask = ISL9305_DCD1_EN,
|
||||||
|
.supply_name = "VINDCD1",
|
||||||
|
.ops = &isl9305_ops,
|
||||||
|
},
|
||||||
|
[ISL9305_DCD2] = {
|
||||||
|
.name = "DCD2",
|
||||||
|
.of_match = of_match_ptr("dcd2"),
|
||||||
|
.regulators_node = of_match_ptr("regulators"),
|
||||||
|
.n_voltages = 0x70,
|
||||||
|
.min_uV = 825000,
|
||||||
|
.uV_step = 25000,
|
||||||
|
.vsel_reg = ISL9305_DCD2OUT,
|
||||||
|
.vsel_mask = 0x7f,
|
||||||
|
.enable_reg = ISL9305_SYSTEM_PARAMETER,
|
||||||
|
.enable_mask = ISL9305_DCD2_EN,
|
||||||
|
.supply_name = "VINDCD2",
|
||||||
|
.ops = &isl9305_ops,
|
||||||
|
},
|
||||||
|
[ISL9305_LDO1] = {
|
||||||
|
.name = "LDO1",
|
||||||
|
.of_match = of_match_ptr("ldo1"),
|
||||||
|
.regulators_node = of_match_ptr("regulators"),
|
||||||
|
.n_voltages = 0x37,
|
||||||
|
.min_uV = 900000,
|
||||||
|
.uV_step = 50000,
|
||||||
|
.vsel_reg = ISL9305_LDO1OUT,
|
||||||
|
.vsel_mask = 0x3f,
|
||||||
|
.enable_reg = ISL9305_SYSTEM_PARAMETER,
|
||||||
|
.enable_mask = ISL9305_LDO1_EN,
|
||||||
|
.supply_name = "VINLDO1",
|
||||||
|
.ops = &isl9305_ops,
|
||||||
|
},
|
||||||
|
[ISL9305_LDO2] = {
|
||||||
|
.name = "LDO2",
|
||||||
|
.of_match = of_match_ptr("ldo2"),
|
||||||
|
.regulators_node = of_match_ptr("regulators"),
|
||||||
|
.n_voltages = 0x37,
|
||||||
|
.min_uV = 900000,
|
||||||
|
.uV_step = 50000,
|
||||||
|
.vsel_reg = ISL9305_LDO2OUT,
|
||||||
|
.vsel_mask = 0x3f,
|
||||||
|
.enable_reg = ISL9305_SYSTEM_PARAMETER,
|
||||||
|
.enable_mask = ISL9305_LDO2_EN,
|
||||||
|
.supply_name = "VINLDO2",
|
||||||
|
.ops = &isl9305_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regmap_config isl9305_regmap = {
|
||||||
|
.reg_bits = 8,
|
||||||
|
.val_bits = 8,
|
||||||
|
|
||||||
|
.max_register = ISL9305_MAX_REG,
|
||||||
|
.cache_type = REGCACHE_RBTREE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int isl9305_i2c_probe(struct i2c_client *i2c,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct regulator_config config = { };
|
||||||
|
struct isl9305_pdata *pdata = i2c->dev.platform_data;
|
||||||
|
struct regulator_dev *rdev;
|
||||||
|
struct regmap *regmap;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
regmap = devm_regmap_init_i2c(i2c, &isl9305_regmap);
|
||||||
|
if (IS_ERR(regmap)) {
|
||||||
|
ret = PTR_ERR(regmap);
|
||||||
|
dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.dev = &i2c->dev;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(isl9305_regulators); i++) {
|
||||||
|
if (pdata)
|
||||||
|
config.init_data = pdata->init_data[i];
|
||||||
|
else
|
||||||
|
config.init_data = NULL;
|
||||||
|
|
||||||
|
rdev = devm_regulator_register(&i2c->dev,
|
||||||
|
&isl9305_regulators[i],
|
||||||
|
&config);
|
||||||
|
if (IS_ERR(rdev)) {
|
||||||
|
ret = PTR_ERR(rdev);
|
||||||
|
dev_err(&i2c->dev, "Failed to register %s: %d\n",
|
||||||
|
isl9305_regulators[i].name, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static const struct of_device_id isl9305_dt_ids[] = {
|
||||||
|
{ .compatible = "isl,isl9305" },
|
||||||
|
{ .compatible = "isl,isl9305h" },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct i2c_device_id isl9305_i2c_id[] = {
|
||||||
|
{ "isl9305", },
|
||||||
|
{ "isl9305h", },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, isl9305_i2c_id);
|
||||||
|
|
||||||
|
static struct i2c_driver isl9305_regulator_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "isl9305",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = of_match_ptr(isl9305_dt_ids),
|
||||||
|
},
|
||||||
|
.probe = isl9305_i2c_probe,
|
||||||
|
.id_table = isl9305_i2c_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_i2c_driver(isl9305_regulator_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Mark Brown");
|
||||||
|
MODULE_DESCRIPTION("Intersil ISL9305 DCDC regulator");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -526,6 +526,7 @@ static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev)
|
||||||
return REGULATOR_MODE_NORMAL;
|
return REGULATOR_MODE_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct regulator_ops mc13892_vcam_ops;
|
||||||
|
|
||||||
static int mc13892_regulator_probe(struct platform_device *pdev)
|
static int mc13892_regulator_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
@ -582,10 +583,12 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
mc13xxx_unlock(mc13892);
|
mc13xxx_unlock(mc13892);
|
||||||
|
|
||||||
mc13892_regulators[MC13892_VCAM].desc.ops->set_mode
|
/* update mc13892_vcam ops */
|
||||||
= mc13892_vcam_set_mode;
|
memcpy(&mc13892_vcam_ops, mc13892_regulators[MC13892_VCAM].desc.ops,
|
||||||
mc13892_regulators[MC13892_VCAM].desc.ops->get_mode
|
sizeof(struct regulator_ops));
|
||||||
= mc13892_vcam_get_mode;
|
mc13892_vcam_ops.set_mode = mc13892_vcam_set_mode,
|
||||||
|
mc13892_vcam_ops.get_mode = mc13892_vcam_get_mode,
|
||||||
|
mc13892_regulators[MC13892_VCAM].desc.ops = &mc13892_vcam_ops;
|
||||||
|
|
||||||
mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators,
|
mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators,
|
||||||
ARRAY_SIZE(mc13892_regulators));
|
ARRAY_SIZE(mc13892_regulators));
|
||||||
|
|
|
@ -14,8 +14,11 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/regulator/machine.h>
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <linux/regulator/driver.h>
|
||||||
#include <linux/regulator/of_regulator.h>
|
#include <linux/regulator/of_regulator.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
static void of_get_regulation_constraints(struct device_node *np,
|
static void of_get_regulation_constraints(struct device_node *np,
|
||||||
struct regulator_init_data **init_data)
|
struct regulator_init_data **init_data)
|
||||||
{
|
{
|
||||||
|
@ -189,3 +192,51 @@ int of_regulator_match(struct device *dev, struct device_node *node,
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_regulator_match);
|
EXPORT_SYMBOL_GPL(of_regulator_match);
|
||||||
|
|
||||||
|
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
|
||||||
|
const struct regulator_desc *desc,
|
||||||
|
struct device_node **node)
|
||||||
|
{
|
||||||
|
struct device_node *search, *child;
|
||||||
|
struct regulator_init_data *init_data = NULL;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (!dev->of_node || !desc->of_match)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (desc->regulators_node)
|
||||||
|
search = of_get_child_by_name(dev->of_node,
|
||||||
|
desc->regulators_node);
|
||||||
|
else
|
||||||
|
search = dev->of_node;
|
||||||
|
|
||||||
|
if (!search) {
|
||||||
|
dev_err(dev, "Failed to find regulator container node\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child_of_node(search, child) {
|
||||||
|
name = of_get_property(child, "regulator-compatible", NULL);
|
||||||
|
if (!name)
|
||||||
|
name = child->name;
|
||||||
|
|
||||||
|
if (strcmp(desc->of_match, name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
init_data = of_get_regulator_init_data(dev, child);
|
||||||
|
if (!init_data) {
|
||||||
|
dev_err(dev,
|
||||||
|
"failed to parse DT for regulator %s\n",
|
||||||
|
child->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
of_node_get(child);
|
||||||
|
*node = child;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
of_node_put(search);
|
||||||
|
|
||||||
|
return init_data;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,197 @@
|
||||||
|
/*
|
||||||
|
* Regulator driver for PWM Regulators
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 - STMicroelectronics Inc.
|
||||||
|
*
|
||||||
|
* Author: Lee Jones <lee.jones@linaro.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/regulator/driver.h>
|
||||||
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <linux/regulator/of_regulator.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/pwm.h>
|
||||||
|
|
||||||
|
struct pwm_regulator_data {
|
||||||
|
struct regulator_desc desc;
|
||||||
|
struct pwm_voltages *duty_cycle_table;
|
||||||
|
struct pwm_device *pwm;
|
||||||
|
bool enabled;
|
||||||
|
int state;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pwm_voltages {
|
||||||
|
unsigned int uV;
|
||||||
|
unsigned int dutycycle;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pwm_regulator_get_voltage_sel(struct regulator_dev *dev)
|
||||||
|
{
|
||||||
|
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return drvdata->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pwm_regulator_set_voltage_sel(struct regulator_dev *dev,
|
||||||
|
unsigned selector)
|
||||||
|
{
|
||||||
|
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
||||||
|
unsigned int pwm_reg_period;
|
||||||
|
int dutycycle;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pwm_reg_period = pwm_get_period(drvdata->pwm);
|
||||||
|
|
||||||
|
dutycycle = (pwm_reg_period *
|
||||||
|
drvdata->duty_cycle_table[selector].dutycycle) / 100;
|
||||||
|
|
||||||
|
ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&dev->dev, "Failed to configure PWM\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
drvdata->state = selector;
|
||||||
|
|
||||||
|
if (!drvdata->enabled) {
|
||||||
|
ret = pwm_enable(drvdata->pwm);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&dev->dev, "Failed to enable PWM\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
drvdata->enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pwm_regulator_list_voltage(struct regulator_dev *dev,
|
||||||
|
unsigned selector)
|
||||||
|
{
|
||||||
|
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (selector >= drvdata->desc.n_voltages)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return drvdata->duty_cycle_table[selector].uV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct regulator_ops pwm_regulator_voltage_ops = {
|
||||||
|
.set_voltage_sel = pwm_regulator_set_voltage_sel,
|
||||||
|
.get_voltage_sel = pwm_regulator_get_voltage_sel,
|
||||||
|
.list_voltage = pwm_regulator_list_voltage,
|
||||||
|
.map_voltage = regulator_map_voltage_iterate,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_desc pwm_regulator_desc = {
|
||||||
|
.name = "pwm-regulator",
|
||||||
|
.ops = &pwm_regulator_voltage_ops,
|
||||||
|
.type = REGULATOR_VOLTAGE,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.supply_name = "pwm",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pwm_regulator_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct pwm_regulator_data *drvdata;
|
||||||
|
struct property *prop;
|
||||||
|
struct regulator_dev *regulator;
|
||||||
|
struct regulator_config config = { };
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
int length, ret;
|
||||||
|
|
||||||
|
if (!np) {
|
||||||
|
dev_err(&pdev->dev, "Device Tree node missing\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
|
||||||
|
if (!drvdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(pwm_regulator_desc));
|
||||||
|
|
||||||
|
/* determine the number of voltage-table */
|
||||||
|
prop = of_find_property(np, "voltage-table", &length);
|
||||||
|
if (!prop) {
|
||||||
|
dev_err(&pdev->dev, "No voltage-table\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((length < sizeof(*drvdata->duty_cycle_table)) ||
|
||||||
|
(length % sizeof(*drvdata->duty_cycle_table))) {
|
||||||
|
dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n",
|
||||||
|
length);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
drvdata->desc.n_voltages = length / sizeof(*drvdata->duty_cycle_table);
|
||||||
|
|
||||||
|
drvdata->duty_cycle_table = devm_kzalloc(&pdev->dev,
|
||||||
|
length, GFP_KERNEL);
|
||||||
|
if (!drvdata->duty_cycle_table)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* read voltage table from DT property */
|
||||||
|
ret = of_property_read_u32_array(np, "voltage-table",
|
||||||
|
(u32 *)drvdata->duty_cycle_table,
|
||||||
|
length / sizeof(u32));
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "read voltage-table failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.init_data = of_get_regulator_init_data(&pdev->dev, np);
|
||||||
|
if (!config.init_data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
config.of_node = np;
|
||||||
|
config.dev = &pdev->dev;
|
||||||
|
config.driver_data = drvdata;
|
||||||
|
|
||||||
|
drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(drvdata->pwm)) {
|
||||||
|
dev_err(&pdev->dev, "Failed to get PWM\n");
|
||||||
|
return PTR_ERR(drvdata->pwm);
|
||||||
|
}
|
||||||
|
|
||||||
|
regulator = devm_regulator_register(&pdev->dev,
|
||||||
|
&drvdata->desc, &config);
|
||||||
|
if (IS_ERR(regulator)) {
|
||||||
|
dev_err(&pdev->dev, "Failed to register regulator %s\n",
|
||||||
|
drvdata->desc.name);
|
||||||
|
return PTR_ERR(regulator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id pwm_of_match[] = {
|
||||||
|
{ .compatible = "pwm-regulator" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, pwm_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver pwm_regulator_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "pwm-regulator",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = of_match_ptr(pwm_of_match),
|
||||||
|
},
|
||||||
|
.probe = pwm_regulator_probe,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(pwm_regulator_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
|
||||||
|
MODULE_DESCRIPTION("PWM Regulator Driver");
|
||||||
|
MODULE_ALIAS("platform:pwm-regulator");
|
|
@ -0,0 +1,798 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Sony Mobile Communications AB.
|
||||||
|
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
* only version 2 as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/regulator/driver.h>
|
||||||
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <linux/regulator/of_regulator.h>
|
||||||
|
#include <linux/mfd/qcom_rpm.h>
|
||||||
|
|
||||||
|
#include <dt-bindings/mfd/qcom-rpm.h>
|
||||||
|
|
||||||
|
#define MAX_REQUEST_LEN 2
|
||||||
|
|
||||||
|
struct request_member {
|
||||||
|
int word;
|
||||||
|
unsigned int mask;
|
||||||
|
int shift;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpm_reg_parts {
|
||||||
|
struct request_member mV; /* used if voltage is in mV */
|
||||||
|
struct request_member uV; /* used if voltage is in uV */
|
||||||
|
struct request_member ip; /* peak current in mA */
|
||||||
|
struct request_member pd; /* pull down enable */
|
||||||
|
struct request_member ia; /* average current in mA */
|
||||||
|
struct request_member fm; /* force mode */
|
||||||
|
struct request_member pm; /* power mode */
|
||||||
|
struct request_member pc; /* pin control */
|
||||||
|
struct request_member pf; /* pin function */
|
||||||
|
struct request_member enable_state; /* NCP and switch */
|
||||||
|
struct request_member comp_mode; /* NCP */
|
||||||
|
struct request_member freq; /* frequency: NCP and SMPS */
|
||||||
|
struct request_member freq_clk_src; /* clock source: SMPS */
|
||||||
|
struct request_member hpm; /* switch: control OCP and SS */
|
||||||
|
int request_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FORCE_MODE_IS_2_BITS(reg) \
|
||||||
|
(((reg)->parts->fm.mask >> (reg)->parts->fm.shift) == 3)
|
||||||
|
|
||||||
|
struct qcom_rpm_reg {
|
||||||
|
struct qcom_rpm *rpm;
|
||||||
|
|
||||||
|
struct mutex lock;
|
||||||
|
struct device *dev;
|
||||||
|
struct regulator_desc desc;
|
||||||
|
const struct rpm_reg_parts *parts;
|
||||||
|
|
||||||
|
int resource;
|
||||||
|
u32 val[MAX_REQUEST_LEN];
|
||||||
|
|
||||||
|
int uV;
|
||||||
|
int is_enabled;
|
||||||
|
|
||||||
|
bool supports_force_mode_auto;
|
||||||
|
bool supports_force_mode_bypass;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rpm_reg_parts rpm8660_ldo_parts = {
|
||||||
|
.request_len = 2,
|
||||||
|
.mV = { 0, 0x00000FFF, 0 },
|
||||||
|
.ip = { 0, 0x00FFF000, 12 },
|
||||||
|
.fm = { 0, 0x03000000, 24 },
|
||||||
|
.pc = { 0, 0x3C000000, 26 },
|
||||||
|
.pf = { 0, 0xC0000000, 30 },
|
||||||
|
.pd = { 1, 0x00000001, 0 },
|
||||||
|
.ia = { 1, 0x00001FFE, 1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rpm_reg_parts rpm8660_smps_parts = {
|
||||||
|
.request_len = 2,
|
||||||
|
.mV = { 0, 0x00000FFF, 0 },
|
||||||
|
.ip = { 0, 0x00FFF000, 12 },
|
||||||
|
.fm = { 0, 0x03000000, 24 },
|
||||||
|
.pc = { 0, 0x3C000000, 26 },
|
||||||
|
.pf = { 0, 0xC0000000, 30 },
|
||||||
|
.pd = { 1, 0x00000001, 0 },
|
||||||
|
.ia = { 1, 0x00001FFE, 1 },
|
||||||
|
.freq = { 1, 0x001FE000, 13 },
|
||||||
|
.freq_clk_src = { 1, 0x00600000, 21 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rpm_reg_parts rpm8660_switch_parts = {
|
||||||
|
.request_len = 1,
|
||||||
|
.enable_state = { 0, 0x00000001, 0 },
|
||||||
|
.pd = { 0, 0x00000002, 1 },
|
||||||
|
.pc = { 0, 0x0000003C, 2 },
|
||||||
|
.pf = { 0, 0x000000C0, 6 },
|
||||||
|
.hpm = { 0, 0x00000300, 8 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rpm_reg_parts rpm8660_ncp_parts = {
|
||||||
|
.request_len = 1,
|
||||||
|
.mV = { 0, 0x00000FFF, 0 },
|
||||||
|
.enable_state = { 0, 0x00001000, 12 },
|
||||||
|
.comp_mode = { 0, 0x00002000, 13 },
|
||||||
|
.freq = { 0, 0x003FC000, 14 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rpm_reg_parts rpm8960_ldo_parts = {
|
||||||
|
.request_len = 2,
|
||||||
|
.uV = { 0, 0x007FFFFF, 0 },
|
||||||
|
.pd = { 0, 0x00800000, 23 },
|
||||||
|
.pc = { 0, 0x0F000000, 24 },
|
||||||
|
.pf = { 0, 0xF0000000, 28 },
|
||||||
|
.ip = { 1, 0x000003FF, 0 },
|
||||||
|
.ia = { 1, 0x000FFC00, 10 },
|
||||||
|
.fm = { 1, 0x00700000, 20 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rpm_reg_parts rpm8960_smps_parts = {
|
||||||
|
.request_len = 2,
|
||||||
|
.uV = { 0, 0x007FFFFF, 0 },
|
||||||
|
.pd = { 0, 0x00800000, 23 },
|
||||||
|
.pc = { 0, 0x0F000000, 24 },
|
||||||
|
.pf = { 0, 0xF0000000, 28 },
|
||||||
|
.ip = { 1, 0x000003FF, 0 },
|
||||||
|
.ia = { 1, 0x000FFC00, 10 },
|
||||||
|
.fm = { 1, 0x00700000, 20 },
|
||||||
|
.pm = { 1, 0x00800000, 23 },
|
||||||
|
.freq = { 1, 0x1F000000, 24 },
|
||||||
|
.freq_clk_src = { 1, 0x60000000, 29 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rpm_reg_parts rpm8960_switch_parts = {
|
||||||
|
.request_len = 1,
|
||||||
|
.enable_state = { 0, 0x00000001, 0 },
|
||||||
|
.pd = { 0, 0x00000002, 1 },
|
||||||
|
.pc = { 0, 0x0000003C, 2 },
|
||||||
|
.pf = { 0, 0x000003C0, 6 },
|
||||||
|
.hpm = { 0, 0x00000C00, 10 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rpm_reg_parts rpm8960_ncp_parts = {
|
||||||
|
.request_len = 1,
|
||||||
|
.uV = { 0, 0x007FFFFF, 0 },
|
||||||
|
.enable_state = { 0, 0x00800000, 23 },
|
||||||
|
.comp_mode = { 0, 0x01000000, 24 },
|
||||||
|
.freq = { 0, 0x3E000000, 25 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Physically available PMIC regulator voltage ranges
|
||||||
|
*/
|
||||||
|
static const struct regulator_linear_range pldo_ranges[] = {
|
||||||
|
REGULATOR_LINEAR_RANGE( 750000, 0, 59, 12500),
|
||||||
|
REGULATOR_LINEAR_RANGE(1500000, 60, 123, 25000),
|
||||||
|
REGULATOR_LINEAR_RANGE(3100000, 124, 160, 50000),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_linear_range nldo_ranges[] = {
|
||||||
|
REGULATOR_LINEAR_RANGE( 750000, 0, 63, 12500),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_linear_range nldo1200_ranges[] = {
|
||||||
|
REGULATOR_LINEAR_RANGE( 375000, 0, 59, 6250),
|
||||||
|
REGULATOR_LINEAR_RANGE( 750000, 60, 123, 12500),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_linear_range smps_ranges[] = {
|
||||||
|
REGULATOR_LINEAR_RANGE( 375000, 0, 29, 12500),
|
||||||
|
REGULATOR_LINEAR_RANGE( 750000, 30, 89, 12500),
|
||||||
|
REGULATOR_LINEAR_RANGE(1500000, 90, 153, 25000),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_linear_range ftsmps_ranges[] = {
|
||||||
|
REGULATOR_LINEAR_RANGE( 350000, 0, 6, 50000),
|
||||||
|
REGULATOR_LINEAR_RANGE( 700000, 7, 63, 12500),
|
||||||
|
REGULATOR_LINEAR_RANGE(1500000, 64, 100, 50000),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_linear_range ncp_ranges[] = {
|
||||||
|
REGULATOR_LINEAR_RANGE(1500000, 0, 31, 50000),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rpm_reg_write(struct qcom_rpm_reg *vreg,
|
||||||
|
const struct request_member *req,
|
||||||
|
const int value)
|
||||||
|
{
|
||||||
|
if (WARN_ON((value << req->shift) & ~req->mask))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
vreg->val[req->word] &= ~req->mask;
|
||||||
|
vreg->val[req->word] |= value << req->shift;
|
||||||
|
|
||||||
|
return qcom_rpm_write(vreg->rpm,
|
||||||
|
vreg->resource,
|
||||||
|
vreg->val,
|
||||||
|
vreg->parts->request_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_set_mV_sel(struct regulator_dev *rdev,
|
||||||
|
unsigned selector)
|
||||||
|
{
|
||||||
|
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||||
|
const struct rpm_reg_parts *parts = vreg->parts;
|
||||||
|
const struct request_member *req = &parts->mV;
|
||||||
|
int ret = 0;
|
||||||
|
int uV;
|
||||||
|
|
||||||
|
if (req->mask == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
uV = regulator_list_voltage_linear_range(rdev, selector);
|
||||||
|
if (uV < 0)
|
||||||
|
return uV;
|
||||||
|
|
||||||
|
mutex_lock(&vreg->lock);
|
||||||
|
vreg->uV = uV;
|
||||||
|
if (vreg->is_enabled)
|
||||||
|
ret = rpm_reg_write(vreg, req, vreg->uV / 1000);
|
||||||
|
mutex_unlock(&vreg->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_set_uV_sel(struct regulator_dev *rdev,
|
||||||
|
unsigned selector)
|
||||||
|
{
|
||||||
|
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||||
|
const struct rpm_reg_parts *parts = vreg->parts;
|
||||||
|
const struct request_member *req = &parts->uV;
|
||||||
|
int ret = 0;
|
||||||
|
int uV;
|
||||||
|
|
||||||
|
if (req->mask == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
uV = regulator_list_voltage_linear_range(rdev, selector);
|
||||||
|
if (uV < 0)
|
||||||
|
return uV;
|
||||||
|
|
||||||
|
mutex_lock(&vreg->lock);
|
||||||
|
vreg->uV = uV;
|
||||||
|
if (vreg->is_enabled)
|
||||||
|
ret = rpm_reg_write(vreg, req, vreg->uV);
|
||||||
|
mutex_unlock(&vreg->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_get_voltage(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||||
|
|
||||||
|
return vreg->uV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_mV_enable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||||
|
const struct rpm_reg_parts *parts = vreg->parts;
|
||||||
|
const struct request_member *req = &parts->mV;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (req->mask == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&vreg->lock);
|
||||||
|
ret = rpm_reg_write(vreg, req, vreg->uV / 1000);
|
||||||
|
if (!ret)
|
||||||
|
vreg->is_enabled = 1;
|
||||||
|
mutex_unlock(&vreg->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_uV_enable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||||
|
const struct rpm_reg_parts *parts = vreg->parts;
|
||||||
|
const struct request_member *req = &parts->uV;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (req->mask == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&vreg->lock);
|
||||||
|
ret = rpm_reg_write(vreg, req, vreg->uV);
|
||||||
|
if (!ret)
|
||||||
|
vreg->is_enabled = 1;
|
||||||
|
mutex_unlock(&vreg->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_switch_enable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||||
|
const struct rpm_reg_parts *parts = vreg->parts;
|
||||||
|
const struct request_member *req = &parts->enable_state;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (req->mask == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&vreg->lock);
|
||||||
|
ret = rpm_reg_write(vreg, req, 1);
|
||||||
|
if (!ret)
|
||||||
|
vreg->is_enabled = 1;
|
||||||
|
mutex_unlock(&vreg->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_mV_disable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||||
|
const struct rpm_reg_parts *parts = vreg->parts;
|
||||||
|
const struct request_member *req = &parts->mV;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (req->mask == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&vreg->lock);
|
||||||
|
ret = rpm_reg_write(vreg, req, 0);
|
||||||
|
if (!ret)
|
||||||
|
vreg->is_enabled = 0;
|
||||||
|
mutex_unlock(&vreg->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_uV_disable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||||
|
const struct rpm_reg_parts *parts = vreg->parts;
|
||||||
|
const struct request_member *req = &parts->uV;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (req->mask == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&vreg->lock);
|
||||||
|
ret = rpm_reg_write(vreg, req, 0);
|
||||||
|
if (!ret)
|
||||||
|
vreg->is_enabled = 0;
|
||||||
|
mutex_unlock(&vreg->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_switch_disable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||||
|
const struct rpm_reg_parts *parts = vreg->parts;
|
||||||
|
const struct request_member *req = &parts->enable_state;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (req->mask == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&vreg->lock);
|
||||||
|
ret = rpm_reg_write(vreg, req, 0);
|
||||||
|
if (!ret)
|
||||||
|
vreg->is_enabled = 0;
|
||||||
|
mutex_unlock(&vreg->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_is_enabled(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
|
||||||
|
|
||||||
|
return vreg->is_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct regulator_ops uV_ops = {
|
||||||
|
.list_voltage = regulator_list_voltage_linear_range,
|
||||||
|
|
||||||
|
.set_voltage_sel = rpm_reg_set_uV_sel,
|
||||||
|
.get_voltage = rpm_reg_get_voltage,
|
||||||
|
|
||||||
|
.enable = rpm_reg_uV_enable,
|
||||||
|
.disable = rpm_reg_uV_disable,
|
||||||
|
.is_enabled = rpm_reg_is_enabled,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct regulator_ops mV_ops = {
|
||||||
|
.list_voltage = regulator_list_voltage_linear_range,
|
||||||
|
|
||||||
|
.set_voltage_sel = rpm_reg_set_mV_sel,
|
||||||
|
.get_voltage = rpm_reg_get_voltage,
|
||||||
|
|
||||||
|
.enable = rpm_reg_mV_enable,
|
||||||
|
.disable = rpm_reg_mV_disable,
|
||||||
|
.is_enabled = rpm_reg_is_enabled,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct regulator_ops switch_ops = {
|
||||||
|
.enable = rpm_reg_switch_enable,
|
||||||
|
.disable = rpm_reg_switch_disable,
|
||||||
|
.is_enabled = rpm_reg_is_enabled,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PM8058 regulators
|
||||||
|
*/
|
||||||
|
static const struct qcom_rpm_reg pm8058_pldo = {
|
||||||
|
.desc.linear_ranges = pldo_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
|
||||||
|
.desc.n_voltages = 161,
|
||||||
|
.desc.ops = &mV_ops,
|
||||||
|
.parts = &rpm8660_ldo_parts,
|
||||||
|
.supports_force_mode_auto = false,
|
||||||
|
.supports_force_mode_bypass = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8058_nldo = {
|
||||||
|
.desc.linear_ranges = nldo_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
|
||||||
|
.desc.n_voltages = 64,
|
||||||
|
.desc.ops = &mV_ops,
|
||||||
|
.parts = &rpm8660_ldo_parts,
|
||||||
|
.supports_force_mode_auto = false,
|
||||||
|
.supports_force_mode_bypass = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8058_smps = {
|
||||||
|
.desc.linear_ranges = smps_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(smps_ranges),
|
||||||
|
.desc.n_voltages = 154,
|
||||||
|
.desc.ops = &mV_ops,
|
||||||
|
.parts = &rpm8660_smps_parts,
|
||||||
|
.supports_force_mode_auto = false,
|
||||||
|
.supports_force_mode_bypass = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8058_ncp = {
|
||||||
|
.desc.linear_ranges = ncp_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(ncp_ranges),
|
||||||
|
.desc.n_voltages = 32,
|
||||||
|
.desc.ops = &mV_ops,
|
||||||
|
.parts = &rpm8660_ncp_parts,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8058_switch = {
|
||||||
|
.desc.ops = &switch_ops,
|
||||||
|
.parts = &rpm8660_switch_parts,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PM8901 regulators
|
||||||
|
*/
|
||||||
|
static const struct qcom_rpm_reg pm8901_pldo = {
|
||||||
|
.desc.linear_ranges = pldo_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
|
||||||
|
.desc.n_voltages = 161,
|
||||||
|
.desc.ops = &mV_ops,
|
||||||
|
.parts = &rpm8660_ldo_parts,
|
||||||
|
.supports_force_mode_auto = false,
|
||||||
|
.supports_force_mode_bypass = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8901_nldo = {
|
||||||
|
.desc.linear_ranges = nldo_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
|
||||||
|
.desc.n_voltages = 64,
|
||||||
|
.desc.ops = &mV_ops,
|
||||||
|
.parts = &rpm8660_ldo_parts,
|
||||||
|
.supports_force_mode_auto = false,
|
||||||
|
.supports_force_mode_bypass = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8901_ftsmps = {
|
||||||
|
.desc.linear_ranges = ftsmps_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(ftsmps_ranges),
|
||||||
|
.desc.n_voltages = 101,
|
||||||
|
.desc.ops = &mV_ops,
|
||||||
|
.parts = &rpm8660_smps_parts,
|
||||||
|
.supports_force_mode_auto = true,
|
||||||
|
.supports_force_mode_bypass = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8901_switch = {
|
||||||
|
.desc.ops = &switch_ops,
|
||||||
|
.parts = &rpm8660_switch_parts,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PM8921 regulators
|
||||||
|
*/
|
||||||
|
static const struct qcom_rpm_reg pm8921_pldo = {
|
||||||
|
.desc.linear_ranges = pldo_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
|
||||||
|
.desc.n_voltages = 161,
|
||||||
|
.desc.ops = &uV_ops,
|
||||||
|
.parts = &rpm8960_ldo_parts,
|
||||||
|
.supports_force_mode_auto = false,
|
||||||
|
.supports_force_mode_bypass = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8921_nldo = {
|
||||||
|
.desc.linear_ranges = nldo_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
|
||||||
|
.desc.n_voltages = 64,
|
||||||
|
.desc.ops = &uV_ops,
|
||||||
|
.parts = &rpm8960_ldo_parts,
|
||||||
|
.supports_force_mode_auto = false,
|
||||||
|
.supports_force_mode_bypass = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8921_nldo1200 = {
|
||||||
|
.desc.linear_ranges = nldo1200_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(nldo1200_ranges),
|
||||||
|
.desc.n_voltages = 124,
|
||||||
|
.desc.ops = &uV_ops,
|
||||||
|
.parts = &rpm8960_ldo_parts,
|
||||||
|
.supports_force_mode_auto = false,
|
||||||
|
.supports_force_mode_bypass = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8921_smps = {
|
||||||
|
.desc.linear_ranges = smps_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(smps_ranges),
|
||||||
|
.desc.n_voltages = 154,
|
||||||
|
.desc.ops = &uV_ops,
|
||||||
|
.parts = &rpm8960_smps_parts,
|
||||||
|
.supports_force_mode_auto = true,
|
||||||
|
.supports_force_mode_bypass = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8921_ftsmps = {
|
||||||
|
.desc.linear_ranges = ftsmps_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(ftsmps_ranges),
|
||||||
|
.desc.n_voltages = 101,
|
||||||
|
.desc.ops = &uV_ops,
|
||||||
|
.parts = &rpm8960_smps_parts,
|
||||||
|
.supports_force_mode_auto = true,
|
||||||
|
.supports_force_mode_bypass = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8921_ncp = {
|
||||||
|
.desc.linear_ranges = ncp_ranges,
|
||||||
|
.desc.n_linear_ranges = ARRAY_SIZE(ncp_ranges),
|
||||||
|
.desc.n_voltages = 32,
|
||||||
|
.desc.ops = &uV_ops,
|
||||||
|
.parts = &rpm8960_ncp_parts,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qcom_rpm_reg pm8921_switch = {
|
||||||
|
.desc.ops = &switch_ops,
|
||||||
|
.parts = &rpm8960_switch_parts,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id rpm_of_match[] = {
|
||||||
|
{ .compatible = "qcom,rpm-pm8058-pldo", .data = &pm8058_pldo },
|
||||||
|
{ .compatible = "qcom,rpm-pm8058-nldo", .data = &pm8058_nldo },
|
||||||
|
{ .compatible = "qcom,rpm-pm8058-smps", .data = &pm8058_smps },
|
||||||
|
{ .compatible = "qcom,rpm-pm8058-ncp", .data = &pm8058_ncp },
|
||||||
|
{ .compatible = "qcom,rpm-pm8058-switch", .data = &pm8058_switch },
|
||||||
|
|
||||||
|
{ .compatible = "qcom,rpm-pm8901-pldo", .data = &pm8901_pldo },
|
||||||
|
{ .compatible = "qcom,rpm-pm8901-nldo", .data = &pm8901_nldo },
|
||||||
|
{ .compatible = "qcom,rpm-pm8901-ftsmps", .data = &pm8901_ftsmps },
|
||||||
|
{ .compatible = "qcom,rpm-pm8901-switch", .data = &pm8901_switch },
|
||||||
|
|
||||||
|
{ .compatible = "qcom,rpm-pm8921-pldo", .data = &pm8921_pldo },
|
||||||
|
{ .compatible = "qcom,rpm-pm8921-nldo", .data = &pm8921_nldo },
|
||||||
|
{ .compatible = "qcom,rpm-pm8921-nldo1200", .data = &pm8921_nldo1200 },
|
||||||
|
{ .compatible = "qcom,rpm-pm8921-smps", .data = &pm8921_smps },
|
||||||
|
{ .compatible = "qcom,rpm-pm8921-ftsmps", .data = &pm8921_ftsmps },
|
||||||
|
{ .compatible = "qcom,rpm-pm8921-ncp", .data = &pm8921_ncp },
|
||||||
|
{ .compatible = "qcom,rpm-pm8921-switch", .data = &pm8921_switch },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, rpm_of_match);
|
||||||
|
|
||||||
|
static int rpm_reg_set(struct qcom_rpm_reg *vreg,
|
||||||
|
const struct request_member *req,
|
||||||
|
const int value)
|
||||||
|
{
|
||||||
|
if (req->mask == 0 || (value << req->shift) & ~req->mask)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
vreg->val[req->word] &= ~req->mask;
|
||||||
|
vreg->val[req->word] |= value << req->shift;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_of_parse_freq(struct device *dev, struct qcom_rpm_reg *vreg)
|
||||||
|
{
|
||||||
|
static const int freq_table[] = {
|
||||||
|
19200000, 9600000, 6400000, 4800000, 3840000, 3200000, 2740000,
|
||||||
|
2400000, 2130000, 1920000, 1750000, 1600000, 1480000, 1370000,
|
||||||
|
1280000, 1200000,
|
||||||
|
|
||||||
|
};
|
||||||
|
const char *key;
|
||||||
|
u32 freq;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
key = "qcom,switch-mode-frequency";
|
||||||
|
ret = of_property_read_u32(dev->of_node, key, &freq);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "regulator requires %s property\n", key);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(freq_table); i++) {
|
||||||
|
if (freq == freq_table[i]) {
|
||||||
|
rpm_reg_set(vreg, &vreg->parts->freq, i + 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_err(dev, "invalid frequency %d\n", freq);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpm_reg_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct regulator_init_data *initdata;
|
||||||
|
const struct qcom_rpm_reg *template;
|
||||||
|
const struct of_device_id *match;
|
||||||
|
struct regulator_config config = { };
|
||||||
|
struct regulator_dev *rdev;
|
||||||
|
struct qcom_rpm_reg *vreg;
|
||||||
|
const char *key;
|
||||||
|
u32 force_mode;
|
||||||
|
bool pwm;
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
match = of_match_device(rpm_of_match, &pdev->dev);
|
||||||
|
template = match->data;
|
||||||
|
|
||||||
|
initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
|
||||||
|
if (!initdata)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
vreg = devm_kmalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
|
||||||
|
if (!vreg) {
|
||||||
|
dev_err(&pdev->dev, "failed to allocate vreg\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
memcpy(vreg, template, sizeof(*vreg));
|
||||||
|
mutex_init(&vreg->lock);
|
||||||
|
vreg->dev = &pdev->dev;
|
||||||
|
vreg->desc.id = -1;
|
||||||
|
vreg->desc.owner = THIS_MODULE;
|
||||||
|
vreg->desc.type = REGULATOR_VOLTAGE;
|
||||||
|
vreg->desc.name = pdev->dev.of_node->name;
|
||||||
|
|
||||||
|
vreg->rpm = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
if (!vreg->rpm) {
|
||||||
|
dev_err(&pdev->dev, "unable to retrieve handle to rpm\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = "reg";
|
||||||
|
ret = of_property_read_u32(pdev->dev.of_node, key, &val);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to read %s\n", key);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
vreg->resource = val;
|
||||||
|
|
||||||
|
if ((vreg->parts->uV.mask || vreg->parts->mV.mask) &&
|
||||||
|
(!initdata->constraints.min_uV || !initdata->constraints.max_uV)) {
|
||||||
|
dev_err(&pdev->dev, "no voltage specified for regulator\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = "bias-pull-down";
|
||||||
|
if (of_property_read_bool(pdev->dev.of_node, key)) {
|
||||||
|
ret = rpm_reg_set(vreg, &vreg->parts->pd, 1);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "%s is invalid", key);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vreg->parts->freq.mask) {
|
||||||
|
ret = rpm_reg_of_parse_freq(&pdev->dev, vreg);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vreg->parts->pm.mask) {
|
||||||
|
key = "qcom,power-mode-hysteretic";
|
||||||
|
pwm = !of_property_read_bool(pdev->dev.of_node, key);
|
||||||
|
|
||||||
|
ret = rpm_reg_set(vreg, &vreg->parts->pm, pwm);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to set power mode\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vreg->parts->fm.mask) {
|
||||||
|
force_mode = -1;
|
||||||
|
|
||||||
|
key = "qcom,force-mode";
|
||||||
|
ret = of_property_read_u32(pdev->dev.of_node, key, &val);
|
||||||
|
if (ret == -EINVAL) {
|
||||||
|
val = QCOM_RPM_FORCE_MODE_NONE;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "failed to read %s\n", key);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If force-mode is encoded as 2 bits then the
|
||||||
|
* possible register values are:
|
||||||
|
* NONE, LPM, HPM
|
||||||
|
* otherwise:
|
||||||
|
* NONE, LPM, AUTO, HPM, BYPASS
|
||||||
|
*/
|
||||||
|
switch (val) {
|
||||||
|
case QCOM_RPM_FORCE_MODE_NONE:
|
||||||
|
force_mode = 0;
|
||||||
|
break;
|
||||||
|
case QCOM_RPM_FORCE_MODE_LPM:
|
||||||
|
force_mode = 1;
|
||||||
|
break;
|
||||||
|
case QCOM_RPM_FORCE_MODE_HPM:
|
||||||
|
if (FORCE_MODE_IS_2_BITS(vreg))
|
||||||
|
force_mode = 2;
|
||||||
|
else
|
||||||
|
force_mode = 3;
|
||||||
|
break;
|
||||||
|
case QCOM_RPM_FORCE_MODE_AUTO:
|
||||||
|
if (vreg->supports_force_mode_auto)
|
||||||
|
force_mode = 2;
|
||||||
|
break;
|
||||||
|
case QCOM_RPM_FORCE_MODE_BYPASS:
|
||||||
|
if (vreg->supports_force_mode_bypass)
|
||||||
|
force_mode = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force_mode < 0) {
|
||||||
|
dev_err(&pdev->dev, "invalid force mode\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rpm_reg_set(vreg, &vreg->parts->fm, force_mode);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "failed to set force mode\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.dev = &pdev->dev;
|
||||||
|
config.init_data = initdata;
|
||||||
|
config.driver_data = vreg;
|
||||||
|
config.of_node = pdev->dev.of_node;
|
||||||
|
rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config);
|
||||||
|
if (IS_ERR(rdev)) {
|
||||||
|
dev_err(&pdev->dev, "can't register regulator\n");
|
||||||
|
return PTR_ERR(rdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver rpm_reg_driver = {
|
||||||
|
.probe = rpm_reg_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "qcom_rpm_reg",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = of_match_ptr(rpm_of_match),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init rpm_reg_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&rpm_reg_driver);
|
||||||
|
}
|
||||||
|
subsys_initcall(rpm_reg_init);
|
||||||
|
|
||||||
|
static void __exit rpm_reg_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&rpm_reg_driver);
|
||||||
|
}
|
||||||
|
module_exit(rpm_reg_exit)
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Qualcomm RPM regulator driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* sky81452-regulator.c SKY81452 regulator driver
|
||||||
|
*
|
||||||
|
* Copyright 2014 Skyworks Solutions Inc.
|
||||||
|
* Author : Gyungoh Yoo <jack.yoo@skyworksinc.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2, or (at your option) any
|
||||||
|
* later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/regulator/driver.h>
|
||||||
|
#include <linux/regulator/of_regulator.h>
|
||||||
|
|
||||||
|
/* registers */
|
||||||
|
#define SKY81452_REG1 0x01
|
||||||
|
#define SKY81452_REG3 0x03
|
||||||
|
|
||||||
|
/* bit mask */
|
||||||
|
#define SKY81452_LEN 0x40
|
||||||
|
#define SKY81452_LOUT 0x1F
|
||||||
|
|
||||||
|
static struct regulator_ops sky81452_reg_ops = {
|
||||||
|
.list_voltage = regulator_list_voltage_linear_range,
|
||||||
|
.map_voltage = regulator_map_voltage_linear_range,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.enable = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_linear_range sky81452_reg_ranges[] = {
|
||||||
|
REGULATOR_LINEAR_RANGE(4500000, 0, 14, 250000),
|
||||||
|
REGULATOR_LINEAR_RANGE(9000000, 15, 31, 1000000),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_desc sky81452_reg = {
|
||||||
|
.name = "LOUT",
|
||||||
|
.ops = &sky81452_reg_ops,
|
||||||
|
.type = REGULATOR_VOLTAGE,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.n_voltages = SKY81452_LOUT + 1,
|
||||||
|
.linear_ranges = sky81452_reg_ranges,
|
||||||
|
.n_linear_ranges = ARRAY_SIZE(sky81452_reg_ranges),
|
||||||
|
.vsel_reg = SKY81452_REG3,
|
||||||
|
.vsel_mask = SKY81452_LOUT,
|
||||||
|
.enable_reg = SKY81452_REG1,
|
||||||
|
.enable_mask = SKY81452_LEN,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static struct regulator_init_data *sky81452_reg_parse_dt(struct device *dev)
|
||||||
|
{
|
||||||
|
struct regulator_init_data *init_data;
|
||||||
|
struct device_node *np;
|
||||||
|
|
||||||
|
np = of_get_child_by_name(dev->parent->of_node, "regulator");
|
||||||
|
if (unlikely(!np)) {
|
||||||
|
dev_err(dev, "regulator node not found");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_data = of_get_regulator_init_data(dev, np);
|
||||||
|
|
||||||
|
of_node_put(np);
|
||||||
|
return init_data;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static struct regulator_init_data *sky81452_reg_parse_dt(struct device *dev)
|
||||||
|
{
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int sky81452_reg_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
const struct regulator_init_data *init_data = dev_get_platdata(dev);
|
||||||
|
struct regulator_config config = { };
|
||||||
|
struct regulator_dev *rdev;
|
||||||
|
|
||||||
|
if (!init_data) {
|
||||||
|
init_data = sky81452_reg_parse_dt(dev);
|
||||||
|
if (IS_ERR(init_data))
|
||||||
|
return PTR_ERR(init_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.dev = dev;
|
||||||
|
config.init_data = init_data;
|
||||||
|
config.of_node = dev->of_node;
|
||||||
|
config.regmap = dev_get_drvdata(dev->parent);
|
||||||
|
|
||||||
|
rdev = devm_regulator_register(dev, &sky81452_reg, &config);
|
||||||
|
if (IS_ERR(rdev))
|
||||||
|
return PTR_ERR(rdev);
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, rdev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver sky81452_reg_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "sky81452-regulator",
|
||||||
|
},
|
||||||
|
.probe = sky81452_reg_probe,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(sky81452_reg_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Skyworks SKY81452 Regulator driver");
|
||||||
|
MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@skyworksinc.com>");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_VERSION("1.0");
|
|
@ -1,190 +0,0 @@
|
||||||
/*
|
|
||||||
* Regulator driver for ST's PWM Regulators
|
|
||||||
*
|
|
||||||
* Copyright (C) 2014 - STMicroelectronics Inc.
|
|
||||||
*
|
|
||||||
* Author: Lee Jones <lee.jones@linaro.org>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/err.h>
|
|
||||||
#include <linux/regulator/driver.h>
|
|
||||||
#include <linux/regulator/machine.h>
|
|
||||||
#include <linux/regulator/of_regulator.h>
|
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/of_device.h>
|
|
||||||
#include <linux/pwm.h>
|
|
||||||
|
|
||||||
#define ST_PWM_REG_PERIOD 8448
|
|
||||||
|
|
||||||
struct st_pwm_regulator_pdata {
|
|
||||||
const struct regulator_desc *desc;
|
|
||||||
struct st_pwm_voltages *duty_cycle_table;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct st_pwm_regulator_data {
|
|
||||||
const struct st_pwm_regulator_pdata *pdata;
|
|
||||||
struct pwm_device *pwm;
|
|
||||||
bool enabled;
|
|
||||||
int state;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct st_pwm_voltages {
|
|
||||||
unsigned int uV;
|
|
||||||
unsigned int dutycycle;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev)
|
|
||||||
{
|
|
||||||
struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
|
||||||
|
|
||||||
return drvdata->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev,
|
|
||||||
unsigned selector)
|
|
||||||
{
|
|
||||||
struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
|
||||||
int dutycycle;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
dutycycle = (ST_PWM_REG_PERIOD / 100) *
|
|
||||||
drvdata->pdata->duty_cycle_table[selector].dutycycle;
|
|
||||||
|
|
||||||
ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&dev->dev, "Failed to configure PWM\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
drvdata->state = selector;
|
|
||||||
|
|
||||||
if (!drvdata->enabled) {
|
|
||||||
ret = pwm_enable(drvdata->pwm);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&dev->dev, "Failed to enable PWM\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
drvdata->enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int st_pwm_regulator_list_voltage(struct regulator_dev *dev,
|
|
||||||
unsigned selector)
|
|
||||||
{
|
|
||||||
struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
|
||||||
|
|
||||||
if (selector >= dev->desc->n_voltages)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return drvdata->pdata->duty_cycle_table[selector].uV;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct regulator_ops st_pwm_regulator_voltage_ops = {
|
|
||||||
.set_voltage_sel = st_pwm_regulator_set_voltage_sel,
|
|
||||||
.get_voltage_sel = st_pwm_regulator_get_voltage_sel,
|
|
||||||
.list_voltage = st_pwm_regulator_list_voltage,
|
|
||||||
.map_voltage = regulator_map_voltage_iterate,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct st_pwm_voltages b2105_duty_cycle_table[] = {
|
|
||||||
{ .uV = 1114000, .dutycycle = 0, },
|
|
||||||
{ .uV = 1095000, .dutycycle = 10, },
|
|
||||||
{ .uV = 1076000, .dutycycle = 20, },
|
|
||||||
{ .uV = 1056000, .dutycycle = 30, },
|
|
||||||
{ .uV = 1036000, .dutycycle = 40, },
|
|
||||||
{ .uV = 1016000, .dutycycle = 50, },
|
|
||||||
/* WARNING: Values above 50% duty-cycle cause boot failures. */
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct regulator_desc b2105_desc = {
|
|
||||||
.name = "b2105-pwm-regulator",
|
|
||||||
.ops = &st_pwm_regulator_voltage_ops,
|
|
||||||
.type = REGULATOR_VOLTAGE,
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.n_voltages = ARRAY_SIZE(b2105_duty_cycle_table),
|
|
||||||
.supply_name = "pwm",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct st_pwm_regulator_pdata b2105_info = {
|
|
||||||
.desc = &b2105_desc,
|
|
||||||
.duty_cycle_table = b2105_duty_cycle_table,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct of_device_id st_pwm_of_match[] = {
|
|
||||||
{ .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, },
|
|
||||||
{ },
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, st_pwm_of_match);
|
|
||||||
|
|
||||||
static int st_pwm_regulator_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct st_pwm_regulator_data *drvdata;
|
|
||||||
struct regulator_dev *regulator;
|
|
||||||
struct regulator_config config = { };
|
|
||||||
struct device_node *np = pdev->dev.of_node;
|
|
||||||
const struct of_device_id *of_match;
|
|
||||||
|
|
||||||
if (!np) {
|
|
||||||
dev_err(&pdev->dev, "Device Tree node missing\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
|
|
||||||
if (!drvdata)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
of_match = of_match_device(st_pwm_of_match, &pdev->dev);
|
|
||||||
if (!of_match) {
|
|
||||||
dev_err(&pdev->dev, "failed to match of device\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
drvdata->pdata = of_match->data;
|
|
||||||
|
|
||||||
config.init_data = of_get_regulator_init_data(&pdev->dev, np);
|
|
||||||
if (!config.init_data)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
config.of_node = np;
|
|
||||||
config.dev = &pdev->dev;
|
|
||||||
config.driver_data = drvdata;
|
|
||||||
|
|
||||||
drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
|
|
||||||
if (IS_ERR(drvdata->pwm)) {
|
|
||||||
dev_err(&pdev->dev, "Failed to get PWM\n");
|
|
||||||
return PTR_ERR(drvdata->pwm);
|
|
||||||
}
|
|
||||||
|
|
||||||
regulator = devm_regulator_register(&pdev->dev,
|
|
||||||
drvdata->pdata->desc, &config);
|
|
||||||
if (IS_ERR(regulator)) {
|
|
||||||
dev_err(&pdev->dev, "Failed to register regulator %s\n",
|
|
||||||
drvdata->pdata->desc->name);
|
|
||||||
return PTR_ERR(regulator);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct platform_driver st_pwm_regulator_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "st-pwm-regulator",
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.of_match_table = of_match_ptr(st_pwm_of_match),
|
|
||||||
},
|
|
||||||
.probe = st_pwm_regulator_probe,
|
|
||||||
};
|
|
||||||
|
|
||||||
module_platform_driver(st_pwm_regulator_driver);
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
|
|
||||||
MODULE_DESCRIPTION("ST PWM Regulator Driver");
|
|
||||||
MODULE_ALIAS("platform:st_pwm-regulator");
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* isl9305 - Intersil ISL9305 DCDC regulator
|
||||||
|
*
|
||||||
|
* Copyright 2014 Linaro Ltd
|
||||||
|
*
|
||||||
|
* Author: Mark Brown <broonie@kernel.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ISL9305_H
|
||||||
|
#define __ISL9305_H
|
||||||
|
|
||||||
|
#define ISL9305_DCD1 0
|
||||||
|
#define ISL9305_DCD2 1
|
||||||
|
#define ISL9305_LDO1 2
|
||||||
|
#define ISL9305_LDO2 3
|
||||||
|
|
||||||
|
#define ISL9305_MAX_REGULATOR ISL9305_LDO2
|
||||||
|
|
||||||
|
struct regulator_init_data;
|
||||||
|
|
||||||
|
struct isl9305_pdata {
|
||||||
|
struct regulator_init_data *init_data[ISL9305_MAX_REGULATOR];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -203,6 +203,8 @@ enum regulator_type {
|
||||||
*
|
*
|
||||||
* @name: Identifying name for the regulator.
|
* @name: Identifying name for the regulator.
|
||||||
* @supply_name: Identifying the regulator supply
|
* @supply_name: Identifying the regulator supply
|
||||||
|
* @of_match: Name used to identify regulator in DT.
|
||||||
|
* @regulators_node: Name of node containing regulator definitions in DT.
|
||||||
* @id: Numerical identifier for the regulator.
|
* @id: Numerical identifier for the regulator.
|
||||||
* @ops: Regulator operations table.
|
* @ops: Regulator operations table.
|
||||||
* @irq: Interrupt number for the regulator.
|
* @irq: Interrupt number for the regulator.
|
||||||
|
@ -240,14 +242,17 @@ enum regulator_type {
|
||||||
* @bypass_val_off: Disabling value for control when using regmap set_bypass
|
* @bypass_val_off: Disabling value for control when using regmap set_bypass
|
||||||
*
|
*
|
||||||
* @enable_time: Time taken for initial enable of regulator (in uS).
|
* @enable_time: Time taken for initial enable of regulator (in uS).
|
||||||
|
* @off_on_delay: guard time (in uS), before re-enabling a regulator
|
||||||
*/
|
*/
|
||||||
struct regulator_desc {
|
struct regulator_desc {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *supply_name;
|
const char *supply_name;
|
||||||
|
const char *of_match;
|
||||||
|
const char *regulators_node;
|
||||||
int id;
|
int id;
|
||||||
bool continuous_voltage_range;
|
bool continuous_voltage_range;
|
||||||
unsigned n_voltages;
|
unsigned n_voltages;
|
||||||
struct regulator_ops *ops;
|
const struct regulator_ops *ops;
|
||||||
int irq;
|
int irq;
|
||||||
enum regulator_type type;
|
enum regulator_type type;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
@ -278,6 +283,8 @@ struct regulator_desc {
|
||||||
unsigned int bypass_val_off;
|
unsigned int bypass_val_off;
|
||||||
|
|
||||||
unsigned int enable_time;
|
unsigned int enable_time;
|
||||||
|
|
||||||
|
unsigned int off_on_delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -350,6 +357,9 @@ struct regulator_dev {
|
||||||
|
|
||||||
struct regulator_enable_gpio *ena_pin;
|
struct regulator_enable_gpio *ena_pin;
|
||||||
unsigned int ena_gpio_state:1;
|
unsigned int ena_gpio_state:1;
|
||||||
|
|
||||||
|
/* time when this regulator was disabled last time */
|
||||||
|
unsigned long last_off_jiffy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct regulator_dev *
|
struct regulator_dev *
|
||||||
|
|
Loading…
Reference in New Issue