Merge remote-tracking branches 'regulator/topic/discharge', 'regulator/topic/fan53555', 'regulator/topic/gpio', 'regulator/topic/hi655x' and 'regulator/topic/lp872x' into regulator-next

This commit is contained in:
Mark Brown 2016-03-13 15:19:35 +07:00
15 changed files with 402 additions and 5 deletions

View File

@ -0,0 +1,29 @@
Hisilicon Hi655x Voltage regulators
Note:
The Hi655x regulator control is managed by Hi655x PMIC.
So the node of this regulator must be child node of Hi655x
PMIC node.
The driver uses the regulator core framework, so please also
take the bindings of regulator.txt for reference.
The valid names for regulators are:
LDO2_2V8 LDO7_SDIO LDO10_2V85 LDO13_1V8 LDO14_2V8
LDO15_1V8 LDO17_2V5 LDO19_3V0 LDO21_1V8 LDO22_1V2
Example:
pmic: pmic@f8000000 {
compatible = "hisilicon,hi655x-pmic";
...
regulators {
ldo2: LDO2@a21 {
regulator-name = "LDO2_2V8";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <3200000>;
regulator-enable-ramp-delay = <120>;
};
...
}
}

View File

@ -28,6 +28,7 @@ Optional properties:
- ti,dvs-gpio: GPIO specifier for external DVS pin control of LP872x devices.
- ti,dvs-vsel: DVS selector. 0 = SEL_V1, 1 = SEL_V2.
- ti,dvs-state: initial DVS pin state. 0 = DVS_LOW, 1 = DVS_HIGH.
- enable-gpios: GPIO specifier for EN pin control of LP872x devices.
Sub nodes for regulator_init_data
LP8720 has maximum 6 nodes. (child name: ldo1 ~ 5 and buck)

View File

@ -44,6 +44,11 @@ Optional properties:
any consumer request.
- regulator-pull-down: Enable pull down resistor when the regulator is disabled.
- regulator-over-current-protection: Enable over current protection.
- regulator-active-discharge: tristate, enable/disable active discharge of
regulators. The values are:
0: Disable active discharge.
1: Enable active discharge.
Absence of this property will leave configuration to default.
Deprecated properties:
- regulator-compatible: If a regulator chip contains multiple

View File

@ -270,6 +270,14 @@ config REGULATOR_HI6421
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_HI655X
tristate "Hisilicon HI655X PMIC regulators support"
depends on ARCH_HISI || COMPILE_TEST
depends on MFD_HI655X_PMIC && OF
help
This driver provides support for the voltage regulators of the
Hisilicon Hi655x PMIC device.
config REGULATOR_ISL9305
tristate "Intersil ISL9305 regulator"
depends on I2C

View File

@ -35,6 +35,7 @@ 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_HI655X) += hi655x-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o

View File

@ -1139,6 +1139,17 @@ static int set_machine_constraints(struct regulator_dev *rdev,
}
}
if (rdev->constraints->active_discharge && ops->set_active_discharge) {
bool ad_state = (rdev->constraints->active_discharge ==
REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;
ret = ops->set_active_discharge(rdev, ad_state);
if (ret < 0) {
rdev_err(rdev, "failed to set active discharge\n");
return ret;
}
}
print_constraints(rdev);
return 0;
}

View File

@ -114,6 +114,22 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)
return 0;
}
static int fan53555_set_suspend_enable(struct regulator_dev *rdev)
{
struct fan53555_device_info *di = rdev_get_drvdata(rdev);
return regmap_update_bits(di->regmap, di->sleep_reg,
VSEL_BUCK_EN, VSEL_BUCK_EN);
}
static int fan53555_set_suspend_disable(struct regulator_dev *rdev)
{
struct fan53555_device_info *di = rdev_get_drvdata(rdev);
return regmap_update_bits(di->regmap, di->sleep_reg,
VSEL_BUCK_EN, 0);
}
static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct fan53555_device_info *di = rdev_get_drvdata(rdev);
@ -192,6 +208,8 @@ static struct regulator_ops fan53555_regulator_ops = {
.set_mode = fan53555_set_mode,
.get_mode = fan53555_get_mode,
.set_ramp_delay = fan53555_set_ramp,
.set_suspend_enable = fan53555_set_suspend_enable,
.set_suspend_disable = fan53555_set_suspend_disable,
};
static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)

