Commit 2c7a6a35 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'regulator/topic/fixed',...

Merge remote-tracking branches 'regulator/topic/fixed', 'regulator/topic/id-const', 'regulator/topic/ltc3589', 'regulator/topic/max8649' and 'regulator/topic/of' into regulator-next
Linear Technology LTC3589, LTC3589-1, and LTC3589-2 8-output regulators
Required properties:
- compatible: "lltc,ltc3589", "lltc,ltc3589-1" or "lltc,ltc3589-2"
- reg: I2C slave address
Required child node:
- regulators: Contains eight regulator child nodes sw1, sw2, sw3, bb-out,
ldo1, ldo2, ldo3, and ldo4, specifying the initialization data as
documented in Documentation/devicetree/bindings/regulator/regulator.txt.
Each regulator is defined using the standard binding for regulators. The
nodes for sw1, sw2, sw3, bb-out, ldo1, and ldo2 additionally need to specify
the resistor values of their external feedback voltage dividers:
Required properties (not on ldo3, ldo4):
- lltc,fb-voltage-divider: An array of two integers containing the resistor
values R1 and R2 of the feedback voltage divider in ohms.
Regulators sw1, sw2, sw3, and ldo2 can regulate the feedback reference from
0.3625 V to 0.75 V in 12.5 mV steps. The output voltage thus ranges between
0.3625 * (1 + R1/R2) V and 0.75 * (1 + R1/R2) V. Regulators bb-out and ldo1
have a fixed 0.8 V reference and thus output 0.8 * (1 + R1/R2) V. The ldo3
regulator is fixed to 1.8 V on LTC3589 and to 2.8 V on LTC3589-1,2. The ldo4
regulator can output between 1.8 V and 3.3 V on LTC3589 and between 1.2 V
and 3.2 V on LTC3589-1,2 in four steps. The ldo1 standby regulator can not
be disabled and thus should have the regulator-always-on property set.
Example:
ltc3589: pmic@34 {
compatible = "lltc,ltc3589-1";
reg = <0x34>;
regulators {
sw1_reg: sw1 {
regulator-min-microvolt = <591930>;
regulator-max-microvolt = <1224671>;
lltc,fb-voltage-divider = <100000 158000>;
regulator-ramp-delay = <7000>;
regulator-boot-on;
regulator-always-on;
};
sw2_reg: sw2 {
regulator-min-microvolt = <704123>;
regulator-max-microvolt = <1456803>;
lltc,fb-voltage-divider = <180000 191000>;
regulator-ramp-delay = <7000>;
regulator-boot-on;
regulator-always-on;
};
sw3_reg: sw3 {
regulator-min-microvolt = <1341250>;
regulator-max-microvolt = <2775000>;
lltc,fb-voltage-divider = <270000 100000>;
regulator-ramp-delay = <7000>;
regulator-boot-on;
regulator-always-on;
};
bb_out_reg: bb-out {
regulator-min-microvolt = <3387341>;
regulator-max-microvolt = <3387341>;
lltc,fb-voltage-divider = <511000 158000>;
regulator-boot-on;
regulator-always-on;
};
ldo1_reg: ldo1 {
regulator-min-microvolt = <1306329>;
regulator-max-microvolt = <1306329>;
lltc,fb-voltage-divider = <100000 158000>;
regulator-boot-on;
regulator-always-on;
};
ldo2_reg: ldo2 {
regulator-min-microvolt = <704123>;
regulator-max-microvolt = <1456806>;
lltc,fb-voltage-divider = <180000 191000>;
regulator-ramp-delay = <7000>;
regulator-boot-on;
regulator-always-on;
};
ldo3_reg: ldo3 {
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
regulator-boot-on;
};
ldo4_reg: ldo4 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3200000>;
};
};
};
...@@ -73,6 +73,7 @@ lantiq Lantiq Semiconductor ...@@ -73,6 +73,7 @@ lantiq Lantiq Semiconductor
lg LG Corporation lg LG Corporation
linux Linux-specific binding linux Linux-specific binding
lsi LSI Corp. (LSI Logic) lsi LSI Corp. (LSI Logic)
lltc Linear Technology Corporation
marvell Marvell Technology Group Ltd. marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products maxim Maxim Integrated Products
microchip Microchip Technology Inc. microchip Microchip Technology Inc.
......
...@@ -272,6 +272,14 @@ config REGULATOR_LP8788 ...@@ -272,6 +272,14 @@ config REGULATOR_LP8788
help help
This driver supports LP8788 voltage regulator chip. This driver supports LP8788 voltage regulator chip.
config REGULATOR_LTC3589
tristate "LTC3589 8-output voltage regulator"
depends on I2C
select REGMAP_I2C
help
This enables support for the LTC3589, LTC3589-1, and LTC3589-2
8-output regulators controlled via I2C.
config REGULATOR_MAX14577 config REGULATOR_MAX14577
tristate "Maxim 14577 regulator" tristate "Maxim 14577 regulator"
depends on MFD_MAX14577 depends on MFD_MAX14577
......
...@@ -38,6 +38,7 @@ obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o ...@@ -38,6 +38,7 @@ obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o
obj-$(CONFIG_REGULATOR_MAX14577) += max14577.o obj-$(CONFIG_REGULATOR_MAX14577) += max14577.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
......
...@@ -300,7 +300,7 @@ static int anatop_regulator_probe(struct platform_device *pdev) ...@@ -300,7 +300,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
return 0; return 0;
} }
static struct of_device_id of_anatop_regulator_match_tbl[] = { static const struct of_device_id of_anatop_regulator_match_tbl[] = {
{ .compatible = "fsl,anatop-regulator", }, { .compatible = "fsl,anatop-regulator", },
{ /* end */ } { /* end */ }
}; };
......
...@@ -3458,7 +3458,7 @@ regulator_register(const struct regulator_desc *regulator_desc, ...@@ -3458,7 +3458,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
/* register with sysfs */ /* register with sysfs */
rdev->dev.class = &regulator_class; rdev->dev.class = &regulator_class;
rdev->dev.of_node = config->of_node; rdev->dev.of_node = of_node_get(config->of_node);
rdev->dev.parent = dev; rdev->dev.parent = dev;
dev_set_name(&rdev->dev, "regulator.%d", dev_set_name(&rdev->dev, "regulator.%d",
atomic_inc_return(&regulator_no) - 1); atomic_inc_return(&regulator_no) - 1);
...@@ -3600,6 +3600,7 @@ void regulator_unregister(struct regulator_dev *rdev) ...@@ -3600,6 +3600,7 @@ void regulator_unregister(struct regulator_dev *rdev)
list_del(&rdev->list); list_del(&rdev->list);
kfree(rdev->constraints); kfree(rdev->constraints);
regulator_ena_gpio_free(rdev); regulator_ena_gpio_free(rdev);
of_node_put(rdev->dev.of_node);
device_unregister(&rdev->dev); device_unregister(&rdev->dev);
mutex_unlock(&regulator_list_mutex); mutex_unlock(&regulator_list_mutex);
} }
......
...@@ -50,7 +50,6 @@ of_get_fixed_voltage_config(struct device *dev) ...@@ -50,7 +50,6 @@ of_get_fixed_voltage_config(struct device *dev)
{ {
struct fixed_voltage_config *config; struct fixed_voltage_config *config;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
const __be32 *delay;
struct regulator_init_data *init_data; struct regulator_init_data *init_data;
config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config), config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
...@@ -91,15 +90,11 @@ of_get_fixed_voltage_config(struct device *dev) ...@@ -91,15 +90,11 @@ of_get_fixed_voltage_config(struct device *dev)
if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER)) if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER))
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
delay = of_get_property(np, "startup-delay-us", NULL); of_property_read_u32(np, "startup-delay-us", &config->startup_delay);
if (delay)
config->startup_delay = be32_to_cpu(*delay);
if (of_find_property(np, "enable-active-high", NULL)) config->enable_high = of_property_read_bool(np, "enable-active-high");
config->enable_high = true; config->gpio_is_open_drain = of_property_read_bool(np,
"gpio-open-drain");
if (of_find_property(np, "gpio-open-drain", NULL))
config->gpio_is_open_drain = true;
if (of_find_property(np, "vin-supply", NULL)) if (of_find_property(np, "vin-supply", NULL))
config->input_supply = "vin"; config->input_supply = "vin";
......
/*
* Linear Technology LTC3589,LTC3589-1 regulator support
*
* Copyright (c) 2014 Philipp Zabel <p.zabel@pengutronix.de>, Pengutronix
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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.
*
* 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/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#define DRIVER_NAME "ltc3589"
#define LTC3589_IRQSTAT 0x02
#define LTC3589_SCR1 0x07
#define LTC3589_OVEN 0x10
#define LTC3589_SCR2 0x12
#define LTC3589_PGSTAT 0x13
#define LTC3589_VCCR 0x20
#define LTC3589_CLIRQ 0x21
#define LTC3589_B1DTV1 0x23
#define LTC3589_B1DTV2 0x24
#define LTC3589_VRRCR 0x25
#define LTC3589_B2DTV1 0x26
#define LTC3589_B2DTV2 0x27
#define LTC3589_B3DTV1 0x29
#define LTC3589_B3DTV2 0x2a
#define LTC3589_L2DTV1 0x32
#define LTC3589_L2DTV2 0x33
#define LTC3589_IRQSTAT_PGOOD_TIMEOUT BIT(3)
#define LTC3589_IRQSTAT_UNDERVOLT_WARN BIT(4)
#define LTC3589_IRQSTAT_UNDERVOLT_FAULT BIT(5)
#define LTC3589_IRQSTAT_THERMAL_WARN BIT(6)
#define LTC3589_IRQSTAT_THERMAL_FAULT BIT(7)
#define LTC3589_OVEN_SW1 BIT(0)
#define LTC3589_OVEN_SW2 BIT(1)
#define LTC3589_OVEN_SW3 BIT(2)
#define LTC3589_OVEN_BB_OUT BIT(3)
#define LTC3589_OVEN_LDO2 BIT(4)
#define LTC3589_OVEN_LDO3 BIT(5)
#define LTC3589_OVEN_LDO4 BIT(6)
#define LTC3589_OVEN_SW_CTRL BIT(7)
#define LTC3589_VCCR_SW1_GO BIT(0)
#define LTC3589_VCCR_SW2_GO BIT(2)
#define LTC3589_VCCR_SW3_GO BIT(4)
#define LTC3589_VCCR_LDO2_GO BIT(6)
enum ltc3589_variant {
LTC3589,
LTC3589_1,
LTC3589_2,
};
enum ltc3589_reg {
LTC3589_SW1,
LTC3589_SW2,
LTC3589_SW3,
LTC3589_BB_OUT,
LTC3589_LDO1,
LTC3589_LDO2,
LTC3589_LDO3,
LTC3589_LDO4,
LTC3589_NUM_REGULATORS,
};
struct ltc3589_regulator {
struct regulator_desc desc;
/* External feedback voltage divider */
unsigned int r1;
unsigned int r2;
};
struct ltc3589 {
struct regmap *regmap;
struct device *dev;
enum ltc3589_variant variant;
struct ltc3589_regulator regulator_descs[LTC3589_NUM_REGULATORS];
struct regulator_dev *regulators[LTC3589_NUM_REGULATORS];
};
static const int ltc3589_ldo4[] = {
2800000, 2500000, 1800000, 3300000,
};
static const int ltc3589_12_ldo4[] = {
1200000, 1800000, 2500000, 3200000,
};
static int ltc3589_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
{
struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev);
int sel, shift;
if (unlikely(ramp_delay <= 0))
return -EINVAL;
/* VRRCR slew rate offsets are the same as VCCR go bit offsets */
shift = ffs(rdev->desc->apply_bit) - 1;
/* The slew rate can be set to 0.88, 1.75, 3.5, or 7 mV/uS */
for (sel = 0; sel < 4; sel++) {
if ((880 << sel) >= ramp_delay) {
return regmap_update_bits(ltc3589->regmap,
LTC3589_VRRCR,
0x3 << shift, sel << shift);
}
}
return -EINVAL;
}
static int ltc3589_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev);
int sel;
sel = regulator_map_voltage_linear(rdev, uV, uV);
if (sel < 0)
return sel;
/* DTV2 register follows right after the corresponding DTV1 register */
return regmap_update_bits(ltc3589->regmap, rdev->desc->vsel_reg + 1,
rdev->desc->vsel_mask, sel);
}
static int ltc3589_set_suspend_mode(struct regulator_dev *rdev,
unsigned int mode)
{
struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev);
int mask, bit = 0;
/* VCCR reference selects are right next to the VCCR go bits */
mask = rdev->desc->apply_bit << 1;
if (mode == REGULATOR_MODE_STANDBY)
bit = mask; /* Select DTV2 */
mask |= rdev->desc->apply_bit;
bit |= rdev->desc->apply_bit;
return regmap_update_bits(ltc3589->regmap, LTC3589_VCCR, mask, bit);
}
/* SW1, SW2, SW3, LDO2 */
static struct regulator_ops ltc3589_linear_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_ramp_delay = ltc3589_set_ramp_delay,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_suspend_voltage = ltc3589_set_suspend_voltage,
.set_suspend_mode = ltc3589_set_suspend_mode,
};
/* BB_OUT, LDO3 */
static struct regulator_ops ltc3589_fixed_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
};
/* LDO1 */
static struct regulator_ops ltc3589_fixed_standby_regulator_ops = {
};
/* LDO4 */
static struct regulator_ops ltc3589_table_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_table,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
#define LTC3589_REG(_name, _ops, en_bit, dtv1_reg, dtv_mask, go_bit) \
[LTC3589_ ## _name] = { \
.desc = { \
.name = #_name, \
.n_voltages = (dtv_mask) + 1, \
.min_uV = (go_bit) ? 362500 : 0, \
.uV_step = (go_bit) ? 12500 : 0, \
.ramp_delay = (go_bit) ? 1750 : 0, \
.fixed_uV = (dtv_mask) ? 0 : 800000, \
.ops = &ltc3589_ ## _ops ## _regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = LTC3589_ ## _name, \
.owner = THIS_MODULE, \
.vsel_reg = (dtv1_reg), \
.vsel_mask = (dtv_mask), \
.apply_reg = (go_bit) ? LTC3589_VCCR : 0, \
.apply_bit = (go_bit), \
.enable_reg = (en_bit) ? LTC3589_OVEN : 0, \
.enable_mask = (en_bit), \
}, \
}
#define LTC3589_LINEAR_REG(_name, _dtv1) \
LTC3589_REG(_name, linear, LTC3589_OVEN_ ## _name, \
LTC3589_ ## _dtv1, 0x1f, \
LTC3589_VCCR_ ## _name ## _GO)
#define LTC3589_FIXED_REG(_name) \
LTC3589_REG(_name, fixed, LTC3589_OVEN_ ## _name, 0, 0, 0)
static struct ltc3589_regulator ltc3589_regulators[LTC3589_NUM_REGULATORS] = {
LTC3589_LINEAR_REG(SW1, B1DTV1),
LTC3589_LINEAR_REG(SW2, B2DTV1),
LTC3589_LINEAR_REG(SW3, B3DTV1),
LTC3589_FIXED_REG(BB_OUT),
LTC3589_REG(LDO1, fixed_standby, 0, 0, 0, 0),
LTC3589_LINEAR_REG(LDO2, L2DTV1),
LTC3589_FIXED_REG(LDO3),
LTC3589_REG(LDO4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2, 0x60, 0),
};
#ifdef CONFIG_OF
static struct of_regulator_match ltc3589_matches[LTC3589_NUM_REGULATORS] = {
{ .name = "sw1", },
{ .name = "sw2", },
{ .name = "sw3", },
{ .name = "bb-out", },
{ .name = "ldo1", }, /* standby */
{ .name = "ldo2", },
{ .name = "ldo3", },
{ .name = "ldo4", },
};
static int ltc3589_parse_regulators_dt(struct ltc3589 *ltc3589)
{
struct device *dev = ltc3589->dev;
struct device_node *node;
int i, ret;
node = of_find_node_by_name(dev->of_node, "regulators");
if (!node) {
dev_err(dev, "regulators node not found\n");
return -EINVAL;
}
ret = of_regulator_match(dev, node, ltc3589_matches,
ARRAY_SIZE(ltc3589_matches));
of_node_put(node);
if (ret < 0) {
dev_err(dev, "Error parsing regulator init data: %d\n", ret);
return ret;
}
if (ret != LTC3589_NUM_REGULATORS) {
dev_err(dev, "Only %d regulators described in device tree\n",
ret);
return -EINVAL;
}
/* Parse feedback voltage dividers. LDO3 and LDO4 don't have them */
for (i = 0; i < LTC3589_LDO3; i++) {
struct ltc3589_regulator *desc = &ltc3589->regulator_descs[i];
struct device_node *np = ltc3589_matches[i].of_node;
u32 vdiv[2];
ret = of_property_read_u32_array(np, "lltc,fb-voltage-divider",
vdiv, 2);
if (ret) {
dev_err(dev, "Failed to parse voltage divider: %d\n",
ret);
return ret;
}
desc->r1 = vdiv[0];
desc->r2 = vdiv[1];
}
return 0;
}
static inline struct regulator_init_data *match_init_data(int index)
{
return ltc3589_matches[index].init_data;
}
static inline struct device_node *match_of_node(int index)
{
return ltc3589_matches[index].of_node;
}
#else
static inline int ltc3589_parse_regulators_dt(struct ltc3589 *ltc3589)
{
return 0;
}
static inline struct regulator_init_data *match_init_data(int index)
{
return NULL;
}
static inline struct device_node *match_of_node(int index)
{
return NULL;
}
#endif
static bool ltc3589_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case LTC3589_IRQSTAT:
case LTC3589_SCR1:
case LTC3589_OVEN:
case LTC3589_SCR2:
case LTC3589_VCCR:
case LTC3589_CLIRQ:
case LTC3589_B1DTV1:
case LTC3589_B1DTV2:
case LTC3589_VRRCR:
case LTC3589_B2DTV1:
case LTC3589_B2DTV2:
case LTC3589_B3DTV1:
case LTC3589_B3DTV2:
case LTC3589_L2DTV1:
case LTC3589_L2DTV2:
return true;
}
return false;
}
static bool ltc3589_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case LTC3589_IRQSTAT:
case LTC3589_SCR1:
case LTC3589_OVEN:
case LTC3589_SCR2:
case LTC3589_PGSTAT:
case LTC3589_VCCR:
case LTC3589_B1DTV1:
case LTC3589_B1DTV2:
case LTC3589_VRRCR:
case LTC3589_B2DTV1:
case LTC3589_B2DTV2:
case LTC3589_B3DTV1:
case LTC3589_B3DTV2:
case LTC3589_L2DTV1:
case LTC3589_L2DTV2:
return true;
}
return false;
}
static bool ltc3589_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case LTC3589_IRQSTAT:
case LTC3589_PGSTAT:
return true;
}
return false;
}
struct reg_default ltc3589_reg_defaults[] = {
{ LTC3589_SCR1, 0x00 },
{ LTC3589_OVEN, 0x00 },
{ LTC3589_SCR2, 0x00 },
{ LTC3589_VCCR, 0x00 },
{ LTC3589_B1DTV1, 0x19 },
{ LTC3589_B1DTV2, 0x19 },
{ LTC3589_VRRCR, 0xff },
{ LTC3589_B2DTV1, 0x19 },
{ LTC3589_B2DTV2, 0x19 },
{ LTC3589_B3DTV1, 0x19 },
{ LTC3589_B3DTV2, 0x19 },
{ LTC3589_L2DTV1, 0x19 },
{ LTC3589_L2DTV2, 0x19 },
};
static const struct regmap_config ltc3589_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.writeable_reg = ltc3589_writeable_reg,
.readable_reg = ltc3589_readable_reg,
.volatile_reg = ltc3589_volatile_reg,
.max_register = LTC3589_L2DTV2,
.reg_defaults = ltc3589_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(ltc3589_reg_defaults),
.use_single_rw = true,
.cache_type = REGCACHE_RBTREE,
};
static irqreturn_t ltc3589_isr(int irq, void *dev_id)
{
struct ltc3589 *ltc3589 = dev_id;
unsigned int i, irqstat, event;
regmap_read(ltc3589->regmap, LTC3589_IRQSTAT, &irqstat);
if (irqstat & LTC3589_IRQSTAT_THERMAL_WARN) {
event = REGULATOR_EVENT_OVER_TEMP;
for (i = 0; i < LTC3589_NUM_REGULATORS; i++)
regulator_notifier_call_chain(ltc3589->regulators[i],
event, NULL);
}
if (irqstat & LTC3589_IRQSTAT_UNDERVOLT_WARN) {
event = REGULATOR_EVENT_UNDER_VOLTAGE;
for (i = 0; i < LTC3589_NUM_REGULATORS; i++)
regulator_notifier_call_chain(ltc3589->regulators[i],
event, NULL);
}
/* Clear warning condition */
regmap_write(ltc3589->regmap, LTC3589_CLIRQ, 0);
return IRQ_HANDLED;
}
static inline unsigned int ltc3589_scale(unsigned int uV, u32 r1, u32 r2)
{
uint64_t tmp;
if (uV == 0)
return 0;
tmp = (uint64_t)uV * r1;
do_div(tmp, r2);
return uV + (unsigned int)tmp;
}
static void ltc3589_apply_fb_voltage_divider(struct ltc3589_regulator *rdesc)
{
struct regulator_desc *desc = &rdesc->desc;
if (!rdesc->r1 || !rdesc->r2)
return;
desc->min_uV = ltc3589_scale(desc->min_uV, rdesc->r1, rdesc->r2);
desc->uV_step = ltc3589_scale(desc->uV_step, rdesc->r1, rdesc->r2);
desc->fixed_uV = ltc3589_scale(desc->fixed_uV, rdesc->r1, rdesc->r2);
}
static int ltc3589_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct ltc3589_regulator *descs;
struct ltc3589 *ltc3589;
int i, ret;
ltc3589 = devm_kzalloc(dev, sizeof(*ltc3589), GFP_KERNEL);
if (!ltc3589)
return -ENOMEM;
i2c_set_clientdata(client, ltc3589);
ltc3589->variant = id->driver_data;
ltc3589->dev = dev;
descs = ltc3589->regulator_descs;
memcpy(descs, ltc3589_regulators, sizeof(ltc3589_regulators));
if (ltc3589->variant == LTC3589) {
descs[LTC3589_LDO3].desc.fixed_uV = 1800000;
descs[LTC3589_LDO4].desc.volt_table = ltc3589_ldo4;
} else {
descs[LTC3589_LDO3].desc.fixed_uV = 2800000;
descs[LTC3589_LDO4].desc.volt_table = ltc3589_12_ldo4;
}
ltc3589->regmap = devm_regmap_init_i2c(client, &ltc3589_regmap_config);
if (IS_ERR(ltc3589->regmap)) {
ret = PTR_ERR(ltc3589->regmap);
dev_err(dev, "failed to initialize regmap: %d\n", ret);
return ret;
}
ret = ltc3589_parse_regulators_dt(ltc3589);
if (ret)
return ret;
for (i = 0; i < LTC3589_NUM_REGULATORS; i++) {
struct ltc3589_regulator *rdesc = &ltc3589->regulator_descs[i];
struct regulator_desc *desc = &rdesc->desc;
struct regulator_init_data *init_data;
struct regulator_config config = { };
init_data = match_init_data(i);
if (i < LTC3589_LDO3)
ltc3589_apply_fb_voltage_divider(rdesc);
config.dev = dev;
config.init_data = init_data;
config.driver_data = ltc3589;
config.of_node = match_of_node(i);
ltc3589->regulators[i] = devm_regulator_register(dev, desc,
&config);
if (IS_ERR(ltc3589->regulators[i])) {
ret = PTR_ERR(ltc3589->regulators[i]);
dev_err(dev, "failed to register regulator %s: %d\n",
desc->name, ret);
return ret;
}
}
ret = devm_request_threaded_irq(dev, client->irq, NULL, ltc3589_isr,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
client->name, ltc3589);
if (ret) {
dev_err(dev, "Failed to request IRQ: %d\n", ret);
return ret;
}
return 0;
}
static struct i2c_device_id ltc3589_i2c_id[] = {
{ "ltc3589", LTC3589 },
{ "ltc3589-1", LTC3589_1 },
{ "ltc3589-2", LTC3589_2 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc3589_i2c_id);
static struct i2c_driver ltc3589_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
.probe = ltc3589_probe,
.id_table = ltc3589_i2c_id,
};
module_i2c_driver(ltc3589_driver);
MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
MODULE_DESCRIPTION("Regulator driver for Linear Technology LTC3589(-1,2)");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("i2c:ltc3589");
...@@ -161,10 +161,8 @@ static int max8649_regulator_probe(struct i2c_client *client, ...@@ -161,10 +161,8 @@ static int max8649_regulator_probe(struct i2c_client *client,
info = devm_kzalloc(&client->dev, sizeof(struct max8649_regulator_info), info = devm_kzalloc(&client->dev, sizeof(struct max8649_regulator_info),
GFP_KERNEL); GFP_KERNEL);
if (!info) { if (!info)
dev_err(&client->dev, "No enough memory\n");
return -ENOMEM; return -ENOMEM;
}
info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config); info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config);
if (IS_ERR(info->regmap)) { if (IS_ERR(info->regmap)) {
......
...@@ -129,7 +129,7 @@ static const struct regulator_desc regulator = { ...@@ -129,7 +129,7 @@ static const struct regulator_desc regulator = {
}; };
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct of_device_id max8952_dt_match[] = { static const struct of_device_id max8952_dt_match[] = {
{ .compatible = "maxim,max8952" }, { .compatible = "maxim,max8952" },
{}, {},
}; };
......
...@@ -19,9 +19,7 @@ ...@@ -19,9 +19,7 @@
static void of_get_regulation_constraints(struct device_node *np, static void of_get_regulation_constraints(struct device_node *np,
struct regulator_init_data **init_data) struct regulator_init_data **init_data)
{ {
const __be32 *min_uV, *max_uV, *uV_offset; const __be32 *min_uV, *max_uV;
const __be32 *min_uA, *max_uA, *ramp_delay;
struct property *prop;
struct regulation_constraints *constraints = &(*init_data)->constraints; struct regulation_constraints *constraints = &(*init_data)->constraints;
int ret; int ret;
u32 pval; u32 pval;
...@@ -42,36 +40,29 @@ static void of_get_regulation_constraints(struct device_node *np, ...@@ -42,36 +40,29 @@ static void of_get_regulation_constraints(struct device_node *np,
if (min_uV && max_uV && constraints->min_uV == constraints->max_uV) if (min_uV && max_uV && constraints->min_uV == constraints->max_uV)
constraints->apply_uV = true; constraints->apply_uV = true;
uV_offset = of_get_property(np, "regulator-microvolt-offset", NULL); if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
if (uV_offset) constraints->uV_offset = pval;
constraints->uV_offset = be32_to_cpu(*uV_offset); if (!of_property_read_u32(np, "regulator-min-microamp", &pval))
min_uA = of_get_property(np, "regulator-min-microamp", NULL); constraints->min_uA = pval;
if (min_uA) if (!of_property_read_u32(np, "regulator-max-microamp", &pval))
constraints->min_uA = be32_to_cpu(*min_uA); constraints->max_uA = pval;
max_uA = of_get_property(np, "regulator-max-microamp", NULL);
if (max_uA)
constraints->max_uA = be32_to_cpu(*max_uA);
/* Current change possible? */ /* Current change possible? */
if (constraints->min_uA != constraints->max_uA) if (constraints->min_uA != constraints->max_uA)
constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT; constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
if (of_find_property(np, "regulator-boot-on", NULL)) constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
constraints->boot_on = true; constraints->always_on = of_property_read_bool(np, "regulator-always-on");
if (!constraints->always_on) /* status change should be possible. */
if (of_find_property(np, "regulator-always-on", NULL))
constraints->always_on = true;
else /* status change should be possible if not always on. */
constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS; constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
if (of_property_read_bool(np, "regulator-allow-bypass")) if (of_property_read_bool(np, "regulator-allow-bypass"))
constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS; constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
prop = of_find_property(np, "regulator-ramp-delay", NULL); ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
if (prop && prop->value) { if (!ret) {
ramp_delay = prop->value; if (pval)
if (*ramp_delay) constraints->ramp_delay = pval;
constraints->ramp_delay = be32_to_cpu(*ramp_delay);
else else
constraints->ramp_disable = true; constraints->ramp_disable = true;
} }
...@@ -106,6 +97,20 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, ...@@ -106,6 +97,20 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
} }
EXPORT_SYMBOL_GPL(of_get_regulator_init_data); EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
struct devm_of_regulator_matches {
struct of_regulator_match *matches;
unsigned int num_matches;
};
static void devm_of_regulator_put_matches(struct device *dev, void *res)
{
struct devm_of_regulator_matches *devm_matches = res;
int i;
for (i = 0; i < devm_matches->num_matches; i++)
of_node_put(devm_matches->matches[i].of_node);
}
/** /**
* of_regulator_match - extract multiple regulator init data from device tree. * of_regulator_match - extract multiple regulator init data from device tree.
* @dev: device requesting the data * @dev: device requesting the data
...@@ -119,7 +124,8 @@ EXPORT_SYMBOL_GPL(of_get_regulator_init_data); ...@@ -119,7 +124,8 @@ EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
* regulator. The data parsed from a child node will be matched to a regulator * regulator. The data parsed from a child node will be matched to a regulator
* based on either the deprecated property regulator-compatible if present, * based on either the deprecated property regulator-compatible if present,
* or otherwise the child node's name. Note that the match table is modified * or otherwise the child node's name. Note that the match table is modified
* in place. * in place and an additional of_node reference is taken for each matched
* regulator.
* *
* Returns the number of matches found or a negative error code on failure. * Returns the number of matches found or a negative error code on failure.
*/ */
...@@ -131,10 +137,22 @@ int of_regulator_match(struct device *dev, struct device_node *node, ...@@ -131,10 +137,22 @@ int of_regulator_match(struct device *dev, struct device_node *node,
unsigned int i; unsigned int i;
const char *name; const char *name;
struct device_node *child; struct device_node *child;
struct devm_of_regulator_matches *devm_matches;
if (!dev || !node) if (!dev || !node)
return -EINVAL; return -EINVAL;
devm_matches = devres_alloc(devm_of_regulator_put_matches,
sizeof(struct devm_of_regulator_matches),
GFP_KERNEL);
if (!devm_matches)
return -ENOMEM;
devm_matches->matches = matches;
devm_matches->num_matches = num_matches;
devres_add(dev, devm_matches);
for (i = 0; i < num_matches; i++) { for (i = 0; i < num_matches; i++) {
struct of_regulator_match *match = &matches[i]; struct of_regulator_match *match = &matches[i];
match->init_data = NULL; match->init_data = NULL;
...@@ -162,7 +180,7 @@ int of_regulator_match(struct device *dev, struct device_node *node, ...@@ -162,7 +180,7 @@ int of_regulator_match(struct device *dev, struct device_node *node,
child->name); child->name);
return -EINVAL; return -EINVAL;
} }
match->of_node = child; match->of_node = of_node_get(child);
count++; count++;
break; break;
} }
......
...@@ -1199,7 +1199,7 @@ static int palmas_regulators_probe(struct platform_device *pdev) ...@@ -1199,7 +1199,7 @@ static int palmas_regulators_probe(struct platform_device *pdev)
return 0; return 0;
} }
static struct of_device_id of_palmas_match_tbl[] = { static const struct of_device_id of_palmas_match_tbl[] = {
{ .compatible = "ti,palmas-pmic", }, { .compatible = "ti,palmas-pmic", },
{ .compatible = "ti,twl6035-pmic", }, { .compatible = "ti,twl6035-pmic", },
{ .compatible = "ti,twl6036-pmic", }, { .compatible = "ti,twl6036-pmic", },
......
...@@ -118,7 +118,7 @@ static const struct st_pwm_regulator_pdata b2105_info = { ...@@ -118,7 +118,7 @@ static const struct st_pwm_regulator_pdata b2105_info = {
.duty_cycle_table = b2105_duty_cycle_table, .duty_cycle_table = b2105_duty_cycle_table,
}; };
static struct of_device_id st_pwm_of_match[] = { static const struct of_device_id st_pwm_of_match[] = {
{ .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, }, { .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, },
{ }, { },
}; };
......
...@@ -123,7 +123,7 @@ static int vexpress_regulator_remove(struct platform_device *pdev) ...@@ -123,7 +123,7 @@ static int vexpress_regulator_remove(struct platform_device *pdev)
return 0; return 0;
} }
static struct of_device_id vexpress_regulator_of_match[] = { static const struct of_device_id vexpress_regulator_of_match[] = {
{ .compatible = "arm,vexpress-volt", }, { .compatible = "arm,vexpress-volt", },
{ } { }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment