summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/regulator/Kconfig83
-rw-r--r--drivers/regulator/Makefile9
-rw-r--r--drivers/regulator/as3711-regulator.c61
-rw-r--r--drivers/regulator/axp20x-regulator.c2
-rw-r--r--drivers/regulator/bcm590xx-regulator.c8
-rw-r--r--drivers/regulator/core.c210
-rw-r--r--drivers/regulator/da9211-regulator.c174
-rw-r--r--drivers/regulator/da9211-regulator.h7
-rw-r--r--drivers/regulator/fan53555.c195
-rw-r--r--drivers/regulator/hi6421-regulator.c634
-rw-r--r--drivers/regulator/internal.h14
-rw-r--r--drivers/regulator/isl9305.c207
-rw-r--r--drivers/regulator/ltc3589.c1
-rw-r--r--drivers/regulator/max1586.c81
-rw-r--r--drivers/regulator/max77802.c586
-rw-r--r--drivers/regulator/mc13892-regulator.c11
-rw-r--r--drivers/regulator/of_regulator.c51
-rw-r--r--drivers/regulator/pwm-regulator.c197
-rw-r--r--drivers/regulator/qcom_rpm-regulator.c798
-rw-r--r--drivers/regulator/rk808-regulator.c381
-rw-r--r--drivers/regulator/rn5t618-regulator.c143
-rw-r--r--drivers/regulator/s2mpa01.c144
-rw-r--r--drivers/regulator/s2mps11.c269
-rw-r--r--drivers/regulator/sky81452-regulator.c130
-rw-r--r--drivers/regulator/st-pwm.c190
-rw-r--r--drivers/regulator/tps65023-regulator.c3
-rw-r--r--drivers/regulator/tps65217-regulator.c114
-rw-r--r--drivers/regulator/tps65910-regulator.c13
28 files changed, 3981 insertions, 735 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 2dc8289e5dba..55d7b7b0f2e0 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -199,13 +199,14 @@ config REGULATOR_DA9210
interface.
config REGULATOR_DA9211
- tristate "Dialog Semiconductor DA9211/DA9212 regulator"
+ tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214 regulator"
depends on I2C
select REGMAP_I2C
help
- Say y here to support for the Dialog Semiconductor DA9211/DA9212.
- The DA9211/DA9212 is a multi-phase synchronous step down
- converter 12A DC-DC Buck controlled through an I2C
+ Say y here to support for the Dialog Semiconductor DA9211/DA9212
+ /DA9213/DA9214.
+ The DA9211/DA9212/DA9213/DA9214 is a multi-phase synchronous
+ step down converter 12A or 16A DC-DC Buck controlled through an I2C
interface.
config REGULATOR_DBX500_PRCMU
@@ -240,6 +241,23 @@ config REGULATOR_GPIO
and the platform has to provide a mapping of GPIO-states
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
tristate "Intersil ISL6271A Power regulator"
depends on I2C
@@ -387,6 +405,15 @@ config REGULATOR_MAX77693
and one current regulator 'CHARGER'. This is suitable for
Exynos-4x12 chips.
+config REGULATOR_MAX77802
+ tristate "Maxim 77802 regulator"
+ depends on MFD_MAX77686
+ help
+ This driver controls a Maxim 77802 regulator
+ via I2C bus. The provided regulator is suitable for
+ Exynos5420/Exynos5800 SoCs to control various voltages.
+ It includes support for control of voltage and ramp speed.
+
config REGULATOR_MC13XXX_CORE
tristate
@@ -449,6 +476,25 @@ config REGULATOR_PFUZE100
Say y here to support the regulators found on the Freescale
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
tristate "RICOH RC5T583 Power regulators"
depends on MFD_RC5T583
@@ -459,6 +505,22 @@ config REGULATOR_RC5T583
through regulator interface. The device supports multiple DCDC/LDO
outputs which can be controlled by i2c communication.
+config REGULATOR_RK808
+ tristate "Rockchip RK808 Power regulators"
+ depends on MFD_RK808
+ help
+ Select this option to enable the power regulator of ROCKCHIP
+ PMIC RK808.
+ This driver supports the control of different power rails of device
+ through regulator interface. The device supports multiple DCDC/LDO
+ outputs which can be controlled by i2c communication.
+
+config REGULATOR_RN5T618
+ tristate "Ricoh RN5T618 voltage regulators"
+ depends on MFD_RN5T618
+ help
+ Say y here to support the regulators found on Ricoh RN5T618 PMIC.
+
config REGULATOR_S2MPA01
tristate "Samsung S2MPA01 voltage regulator"
depends on MFD_SEC_CORE
@@ -483,11 +545,16 @@ config REGULATOR_S5M8767
via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
supports DVS mode with 8bits of output voltage control.
-config REGULATOR_ST_PWM
- tristate "STMicroelectronics PWM voltage regulator"
- depends on ARCH_STI
+config REGULATOR_SKY81452
+ tristate "Skyworks Solutions SKY81452 voltage regulator"
+ depends on SKY81452
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
tristate "TI Adaptive Body Bias on-chip LDO"
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index aa4a6aa7b558..1029ed39c512 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -32,7 +32,9 @@ obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.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_ISL9305) += isl9305.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
@@ -52,20 +54,25 @@ obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
+obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.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_PFUZE100) += pfuze100-regulator.o
+obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
+obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o
+obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.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_TI_ABB) += ti-abb-regulator.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index b47283f91e2d..8459b0b648cd 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -22,12 +22,10 @@
struct as3711_regulator_info {
struct regulator_desc desc;
- unsigned int max_uV;
};
struct as3711_regulator {
struct as3711_regulator_info *reg_info;
- struct regulator_dev *rdev;
};
/*
@@ -132,39 +130,37 @@ static const struct regulator_linear_range as3711_dldo_ranges[] = {
REGULATOR_LINEAR_RANGE(1750000, 0x20, 0x3f, 50000),
};
-#define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx) \
- [AS3711_REGULATOR_ ## _id] = { \
- .desc = { \
- .name = "as3711-regulator-" # _id, \
- .id = AS3711_REGULATOR_ ## _id, \
- .n_voltages = (_vmask + 1), \
- .ops = &as3711_ ## _sfx ## _ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .vsel_reg = AS3711_ ## _id ## _VOLTAGE, \
- .vsel_mask = _vmask << _vshift, \
- .enable_reg = AS3711_ ## _en_reg, \
- .enable_mask = BIT(_en_bit), \
- .min_uV = _min_uV, \
- .linear_ranges = as3711_ ## _sfx ## _ranges, \
- .n_linear_ranges = ARRAY_SIZE(as3711_ ## _sfx ## _ranges), \
- }, \
- .max_uV = _max_uV, \
+#define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _sfx) \
+ [AS3711_REGULATOR_ ## _id] = { \
+ .desc = { \
+ .name = "as3711-regulator-" # _id, \
+ .id = AS3711_REGULATOR_ ## _id, \
+ .n_voltages = (_vmask + 1), \
+ .ops = &as3711_ ## _sfx ## _ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = AS3711_ ## _id ## _VOLTAGE, \
+ .vsel_mask = _vmask, \
+ .enable_reg = AS3711_ ## _en_reg, \
+ .enable_mask = BIT(_en_bit), \
+ .linear_ranges = as3711_ ## _sfx ## _ranges, \
+ .n_linear_ranges = ARRAY_SIZE(as3711_ ## _sfx ## _ranges), \
+ }, \
}
static struct as3711_regulator_info as3711_reg_info[] = {
- AS3711_REG(SD_1, SD_CONTROL, 0, 0x7f, 0, 612500, 3350000, sd),
- AS3711_REG(SD_2, SD_CONTROL, 1, 0x7f, 0, 612500, 3350000, sd),
- AS3711_REG(SD_3, SD_CONTROL, 2, 0x7f, 0, 612500, 3350000, sd),
- AS3711_REG(SD_4, SD_CONTROL, 3, 0x7f, 0, 612500, 3350000, sd),
- AS3711_REG(LDO_1, LDO_1_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo),
- AS3711_REG(LDO_2, LDO_2_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo),
- AS3711_REG(LDO_3, LDO_3_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
- AS3711_REG(LDO_4, LDO_4_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
- AS3711_REG(LDO_5, LDO_5_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
- AS3711_REG(LDO_6, LDO_6_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
- AS3711_REG(LDO_7, LDO_7_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
- AS3711_REG(LDO_8, LDO_8_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo),
+ AS3711_REG(SD_1, SD_CONTROL, 0, 0x7f, sd),
+ AS3711_REG(SD_2, SD_CONTROL, 1, 0x7f, sd),
+ AS3711_REG(SD_3, SD_CONTROL, 2, 0x7f, sd),
+ AS3711_REG(SD_4, SD_CONTROL, 3, 0x7f, sd),
+ AS3711_REG(LDO_1, LDO_1_VOLTAGE, 7, 0x1f, aldo),
+ AS3711_REG(LDO_2, LDO_2_VOLTAGE, 7, 0x1f, aldo),
+ AS3711_REG(LDO_3, LDO_3_VOLTAGE, 7, 0x3f, dldo),
+ AS3711_REG(LDO_4, LDO_4_VOLTAGE, 7, 0x3f, dldo),
+ AS3711_REG(LDO_5, LDO_5_VOLTAGE, 7, 0x3f, dldo),
+ AS3711_REG(LDO_6, LDO_6_VOLTAGE, 7, 0x3f, dldo),
+ AS3711_REG(LDO_7, LDO_7_VOLTAGE, 7, 0x3f, dldo),
+ AS3711_REG(LDO_8, LDO_8_VOLTAGE, 7, 0x3f, dldo),
/* StepUp output voltage depends on supplying regulator */
};
@@ -263,7 +259,6 @@ static int as3711_regulator_probe(struct platform_device *pdev)
ri->desc.name);
return PTR_ERR(rdev);
}
- reg->rdev = rdev;
}
platform_set_drvdata(pdev, regs);
return 0;
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 004aadb7bcc1..2e1010a34ddc 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -245,7 +245,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
for (i = 0; i < AXP20X_REG_ID_MAX; i++) {
init_data = axp20x_matches[i].init_data;
- config.dev = &pdev->dev;
+ config.dev = pdev->dev.parent;
config.init_data = init_data;
config.regmap = axp20x->regmap;
config.of_node = axp20x_matches[i].of_node;
diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c
index 5d1fd6f3d10a..fe6ac69549a6 100644
--- a/drivers/regulator/bcm590xx-regulator.c
+++ b/drivers/regulator/bcm590xx-regulator.c
@@ -202,7 +202,6 @@ static struct bcm590xx_info bcm590xx_regs[] = {
struct bcm590xx_reg {
struct regulator_desc *desc;
struct bcm590xx *mfd;
- struct bcm590xx_info **info;
};
static int bcm590xx_get_vsel_register(int id)
@@ -389,11 +388,6 @@ static int bcm590xx_probe(struct platform_device *pdev)
if (!pmu->desc)
return -ENOMEM;
- pmu->info = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS *
- sizeof(struct bcm590xx_info *), GFP_KERNEL);
- if (!pmu->info)
- return -ENOMEM;
-
info = bcm590xx_regs;
for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) {
@@ -403,8 +397,6 @@ static int bcm590xx_probe(struct platform_device *pdev)
reg_data = NULL;
/* Register the regulators */
- pmu->info[i] = info;
-
pmu->desc[i].name = info->name;
pmu->desc[i].supply_name = info->vin_name;
pmu->desc[i].id = i;
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index a3c3785901f5..cd87c0c37034 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -102,7 +102,7 @@ static int _regulator_disable(struct regulator_dev *rdev);
static int _regulator_get_voltage(struct regulator_dev *rdev);
static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
-static void _notifier_call_chain(struct regulator_dev *rdev,
+static int _notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data);
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV);
@@ -839,7 +839,7 @@ static void print_constraints(struct regulator_dev *rdev)
static int machine_constraints_voltage(struct regulator_dev *rdev,
struct regulation_constraints *constraints)
{
- struct regulator_ops *ops = rdev->desc->ops;
+ const struct regulator_ops *ops = rdev->desc->ops;
int ret;
/* 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,
struct regulation_constraints *constraints)
{
- struct regulator_ops *ops = rdev->desc->ops;
+ const struct regulator_ops *ops = rdev->desc->ops;
int ret;
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)
{
int ret = 0;
- struct regulator_ops *ops = rdev->desc->ops;
+ const struct regulator_ops *ops = rdev->desc->ops;
if (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;
}
+/**
+ * _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)
{
int ret, delay;
@@ -1774,6 +1813,31 @@ static int _regulator_do_enable(struct regulator_dev *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) {
ret = regulator_ena_gpio_ctrl(rdev, true);
if (ret < 0)
@@ -1792,40 +1856,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
* together. */
trace_regulator_enable_delay(rdev_get_name(rdev));
- /*
- * 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);
- }
+ _regulator_enable_delay(delay);
trace_regulator_enable_complete(rdev_get_name(rdev));
@@ -1919,6 +1950,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
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));
return 0;
@@ -2208,9 +2245,9 @@ EXPORT_SYMBOL_GPL(regulator_count_voltages);
*/
int regulator_list_voltage(struct regulator *regulator, unsigned selector)
{
- struct regulator_dev *rdev = regulator->rdev;
- struct regulator_ops *ops = rdev->desc->ops;
- int ret;
+ struct regulator_dev *rdev = regulator->rdev;
+ const struct regulator_ops *ops = rdev->desc->ops;
+ int ret;
if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector)
return rdev->desc->fixed_uV;
@@ -2270,8 +2307,8 @@ int regulator_get_hardware_vsel_register(struct regulator *regulator,
unsigned *vsel_reg,
unsigned *vsel_mask)
{
- struct regulator_dev *rdev = regulator->rdev;
- struct regulator_ops *ops = rdev->desc->ops;
+ struct regulator_dev *rdev = regulator->rdev;
+ const struct regulator_ops *ops = rdev->desc->ops;
if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap)
return -EOPNOTSUPP;
@@ -2297,8 +2334,8 @@ EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register);
int regulator_list_hardware_vsel(struct regulator *regulator,
unsigned selector)
{
- struct regulator_dev *rdev = regulator->rdev;
- struct regulator_ops *ops = rdev->desc->ops;
+ struct regulator_dev *rdev = regulator->rdev;
+ const struct regulator_ops *ops = rdev->desc->ops;
if (selector >= rdev->desc->n_voltages)
return -EINVAL;
@@ -2369,6 +2406,55 @@ int regulator_is_supported_voltage(struct regulator *regulator,
}
EXPORT_SYMBOL_GPL(regulator_is_supported_voltage);
+static int _regulator_call_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV,
+ unsigned *selector)
+{
+ struct pre_voltage_change_data data;
+ int ret;
+
+ data.old_uV = _regulator_get_voltage(rdev);
+ data.min_uV = min_uV;
+ data.max_uV = max_uV;
+ ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE,
+ &data);
+ if (ret & NOTIFY_STOP_MASK)
+ return -EINVAL;
+
+ ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, selector);
+ if (ret >= 0)
+ return ret;
+
+ _notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE,
+ (void *)data.old_uV);
+
+ return ret;
+}
+
+static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev,
+ int uV, unsigned selector)
+{
+ struct pre_voltage_change_data data;
+ int ret;
+
+ data.old_uV = _regulator_get_voltage(rdev);
+ data.min_uV = uV;
+ data.max_uV = uV;
+ ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE,
+ &data);
+ if (ret & NOTIFY_STOP_MASK)
+ return -EINVAL;
+
+ ret = rdev->desc->ops->set_voltage_sel(rdev, selector);
+ if (ret >= 0)
+ return ret;
+
+ _notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE,
+ (void *)data.old_uV);
+
+ return ret;
+}
+
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
@@ -2396,8 +2482,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
}
if (rdev->desc->ops->set_voltage) {
- ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
- &selector);
+ ret = _regulator_call_set_voltage(rdev, min_uV, max_uV,
+ &selector);
if (ret >= 0) {
if (rdev->desc->ops->list_voltage)
@@ -2432,8 +2518,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
if (old_selector == selector)
ret = 0;
else
- ret = rdev->desc->ops->set_voltage_sel(
- rdev, ret);
+ ret = _regulator_call_set_voltage_sel(
+ rdev, best_val, selector);
} else {
ret = -EINVAL;
}
@@ -2572,8 +2658,8 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage);
int regulator_set_voltage_time(struct regulator *regulator,
int old_uV, int new_uV)
{
- struct regulator_dev *rdev = regulator->rdev;
- struct regulator_ops *ops = rdev->desc->ops;
+ struct regulator_dev *rdev = regulator->rdev;
+ const struct regulator_ops *ops = rdev->desc->ops;
int old_sel = -1;
int new_sel = -1;
int voltage;
@@ -3079,11 +3165,11 @@ EXPORT_SYMBOL_GPL(regulator_unregister_notifier);
/* notify regulator consumers and downstream regulator consumers.
* Note mutex must be held by caller.
*/
-static void _notifier_call_chain(struct regulator_dev *rdev,
+static int _notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data)
{
/* call rdev chain first */
- blocking_notifier_call_chain(&rdev->notifier, event, data);
+ return blocking_notifier_call_chain(&rdev->notifier, event, data);
}
/**
@@ -3336,9 +3422,9 @@ EXPORT_SYMBOL_GPL(regulator_mode_to_status);
*/
static int add_regulator_attributes(struct regulator_dev *rdev)
{
- struct device *dev = &rdev->dev;
- struct regulator_ops *ops = rdev->desc->ops;
- int status = 0;
+ struct device *dev = &rdev->dev;
+ const struct regulator_ops *ops = rdev->desc->ops;
+ int status = 0;
/* some attributes need specific methods to be displayed */
if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
@@ -3516,12 +3602,17 @@ regulator_register(const struct regulator_desc *regulator_desc,
return ERR_PTR(-EINVAL);
}
- init_data = config->init_data;
-
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
if (rdev == NULL)
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(&regulator_list_mutex);
mutex_init(&rdev->mutex);
@@ -3548,7 +3639,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
/* register with sysfs */
rdev->dev.class = &regulator_class;
- rdev->dev.of_node = of_node_get(config->of_node);
rdev->dev.parent = dev;
dev_set_name(&rdev->dev, "regulator.%d",
atomic_inc_return(&regulator_no) - 1);
@@ -3905,7 +3995,7 @@ core_initcall(regulator_init);
static int __init regulator_init_complete(void)
{
struct regulator_dev *rdev;
- struct regulator_ops *ops;
+ const struct regulator_ops *ops;
struct regulation_constraints *c;
int enabled, ret;
diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c
index 1482adafa1ad..c78d2106d6cb 100644
--- a/drivers/regulator/da9211-regulator.c
+++ b/drivers/regulator/da9211-regulator.c
@@ -1,5 +1,5 @@
/*
- * da9211-regulator.c - Regulator device driver for DA9211
+ * da9211-regulator.c - Regulator device driver for DA9211/DA9213
* Copyright (C) 2014 Dialog Semiconductor Ltd.
*
* This library is free software; you can redistribute it and/or
@@ -24,9 +24,14 @@
#include <linux/regmap.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/regulator/da9211.h>
#include "da9211-regulator.h"
+/* DEVICE IDs */
+#define DA9211_DEVICE_ID 0x22
+#define DA9213_DEVICE_ID 0x23
+
#define DA9211_BUCK_MODE_SLEEP 1
#define DA9211_BUCK_MODE_SYNC 2
#define DA9211_BUCK_MODE_AUTO 3
@@ -42,6 +47,7 @@ struct da9211 {
struct regulator_dev *rdev[DA9211_MAX_REGULATORS];
int num_regulator;
int chip_irq;
+ int chip_id;
};
static const struct regmap_range_cfg da9211_regmap_range[] = {
@@ -52,14 +58,14 @@ static const struct regmap_range_cfg da9211_regmap_range[] = {
.window_start = 0,
.window_len = 256,
.range_min = 0,
- .range_max = 2*256,
+ .range_max = 5*128,
},
};
static const struct regmap_config da9211_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = 2 * 256,
+ .max_register = 5 * 128,
.ranges = da9211_regmap_range,
.num_ranges = ARRAY_SIZE(da9211_regmap_range),
};
@@ -69,11 +75,20 @@ static const struct regmap_config da9211_regmap_config = {
#define DA9211_MAX_MV 1570
#define DA9211_STEP_MV 10
-/* Current limits for buck (uA) indices corresponds with register values */
+/* Current limits for DA9211 buck (uA) indices
+ * corresponds with register values
+ */
static const int da9211_current_limits[] = {
2000000, 2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000,
3600000, 3800000, 4000000, 4200000, 4400000, 4600000, 4800000, 5000000
};
+/* Current limits for DA9213 buck (uA) indices
+ * corresponds with register values
+ */
+static const int da9213_current_limits[] = {
+ 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000,
+ 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000
+};
static unsigned int da9211_buck_get_mode(struct regulator_dev *rdev)
{
@@ -129,12 +144,26 @@ static int da9211_set_current_limit(struct regulator_dev *rdev, int min,
{
int id = rdev_get_id(rdev);
struct da9211 *chip = rdev_get_drvdata(rdev);
- int i;
+ int i, max_size;
+ const int *current_limits;
+
+ switch (chip->chip_id) {
+ case DA9211:
+ current_limits = da9211_current_limits;
+ max_size = ARRAY_SIZE(da9211_current_limits)-1;
+ break;
+ case DA9213:
+ current_limits = da9213_current_limits;
+ max_size = ARRAY_SIZE(da9213_current_limits)-1;
+ break;
+ default:
+ return -EINVAL;
+ }
/* search for closest to maximum */
- for (i = ARRAY_SIZE(da9211_current_limits)-1; i >= 0; i--) {
- if (min <= da9211_current_limits[i] &&
- max >= da9211_current_limits[i]) {
+ for (i = max_size; i >= 0; i--) {
+ if (min <= current_limits[i] &&
+ max >= current_limits[i]) {
return regmap_update_bits(chip->regmap,
DA9211_REG_BUCK_ILIM,
(0x0F << id*4), (i << id*4));
@@ -150,14 +179,28 @@ static int da9211_get_current_limit(struct regulator_dev *rdev)
struct da9211 *chip = rdev_get_drvdata(rdev);
unsigned int data;
int ret;
+ const int *current_limits;
+
+ switch (chip->chip_id) {
+ case DA9211:
+ current_limits = da9211_current_limits;
+ break;
+ case DA9213:
+ current_limits = da9213_current_limits;
+ break;
+ default:
+ return -EINVAL;
+ }
ret = regmap_read(chip->regmap, DA9211_REG_BUCK_ILIM, &data);
if (ret < 0)
return ret;
- /* select one of 16 values: 0000 (2000mA) to 1111 (5000mA) */
+ /* select one of 16 values: 0000 (2000mA or 3000mA)
+ * to 1111 (5000mA or 6000mA).
+ */
data = (data >> id*4) & 0x0F;
- return da9211_current_limits[data];
+ return current_limits[data];
}
static struct regulator_ops da9211_buck_ops = {
@@ -194,6 +237,59 @@ static struct regulator_desc da9211_regulators[] = {
DA9211_BUCK(BUCKB),
};
+#ifdef CONFIG_OF
+static struct of_regulator_match da9211_matches[] = {
+ [DA9211_ID_BUCKA] = { .name = "BUCKA" },
+ [DA9211_ID_BUCKB] = { .name = "BUCKB" },
+ };
+
+static struct da9211_pdata *da9211_parse_regulators_dt(
+ struct device *dev)
+{
+ struct da9211_pdata *pdata;
+ struct device_node *node;
+ int i, num, n;
+
+ node = of_get_child_by_name(dev->of_node, "regulators");
+ if (!node) {
+ dev_err(dev, "regulators node not found\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ num = of_regulator_match(dev, node, da9211_matches,
+ ARRAY_SIZE(da9211_matches));
+ of_node_put(node);
+ if (num < 0) {
+ dev_err(dev, "Failed to match regulators\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->num_buck = num;
+
+ n = 0;
+ for (i = 0; i < ARRAY_SIZE(da9211_matches); i++) {
+ if (!da9211_matches[i].init_data)
+ continue;
+
+ pdata->init_data[n] = da9211_matches[i].init_data;
+
+ n++;
+ }
+
+ return pdata;
+}
+#else
+static struct da9211_pdata *da9211_parse_regulators_dt(
+ struct device *dev)
+{
+ return ERR_PTR(-ENODEV);
+}
+#endif
+
static irqreturn_t da9211_irq_handler(int irq, void *data)
{
struct da9211 *chip = data;
@@ -264,13 +360,11 @@ static int da9211_regulator_init(struct da9211 *chip)
}
for (i = 0; i < chip->num_regulator; i++) {
- if (chip->pdata)
- config.init_data =
- &(chip->pdata->init_data[i]);
-
+ config.init_data = chip->pdata->init_data[i];
config.dev = chip->dev;
config.driver_data = chip;
config.regmap = chip->regmap;
+ config.of_node = chip->dev->of_node;
chip->rdev[i] = devm_regulator_register(chip->dev,
&da9211_regulators[i], &config);
@@ -282,7 +376,7 @@ static int da9211_regulator_init(struct da9211 *chip)
if (chip->chip_irq != 0) {
ret = regmap_update_bits(chip->regmap,
- DA9211_REG_MASK_B, DA9211_M_OV_CURR_A << i, 1);
+ DA9211_REG_MASK_B, DA9211_M_OV_CURR_A << i, 0);
if (ret < 0) {
dev_err(chip->dev,
"Failed to update mask reg: %d\n", ret);
@@ -293,6 +387,7 @@ static int da9211_regulator_init(struct da9211 *chip)
return 0;
}
+
/*
* I2C driver interface functions
*/
@@ -301,14 +396,17 @@ static int da9211_i2c_probe(struct i2c_client *i2c,
{
struct da9211 *chip;
int error, ret;
+ unsigned int data;
chip = devm_kzalloc(&i2c->dev, sizeof(struct da9211), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
chip->dev = &i2c->dev;
chip->regmap = devm_regmap_init_i2c(i2c, &da9211_regmap_config);
if (IS_ERR(chip->regmap)) {
error = PTR_ERR(chip->regmap);
- dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ dev_err(chip->dev, "Failed to allocate register map: %d\n",
error);
return error;
}
@@ -316,11 +414,33 @@ static int da9211_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, chip);
chip->pdata = i2c->dev.platform_data;
- if (!chip->pdata) {
- dev_err(&i2c->dev, "No platform init data supplied\n");
+
+ ret = regmap_read(chip->regmap, DA9211_REG_DEVICE_ID, &data);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read DEVICE_ID reg: %d\n", ret);
+ return ret;
+ }
+
+ switch (data) {
+ case DA9211_DEVICE_ID:
+ chip->chip_id = DA9211;
+ break;
+ case DA9213_DEVICE_ID:
+ chip->chip_id = DA9213;
+ break;
+ default:
+ dev_err(chip->dev, "Unsupported device id = 0x%x.\n", data);
return -ENODEV;
}
+ if (!chip->pdata)
+ chip->pdata = da9211_parse_regulators_dt(chip->dev);
+
+ if (IS_ERR(chip->pdata)) {
+ dev_err(chip->dev, "No regulators defined for the platform\n");
+ return PTR_ERR(chip->pdata);
+ }
+
chip->chip_irq = i2c->irq;
if (chip->chip_irq != 0) {
@@ -340,22 +460,32 @@ static int da9211_i2c_probe(struct i2c_client *i2c,
ret = da9211_regulator_init(chip);
if (ret < 0)
- dev_err(&i2c->dev, "Failed to initialize regulator: %d\n", ret);
+ dev_err(chip->dev, "Failed to initialize regulator: %d\n", ret);
return ret;
}
static const struct i2c_device_id da9211_i2c_id[] = {
- {"da9211", 0},
+ {"da9211", DA9211},
+ {"da9213", DA9213},
{},
};
-
MODULE_DEVICE_TABLE(i2c, da9211_i2c_id);
+#ifdef CONFIG_OF
+static const struct of_device_id da9211_dt_ids[] = {
+ { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] },
+ { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] },
+ {},
+};
+MODULE_DEVICE_TABLE(of, da9211_dt_ids);
+#endif
+
static struct i2c_driver da9211_regulator_driver = {
.driver = {
.name = "da9211",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(da9211_dt_ids),
},
.probe = da9211_i2c_probe,
.id_table = da9211_i2c_id,
@@ -364,5 +494,5 @@ static struct i2c_driver da9211_regulator_driver = {
module_i2c_driver(da9211_regulator_driver);
MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
-MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211");
+MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/da9211-regulator.h b/drivers/regulator/da9211-regulator.h
index 88b1769e8058..93fa9df2721c 100644
--- a/drivers/regulator/da9211-regulator.h
+++ b/drivers/regulator/da9211-regulator.h
@@ -1,5 +1,5 @@
/*
- * da9211-regulator.h - Regulator definitions for DA9211
+ * da9211-regulator.h - Regulator definitions for DA9211/DA9213
* Copyright (C) 2014 Dialog Semiconductor Ltd.
*
* This library is free software; you can redistribute it and/or
@@ -53,12 +53,15 @@
/* BUCK Phase Selection*/
#define DA9211_REG_CONFIG_E 0x147
+/* Device ID */
+#define DA9211_REG_DEVICE_ID 0x201
+
/*
* Registers bits
*/
/* DA9211_REG_PAGE_CON (addr=0x00) */
#define DA9211_REG_PAGE_SHIFT 1
-#define DA9211_REG_PAGE_MASK 0x02
+#define DA9211_REG_PAGE_MASK 0x06
/* On I2C registers 0x00 - 0xFF */
#define DA9211_REG_PAGE0 0
/* On I2C registers 0x100 - 0x1FF */
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index 714fd9a89aa1..f8e4257aef92 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -18,6 +18,8 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of_device.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@@ -50,6 +52,11 @@
#define FAN53555_NVOLTAGES 64 /* Numbers of voltages */
+enum fan53555_vendor {
+ FAN53555_VENDOR_FAIRCHILD = 0,
+ FAN53555_VENDOR_SILERGY,
+};
+
/* IC Type */
enum {
FAN53555_CHIP_ID_00 = 0,
@@ -60,7 +67,12 @@ enum {
FAN53555_CHIP_ID_05,
};
+enum {
+ SILERGY_SYR82X = 8,
+};
+
struct fan53555_device_info {
+ enum fan53555_vendor vendor;
struct regmap *regmap;
struct device *dev;
struct regulator_desc desc;
@@ -135,6 +147,38 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
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 = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -146,8 +190,50 @@ static struct regulator_ops fan53555_regulator_ops = {
.is_enabled = regulator_is_enabled_regmap,
.set_mode = fan53555_set_mode,
.get_mode = fan53555_get_mode,
+ .set_ramp_delay = fan53555_set_ramp,
};
+static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
+{
+ /* Init voltage range and step */
+ switch (di->chip_id) {
+ case FAN53555_CHIP_ID_00:
+ case FAN53555_CHIP_ID_01:
+ case FAN53555_CHIP_ID_03:
+ case FAN53555_CHIP_ID_05:
+ di->vsel_min = 600000;
+ di->vsel_step = 10000;
+ break;
+ case FAN53555_CHIP_ID_04:
+ di->vsel_min = 603000;
+ di->vsel_step = 12826;
+ break;
+ default:
+ dev_err(di->dev,
+ "Chip ID %d not supported!\n", di->chip_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di)
+{
+ /* Init voltage range and step */
+ switch (di->chip_id) {
+ 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:
@@ -156,7 +242,7 @@ static struct regulator_ops fan53555_regulator_ops = {
static int fan53555_device_setup(struct fan53555_device_info *di,
struct fan53555_platform_data *pdata)
{
- unsigned int reg, data, mask;
+ int ret = 0;
/* Setup voltage control register */
switch (pdata->sleep_vsel_id) {
@@ -172,33 +258,20 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
dev_err(di->dev, "Invalid VSEL ID!\n");
return -EINVAL;
}
- /* Init voltage range and step */
- switch (di->chip_id) {
- case FAN53555_CHIP_ID_00:
- case FAN53555_CHIP_ID_01:
- case FAN53555_CHIP_ID_03:
- case FAN53555_CHIP_ID_05:
- di->vsel_min = 600000;
- di->vsel_step = 10000;
+
+ switch (di->vendor) {
+ case FAN53555_VENDOR_FAIRCHILD:
+ ret = fan53555_voltages_setup_fairchild(di);
break;
- case FAN53555_CHIP_ID_04:
- di->vsel_min = 603000;
- di->vsel_step = 12826;
+ case FAN53555_VENDOR_SILERGY:
+ ret = fan53555_voltages_setup_silergy(di);
break;
default:
- dev_err(di->dev,
- "Chip ID[%d]\n not supported!\n", di->chip_id);
+ dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
return -EINVAL;
}
- /* Init slew rate */
- if (pdata->slew_rate & 0x7)
- di->slew_rate = pdata->slew_rate;
- else
- di->slew_rate = FAN53555_SLEW_RATE_64MV;
- reg = FAN53555_CONTROL;
- data = di->slew_rate << CTL_SLEW_SHIFT;
- mask = CTL_SLEW_MASK;
- return regmap_update_bits(di->regmap, reg, mask, data);
+
+ return ret;
}
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;
rdesc->name = "fan53555-reg";
+ rdesc->supply_name = "vin";
rdesc->ops = &fan53555_regulator_ops;
rdesc->type = REGULATOR_VOLTAGE;
rdesc->n_voltages = FAN53555_NVOLTAGES;
@@ -227,9 +301,46 @@ static struct regmap_config fan53555_regmap_config = {
.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,
const struct i2c_device_id *id)
{
+ struct device_node *np = client->dev.of_node;
struct fan53555_device_info *di;
struct fan53555_platform_data *pdata;
struct regulator_config config = { };
@@ -237,6 +348,9 @@ static int fan53555_regulator_probe(struct i2c_client *client,
int ret;
pdata = dev_get_platdata(&client->dev);
+ if (!pdata)
+ pdata = fan53555_parse_dt(&client->dev, np);
+
if (!pdata || !pdata->regulator) {
dev_err(&client->dev, "Platform data not found!\n");
return -ENODEV;
@@ -247,13 +361,35 @@ static int fan53555_regulator_probe(struct i2c_client *client,
if (!di)
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);
if (IS_ERR(di->regmap)) {
dev_err(&client->dev, "Failed to allocate regmap!\n");
return PTR_ERR(di->regmap);
}
di->dev = &client->dev;
- di->regulator = pdata->regulator;
i2c_set_clientdata(client, di);
/* Get chip ID */
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.regmap = di->regmap;
config.driver_data = di;
+ config.of_node = np;
+
ret = fan53555_regulator_register(di, &config);
if (ret < 0)
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[] = {
- {"fan53555", -1},
+ {
+ .name = "fan53555",
+ .driver_data = FAN53555_VENDOR_FAIRCHILD
+ }, {
+ .name = "syr82x",
+ .driver_data = FAN53555_VENDOR_SILERGY
+ },
{ },
};
static struct i2c_driver fan53555_regulator_driver = {
.driver = {
.name = "fan53555-regulator",
+ .of_match_table = of_match_ptr(fan53555_dt_ids),
},
.probe = fan53555_regulator_probe,
.id_table = fan53555_id,
diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c
new file mode 100644
index 000000000000..156d0d1a55f1
--- /dev/null
+++ b/drivers/regulator/hi6421-regulator.c
@@ -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, &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, &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");
diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h
index 84bbda10c396..80ba2a35a04b 100644
--- a/drivers/regulator/internal.h
+++ b/drivers/regulator/internal.h
@@ -35,4 +35,18 @@ struct regulator {
struct dentry *debugfs;
};
+#ifdef CONFIG_OF
+struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
+ const struct regulator_desc *desc,
+ struct device_node **node);
+#else
+static inline struct regulator_init_data *
+regulator_of_get_init_data(struct device *dev,
+ const struct regulator_desc *desc,
+ struct device_node **node)
+{
+ return NULL;
+}
+#endif
+
#endif
diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c
new file mode 100644
index 000000000000..92fefd98da58
--- /dev/null
+++ b/drivers/regulator/isl9305.c
@@ -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");
diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c
index c756955bfcc5..0ce8e4e0fa73 100644
--- a/drivers/regulator/ltc3589.c
+++ b/drivers/regulator/ltc3589.c
@@ -372,6 +372,7 @@ static bool ltc3589_volatile_reg(struct device *dev, unsigned int reg)
switch (reg) {
case LTC3589_IRQSTAT:
case LTC3589_PGSTAT:
+ case LTC3589_VCCR:
return true;
}
return false;
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index d23d0577754b..86db310d5304 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -24,6 +24,8 @@
#include <linux/regulator/driver.h>
#include <linux/slab.h>
#include <linux/regulator/max1586.h>
+#include <linux/of_device.h>
+#include <linux/regulator/of_regulator.h>
#define MAX1586_V3_MAX_VSEL 31
#define MAX1586_V6_MAX_VSEL 3
@@ -157,13 +159,87 @@ static struct regulator_desc max1586_reg[] = {
},
};
+static int of_get_max1586_platform_data(struct device *dev,
+ struct max1586_platform_data *pdata)
+{
+ struct max1586_subdev_data *sub;
+ struct of_regulator_match rmatch[ARRAY_SIZE(max1586_reg)];
+ struct device_node *np = dev->of_node;
+ int i, matched;
+
+ if (of_property_read_u32(np, "v3-gain",
+ &pdata->v3_gain) < 0) {
+ dev_err(dev, "%s has no 'v3-gain' property\n", np->full_name);
+ return -EINVAL;
+ }
+
+ np = of_get_child_by_name(np, "regulators");
+ if (!np) {
+ dev_err(dev, "missing 'regulators' subnode in DT\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(rmatch); i++)
+ rmatch[i].name = max1586_reg[i].name;
+
+ matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch));
+ of_node_put(np);
+ /*
+ * If matched is 0, ie. neither Output_V3 nor Output_V6 have been found,
+ * return 0, which signals the normal situation where no subregulator is
+ * available. This is normal because the max1586 doesn't provide any
+ * readback support, so the subregulators can't report any status
+ * anyway. If matched < 0, return the error.
+ */
+ if (matched <= 0)
+ return matched;
+
+ pdata->subdevs = devm_kzalloc(dev, sizeof(struct max1586_subdev_data) *
+ matched, GFP_KERNEL);
+ if (!pdata->subdevs)
+ return -ENOMEM;
+
+ pdata->num_subdevs = matched;
+ sub = pdata->subdevs;
+
+ for (i = 0; i < matched; i++) {
+ sub->id = i;
+ sub->name = rmatch[i].of_node->name;
+ sub->platform_data = rmatch[i].init_data;
+ sub++;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id max1586_of_match[] = {
+ { .compatible = "maxim,max1586", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, max1586_of_match);
+
static int max1586_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
- struct max1586_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct max1586_platform_data *pdata, pdata_of;
struct regulator_config config = { };
struct max1586_data *max1586;
- int i, id;
+ int i, id, ret;
+ const struct of_device_id *match;
+
+ pdata = dev_get_platdata(&client->dev);
+ if (client->dev.of_node && !pdata) {
+ match = of_match_device(of_match_ptr(max1586_of_match),
+ &client->dev);
+ if (!match) {
+ dev_err(&client->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+ ret = of_get_max1586_platform_data(&client->dev, &pdata_of);
+ if (ret < 0)
+ return ret;
+ pdata = &pdata_of;
+ }
max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data),
GFP_KERNEL);
@@ -229,6 +305,7 @@ static struct i2c_driver max1586_pmic_driver = {
.driver = {
.name = "max1586",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(max1586_of_match),
},
.id_table = max1586_id,
};
diff --git a/drivers/regulator/max77802.c b/drivers/regulator/max77802.c
new file mode 100644
index 000000000000..d89792b084e9
--- /dev/null
+++ b/drivers/regulator/max77802.c
@@ -0,0 +1,586 @@
+/*
+ * max77802.c - Regulator driver for the Maxim 77802
+ *
+ * Copyright (C) 2013-2014 Google, Inc
+ * Simon Glass <sjg@chromium.org>
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Chiwoong Byun <woong.byun@smasung.com>
+ * Jonghwa Lee <jonghwa3.lee@samsung.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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This driver is based on max8997.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/gpio/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/max77686.h>
+#include <linux/mfd/max77686-private.h>
+
+/* Default ramp delay in case it is not manually set */
+#define MAX77802_RAMP_DELAY 100000 /* uV/us */
+
+#define MAX77802_OPMODE_SHIFT_LDO 6
+#define MAX77802_OPMODE_BUCK234_SHIFT 4
+#define MAX77802_OPMODE_MASK 0x3
+
+#define MAX77802_VSEL_MASK 0x3F
+#define MAX77802_DVS_VSEL_MASK 0xFF
+
+#define MAX77802_RAMP_RATE_MASK_2BIT 0xC0
+#define MAX77802_RAMP_RATE_SHIFT_2BIT 6
+#define MAX77802_RAMP_RATE_MASK_4BIT 0xF0
+#define MAX77802_RAMP_RATE_SHIFT_4BIT 4
+
+/* MAX77802 has two register formats: 2-bit and 4-bit */
+static const unsigned int ramp_table_77802_2bit[] = {
+ 12500,
+ 25000,
+ 50000,
+ 100000,
+};
+
+static unsigned int ramp_table_77802_4bit[] = {
+ 1000, 2000, 3030, 4000,
+ 5000, 5880, 7140, 8330,
+ 9090, 10000, 11110, 12500,
+ 16670, 25000, 50000, 100000,
+};
+
+struct max77802_regulator_prv {
+ unsigned int opmode[MAX77802_REG_MAX];
+};
+
+static int max77802_get_opmode_shift(int id)
+{
+ if (id == MAX77802_BUCK1 || (id >= MAX77802_BUCK5 &&
+ id <= MAX77802_BUCK10))
+ return 0;
+
+ if (id >= MAX77802_BUCK2 && id <= MAX77802_BUCK4)
+ return MAX77802_OPMODE_BUCK234_SHIFT;
+
+ if (id >= MAX77802_LDO1 && id <= MAX77802_LDO35)
+ return MAX77802_OPMODE_SHIFT_LDO;
+
+ return -EINVAL;
+}
+
+/*
+ * Some BUCKS supports Normal[ON/OFF] mode during suspend
+ *
+ * BUCK 1, 6, 2-4, 5, 7-10 (all)
+ *
+ * The other mode (0x02) will make PWRREQ switch between normal
+ * and low power.
+ */
+static int max77802_buck_set_suspend_disable(struct regulator_dev *rdev)
+{
+ unsigned int val = MAX77802_OPMODE_STANDBY;
+ struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ int shift = max77802_get_opmode_shift(id);
+
+ max77802->opmode[id] = val;
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val << shift);
+}
+
+/*
+ * Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state
+ * (Enable Control Logic1 by PWRREQ)
+ *
+ * LDOs 2, 4-19, 22-35.
+ *
+ */
+static int max77802_ldo_set_suspend_mode_logic1(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ unsigned int val;
+ int shift = max77802_get_opmode_shift(id);
+
+ switch (mode) {
+ case REGULATOR_MODE_IDLE: /* ON in LP Mode */
+ val = MAX77802_OPMODE_LP;
+ break;
+ case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */
+ val = MAX77802_OPMODE_NORMAL;
+ break;
+ case REGULATOR_MODE_STANDBY: /* ON/OFF by PWRREQ */
+ val = MAX77802_OPMODE_STANDBY;
+ break;
+ default:
+ dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n",
+ rdev->desc->name, mode);
+ return -EINVAL;
+ }
+
+ max77802->opmode[id] = val;
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val << shift);
+}
+
+/*
+ * Mode 1 (Output[ON/OFF] by PWRREQ) is not supported on some LDOs
+ * (Enable Control Logic2 by PWRREQ)
+ *
+ * LDOs 1, 20, 21, and 3,
+ *
+ */
+static int max77802_ldo_set_suspend_mode_logic2(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ unsigned int val;
+ int shift = max77802_get_opmode_shift(id);
+
+ switch (mode) {
+ case REGULATOR_MODE_IDLE: /* ON in LP Mode */
+ val = MAX77802_OPMODE_LP;
+ break;
+ case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */
+ val = MAX77802_OPMODE_NORMAL;
+ break;
+ default:
+ dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n",
+ rdev->desc->name, mode);
+ return -EINVAL;
+ }
+
+ max77802->opmode[id] = val;
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val << shift);
+}
+
+static int max77802_enable(struct regulator_dev *rdev)
+{
+ struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ int shift = max77802_get_opmode_shift(id);
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask,
+ max77802->opmode[id] << shift);
+}
+
+static int max77802_find_ramp_value(struct regulator_dev *rdev,
+ const unsigned int limits[], int size,
+ unsigned int ramp_delay)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (ramp_delay <= limits[i])
+ return i;
+ }
+
+ /* Use maximum value for no ramp control */
+ dev_warn(&rdev->dev, "%s: ramp_delay: %d not supported, setting 100000\n",
+ rdev->desc->name, ramp_delay);
+ return size - 1;
+}
+
+/* Used for BUCKs 2-4 */
+static int max77802_set_ramp_delay_2bit(struct regulator_dev *rdev,
+ int ramp_delay)
+{
+ int id = rdev_get_id(rdev);
+ unsigned int ramp_value;
+
+ if (id > MAX77802_BUCK4) {
+ dev_warn(&rdev->dev,
+ "%s: regulator: ramp delay not supported\n",
+ rdev->desc->name);
+ return -EINVAL;
+ }
+ ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_2bit,
+ ARRAY_SIZE(ramp_table_77802_2bit), ramp_delay);
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ MAX77802_RAMP_RATE_MASK_2BIT,
+ ramp_value << MAX77802_RAMP_RATE_SHIFT_2BIT);
+}
+
+/* For BUCK1, 6 */
+static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev,
+ int ramp_delay)
+{
+ unsigned int ramp_value;
+
+ ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_4bit,
+ ARRAY_SIZE(ramp_table_77802_4bit), ramp_delay);
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ MAX77802_RAMP_RATE_MASK_4BIT,
+ ramp_value << MAX77802_RAMP_RATE_SHIFT_4BIT);
+}
+
+/*
+ * LDOs 2, 4-19, 22-35
+ */
+static struct regulator_ops max77802_ldo_ops_logic1 = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = max77802_enable,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_mode = max77802_ldo_set_suspend_mode_logic1,
+};
+
+/*
+ * LDOs 1, 20, 21, 3
+ */
+static struct regulator_ops max77802_ldo_ops_logic2 = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = max77802_enable,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_mode = max77802_ldo_set_suspend_mode_logic2,
+};
+
+/* BUCKS 1, 6 */
+static struct regulator_ops max77802_buck_16_dvs_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = max77802_enable,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = max77802_set_ramp_delay_4bit,
+ .set_suspend_disable = max77802_buck_set_suspend_disable,
+};
+
+/* BUCKs 2-4, 5, 7-10 */
+static struct regulator_ops max77802_buck_dvs_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = max77802_enable,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = max77802_set_ramp_delay_2bit,
+ .set_suspend_disable = max77802_buck_set_suspend_disable,
+};
+
+/* LDOs 3-7, 9-14, 18-26, 28, 29, 32-34 */
+#define regulator_77802_desc_p_ldo(num, supply, log) { \
+ .name = "LDO"#num, \
+ .id = MAX77802_LDO##num, \
+ .supply_name = "inl"#supply, \
+ .ops = &max77802_ldo_ops_logic##log, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 800000, \
+ .uV_step = 50000, \
+ .ramp_delay = MAX77802_RAMP_DELAY, \
+ .n_voltages = 1 << 6, \
+ .vsel_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \
+ .vsel_mask = MAX77802_VSEL_MASK, \
+ .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \
+ .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \
+}
+
+/* LDOs 1, 2, 8, 15, 17, 27, 30, 35 */
+#define regulator_77802_desc_n_ldo(num, supply, log) { \
+ .name = "LDO"#num, \
+ .id = MAX77802_LDO##num, \
+ .supply_name = "inl"#supply, \
+ .ops = &max77802_ldo_ops_logic##log, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 800000, \
+ .uV_step = 25000, \
+ .ramp_delay = MAX77802_RAMP_DELAY, \
+ .n_voltages = 1 << 6, \
+ .vsel_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \
+ .vsel_mask = MAX77802_VSEL_MASK, \
+ .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \
+ .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \
+}
+
+/* BUCKs 1, 6 */
+#define regulator_77802_desc_16_buck(num) { \
+ .name = "BUCK"#num, \
+ .id = MAX77802_BUCK##num, \
+ .supply_name = "inb"#num, \
+ .ops = &max77802_buck_16_dvs_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 612500, \
+ .uV_step = 6250, \
+ .ramp_delay = MAX77802_RAMP_DELAY, \
+ .n_voltages = 1 << 8, \
+ .vsel_reg = MAX77802_REG_BUCK ## num ## DVS1, \
+ .vsel_mask = MAX77802_DVS_VSEL_MASK, \
+ .enable_reg = MAX77802_REG_BUCK ## num ## CTRL, \
+ .enable_mask = MAX77802_OPMODE_MASK, \
+}
+
+/* BUCKS 2-4 */
+#define regulator_77802_desc_234_buck(num) { \
+ .name = "BUCK"#num, \
+ .id = MAX77802_BUCK##num, \
+ .supply_name = "inb"#num, \
+ .ops = &max77802_buck_dvs_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 600000, \
+ .uV_step = 6250, \
+ .ramp_delay = MAX77802_RAMP_DELAY, \
+ .n_voltages = 0x91, \
+ .vsel_reg = MAX77802_REG_BUCK ## num ## DVS1, \
+ .vsel_mask = MAX77802_DVS_VSEL_MASK, \
+ .enable_reg = MAX77802_REG_BUCK ## num ## CTRL1, \
+ .enable_mask = MAX77802_OPMODE_MASK << \
+ MAX77802_OPMODE_BUCK234_SHIFT, \
+}
+
+/* BUCK 5 */
+#define regulator_77802_desc_buck5(num) { \
+ .name = "BUCK"#num, \
+ .id = MAX77802_BUCK##num, \
+ .supply_name = "inb"#num, \
+ .ops = &max77802_buck_dvs_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 750000, \
+ .uV_step = 50000, \
+ .ramp_delay = MAX77802_RAMP_DELAY, \
+ .n_voltages = 1 << 6, \
+ .vsel_reg = MAX77802_REG_BUCK5OUT, \
+ .vsel_mask = MAX77802_VSEL_MASK, \
+ .enable_reg = MAX77802_REG_BUCK5CTRL, \
+ .enable_mask = MAX77802_OPMODE_MASK, \
+}
+
+/* BUCKs 7-10 */
+#define regulator_77802_desc_buck7_10(num) { \
+ .name = "BUCK"#num, \
+ .id = MAX77802_BUCK##num, \
+ .supply_name = "inb"#num, \
+ .ops = &max77802_buck_dvs_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 750000, \
+ .uV_step = 50000, \
+ .ramp_delay = MAX77802_RAMP_DELAY, \
+ .n_voltages = 1 << 6, \
+ .vsel_reg = MAX77802_REG_BUCK7OUT + (num - 7) * 3, \
+ .vsel_mask = MAX77802_VSEL_MASK, \
+ .enable_reg = MAX77802_REG_BUCK7CTRL + (num - 7) * 3, \
+ .enable_mask = MAX77802_OPMODE_MASK, \
+}
+
+static struct regulator_desc regulators[] = {
+ regulator_77802_desc_16_buck(1),
+ regulator_77802_desc_234_buck(2),
+ regulator_77802_desc_234_buck(3),
+ regulator_77802_desc_234_buck(4),
+ regulator_77802_desc_buck5(5),
+ regulator_77802_desc_16_buck(6),
+ regulator_77802_desc_buck7_10(7),
+ regulator_77802_desc_buck7_10(8),
+ regulator_77802_desc_buck7_10(9),
+ regulator_77802_desc_buck7_10(10),
+ regulator_77802_desc_n_ldo(1, 10, 2),
+ regulator_77802_desc_n_ldo(2, 10, 1),
+ regulator_77802_desc_p_ldo(3, 3, 2),
+ regulator_77802_desc_p_ldo(4, 6, 1),
+ regulator_77802_desc_p_ldo(5, 3, 1),
+ regulator_77802_desc_p_ldo(6, 3, 1),
+ regulator_77802_desc_p_ldo(7, 3, 1),
+ regulator_77802_desc_n_ldo(8, 1, 1),
+ regulator_77802_desc_p_ldo(9, 5, 1),
+ regulator_77802_desc_p_ldo(10, 4, 1),
+ regulator_77802_desc_p_ldo(11, 4, 1),
+ regulator_77802_desc_p_ldo(12, 9, 1),
+ regulator_77802_desc_p_ldo(13, 4, 1),
+ regulator_77802_desc_p_ldo(14, 4, 1),
+ regulator_77802_desc_n_ldo(15, 1, 1),
+ regulator_77802_desc_n_ldo(17, 2, 1),
+ regulator_77802_desc_p_ldo(18, 7, 1),
+ regulator_77802_desc_p_ldo(19, 5, 1),
+ regulator_77802_desc_p_ldo(20, 7, 2),
+ regulator_77802_desc_p_ldo(21, 6, 2),
+ regulator_77802_desc_p_ldo(23, 9, 1),
+ regulator_77802_desc_p_ldo(24, 6, 1),
+ regulator_77802_desc_p_ldo(25, 9, 1),
+ regulator_77802_desc_p_ldo(26, 9, 1),
+ regulator_77802_desc_n_ldo(27, 2, 1),
+ regulator_77802_desc_p_ldo(28, 7, 1),
+ regulator_77802_desc_p_ldo(29, 7, 1),
+ regulator_77802_desc_n_ldo(30, 2, 1),
+ regulator_77802_desc_p_ldo(32, 9, 1),
+ regulator_77802_desc_p_ldo(33, 6, 1),
+ regulator_77802_desc_p_ldo(34, 9, 1),
+ regulator_77802_desc_n_ldo(35, 2, 1),
+};
+
+#ifdef CONFIG_OF
+static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
+ struct max77686_platform_data *pdata)
+{
+ struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ struct device_node *pmic_np, *regulators_np;
+ struct max77686_regulator_data *rdata;
+ struct of_regulator_match rmatch;
+ unsigned int i;
+
+ pmic_np = iodev->dev->of_node;
+ regulators_np = of_get_child_by_name(pmic_np, "regulators");
+ if (!regulators_np) {
+ dev_err(&pdev->dev, "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
+
+ pdata->num_regulators = ARRAY_SIZE(regulators);
+ rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
+ pdata->num_regulators, GFP_KERNEL);
+ if (!rdata) {
+ of_node_put(regulators_np);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < pdata->num_regulators; i++) {
+ rmatch.name = regulators[i].name;
+ rmatch.init_data = NULL;
+ rmatch.of_node = NULL;
+ if (of_regulator_match(&pdev->dev, regulators_np, &rmatch,
+ 1) != 1) {
+ dev_warn(&pdev->dev, "No matching regulator for '%s'\n",
+ rmatch.name);
+ continue;
+ }
+ rdata[i].initdata = rmatch.init_data;
+ rdata[i].of_node = rmatch.of_node;
+ rdata[i].id = regulators[i].id;
+ }
+
+ pdata->regulators = rdata;
+ of_node_put(regulators_np);
+
+ return 0;
+}
+#else
+static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
+ struct max77686_platform_data *pdata)
+{
+ return 0;
+}
+#endif /* CONFIG_OF */
+
+static int max77802_pmic_probe(struct platform_device *pdev)
+{
+ struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct max77802_regulator_prv *max77802;
+ int i, ret = 0, val;
+ struct regulator_config config = { };
+
+ /* This is allocated by the MFD driver */
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data found for regulator\n");
+ return -ENODEV;
+ }
+
+ max77802 = devm_kzalloc(&pdev->dev,
+ sizeof(struct max77802_regulator_prv),
+ GFP_KERNEL);
+ if (!max77802)
+ return -ENOMEM;
+
+ if (iodev->dev->of_node) {
+ ret = max77802_pmic_dt_parse_pdata(pdev, pdata);
+ if (ret)
+ return ret;
+ }
+
+ config.dev = iodev->dev;
+ config.regmap = iodev->regmap;
+ config.driver_data = max77802;
+ platform_set_drvdata(pdev, max77802);
+
+ for (i = 0; i < MAX77802_REG_MAX; i++) {
+ struct regulator_dev *rdev;
+ int id = pdata->regulators[i].id;
+ int shift = max77802_get_opmode_shift(id);
+
+ config.init_data = pdata->regulators[i].initdata;
+ config.of_node = pdata->regulators[i].of_node;
+
+ ret = regmap_read(iodev->regmap, regulators[i].enable_reg, &val);
+ val = val >> shift & MAX77802_OPMODE_MASK;
+
+ /*
+ * If the regulator is disabled and the system warm rebooted,
+ * the hardware reports OFF as the regulator operating mode.
+ * Default to operating mode NORMAL in that case.
+ */
+ if (val == MAX77802_OPMODE_OFF)
+ max77802->opmode[id] = MAX77802_OPMODE_NORMAL;
+ else
+ max77802->opmode[id] = val;
+
+ rdev = devm_regulator_register(&pdev->dev,
+ &regulators[i], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
+ "regulator init failed for %d\n", i);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id max77802_pmic_id[] = {
+ {"max77802-pmic", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(platform, max77802_pmic_id);
+
+static struct platform_driver max77802_pmic_driver = {
+ .driver = {
+ .name = "max77802-pmic",
+ .owner = THIS_MODULE,
+ },
+ .probe = max77802_pmic_probe,
+ .id_table = max77802_pmic_id,
+};
+
+module_platform_driver(max77802_pmic_driver);
+
+MODULE_DESCRIPTION("MAXIM 77802 Regulator Driver");
+MODULE_AUTHOR("Simon Glass <sjg@chromium.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index f374fa57220f..793b662a1967 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -526,6 +526,7 @@ static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev)
return REGULATOR_MODE_NORMAL;
}
+static struct regulator_ops mc13892_vcam_ops;
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);
- mc13892_regulators[MC13892_VCAM].desc.ops->set_mode
- = mc13892_vcam_set_mode;
- mc13892_regulators[MC13892_VCAM].desc.ops->get_mode
- = mc13892_vcam_get_mode;
+ /* update mc13892_vcam ops */
+ memcpy(&mc13892_vcam_ops, mc13892_regulators[MC13892_VCAM].desc.ops,
+ sizeof(struct regulator_ops));
+ 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,
ARRAY_SIZE(mc13892_regulators));
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index ee5e67bc8d5b..7a51814abdc5 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -14,8 +14,11 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
+#include "internal.h"
+
static void of_get_regulation_constraints(struct device_node *np,
struct regulator_init_data **init_data)
{
@@ -189,3 +192,51 @@ int of_regulator_match(struct device *dev, struct device_node *node,
return count;
}
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;
+}
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
new file mode 100644
index 000000000000..d3f55eaea058
--- /dev/null
+++ b/drivers/regulator/pwm-regulator.c
@@ -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");
diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c
new file mode 100644
index 000000000000..b55cd5b50ebe
--- /dev/null
+++ b/drivers/regulator/qcom_rpm-regulator.c
@@ -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");
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
new file mode 100644
index 000000000000..e305416d7697
--- /dev/null
+++ b/drivers/regulator/rk808-regulator.c
@@ -0,0 +1,381 @@
+/*
+ * Regulator driver for Rockchip RK808
+ *
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * Author: Chris Zhong <zyw@rock-chips.com>
+ * Author: Zhang Qing <zhangqing@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/i2c.h>
+#include <linux/mfd/rk808.h>
+#include <linux/of_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+/* Field Definitions */
+#define RK808_BUCK_VSEL_MASK 0x3f
+#define RK808_BUCK4_VSEL_MASK 0xf
+#define RK808_LDO_VSEL_MASK 0x1f
+
+/* Ramp rate definitions for buck1 / buck2 only */
+#define RK808_RAMP_RATE_OFFSET 3
+#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_2MV_PER_US (0 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_4MV_PER_US (1 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET)
+#define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET)
+
+static const int rk808_buck_config_regs[] = {
+ RK808_BUCK1_CONFIG_REG,
+ RK808_BUCK2_CONFIG_REG,
+ RK808_BUCK3_CONFIG_REG,
+ RK808_BUCK4_CONFIG_REG,
+};
+
+static const struct regulator_linear_range rk808_buck_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0, 63, 12500),
+};
+
+static const struct regulator_linear_range rk808_buck4_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0, 15, 100000),
+};
+
+static const struct regulator_linear_range rk808_ldo_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0, 16, 100000),
+};
+
+static const struct regulator_linear_range rk808_ldo3_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0, 13, 100000),
+ REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0),
+};
+
+static const struct regulator_linear_range rk808_ldo6_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0, 17, 100000),
+};
+
+static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ unsigned int ramp_value = RK808_RAMP_RATE_10MV_PER_US;
+ unsigned int reg = rk808_buck_config_regs[rdev->desc->id -
+ RK808_ID_DCDC1];
+
+ switch (ramp_delay) {
+ case 1 ... 2000:
+ ramp_value = RK808_RAMP_RATE_2MV_PER_US;
+ break;
+ case 2001 ... 4000:
+ ramp_value = RK808_RAMP_RATE_4MV_PER_US;
+ break;
+ case 4001 ... 6000:
+ ramp_value = RK808_RAMP_RATE_6MV_PER_US;
+ break;
+ case 6001 ... 10000:
+ break;
+ default:
+ pr_warn("%s ramp_delay: %d not supported, setting 10000\n",
+ rdev->desc->name, ramp_delay);
+ }
+
+ return regmap_update_bits(rdev->regmap, reg,
+ RK808_RAMP_RATE_MASK, ramp_value);
+}
+
+static struct regulator_ops rk808_buck1_2_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,
+ .set_ramp_delay = rk808_set_ramp_delay,
+};
+
+static struct regulator_ops rk808_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 struct regulator_ops rk808_switch_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_desc rk808_reg[] = {
+ {
+ .name = "DCDC_REG1",
+ .supply_name = "vcc1",
+ .id = RK808_ID_DCDC1,
+ .ops = &rk808_buck1_2_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 64,
+ .linear_ranges = rk808_buck_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_buck_voltage_ranges),
+ .vsel_reg = RK808_BUCK1_ON_VSEL_REG,
+ .vsel_mask = RK808_BUCK_VSEL_MASK,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(0),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG2",
+ .supply_name = "vcc2",
+ .id = RK808_ID_DCDC2,
+ .ops = &rk808_buck1_2_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 64,
+ .linear_ranges = rk808_buck_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_buck_voltage_ranges),
+ .vsel_reg = RK808_BUCK2_ON_VSEL_REG,
+ .vsel_mask = RK808_BUCK_VSEL_MASK,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(1),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG3",
+ .supply_name = "vcc3",
+ .id = RK808_ID_DCDC3,
+ .ops = &rk808_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 1,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(2),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG4",
+ .supply_name = "vcc4",
+ .id = RK808_ID_DCDC4,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 16,
+ .linear_ranges = rk808_buck4_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_buck4_voltage_ranges),
+ .vsel_reg = RK808_BUCK4_ON_VSEL_REG,
+ .vsel_mask = RK808_BUCK4_VSEL_MASK,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(3),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "LDO_REG1",
+ .supply_name = "vcc6",
+ .id = RK808_ID_LDO1,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 17,
+ .linear_ranges = rk808_ldo_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
+ .vsel_reg = RK808_LDO1_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(0),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "LDO_REG2",
+ .supply_name = "vcc6",
+ .id = RK808_ID_LDO2,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 17,
+ .linear_ranges = rk808_ldo_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
+ .vsel_reg = RK808_LDO2_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(1),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "LDO_REG3",
+ .supply_name = "vcc7",
+ .id = RK808_ID_LDO3,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 16,
+ .linear_ranges = rk808_ldo3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges),
+ .vsel_reg = RK808_LDO3_ON_VSEL_REG,
+ .vsel_mask = RK808_BUCK4_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(2),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "LDO_REG4",
+ .supply_name = "vcc9",
+ .id = RK808_ID_LDO4,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 17,
+ .linear_ranges = rk808_ldo_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
+ .vsel_reg = RK808_LDO4_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(3),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "LDO_REG5",
+ .supply_name = "vcc9",
+ .id = RK808_ID_LDO5,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 17,
+ .linear_ranges = rk808_ldo_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
+ .vsel_reg = RK808_LDO5_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(4),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "LDO_REG6",
+ .supply_name = "vcc10",
+ .id = RK808_ID_LDO6,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 18,
+ .linear_ranges = rk808_ldo6_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo6_voltage_ranges),
+ .vsel_reg = RK808_LDO6_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(5),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "LDO_REG7",
+ .supply_name = "vcc7",
+ .id = RK808_ID_LDO7,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 18,
+ .linear_ranges = rk808_ldo6_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo6_voltage_ranges),
+ .vsel_reg = RK808_LDO7_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(6),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "LDO_REG8",
+ .supply_name = "vcc11",
+ .id = RK808_ID_LDO8,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 17,
+ .linear_ranges = rk808_ldo_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
+ .vsel_reg = RK808_LDO8_ON_VSEL_REG,
+ .vsel_mask = RK808_LDO_VSEL_MASK,
+ .enable_reg = RK808_LDO_EN_REG,
+ .enable_mask = BIT(7),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "SWITCH_REG1",
+ .supply_name = "vcc8",
+ .id = RK808_ID_SWITCH1,
+ .ops = &rk808_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(5),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "SWITCH_REG2",
+ .supply_name = "vcc12",
+ .id = RK808_ID_SWITCH2,
+ .ops = &rk808_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .enable_reg = RK808_DCDC_EN_REG,
+ .enable_mask = BIT(6),
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct of_regulator_match rk808_reg_matches[] = {
+ [RK808_ID_DCDC1] = { .name = "DCDC_REG1" },
+ [RK808_ID_DCDC2] = { .name = "DCDC_REG2" },
+ [RK808_ID_DCDC3] = { .name = "DCDC_REG3" },
+ [RK808_ID_DCDC4] = { .name = "DCDC_REG4" },
+ [RK808_ID_LDO1] = { .name = "LDO_REG1" },
+ [RK808_ID_LDO2] = { .name = "LDO_REG2" },
+ [RK808_ID_LDO3] = { .name = "LDO_REG3" },
+ [RK808_ID_LDO4] = { .name = "LDO_REG4" },
+ [RK808_ID_LDO5] = { .name = "LDO_REG5" },
+ [RK808_ID_LDO6] = { .name = "LDO_REG6" },
+ [RK808_ID_LDO7] = { .name = "LDO_REG7" },
+ [RK808_ID_LDO8] = { .name = "LDO_REG8" },
+ [RK808_ID_SWITCH1] = { .name = "SWITCH_REG1" },
+ [RK808_ID_SWITCH2] = { .name = "SWITCH_REG2" },
+};
+
+static int rk808_regulator_probe(struct platform_device *pdev)
+{
+ struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
+ struct i2c_client *client = rk808->i2c;
+ struct device_node *reg_np;
+ struct regulator_config config = {};
+ struct regulator_dev *rk808_rdev;
+ int ret, i;
+
+ reg_np = of_get_child_by_name(client->dev.of_node, "regulators");
+ if (!reg_np)
+ return -ENXIO;
+
+ ret = of_regulator_match(&pdev->dev, reg_np, rk808_reg_matches,
+ RK808_NUM_REGULATORS);
+ of_node_put(reg_np);
+ if (ret < 0)
+ return ret;
+
+ /* Instantiate the regulators */
+ for (i = 0; i < RK808_NUM_REGULATORS; i++) {
+ if (!rk808_reg_matches[i].init_data ||
+ !rk808_reg_matches[i].of_node)
+ continue;
+
+ config.dev = &client->dev;
+ config.driver_data = rk808;
+ config.regmap = rk808->regmap;
+ config.of_node = rk808_reg_matches[i].of_node;
+ config.init_data = rk808_reg_matches[i].init_data;
+
+ rk808_rdev = devm_regulator_register(&pdev->dev,
+ &rk808_reg[i], &config);
+ if (IS_ERR(rk808_rdev)) {
+ dev_err(&client->dev,
+ "failed to register %d regulator\n", i);
+ return PTR_ERR(rk808_rdev);
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver rk808_regulator_driver = {
+ .probe = rk808_regulator_probe,
+ .driver = {
+ .name = "rk808-regulator",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(rk808_regulator_driver);
+
+MODULE_DESCRIPTION("regulator driver for the rk808 series PMICs");
+MODULE_AUTHOR("Chris Zhong<zyw@rock-chips.com>");
+MODULE_AUTHOR("Zhang Qing<zhangqing@rock-chips.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rk808-regulator");
diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c
new file mode 100644
index 000000000000..e58d79aeb393
--- /dev/null
+++ b/drivers/regulator/rn5t618-regulator.c
@@ -0,0 +1,143 @@
+/*
+ * Regulator driver for Ricoh RN5T618 PMIC
+ *
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/mfd/rn5t618.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+static struct regulator_ops rn5t618_reg_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+#define REG(rid, ereg, emask, vreg, vmask, min, max, step) \
+ [RN5T618_##rid] = { \
+ .name = #rid, \
+ .id = RN5T618_##rid, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .ops = &rn5t618_reg_ops, \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .enable_reg = RN5T618_##ereg, \
+ .enable_mask = (emask), \
+ .vsel_reg = RN5T618_##vreg, \
+ .vsel_mask = (vmask), \
+ }
+
+static struct regulator_desc rn5t618_regulators[] = {
+ /* DCDC */
+ REG(DCDC1, DC1CTL, BIT(0), DC1DAC, 0xff, 600000, 3500000, 12500),
+ REG(DCDC2, DC2CTL, BIT(0), DC2DAC, 0xff, 600000, 3500000, 12500),
+ REG(DCDC3, DC3CTL, BIT(0), DC3DAC, 0xff, 600000, 3500000, 12500),
+ /* LDO */
+ REG(LDO1, LDOEN1, BIT(0), LDO1DAC, 0x7f, 900000, 3500000, 25000),
+ REG(LDO2, LDOEN1, BIT(1), LDO2DAC, 0x7f, 900000, 3500000, 25000),
+ REG(LDO3, LDOEN1, BIT(2), LDO3DAC, 0x7f, 600000, 3500000, 25000),
+ REG(LDO4, LDOEN1, BIT(3), LDO4DAC, 0x7f, 900000, 3500000, 25000),
+ REG(LDO5, LDOEN1, BIT(4), LDO5DAC, 0x7f, 900000, 3500000, 25000),
+ /* LDO RTC */
+ REG(LDORTC1, LDOEN2, BIT(4), LDORTCDAC, 0x7f, 1700000, 3500000, 25000),
+ REG(LDORTC2, LDOEN2, BIT(5), LDORTC2DAC, 0x7f, 900000, 3500000, 25000),
+};
+
+static struct of_regulator_match rn5t618_matches[] = {
+ [RN5T618_DCDC1] = { .name = "DCDC1" },
+ [RN5T618_DCDC2] = { .name = "DCDC2" },
+ [RN5T618_DCDC3] = { .name = "DCDC3" },
+ [RN5T618_LDO1] = { .name = "LDO1" },
+ [RN5T618_LDO2] = { .name = "LDO2" },
+ [RN5T618_LDO3] = { .name = "LDO3" },
+ [RN5T618_LDO4] = { .name = "LDO4" },
+ [RN5T618_LDO5] = { .name = "LDO5" },
+ [RN5T618_LDORTC1] = { .name = "LDORTC1" },
+ [RN5T618_LDORTC2] = { .name = "LDORTC2" },
+};
+
+static int rn5t618_regulator_parse_dt(struct platform_device *pdev)
+{
+ struct device_node *np, *regulators;
+ int ret;
+
+ np = of_node_get(pdev->dev.parent->of_node);
+ if (!np)
+ return 0;
+
+ regulators = of_get_child_by_name(np, "regulators");
+ if (!regulators) {
+ dev_err(&pdev->dev, "regulators node not found\n");
+ return -EINVAL;
+ }
+
+ ret = of_regulator_match(&pdev->dev, regulators, rn5t618_matches,
+ ARRAY_SIZE(rn5t618_matches));
+ of_node_put(regulators);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "error parsing regulator init data: %d\n",
+ ret);
+ }
+
+ return 0;
+}
+
+static int rn5t618_regulator_probe(struct platform_device *pdev)
+{
+ struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = { };
+ struct regulator_dev *rdev;
+ int ret, i;
+
+ ret = rn5t618_regulator_parse_dt(pdev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < RN5T618_REG_NUM; i++) {
+ config.dev = &pdev->dev;
+ config.init_data = rn5t618_matches[i].init_data;
+ config.of_node = rn5t618_matches[i].of_node;
+ config.regmap = rn5t618->regmap;
+
+ rdev = devm_regulator_register(&pdev->dev,
+ &rn5t618_regulators[i],
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register %s regulator\n",
+ rn5t618_regulators[i].name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver rn5t618_regulator_driver = {
+ .probe = rn5t618_regulator_probe,
+ .driver = {
+ .name = "rn5t618-regulator",
+ },
+};
+
+module_platform_driver(rn5t618_regulator_driver);
+
+MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
+MODULE_DESCRIPTION("RN5T618 regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
index ee83b4876420..4acefa6b462e 100644
--- a/drivers/regulator/s2mpa01.c
+++ b/drivers/regulator/s2mpa01.c
@@ -235,28 +235,14 @@ static struct regulator_ops s2mpa01_buck_ops = {
.set_ramp_delay = s2mpa01_set_ramp_delay,
};
-#define regulator_desc_ldo1(num) { \
+#define regulator_desc_ldo(num, step) { \
.name = "LDO"#num, \
.id = S2MPA01_LDO##num, \
.ops = &s2mpa01_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = S2MPA01_LDO_MIN, \
- .uV_step = S2MPA01_LDO_STEP1, \
- .n_voltages = S2MPA01_LDO_N_VOLTAGES, \
- .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \
- .vsel_mask = S2MPA01_LDO_VSEL_MASK, \
- .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \
- .enable_mask = S2MPA01_ENABLE_MASK \
-}
-#define regulator_desc_ldo2(num) { \
- .name = "LDO"#num, \
- .id = S2MPA01_LDO##num, \
- .ops = &s2mpa01_ldo_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .min_uV = S2MPA01_LDO_MIN, \
- .uV_step = S2MPA01_LDO_STEP2, \
+ .min_uV = MIN_800_MV, \
+ .uV_step = step, \
.n_voltages = S2MPA01_LDO_N_VOLTAGES, \
.vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \
.vsel_mask = S2MPA01_LDO_VSEL_MASK, \
@@ -270,8 +256,8 @@ static struct regulator_ops s2mpa01_buck_ops = {
.ops = &s2mpa01_buck_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = S2MPA01_BUCK_MIN1, \
- .uV_step = S2MPA01_BUCK_STEP1, \
+ .min_uV = MIN_600_MV, \
+ .uV_step = STEP_6_25_MV, \
.n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
.ramp_delay = S2MPA01_RAMP_DELAY, \
.vsel_reg = S2MPA01_REG_B1CTRL2 + (num - 1) * 2, \
@@ -286,8 +272,8 @@ static struct regulator_ops s2mpa01_buck_ops = {
.ops = &s2mpa01_buck_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = S2MPA01_BUCK_MIN2, \
- .uV_step = S2MPA01_BUCK_STEP1, \
+ .min_uV = MIN_800_MV, \
+ .uV_step = STEP_6_25_MV, \
.n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
.ramp_delay = S2MPA01_RAMP_DELAY, \
.vsel_reg = S2MPA01_REG_B5CTRL2, \
@@ -296,14 +282,14 @@ static struct regulator_ops s2mpa01_buck_ops = {
.enable_mask = S2MPA01_ENABLE_MASK \
}
-#define regulator_desc_buck6_7(num) { \
+#define regulator_desc_buck6_10(num, min, step) { \
.name = "BUCK"#num, \
.id = S2MPA01_BUCK##num, \
.ops = &s2mpa01_buck_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = S2MPA01_BUCK_MIN1, \
- .uV_step = S2MPA01_BUCK_STEP1, \
+ .min_uV = min, \
+ .uV_step = step, \
.n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
.ramp_delay = S2MPA01_RAMP_DELAY, \
.vsel_reg = S2MPA01_REG_B6CTRL2 + (num - 6) * 2, \
@@ -312,91 +298,43 @@ static struct regulator_ops s2mpa01_buck_ops = {
.enable_mask = S2MPA01_ENABLE_MASK \
}
-#define regulator_desc_buck8 { \
- .name = "BUCK8", \
- .id = S2MPA01_BUCK8, \
- .ops = &s2mpa01_buck_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .min_uV = S2MPA01_BUCK_MIN2, \
- .uV_step = S2MPA01_BUCK_STEP2, \
- .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
- .ramp_delay = S2MPA01_RAMP_DELAY, \
- .vsel_reg = S2MPA01_REG_B8CTRL2, \
- .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
- .enable_reg = S2MPA01_REG_B8CTRL1, \
- .enable_mask = S2MPA01_ENABLE_MASK \
-}
-
-#define regulator_desc_buck9 { \
- .name = "BUCK9", \
- .id = S2MPA01_BUCK9, \
- .ops = &s2mpa01_buck_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .min_uV = S2MPA01_BUCK_MIN4, \
- .uV_step = S2MPA01_BUCK_STEP2, \
- .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
- .ramp_delay = S2MPA01_RAMP_DELAY, \
- .vsel_reg = S2MPA01_REG_B9CTRL2, \
- .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
- .enable_reg = S2MPA01_REG_B9CTRL1, \
- .enable_mask = S2MPA01_ENABLE_MASK \
-}
-
-#define regulator_desc_buck10 { \
- .name = "BUCK10", \
- .id = S2MPA01_BUCK10, \
- .ops = &s2mpa01_buck_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .min_uV = S2MPA01_BUCK_MIN3, \
- .uV_step = S2MPA01_BUCK_STEP2, \
- .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \
- .ramp_delay = S2MPA01_RAMP_DELAY, \
- .vsel_reg = S2MPA01_REG_B10CTRL2, \
- .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \
- .enable_reg = S2MPA01_REG_B10CTRL1, \
- .enable_mask = S2MPA01_ENABLE_MASK \
-}
-
static struct regulator_desc regulators[] = {
- regulator_desc_ldo2(1),
- regulator_desc_ldo1(2),
- regulator_desc_ldo1(3),
- regulator_desc_ldo1(4),
- regulator_desc_ldo1(5),
- regulator_desc_ldo2(6),
- regulator_desc_ldo1(7),
- regulator_desc_ldo1(8),
- regulator_desc_ldo1(9),
- regulator_desc_ldo1(10),
- regulator_desc_ldo2(11),
- regulator_desc_ldo1(12),
- regulator_desc_ldo1(13),
- regulator_desc_ldo1(14),
- regulator_desc_ldo1(15),
- regulator_desc_ldo1(16),
- regulator_desc_ldo1(17),
- regulator_desc_ldo1(18),
- regulator_desc_ldo1(19),
- regulator_desc_ldo1(20),
- regulator_desc_ldo1(21),
- regulator_desc_ldo2(22),
- regulator_desc_ldo2(23),
- regulator_desc_ldo1(24),
- regulator_desc_ldo1(25),
- regulator_desc_ldo1(26),
+ regulator_desc_ldo(1, STEP_25_MV),
+ regulator_desc_ldo(2, STEP_50_MV),
+ regulator_desc_ldo(3, STEP_50_MV),
+ regulator_desc_ldo(4, STEP_50_MV),
+ regulator_desc_ldo(5, STEP_50_MV),
+ regulator_desc_ldo(6, STEP_25_MV),
+ regulator_desc_ldo(7, STEP_50_MV),
+ regulator_desc_ldo(8, STEP_50_MV),
+ regulator_desc_ldo(9, STEP_50_MV),
+ regulator_desc_ldo(10, STEP_50_MV),
+ regulator_desc_ldo(11, STEP_25_MV),
+ regulator_desc_ldo(12, STEP_50_MV),
+ regulator_desc_ldo(13, STEP_50_MV),
+ regulator_desc_ldo(14, STEP_50_MV),
+ regulator_desc_ldo(15, STEP_50_MV),
+ regulator_desc_ldo(16, STEP_50_MV),
+ regulator_desc_ldo(17, STEP_50_MV),
+ regulator_desc_ldo(18, STEP_50_MV),
+ regulator_desc_ldo(19, STEP_50_MV),
+ regulator_desc_ldo(20, STEP_50_MV),
+ regulator_desc_ldo(21, STEP_50_MV),
+ regulator_desc_ldo(22, STEP_25_MV),
+ regulator_desc_ldo(23, STEP_25_MV),
+ regulator_desc_ldo(24, STEP_50_MV),
+ regulator_desc_ldo(25, STEP_50_MV),
+ regulator_desc_ldo(26, STEP_50_MV),
regulator_desc_buck1_4(1),
regulator_desc_buck1_4(2),
regulator_desc_buck1_4(3),
regulator_desc_buck1_4(4),
regulator_desc_buck5,
- regulator_desc_buck6_7(6),
- regulator_desc_buck6_7(7),
- regulator_desc_buck8,
- regulator_desc_buck9,
- regulator_desc_buck10,
+ regulator_desc_buck6_10(6, MIN_600_MV, STEP_6_25_MV),
+ regulator_desc_buck6_10(7, MIN_600_MV, STEP_6_25_MV),
+ regulator_desc_buck6_10(8, MIN_800_MV, STEP_12_5_MV),
+ regulator_desc_buck6_10(9, MIN_1500_MV, STEP_12_5_MV),
+ regulator_desc_buck6_10(10, MIN_1000_MV, STEP_12_5_MV),
};
static int s2mpa01_pmic_probe(struct platform_device *pdev)
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index b16c53a8272f..adab82d5279f 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -255,28 +255,14 @@ static struct regulator_ops s2mps11_buck_ops = {
.set_ramp_delay = s2mps11_set_ramp_delay,
};
-#define regulator_desc_s2mps11_ldo1(num) { \
+#define regulator_desc_s2mps11_ldo(num, step) { \
.name = "LDO"#num, \
.id = S2MPS11_LDO##num, \
.ops = &s2mps11_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = S2MPS11_LDO_MIN, \
- .uV_step = S2MPS11_LDO_STEP1, \
- .n_voltages = S2MPS11_LDO_N_VOLTAGES, \
- .vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \
- .vsel_mask = S2MPS11_LDO_VSEL_MASK, \
- .enable_reg = S2MPS11_REG_L1CTRL + num - 1, \
- .enable_mask = S2MPS11_ENABLE_MASK \
-}
-#define regulator_desc_s2mps11_ldo2(num) { \
- .name = "LDO"#num, \
- .id = S2MPS11_LDO##num, \
- .ops = &s2mps11_ldo_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .min_uV = S2MPS11_LDO_MIN, \
- .uV_step = S2MPS11_LDO_STEP2, \
+ .min_uV = MIN_800_MV, \
+ .uV_step = step, \
.n_voltages = S2MPS11_LDO_N_VOLTAGES, \
.vsel_reg = S2MPS11_REG_L1CTRL + num - 1, \
.vsel_mask = S2MPS11_LDO_VSEL_MASK, \
@@ -290,8 +276,8 @@ static struct regulator_ops s2mps11_buck_ops = {
.ops = &s2mps11_buck_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = S2MPS11_BUCK_MIN1, \
- .uV_step = S2MPS11_BUCK_STEP1, \
+ .min_uV = MIN_600_MV, \
+ .uV_step = STEP_6_25_MV, \
.n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
.ramp_delay = S2MPS11_RAMP_DELAY, \
.vsel_reg = S2MPS11_REG_B1CTRL2 + (num - 1) * 2, \
@@ -306,8 +292,8 @@ static struct regulator_ops s2mps11_buck_ops = {
.ops = &s2mps11_buck_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = S2MPS11_BUCK_MIN1, \
- .uV_step = S2MPS11_BUCK_STEP1, \
+ .min_uV = MIN_600_MV, \
+ .uV_step = STEP_6_25_MV, \
.n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
.ramp_delay = S2MPS11_RAMP_DELAY, \
.vsel_reg = S2MPS11_REG_B5CTRL2, \
@@ -316,14 +302,14 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_s2mps11_buck6_8(num) { \
+#define regulator_desc_s2mps11_buck6_10(num, min, step) { \
.name = "BUCK"#num, \
.id = S2MPS11_BUCK##num, \
.ops = &s2mps11_buck_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = S2MPS11_BUCK_MIN1, \
- .uV_step = S2MPS11_BUCK_STEP1, \
+ .min_uV = min, \
+ .uV_step = step, \
.n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
.ramp_delay = S2MPS11_RAMP_DELAY, \
.vsel_reg = S2MPS11_REG_B6CTRL2 + (num - 6) * 2, \
@@ -332,87 +318,55 @@ static struct regulator_ops s2mps11_buck_ops = {
.enable_mask = S2MPS11_ENABLE_MASK \
}
-#define regulator_desc_s2mps11_buck9 { \
- .name = "BUCK9", \
- .id = S2MPS11_BUCK9, \
- .ops = &s2mps11_buck_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .min_uV = S2MPS11_BUCK_MIN3, \
- .uV_step = S2MPS11_BUCK_STEP3, \
- .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
- .ramp_delay = S2MPS11_RAMP_DELAY, \
- .vsel_reg = S2MPS11_REG_B9CTRL2, \
- .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
- .enable_reg = S2MPS11_REG_B9CTRL1, \
- .enable_mask = S2MPS11_ENABLE_MASK \
-}
-
-#define regulator_desc_s2mps11_buck10 { \
- .name = "BUCK10", \
- .id = S2MPS11_BUCK10, \
- .ops = &s2mps11_buck_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .min_uV = S2MPS11_BUCK_MIN2, \
- .uV_step = S2MPS11_BUCK_STEP2, \
- .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \
- .ramp_delay = S2MPS11_RAMP_DELAY, \
- .vsel_reg = S2MPS11_REG_B10CTRL2, \
- .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \
- .enable_reg = S2MPS11_REG_B10CTRL1, \
- .enable_mask = S2MPS11_ENABLE_MASK \
-}
-
static const struct regulator_desc s2mps11_regulators[] = {
- regulator_desc_s2mps11_ldo2(1),
- regulator_desc_s2mps11_ldo1(2),
- regulator_desc_s2mps11_ldo1(3),
- regulator_desc_s2mps11_ldo1(4),
- regulator_desc_s2mps11_ldo1(5),
- regulator_desc_s2mps11_ldo2(6),
- regulator_desc_s2mps11_ldo1(7),
- regulator_desc_s2mps11_ldo1(8),
- regulator_desc_s2mps11_ldo1(9),
- regulator_desc_s2mps11_ldo1(10),
- regulator_desc_s2mps11_ldo2(11),
- regulator_desc_s2mps11_ldo1(12),
- regulator_desc_s2mps11_ldo1(13),
- regulator_desc_s2mps11_ldo1(14),
- regulator_desc_s2mps11_ldo1(15),
- regulator_desc_s2mps11_ldo1(16),
- regulator_desc_s2mps11_ldo1(17),
- regulator_desc_s2mps11_ldo1(18),
- regulator_desc_s2mps11_ldo1(19),
- regulator_desc_s2mps11_ldo1(20),
- regulator_desc_s2mps11_ldo1(21),
- regulator_desc_s2mps11_ldo2(22),
- regulator_desc_s2mps11_ldo2(23),
- regulator_desc_s2mps11_ldo1(24),
- regulator_desc_s2mps11_ldo1(25),
- regulator_desc_s2mps11_ldo1(26),
- regulator_desc_s2mps11_ldo2(27),
- regulator_desc_s2mps11_ldo1(28),
- regulator_desc_s2mps11_ldo1(29),
- regulator_desc_s2mps11_ldo1(30),
- regulator_desc_s2mps11_ldo1(31),
- regulator_desc_s2mps11_ldo1(32),
- regulator_desc_s2mps11_ldo1(33),
- regulator_desc_s2mps11_ldo1(34),
- regulator_desc_s2mps11_ldo1(35),
- regulator_desc_s2mps11_ldo1(36),
- regulator_desc_s2mps11_ldo1(37),
- regulator_desc_s2mps11_ldo1(38),
+ regulator_desc_s2mps11_ldo(1, STEP_25_MV),
+ regulator_desc_s2mps11_ldo(2, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(3, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(4, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(5, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(6, STEP_25_MV),
+ regulator_desc_s2mps11_ldo(7, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(8, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(9, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(10, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(11, STEP_25_MV),
+ regulator_desc_s2mps11_ldo(12, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(13, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(14, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(15, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(16, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(17, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(18, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(19, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(20, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(21, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(22, STEP_25_MV),
+ regulator_desc_s2mps11_ldo(23, STEP_25_MV),
+ regulator_desc_s2mps11_ldo(24, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(25, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(26, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(27, STEP_25_MV),
+ regulator_desc_s2mps11_ldo(28, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(29, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(30, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(31, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(32, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(33, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(34, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(35, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(36, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(37, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(38, STEP_50_MV),
regulator_desc_s2mps11_buck1_4(1),
regulator_desc_s2mps11_buck1_4(2),
regulator_desc_s2mps11_buck1_4(3),
regulator_desc_s2mps11_buck1_4(4),
regulator_desc_s2mps11_buck5,
- regulator_desc_s2mps11_buck6_8(6),
- regulator_desc_s2mps11_buck6_8(7),
- regulator_desc_s2mps11_buck6_8(8),
- regulator_desc_s2mps11_buck9,
- regulator_desc_s2mps11_buck10,
+ regulator_desc_s2mps11_buck6_10(6, MIN_600_MV, STEP_6_25_MV),
+ regulator_desc_s2mps11_buck6_10(7, MIN_600_MV, STEP_6_25_MV),
+ regulator_desc_s2mps11_buck6_10(8, MIN_600_MV, STEP_6_25_MV),
+ regulator_desc_s2mps11_buck6_10(9, MIN_3000_MV, STEP_25_MV),
+ regulator_desc_s2mps11_buck6_10(10, MIN_750_MV, STEP_12_5_MV),
};
static int s2mps14_regulator_enable(struct regulator_dev *rdev)
@@ -510,56 +464,29 @@ static struct regulator_ops s2mps14_reg_ops = {
.set_suspend_disable = s2mps14_regulator_set_suspend_disable,
};
-#define regulator_desc_s2mps14_ldo1(num) { \
- .name = "LDO"#num, \
- .id = S2MPS14_LDO##num, \
- .ops = &s2mps14_reg_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .min_uV = S2MPS14_LDO_MIN_800MV, \
- .uV_step = S2MPS14_LDO_STEP_25MV, \
- .n_voltages = S2MPS14_LDO_N_VOLTAGES, \
- .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \
- .vsel_mask = S2MPS14_LDO_VSEL_MASK, \
- .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \
- .enable_mask = S2MPS14_ENABLE_MASK \
-}
-#define regulator_desc_s2mps14_ldo2(num) { \
- .name = "LDO"#num, \
- .id = S2MPS14_LDO##num, \
- .ops = &s2mps14_reg_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .min_uV = S2MPS14_LDO_MIN_1800MV, \
- .uV_step = S2MPS14_LDO_STEP_25MV, \
- .n_voltages = S2MPS14_LDO_N_VOLTAGES, \
- .vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \
- .vsel_mask = S2MPS14_LDO_VSEL_MASK, \
- .enable_reg = S2MPS14_REG_L1CTRL + num - 1, \
- .enable_mask = S2MPS14_ENABLE_MASK \
-}
-#define regulator_desc_s2mps14_ldo3(num) { \
+#define regulator_desc_s2mps14_ldo(num, min, step) { \
.name = "LDO"#num, \
.id = S2MPS14_LDO##num, \
.ops = &s2mps14_reg_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = S2MPS14_LDO_MIN_800MV, \
- .uV_step = S2MPS14_LDO_STEP_12_5MV, \
+ .min_uV = min, \
+ .uV_step = step, \
.n_voltages = S2MPS14_LDO_N_VOLTAGES, \
.vsel_reg = S2MPS14_REG_L1CTRL + num - 1, \
.vsel_mask = S2MPS14_LDO_VSEL_MASK, \
.enable_reg = S2MPS14_REG_L1CTRL + num - 1, \
.enable_mask = S2MPS14_ENABLE_MASK \
}
-#define regulator_desc_s2mps14_buck1235(num) { \
+
+#define regulator_desc_s2mps14_buck(num, min, step) { \
.name = "BUCK"#num, \
.id = S2MPS14_BUCK##num, \
.ops = &s2mps14_reg_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .min_uV = S2MPS14_BUCK1235_MIN_600MV, \
- .uV_step = S2MPS14_BUCK1235_STEP_6_25MV, \
+ .min_uV = min, \
+ .uV_step = step, \
.n_voltages = S2MPS14_BUCK_N_VOLTAGES, \
.linear_min_sel = S2MPS14_BUCK1235_START_SEL, \
.ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \
@@ -568,54 +495,38 @@ static struct regulator_ops s2mps14_reg_ops = {
.enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \
.enable_mask = S2MPS14_ENABLE_MASK \
}
-#define regulator_desc_s2mps14_buck4(num) { \
- .name = "BUCK"#num, \
- .id = S2MPS14_BUCK##num, \
- .ops = &s2mps14_reg_ops, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .min_uV = S2MPS14_BUCK4_MIN_1400MV, \
- .uV_step = S2MPS14_BUCK4_STEP_12_5MV, \
- .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \
- .linear_min_sel = S2MPS14_BUCK4_START_SEL, \
- .ramp_delay = S2MPS14_BUCK_RAMP_DELAY, \
- .vsel_reg = S2MPS14_REG_B1CTRL2 + (num - 1) * 2, \
- .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \
- .enable_reg = S2MPS14_REG_B1CTRL1 + (num - 1) * 2, \
- .enable_mask = S2MPS14_ENABLE_MASK \
-}
static const struct regulator_desc s2mps14_regulators[] = {
- regulator_desc_s2mps14_ldo3(1),
- regulator_desc_s2mps14_ldo3(2),
- regulator_desc_s2mps14_ldo1(3),
- regulator_desc_s2mps14_ldo1(4),
- regulator_desc_s2mps14_ldo3(5),
- regulator_desc_s2mps14_ldo3(6),
- regulator_desc_s2mps14_ldo1(7),
- regulator_desc_s2mps14_ldo2(8),
- regulator_desc_s2mps14_ldo3(9),
- regulator_desc_s2mps14_ldo3(10),
- regulator_desc_s2mps14_ldo1(11),
- regulator_desc_s2mps14_ldo2(12),
- regulator_desc_s2mps14_ldo2(13),
- regulator_desc_s2mps14_ldo2(14),
- regulator_desc_s2mps14_ldo2(15),
- regulator_desc_s2mps14_ldo2(16),
- regulator_desc_s2mps14_ldo2(17),
- regulator_desc_s2mps14_ldo2(18),
- regulator_desc_s2mps14_ldo1(19),
- regulator_desc_s2mps14_ldo1(20),
- regulator_desc_s2mps14_ldo1(21),
- regulator_desc_s2mps14_ldo3(22),
- regulator_desc_s2mps14_ldo1(23),
- regulator_desc_s2mps14_ldo2(24),
- regulator_desc_s2mps14_ldo2(25),
- regulator_desc_s2mps14_buck1235(1),
- regulator_desc_s2mps14_buck1235(2),
- regulator_desc_s2mps14_buck1235(3),
- regulator_desc_s2mps14_buck4(4),
- regulator_desc_s2mps14_buck1235(5),
+ regulator_desc_s2mps14_ldo(1, MIN_800_MV, STEP_12_5_MV),
+ regulator_desc_s2mps14_ldo(2, MIN_800_MV, STEP_12_5_MV),
+ regulator_desc_s2mps14_ldo(3, MIN_800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(4, MIN_800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(5, MIN_800_MV, STEP_12_5_MV),
+ regulator_desc_s2mps14_ldo(6, MIN_800_MV, STEP_12_5_MV),
+ regulator_desc_s2mps14_ldo(7, MIN_800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(8, MIN_1800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(9, MIN_800_MV, STEP_12_5_MV),
+ regulator_desc_s2mps14_ldo(10, MIN_800_MV, STEP_12_5_MV),
+ regulator_desc_s2mps14_ldo(11, MIN_800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(12, MIN_1800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(13, MIN_1800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(14, MIN_1800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(15, MIN_1800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(16, MIN_1800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(17, MIN_1800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(18, MIN_1800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(19, MIN_800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(20, MIN_800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(21, MIN_800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(22, MIN_800_MV, STEP_12_5_MV),
+ regulator_desc_s2mps14_ldo(23, MIN_800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(24, MIN_1800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_ldo(25, MIN_1800_MV, STEP_25_MV),
+ regulator_desc_s2mps14_buck(1, MIN_600_MV, STEP_6_25_MV),
+ regulator_desc_s2mps14_buck(2, MIN_600_MV, STEP_6_25_MV),
+ regulator_desc_s2mps14_buck(3, MIN_600_MV, STEP_6_25_MV),
+ regulator_desc_s2mps14_buck(4, MIN_1400_MV, STEP_12_5_MV),
+ regulator_desc_s2mps14_buck(5, MIN_600_MV, STEP_6_25_MV),
};
static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11,
diff --git a/drivers/regulator/sky81452-regulator.c b/drivers/regulator/sky81452-regulator.c
new file mode 100644
index 000000000000..97aff0ccd65f
--- /dev/null
+++ b/drivers/regulator/sky81452-regulator.c
@@ -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");
diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c
deleted file mode 100644
index 5ea78df449f8..000000000000
--- a/drivers/regulator/st-pwm.c
+++ /dev/null
@@ -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");
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index 3ef67a86115c..7380af8bd50d 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -211,9 +211,6 @@ static int tps_65023_probe(struct i2c_client *client,
int i;
int error;
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EIO;
-
/**
* init_data points to array of regulator_init structures
* coming from the board-evm file.
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index d58db72a63b0..adbe4fc5cf07 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -27,10 +27,13 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65217.h>
-#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t, _lr, _nlr) \
+#define TPS65217_REGULATOR(_name, _id, _of_match, _ops, _n, _vr, _vm, _em, \
+ _t, _lr, _nlr) \
{ \
.name = _name, \
.id = _id, \
+ .of_match = of_match_ptr(_of_match), \
+ .regulators_node= of_match_ptr("regulators"), \
.ops = &_ops, \
.n_voltages = _n, \
.type = REGULATOR_VOLTAGE, \
@@ -138,87 +141,40 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = {
};
static const struct regulator_desc regulators[] = {
- TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64,
- TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK,
- TPS65217_ENABLE_DC1_EN, NULL, tps65217_uv1_ranges,
- 2), /* DCDC1 voltage range: 900000 ~ 1800000 */
- TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64,
- TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK,
- TPS65217_ENABLE_DC2_EN, NULL, tps65217_uv1_ranges,
+ TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, "dcdc1",
+ tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC1,
+ TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC1_EN,
+ NULL, tps65217_uv1_ranges, 2),
+ TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, "dcdc2",
+ tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC2,
+ TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC2_EN,
+ NULL, tps65217_uv1_ranges,
ARRAY_SIZE(tps65217_uv1_ranges)),
- TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64,
- TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK,
- TPS65217_ENABLE_DC3_EN, NULL, tps65217_uv1_ranges,
- 1), /* DCDC3 voltage range: 900000 ~ 1500000 */
- TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16,
- TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK,
- TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table, NULL, 0),
- TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64,
- TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK,
- TPS65217_ENABLE_LDO2_EN, NULL, tps65217_uv1_ranges,
+ TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, "dcdc3",
+ tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC3,
+ TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC3_EN,
+ NULL, tps65217_uv1_ranges, 1),
+ TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, "ldo1",
+ tps65217_pmic_ldo1_ops, 16, TPS65217_REG_DEFLDO1,
+ TPS65217_DEFLDO1_LDO1_MASK, TPS65217_ENABLE_LDO1_EN,
+ LDO1_VSEL_table, NULL, 0),
+ TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, "ldo2", tps65217_pmic_ops,
+ 64, TPS65217_REG_DEFLDO2,
+ TPS65217_DEFLDO2_LDO2_MASK, TPS65217_ENABLE_LDO2_EN,
+ NULL, tps65217_uv1_ranges,
ARRAY_SIZE(tps65217_uv1_ranges)),
- TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32,
- TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK,
+ TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, "ldo3", tps65217_pmic_ops,
+ 32, TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK,
TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
NULL, tps65217_uv2_ranges,
ARRAY_SIZE(tps65217_uv2_ranges)),
- TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32,
- TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK,
+ TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, "ldo4", tps65217_pmic_ops,
+ 32, TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK,
TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
NULL, tps65217_uv2_ranges,
ARRAY_SIZE(tps65217_uv2_ranges)),
};
-#ifdef CONFIG_OF
-static struct of_regulator_match reg_matches[] = {
- { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 },
- { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 },
- { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 },
- { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 },
- { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 },
- { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 },
- { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 },
-};
-
-static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
-{
- struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
- struct device_node *node = tps->dev->of_node;
- struct tps65217_board *pdata;
- struct device_node *regs;
- int i, count;
-
- regs = of_get_child_by_name(node, "regulators");
- if (!regs)
- return NULL;
-
- count = of_regulator_match(&pdev->dev, regs, reg_matches,
- TPS65217_NUM_REGULATOR);
- of_node_put(regs);
- if ((count < 0) || (count > TPS65217_NUM_REGULATOR))
- return NULL;
-
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return NULL;
-
- for (i = 0; i < count; i++) {
- if (!reg_matches[i].of_node)
- continue;
-
- pdata->tps65217_init_data[i] = reg_matches[i].init_data;
- pdata->of_node[i] = reg_matches[i].of_node;
- }
-
- return pdata;
-}
-#else
-static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
-{
- return NULL;
-}
-#endif
-
static int tps65217_regulator_probe(struct platform_device *pdev)
{
struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
@@ -227,14 +183,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
struct regulator_config config = { };
int i;
- if (tps->dev->of_node)
- pdata = tps65217_parse_dt(pdev);
-
- if (!pdata) {
- dev_err(&pdev->dev, "Platform data not found\n");
- return -EINVAL;
- }
-
if (tps65217_chip_id(tps) != TPS65217) {
dev_err(&pdev->dev, "Invalid tps chip version\n");
return -ENODEV;
@@ -245,11 +193,10 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
/* Register the regulators */
config.dev = tps->dev;
- config.init_data = pdata->tps65217_init_data[i];
+ if (pdata)
+ config.init_data = pdata->tps65217_init_data[i];
config.driver_data = tps;
config.regmap = tps->regmap;
- if (tps->dev->of_node)
- config.of_node = pdata->of_node[i];
rdev = devm_regulator_register(&pdev->dev, &regulators[i],
&config);
@@ -259,6 +206,7 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
return PTR_ERR(rdev);
}
}
+
return 0;
}
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index e584c998b55f..18fc991175bc 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -1047,7 +1047,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
*tps65910_reg_matches = matches;
for (idx = 0; idx < count; idx++) {
- if (!matches[idx].init_data || !matches[idx].of_node)
+ if (!matches[idx].of_node)
continue;
pmic_plat_data->tps65910_pmic_init_data[idx] =
@@ -1077,7 +1077,6 @@ static int tps65910_probe(struct platform_device *pdev)
struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
struct regulator_config config = { };
struct tps_info *info;
- struct regulator_init_data *reg_data;
struct regulator_dev *rdev;
struct tps65910_reg *pmic;
struct tps65910_board *pmic_plat_data;
@@ -1140,14 +1139,6 @@ static int tps65910_probe(struct platform_device *pdev)
for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS;
i++, info++) {
-
- reg_data = pmic_plat_data->tps65910_pmic_init_data[i];
-
- /* Regulator API handles empty constraints but not NULL
- * constraints */
- if (!reg_data)
- continue;
-
/* Register the regulators */
pmic->info[i] = info;
@@ -1199,7 +1190,7 @@ static int tps65910_probe(struct platform_device *pdev)
pmic->desc[i].enable_mask = TPS65910_SUPPLY_STATE_ENABLED;
config.dev = tps65910->dev;
- config.init_data = reg_data;
+ config.init_data = pmic_plat_data->tps65910_pmic_init_data[i];
config.driver_data = pmic;
config.regmap = tps65910->regmap;