View File

@ -283,8 +283,10 @@ static int gpio_regulator_probe(struct platform_device *pdev)
drvdata->nr_gpios = config->nr_gpios;
ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios);
if (ret) {
dev_err(&pdev->dev,
"Could not obtain regulator setting GPIOs: %d\n", ret);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"Could not obtain regulator setting GPIOs: %d\n",
ret);
goto err_memstate;
}
}

View File

@ -465,3 +465,26 @@ int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
return 0;
}
EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
/**
* regulator_set_active_discharge_regmap - Default set_active_discharge()
* using regmap
*
* @rdev: device to operate on.
* @enable: state to set, 0 to disable and 1 to enable.
*/
int regulator_set_active_discharge_regmap(struct regulator_dev *rdev,
bool enable)
{
unsigned int val;
if (enable)
val = rdev->desc->active_discharge_on;
else
val = rdev->desc->active_discharge_off;
return regmap_update_bits(rdev->regmap,
rdev->desc->active_discharge_reg,
rdev->desc->active_discharge_mask, val);
}
EXPORT_SYMBOL_GPL(regulator_set_active_discharge_regmap);

View File

@ -0,0 +1,227 @@
/*
* Device driver for regulators in Hi655x IC
*
* Copyright (c) 2016 Hisilicon.
*
* Authors:
* Chen Feng <puck.chen@hisilicon.com>
* Fei Wang <w.f@huawei.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/hi655x-pmic.h>
struct hi655x_regulator {
unsigned int disable_reg;
unsigned int status_reg;
unsigned int ctrl_regs;
unsigned int ctrl_mask;
struct regulator_desc rdesc;
};
/* LDO7 & LDO10 */
static const unsigned int ldo7_voltages[] = {
1800000, 1850000, 2850000, 2900000,
3000000, 3100000, 3200000, 3300000,
};
static const unsigned int ldo19_voltages[] = {
1800000, 1850000, 1900000, 1750000,
2800000, 2850000, 2900000, 3000000,
};
static const unsigned int ldo22_voltages[] = {
900000, 1000000, 1050000, 1100000,
1150000, 1175000, 1185000, 1200000,
};
enum hi655x_regulator_id {
HI655X_LDO0,
HI655X_LDO1,
HI655X_LDO2,
HI655X_LDO3,
HI655X_LDO4,
HI655X_LDO5,
HI655X_LDO6,
HI655X_LDO7,
HI655X_LDO8,
HI655X_LDO9,
HI655X_LDO10,
HI655X_LDO11,
HI655X_LDO12,
HI655X_LDO13,
HI655X_LDO14,
HI655X_LDO15,
HI655X_LDO16,
HI655X_LDO17,
HI655X_LDO18,
HI655X_LDO19,
HI655X_LDO20,
HI655X_LDO21,
HI655X_LDO22,
};
static int hi655x_is_enabled(struct regulator_dev *rdev)
{
unsigned int value = 0;
struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
regmap_read(rdev->regmap, regulator->status_reg, &value);
return (value & BIT(regulator->ctrl_mask));
}
static int hi655x_disable(struct regulator_dev *rdev)
{
int ret = 0;
struct hi655x_regulator *regulator = rdev_get_drvdata(rdev);
ret = regmap_write(rdev->regmap, regulator->disable_reg,
BIT(regulator->ctrl_mask));
return ret;
}
static struct regulator_ops hi655x_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = hi655x_disable,
.is_enabled = hi655x_is_enabled,
.list_voltage = regulator_list_voltage_table,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
static struct regulator_ops hi655x_ldo_linear_ops = {
.enable = regulator_enable_regmap,
.disable = hi655x_disable,
.is_enabled = hi655x_is_enabled,
.list_voltage = regulator_list_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
#define HI655X_LDO(_ID, vreg, vmask, ereg, dreg, \
sreg, cmask, vtable) { \
.rdesc = { \
.name = #_ID, \
.of_match = of_match_ptr(#_ID), \
.ops = &hi655x_regulator_ops, \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = HI655X_##_ID, \
.owner = THIS_MODULE, \
.n_voltages = ARRAY_SIZE(vtable), \
.volt_table = vtable, \
.vsel_reg = HI655X_BUS_ADDR(vreg), \
.vsel_mask = vmask, \
.enable_reg = HI655X_BUS_ADDR(ereg), \
.enable_mask = BIT(cmask), \
}, \
.disable_reg = HI655X_BUS_ADDR(dreg), \
.status_reg = HI655X_BUS_ADDR(sreg), \
.ctrl_mask = cmask, \
}
#define HI655X_LDO_LINEAR(_ID, vreg, vmask, ereg, dreg, \
sreg, cmask, minv, nvolt, vstep) { \
.rdesc = { \
.name = #_ID, \
.of_match = of_match_ptr(#_ID), \
.ops = &hi655x_ldo_linear_ops, \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = HI655X_##_ID, \
.owner = THIS_MODULE, \
.min_uV = minv, \
.n_voltages = nvolt, \
.uV_step = vstep, \
.vsel_reg = HI655X_BUS_ADDR(vreg), \
.vsel_mask = vmask, \
.enable_reg = HI655X_BUS_ADDR(ereg), \
.enable_mask = BIT(cmask), \
}, \
.disable_reg = HI655X_BUS_ADDR(dreg), \
.status_reg = HI655X_BUS_ADDR(sreg), \
.ctrl_mask = cmask, \
}
static struct hi655x_regulator regulators[] = {
HI655X_LDO_LINEAR(LDO2, 0x72, 0x07, 0x29, 0x2a, 0x2b, 0x01,
2500000, 8, 100000),
HI655X_LDO(LDO7, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x06, ldo7_voltages),
HI655X_LDO(LDO10, 0x78, 0x07, 0x29, 0x2a, 0x2b, 0x01, ldo7_voltages),
HI655X_LDO_LINEAR(LDO13, 0x7e, 0x07, 0x2c, 0x2d, 0x2e, 0x04,
1600000, 8, 50000),
HI655X_LDO_LINEAR(LDO14, 0x7f, 0x07, 0x2c, 0x2d, 0x2e, 0x05,
2500000, 8, 100000),
HI655X_LDO_LINEAR(LDO15, 0x80, 0x07, 0x2c, 0x2d, 0x2e, 0x06,
1600000, 8, 50000),
HI655X_LDO_LINEAR(LDO17, 0x82, 0x07, 0x2f, 0x30, 0x31, 0x00,
2500000, 8, 100000),
HI655X_LDO(LDO19, 0x84, 0x07, 0x2f, 0x30, 0x31, 0x02, ldo19_voltages),
HI655X_LDO_LINEAR(LDO21, 0x86, 0x07, 0x2f, 0x30, 0x31, 0x04,
1650000, 8, 50000),
HI655X_LDO(LDO22, 0x87, 0x07, 0x2f, 0x30, 0x31, 0x05, ldo22_voltages),
};
static int hi655x_regulator_probe(struct platform_device *pdev)
{
unsigned int i;
struct hi655x_regulator *regulator;
struct hi655x_pmic *pmic;
struct regulator_config config = { };
struct regulator_dev *rdev;
pmic = dev_get_drvdata(pdev->dev.parent);
if (!pmic) {
dev_err(&pdev->dev, "no pmic in the regulator parent node\n");
return -ENODEV;
}
regulator = devm_kzalloc(&pdev->dev, sizeof(*regulator), GFP_KERNEL);
if (!regulator)
return -ENOMEM;
platform_set_drvdata(pdev, regulator);
config.dev = pdev->dev.parent;
config.regmap = pmic->regmap;
config.driver_data = regulator;
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
rdev = devm_regulator_register(&pdev->dev,
&regulators[i].rdesc,
&config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
regulator->rdesc.name);
return PTR_ERR(rdev);
}
}
return 0;
}
static struct platform_driver hi655x_regulator_driver = {
.driver = {
.name = "hi655x-regulator",
},
.probe = hi655x_regulator_probe,
};
module_platform_driver(hi655x_regulator_driver);
MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>");
MODULE_DESCRIPTION("Hisilicon Hi655x regulator driver");
MODULE_LICENSE("GPL v2");

