You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge remote-tracking branches 'regulator/topic/drivers', 'regulator/topic/enable', 'regulator/topic/fan53555', 'regulator/topic/hi6421' and 'regulator/topic/isl9305' into regulator-next
This commit is contained in:
@@ -241,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
|
||||
@@ -450,6 +467,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
|
||||
@@ -484,11 +520,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"
|
||||
|
||||
@@ -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
|
||||
@@ -55,8 +57,10 @@ obj-$(CONFIG_REGULATOR_MAX77693) += max77693.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
|
||||
@@ -65,7 +69,7 @@ obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-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
|
||||
|
||||
+94
-53
@@ -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;
|
||||
@@ -2572,8 +2609,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;
|
||||
@@ -3336,9 +3373,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 +3553,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(®ulator_list_mutex);
|
||||
|
||||
mutex_init(&rdev->mutex);
|
||||
@@ -3548,7 +3590,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
|
||||
|
||||
/* register with sysfs */
|
||||
rdev->dev.class = ®ulator_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(®ulator_no) - 1);
|
||||
@@ -3905,7 +3946,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;
|
||||
|
||||
|
||||
+180
-35
@@ -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,32 +190,11 @@ 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,
|
||||
};
|
||||
|
||||
/* For 00,01,03,05 options:
|
||||
* VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V.
|
||||
* For 04 option:
|
||||
* VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V.
|
||||
* */
|
||||
static int fan53555_device_setup(struct fan53555_device_info *di,
|
||||
struct fan53555_platform_data *pdata)
|
||||
static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
|
||||
{
|
||||
unsigned int reg, data, mask;
|
||||
|
||||
/* Setup voltage control register */
|
||||
switch (pdata->sleep_vsel_id) {
|
||||
case FAN53555_VSEL_ID_0:
|
||||
di->sleep_reg = FAN53555_VSEL0;
|
||||
di->vol_reg = FAN53555_VSEL1;
|
||||
break;
|
||||
case FAN53555_VSEL_ID_1:
|
||||
di->sleep_reg = FAN53555_VSEL1;
|
||||
di->vol_reg = FAN53555_VSEL0;
|
||||
break;
|
||||
default:
|
||||
dev_err(di->dev, "Invalid VSEL ID!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Init voltage range and step */
|
||||
switch (di->chip_id) {
|
||||
case FAN53555_CHIP_ID_00:
|
||||
@@ -187,18 +210,68 @@ static int fan53555_device_setup(struct fan53555_device_info *di,
|
||||
break;
|
||||
default:
|
||||
dev_err(di->dev,
|
||||
"Chip ID[%d]\n not supported!\n", di->chip_id);
|
||||
"Chip ID %d not supported!\n", di->chip_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* 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 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:
|
||||
* VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V.
|
||||
* */
|
||||
static int fan53555_device_setup(struct fan53555_device_info *di,
|
||||
struct fan53555_platform_data *pdata)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Setup voltage control register */
|
||||
switch (pdata->sleep_vsel_id) {
|
||||
case FAN53555_VSEL_ID_0:
|
||||
di->sleep_reg = FAN53555_VSEL0;
|
||||
di->vol_reg = FAN53555_VSEL1;
|
||||
break;
|
||||
case FAN53555_VSEL_ID_1:
|
||||
di->sleep_reg = FAN53555_VSEL1;
|
||||
di->vol_reg = FAN53555_VSEL0;
|
||||
break;
|
||||
default:
|
||||
dev_err(di->dev, "Invalid VSEL ID!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (di->vendor) {
|
||||
case FAN53555_VENDOR_FAIRCHILD:
|
||||
ret = fan53555_voltages_setup_fairchild(di);
|
||||
break;
|
||||
case FAN53555_VENDOR_SILERGY:
|
||||
ret = fan53555_voltages_setup_silergy(di);
|
||||
break;
|
||||
default:
|
||||
dev_err(di->dev, "vendor %d not supported!\n", di->vendor);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fan53555_regulator_register(struct fan53555_device_info *di,
|
||||
@@ -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,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,4 +35,8 @@ struct regulator {
|
||||
struct dentry *debugfs;
|
||||
};
|
||||
|
||||
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
|
||||
const struct regulator_desc *desc,
|
||||
struct device_node **node);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* isl9305 - Intersil ISL9305 DCDC regulator
|
||||
*
|
||||
* Copyright 2014 Linaro Ltd
|
||||
*
|
||||
* Author: Mark Brown <broonie@kernel.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/isl9305.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* Registers
|
||||
*/
|
||||
#define ISL9305_DCD1OUT 0x0
|
||||
#define ISL9305_DCD2OUT 0x1
|
||||
#define ISL9305_LDO1OUT 0x2
|
||||
#define ISL9305_LDO2OUT 0x3
|
||||
#define ISL9305_DCD_PARAMETER 0x4
|
||||
#define ISL9305_SYSTEM_PARAMETER 0x5
|
||||
#define ISL9305_DCD_SRCTL 0x6
|
||||
|
||||
#define ISL9305_MAX_REG ISL9305_DCD_SRCTL
|
||||
|
||||
/*
|
||||
* DCD_PARAMETER
|
||||
*/
|
||||
#define ISL9305_DCD_PHASE 0x40
|
||||
#define ISL9305_DCD2_ULTRA 0x20
|
||||
#define ISL9305_DCD1_ULTRA 0x10
|
||||
#define ISL9305_DCD2_BLD 0x08
|
||||
#define ISL9305_DCD1_BLD 0x04
|
||||
#define ISL9305_DCD2_MODE 0x02
|
||||
#define ISL9305_DCD1_MODE 0x01
|
||||
|
||||
/*
|
||||
* SYSTEM_PARAMETER
|
||||
*/
|
||||
#define ISL9305_I2C_EN 0x40
|
||||
#define ISL9305_DCDPOR_MASK 0x30
|
||||
#define ISL9305_LDO2_EN 0x08
|
||||
#define ISL9305_LDO1_EN 0x04
|
||||
#define ISL9305_DCD2_EN 0x02
|
||||
#define ISL9305_DCD1_EN 0x01
|
||||
|
||||
/*
|
||||
* DCD_SRCTL
|
||||
*/
|
||||
#define ISL9305_DCD2SR_MASK 0xc0
|
||||
#define ISL9305_DCD1SR_MASK 0x07
|
||||
|
||||
static const struct regulator_ops isl9305_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
};
|
||||
|
||||
static const struct regulator_desc isl9305_regulators[] = {
|
||||
[ISL9305_DCD1] = {
|
||||
.name = "DCD1",
|
||||
.of_match = of_match_ptr("dcd1"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.n_voltages = 0x70,
|
||||
.min_uV = 825000,
|
||||
.uV_step = 25000,
|
||||
.vsel_reg = ISL9305_DCD1OUT,
|
||||
.vsel_mask = 0x7f,
|
||||
.enable_reg = ISL9305_SYSTEM_PARAMETER,
|
||||
.enable_mask = ISL9305_DCD1_EN,
|
||||
.supply_name = "VINDCD1",
|
||||
.ops = &isl9305_ops,
|
||||
},
|
||||
[ISL9305_DCD2] = {
|
||||
.name = "DCD2",
|
||||
.of_match = of_match_ptr("dcd2"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.n_voltages = 0x70,
|
||||
.min_uV = 825000,
|
||||
.uV_step = 25000,
|
||||
.vsel_reg = ISL9305_DCD2OUT,
|
||||
.vsel_mask = 0x7f,
|
||||
.enable_reg = ISL9305_SYSTEM_PARAMETER,
|
||||
.enable_mask = ISL9305_DCD2_EN,
|
||||
.supply_name = "VINDCD2",
|
||||
.ops = &isl9305_ops,
|
||||
},
|
||||
[ISL9305_LDO1] = {
|
||||
.name = "LDO1",
|
||||
.of_match = of_match_ptr("ldo1"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.n_voltages = 0x37,
|
||||
.min_uV = 900000,
|
||||
.uV_step = 50000,
|
||||
.vsel_reg = ISL9305_LDO1OUT,
|
||||
.vsel_mask = 0x3f,
|
||||
.enable_reg = ISL9305_SYSTEM_PARAMETER,
|
||||
.enable_mask = ISL9305_LDO1_EN,
|
||||
.supply_name = "VINLDO1",
|
||||
.ops = &isl9305_ops,
|
||||
},
|
||||
[ISL9305_LDO2] = {
|
||||
.name = "LDO2",
|
||||
.of_match = of_match_ptr("ldo2"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.n_voltages = 0x37,
|
||||
.min_uV = 900000,
|
||||
.uV_step = 50000,
|
||||
.vsel_reg = ISL9305_LDO2OUT,
|
||||
.vsel_mask = 0x3f,
|
||||
.enable_reg = ISL9305_SYSTEM_PARAMETER,
|
||||
.enable_mask = ISL9305_LDO2_EN,
|
||||
.supply_name = "VINLDO2",
|
||||
.ops = &isl9305_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config isl9305_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = ISL9305_MAX_REG,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int isl9305_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regulator_config config = { };
|
||||
struct isl9305_pdata *pdata = i2c->dev.platform_data;
|
||||
struct regulator_dev *rdev;
|
||||
struct regmap *regmap;
|
||||
int i, ret;
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, &isl9305_regmap);
|
||||
if (IS_ERR(regmap)) {
|
||||
ret = PTR_ERR(regmap);
|
||||
dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
config.dev = &i2c->dev;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(isl9305_regulators); i++) {
|
||||
if (pdata)
|
||||
config.init_data = pdata->init_data[i];
|
||||
else
|
||||
config.init_data = NULL;
|
||||
|
||||
rdev = devm_regulator_register(&i2c->dev,
|
||||
&isl9305_regulators[i],
|
||||
&config);
|
||||
if (IS_ERR(rdev)) {
|
||||
ret = PTR_ERR(rdev);
|
||||
dev_err(&i2c->dev, "Failed to register %s: %d\n",
|
||||
isl9305_regulators[i].name, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id isl9305_dt_ids[] = {
|
||||
{ .compatible = "isl,isl9305" },
|
||||
{ .compatible = "isl,isl9305h" },
|
||||
{},
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id isl9305_i2c_id[] = {
|
||||
{ "isl9305", },
|
||||
{ "isl9305h", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, isl9305_i2c_id);
|
||||
|
||||
static struct i2c_driver isl9305_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "isl9305",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(isl9305_dt_ids),
|
||||
},
|
||||
.probe = isl9305_i2c_probe,
|
||||
.id_table = isl9305_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(isl9305_regulator_driver);
|
||||
|
||||
MODULE_AUTHOR("Mark Brown");
|
||||
MODULE_DESCRIPTION("Intersil ISL9305 DCDC regulator");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -526,6 +526,7 @@ static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev)
|
||||
return REGULATOR_MODE_NORMAL;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* sky81452-regulator.c SKY81452 regulator driver
|
||||
*
|
||||
* Copyright 2014 Skyworks Solutions Inc.
|
||||
* Author : Gyungoh Yoo <jack.yoo@skyworksinc.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
|
||||
/* registers */
|
||||
#define SKY81452_REG1 0x01
|
||||
#define SKY81452_REG3 0x03
|
||||
|
||||
/* bit mask */
|
||||
#define SKY81452_LEN 0x40
|
||||
#define SKY81452_LOUT 0x1F
|
||||
|
||||
static struct regulator_ops sky81452_reg_ops = {
|
||||
.list_voltage = regulator_list_voltage_linear_range,
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range sky81452_reg_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(4500000, 0, 14, 250000),
|
||||
REGULATOR_LINEAR_RANGE(9000000, 15, 31, 1000000),
|
||||
};
|
||||
|
||||
static const struct regulator_desc sky81452_reg = {
|
||||
.name = "LOUT",
|
||||
.ops = &sky81452_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
.n_voltages = SKY81452_LOUT + 1,
|
||||
.linear_ranges = sky81452_reg_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(sky81452_reg_ranges),
|
||||
.vsel_reg = SKY81452_REG3,
|
||||
.vsel_mask = SKY81452_LOUT,
|
||||
.enable_reg = SKY81452_REG1,
|
||||
.enable_mask = SKY81452_LEN,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct regulator_init_data *sky81452_reg_parse_dt(struct device *dev)
|
||||
{
|
||||
struct regulator_init_data *init_data;
|
||||
struct device_node *np;
|
||||
|
||||
np = of_get_child_by_name(dev->parent->of_node, "regulator");
|
||||
if (unlikely(!np)) {
|
||||
dev_err(dev, "regulator node not found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
init_data = of_get_regulator_init_data(dev, np);
|
||||
|
||||
of_node_put(np);
|
||||
return init_data;
|
||||
}
|
||||
#else
|
||||
static struct regulator_init_data *sky81452_reg_parse_dt(struct device *dev)
|
||||
{
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int sky81452_reg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct regulator_init_data *init_data = dev_get_platdata(dev);
|
||||
struct regulator_config config = { };
|
||||
struct regulator_dev *rdev;
|
||||
|
||||
if (!init_data) {
|
||||
init_data = sky81452_reg_parse_dt(dev);
|
||||
if (IS_ERR(init_data))
|
||||
return PTR_ERR(init_data);
|
||||
}
|
||||
|
||||
config.dev = dev;
|
||||
config.init_data = init_data;
|
||||
config.of_node = dev->of_node;
|
||||
config.regmap = dev_get_drvdata(dev->parent);
|
||||
|
||||
rdev = devm_regulator_register(dev, &sky81452_reg, &config);
|
||||
if (IS_ERR(rdev))
|
||||
return PTR_ERR(rdev);
|
||||
|
||||
platform_set_drvdata(pdev, rdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver sky81452_reg_driver = {
|
||||
.driver = {
|
||||
.name = "sky81452-regulator",
|
||||
},
|
||||
.probe = sky81452_reg_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(sky81452_reg_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Skyworks SKY81452 Regulator driver");
|
||||
MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@skyworksinc.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("1.0");
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
* Regulator driver for ST's PWM Regulators
|
||||
*
|
||||
* Copyright (C) 2014 - STMicroelectronics Inc.
|
||||
*
|
||||
* Author: Lee Jones <lee.jones@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pwm.h>
|
||||
|
||||
#define ST_PWM_REG_PERIOD 8448
|
||||
|
||||
struct st_pwm_regulator_pdata {
|
||||
const struct regulator_desc *desc;
|
||||
struct st_pwm_voltages *duty_cycle_table;
|
||||
};
|
||||
|
||||
struct st_pwm_regulator_data {
|
||||
const struct st_pwm_regulator_pdata *pdata;
|
||||
struct pwm_device *pwm;
|
||||
bool enabled;
|
||||
int state;
|
||||
};
|
||||
|
||||
struct st_pwm_voltages {
|
||||
unsigned int uV;
|
||||
unsigned int dutycycle;
|
||||
};
|
||||
|
||||
static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev)
|
||||
{
|
||||
struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
||||
|
||||
return drvdata->state;
|
||||
}
|
||||
|
||||
static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
||||
int dutycycle;
|
||||
int ret;
|
||||
|
||||
dutycycle = (ST_PWM_REG_PERIOD / 100) *
|
||||
drvdata->pdata->duty_cycle_table[selector].dutycycle;
|
||||
|
||||
ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD);
|
||||
if (ret) {
|
||||
dev_err(&dev->dev, "Failed to configure PWM\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drvdata->state = selector;
|
||||
|
||||
if (!drvdata->enabled) {
|
||||
ret = pwm_enable(drvdata->pwm);
|
||||
if (ret) {
|
||||
dev_err(&dev->dev, "Failed to enable PWM\n");
|
||||
return ret;
|
||||
}
|
||||
drvdata->enabled = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_pwm_regulator_list_voltage(struct regulator_dev *dev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
|
||||
|
||||
if (selector >= dev->desc->n_voltages)
|
||||
return -EINVAL;
|
||||
|
||||
return drvdata->pdata->duty_cycle_table[selector].uV;
|
||||
}
|
||||
|
||||
static struct regulator_ops st_pwm_regulator_voltage_ops = {
|
||||
.set_voltage_sel = st_pwm_regulator_set_voltage_sel,
|
||||
.get_voltage_sel = st_pwm_regulator_get_voltage_sel,
|
||||
.list_voltage = st_pwm_regulator_list_voltage,
|
||||
.map_voltage = regulator_map_voltage_iterate,
|
||||
};
|
||||
|
||||
static struct st_pwm_voltages b2105_duty_cycle_table[] = {
|
||||
{ .uV = 1114000, .dutycycle = 0, },
|
||||
{ .uV = 1095000, .dutycycle = 10, },
|
||||
{ .uV = 1076000, .dutycycle = 20, },
|
||||
{ .uV = 1056000, .dutycycle = 30, },
|
||||
{ .uV = 1036000, .dutycycle = 40, },
|
||||
{ .uV = 1016000, .dutycycle = 50, },
|
||||
/* WARNING: Values above 50% duty-cycle cause boot failures. */
|
||||
};
|
||||
|
||||
static const struct regulator_desc b2105_desc = {
|
||||
.name = "b2105-pwm-regulator",
|
||||
.ops = &st_pwm_regulator_voltage_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
.n_voltages = ARRAY_SIZE(b2105_duty_cycle_table),
|
||||
.supply_name = "pwm",
|
||||
};
|
||||
|
||||
static const struct st_pwm_regulator_pdata b2105_info = {
|
||||
.desc = &b2105_desc,
|
||||
.duty_cycle_table = b2105_duty_cycle_table,
|
||||
};
|
||||
|
||||
static const struct of_device_id st_pwm_of_match[] = {
|
||||
{ .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_pwm_of_match);
|
||||
|
||||
static int st_pwm_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct st_pwm_regulator_data *drvdata;
|
||||
struct regulator_dev *regulator;
|
||||
struct regulator_config config = { };
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct of_device_id *of_match;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "Device Tree node missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
|
||||
of_match = of_match_device(st_pwm_of_match, &pdev->dev);
|
||||
if (!of_match) {
|
||||
dev_err(&pdev->dev, "failed to match of device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
drvdata->pdata = of_match->data;
|
||||
|
||||
config.init_data = of_get_regulator_init_data(&pdev->dev, np);
|
||||
if (!config.init_data)
|
||||
return -ENOMEM;
|
||||
|
||||
config.of_node = np;
|
||||
config.dev = &pdev->dev;
|
||||
config.driver_data = drvdata;
|
||||
|
||||
drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(drvdata->pwm)) {
|
||||
dev_err(&pdev->dev, "Failed to get PWM\n");
|
||||
return PTR_ERR(drvdata->pwm);
|
||||
}
|
||||
|
||||
regulator = devm_regulator_register(&pdev->dev,
|
||||
drvdata->pdata->desc, &config);
|
||||
if (IS_ERR(regulator)) {
|
||||
dev_err(&pdev->dev, "Failed to register regulator %s\n",
|
||||
drvdata->pdata->desc->name);
|
||||
return PTR_ERR(regulator);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver st_pwm_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "st-pwm-regulator",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(st_pwm_of_match),
|
||||
},
|
||||
.probe = st_pwm_regulator_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(st_pwm_regulator_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");
|
||||
MODULE_DESCRIPTION("ST PWM Regulator Driver");
|
||||
MODULE_ALIAS("platform:st_pwm-regulator");
|
||||
Reference in New Issue
Block a user