View File

@ -15,6 +15,7 @@
#include <linux/regmap.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/regulator/lp872x.h>
#include <linux/regulator/driver.h>
#include <linux/platform_device.h>
@ -738,10 +739,8 @@ static int lp872x_init_dvs(struct lp872x *lp)
goto set_default_dvs_mode;
gpio = dvs->gpio;
if (!gpio_is_valid(gpio)) {
dev_warn(lp->dev, "invalid gpio: %d\n", gpio);
if (!gpio_is_valid(gpio))
goto set_default_dvs_mode;
}
pinstate = dvs->init_state;
ret = devm_gpio_request_one(lp->dev, gpio, pinstate, "LP872X DVS");
@ -759,6 +758,33 @@ set_default_dvs_mode:
default_dvs_mode[lp->chipid]);
}
static int lp872x_hw_enable(struct lp872x *lp)
{
int ret, gpio;
if (!lp->pdata)
return -EINVAL;
gpio = lp->pdata->enable_gpio;
if (!gpio_is_valid(gpio))
return 0;
/* Always set enable GPIO high. */
ret = devm_gpio_request_one(lp->dev, gpio, GPIOF_OUT_INIT_HIGH, "LP872X EN");
if (ret) {
dev_err(lp->dev, "gpio request err: %d\n", ret);
return ret;
}
/* Each chip has a different enable delay. */
if (lp->chipid == LP8720)
usleep_range(LP8720_ENABLE_DELAY, 1.5 * LP8720_ENABLE_DELAY);
else
usleep_range(LP8725_ENABLE_DELAY, 1.5 * LP8725_ENABLE_DELAY);
return 0;
}
static int lp872x_config(struct lp872x *lp)
{
struct lp872x_platform_data *pdata = lp->pdata;
@ -877,6 +903,8 @@ static struct lp872x_platform_data
of_property_read_u8(np, "ti,dvs-state", &dvs_state);
pdata->dvs->init_state = dvs_state ? DVS_HIGH : DVS_LOW;
pdata->enable_gpio = of_get_named_gpio(np, "enable-gpios", 0);
if (of_get_child_count(np) == 0)
goto out;
@ -950,6 +978,10 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
lp->chipid = id->driver_data;
i2c_set_clientdata(cl, lp);
ret = lp872x_hw_enable(lp);
if (ret)
return ret;
ret = lp872x_config(lp);
if (ret)
return ret;

View File

@ -93,6 +93,12 @@ static void of_get_regulation_constraints(struct device_node *np,
constraints->soft_start = of_property_read_bool(np,
"regulator-soft-start");
ret = of_property_read_u32(np, "regulator-active-discharge", &pval);
if (!ret) {
constraints->active_discharge =
(pval) ? REGULATOR_ACTIVE_DISCHARGE_ENABLE :
REGULATOR_ACTIVE_DISCHARGE_DISABLE;
}
if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) {
if (desc && desc->of_map_mode) {

View File

@ -93,6 +93,8 @@ struct regulator_linear_range {
* @get_current_limit: Get the configured limit for a current-limited regulator.
* @set_input_current_limit: Configure an input limit.
*
* @set_active_discharge: Set active discharge enable/disable of regulators.
*
* @set_mode: Set the configured operating mode for the regulator.
* @get_mode: Get the configured operating mode for the regulator.
* @get_status: Return actual (not as-configured) status of regulator, as a
@ -149,6 +151,7 @@ struct regulator_ops {
int (*set_input_current_limit) (struct regulator_dev *, int lim_uA);
int (*set_over_current_protection) (struct regulator_dev *);
int (*set_active_discharge) (struct regulator_dev *, bool enable);
/* enable/disable regulator */
int (*enable) (struct regulator_dev *);
@ -266,6 +269,14 @@ enum regulator_type {
* @bypass_mask: Mask for control when using regmap set_bypass
* @bypass_val_on: Enabling value for control when using regmap set_bypass
* @bypass_val_off: Disabling value for control when using regmap set_bypass
* @active_discharge_off: Enabling value for control when using regmap
* set_active_discharge
* @active_discharge_on: Disabling value for control when using regmap
* set_active_discharge
* @active_discharge_mask: Mask for control when using regmap
* set_active_discharge
* @active_discharge_reg: Register for control when using regmap
* set_active_discharge
*
* @enable_time: Time taken for initial enable of regulator (in uS).
* @off_on_delay: guard time (in uS), before re-enabling a regulator
@ -315,6 +326,10 @@ struct regulator_desc {
unsigned int bypass_mask;
unsigned int bypass_val_on;
unsigned int bypass_val_off;
unsigned int active_discharge_on;
unsigned int active_discharge_off;
unsigned int active_discharge_mask;
unsigned int active_discharge_reg;
unsigned int enable_time;
@ -447,6 +462,8 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable);
int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable);
int regulator_set_active_discharge_regmap(struct regulator_dev *rdev,
bool enable);
void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
#endif

View File

@ -18,6 +18,9 @@
#define LP872X_MAX_REGULATORS 9
#define LP8720_ENABLE_DELAY 200
#define LP8725_ENABLE_DELAY 30000
enum lp872x_regulator_id {
LP8720_ID_BASE,
LP8720_ID_LDO1 = LP8720_ID_BASE,
@ -79,12 +82,14 @@ struct lp872x_regulator_data {
* @update_config : if LP872X_GENERAL_CFG register is updated, set true
* @regulator_data : platform regulator id and init data
* @dvs : dvs data for buck voltage control
* @enable_gpio : gpio pin number for enable control
*/
struct lp872x_platform_data {
u8 general_config;
bool update_config;
struct lp872x_regulator_data regulator_data[LP872X_MAX_REGULATORS];
struct lp872x_dvs *dvs;
int enable_gpio;
};
#endif

View File

@ -42,6 +42,13 @@ struct regulator;
#define REGULATOR_CHANGE_DRMS 0x10
#define REGULATOR_CHANGE_BYPASS 0x20
/* Regulator active discharge flags */
enum regulator_active_discharge {
REGULATOR_ACTIVE_DISCHARGE_DEFAULT,
REGULATOR_ACTIVE_DISCHARGE_DISABLE,
REGULATOR_ACTIVE_DISCHARGE_ENABLE,
};
/**
* struct regulator_state - regulator state during low power system states
*
@ -100,6 +107,9 @@ struct regulator_state {
* @initial_state: Suspend state to set by default.
* @initial_mode: Mode to set at startup.
* @ramp_delay: Time to settle down after voltage change (unit: uV/us)
* @active_discharge: Enable/disable active discharge. The enum
* regulator_active_discharge values are used for
* initialisation.
* @enable_time: Turn-on time of the rails (unit: microseconds)
*/
struct regulation_constraints {
@ -140,6 +150,8 @@ struct regulation_constraints {
unsigned int ramp_delay;
unsigned int enable_time;
unsigned int active_discharge;
/* constraint flags */
unsigned always_on:1; /* regulator never off when system is on */
unsigned boot_on:1; /* bootloader/firmware enabled regulator */