commit
1f9cc5f771
@ -0,0 +1,40 @@ |
||||
Max8925 Voltage regulators |
||||
|
||||
Required nodes: |
||||
-nodes: |
||||
- SDV1 for SDV SDV1 |
||||
- SDV2 for SDV SDV2 |
||||
- SDV3 for SDV SDV3 |
||||
- LDO1 for LDO LDO1 |
||||
- LDO2 for LDO LDO2 |
||||
- LDO3 for LDO LDO3 |
||||
- LDO4 for LDO LDO4 |
||||
- LDO5 for LDO LDO5 |
||||
- LDO6 for LDO LDO6 |
||||
- LDO7 for LDO LDO7 |
||||
- LDO8 for LDO LDO8 |
||||
- LDO9 for LDO LDO9 |
||||
- LDO10 for LDO LDO10 |
||||
- LDO11 for LDO LDO11 |
||||
- LDO12 for LDO LDO12 |
||||
- LDO13 for LDO LDO13 |
||||
- LDO14 for LDO LDO14 |
||||
- LDO15 for LDO LDO15 |
||||
- LDO16 for LDO LDO16 |
||||
- LDO17 for LDO LDO17 |
||||
- LDO18 for LDO LDO18 |
||||
- LDO19 for LDO LDO19 |
||||
- LDO20 for LDO LDO20 |
||||
|
||||
Optional properties: |
||||
- Any optional property defined in bindings/regulator/regulator.txt |
||||
|
||||
Example: |
||||
|
||||
SDV1 { |
||||
regulator-min-microvolt = <637500>; |
||||
regulator-max-microvolt = <1425000>; |
||||
regulator-boot-on; |
||||
regulator-always-on; |
||||
}; |
||||
|
@ -0,0 +1,32 @@ |
||||
Versatile Express voltage regulators |
||||
------------------------------------ |
||||
|
||||
Requires node properties: |
||||
- "compatible" value: "arm,vexpress-volt" |
||||
- "arm,vexpress-sysreg,func" when controlled via vexpress-sysreg |
||||
(see Documentation/devicetree/bindings/arm/vexpress-sysreg.txt |
||||
for more details) |
||||
|
||||
Required regulator properties: |
||||
- "regulator-name" |
||||
- "regulator-always-on" |
||||
|
||||
Optional regulator properties: |
||||
- "regulator-min-microvolt" |
||||
- "regulator-max-microvolt" |
||||
|
||||
See Documentation/devicetree/bindings/regulator/regulator.txt |
||||
for more details about the regulator properties. |
||||
|
||||
When no "regulator-[min|max]-microvolt" properties are defined, |
||||
the device is treated as fixed (or rather "read-only") regulator. |
||||
|
||||
Example: |
||||
volt@0 { |
||||
compatible = "arm,vexpress-volt"; |
||||
arm,vexpress-sysreg,func = <2 0>; |
||||
regulator-name = "Cores"; |
||||
regulator-min-microvolt = <800000>; |
||||
regulator-max-microvolt = <1050000>; |
||||
regulator-always-on; |
||||
}; |
@ -0,0 +1,332 @@ |
||||
/*
|
||||
* tps51632-regulator.c -- TI TPS51632 |
||||
* |
||||
* Regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down Driverless |
||||
* Controller with serial VID control and DVFS. |
||||
* |
||||
* Copyright (c) 2012, NVIDIA Corporation. |
||||
* |
||||
* Author: Laxman Dewangan <ldewangan@nvidia.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 version 2. |
||||
* |
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, |
||||
* whether express or implied; 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, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
||||
* 02111-1307, USA |
||||
*/ |
||||
|
||||
#include <linux/err.h> |
||||
#include <linux/i2c.h> |
||||
#include <linux/init.h> |
||||
#include <linux/kernel.h> |
||||
#include <linux/module.h> |
||||
#include <linux/platform_device.h> |
||||
#include <linux/regmap.h> |
||||
#include <linux/regulator/driver.h> |
||||
#include <linux/regulator/machine.h> |
||||
#include <linux/regulator/tps51632-regulator.h> |
||||
#include <linux/slab.h> |
||||
|
||||
/* Register definitions */ |
||||
#define TPS51632_VOLTAGE_SELECT_REG 0x0 |
||||
#define TPS51632_VOLTAGE_BASE_REG 0x1 |
||||
#define TPS51632_OFFSET_REG 0x2 |
||||
#define TPS51632_IMON_REG 0x3 |
||||
#define TPS51632_VMAX_REG 0x4 |
||||
#define TPS51632_DVFS_CONTROL_REG 0x5 |
||||
#define TPS51632_POWER_STATE_REG 0x6 |
||||
#define TPS51632_SLEW_REGS 0x7 |
||||
#define TPS51632_FAULT_REG 0x14 |
||||
|
||||
#define TPS51632_MAX_REG 0x15 |
||||
|
||||
#define TPS51632_VOUT_MASK 0x7F |
||||
#define TPS51632_VOUT_OFFSET_MASK 0x1F |
||||
#define TPS51632_VMAX_MASK 0x7F |
||||
#define TPS51632_VMAX_LOCK 0x80 |
||||
|
||||
/* TPS51632_DVFS_CONTROL_REG */ |
||||
#define TPS51632_DVFS_PWMEN 0x1 |
||||
#define TPS51632_DVFS_STEP_20 0x2 |
||||
#define TPS51632_DVFS_VMAX_PG 0x4 |
||||
#define TPS51632_DVFS_PWMRST 0x8 |
||||
#define TPS51632_DVFS_OCA_EN 0x10 |
||||
#define TPS51632_DVFS_FCCM 0x20 |
||||
|
||||
/* TPS51632_POWER_STATE_REG */ |
||||
#define TPS51632_POWER_STATE_MASK 0x03 |
||||
#define TPS51632_POWER_STATE_MULTI_PHASE_CCM 0x0 |
||||
#define TPS51632_POWER_STATE_SINGLE_PHASE_CCM 0x1 |
||||
#define TPS51632_POWER_STATE_SINGLE_PHASE_DCM 0x2 |
||||
|
||||
#define TPS51632_MIN_VOLATGE 500000 |
||||
#define TPS51632_MAX_VOLATGE 1520000 |
||||
#define TPS51632_VOLATGE_STEP_10mV 10000 |
||||
#define TPS51632_VOLATGE_STEP_20mV 20000 |
||||
#define TPS51632_MAX_VSEL 0x7F |
||||
#define TPS51632_MIN_VSEL 0x19 |
||||
#define TPS51632_DEFAULT_RAMP_DELAY 6000 |
||||
#define TPS51632_VOLT_VSEL(uV) \ |
||||
(DIV_ROUND_UP(uV - TPS51632_MIN_VOLATGE, \
|
||||
TPS51632_VOLATGE_STEP_10mV) + \
|
||||
TPS51632_MIN_VSEL) |
||||
|
||||
/* TPS51632 chip information */ |
||||
struct tps51632_chip { |
||||
struct device *dev; |
||||
struct regulator_desc desc; |
||||
struct regulator_dev *rdev; |
||||
struct regmap *regmap; |
||||
bool enable_pwm_dvfs; |
||||
}; |
||||
|
||||
static int tps51632_dcdc_get_voltage_sel(struct regulator_dev *rdev) |
||||
{ |
||||
struct tps51632_chip *tps = rdev_get_drvdata(rdev); |
||||
unsigned int data; |
||||
int ret; |
||||
unsigned int reg = TPS51632_VOLTAGE_SELECT_REG; |
||||
int vsel; |
||||
|
||||
if (tps->enable_pwm_dvfs) |
||||
reg = TPS51632_VOLTAGE_BASE_REG; |
||||
|
||||
ret = regmap_read(tps->regmap, reg, &data); |
||||
if (ret < 0) { |
||||
dev_err(tps->dev, "reg read failed, err %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
vsel = data & TPS51632_VOUT_MASK; |
||||
|
||||
if (vsel < TPS51632_MIN_VSEL) |
||||
return 0; |
||||
else |
||||
return vsel - TPS51632_MIN_VSEL; |
||||
} |
||||
|
||||
static int tps51632_dcdc_set_voltage_sel(struct regulator_dev *rdev, |
||||
unsigned selector) |
||||
{ |
||||
struct tps51632_chip *tps = rdev_get_drvdata(rdev); |
||||
int vsel; |
||||
int ret; |
||||
unsigned int reg = TPS51632_VOLTAGE_SELECT_REG; |
||||
|
||||
if (tps->enable_pwm_dvfs) |
||||
reg = TPS51632_VOLTAGE_BASE_REG; |
||||
|
||||
vsel = selector + TPS51632_MIN_VSEL; |
||||
if (vsel > TPS51632_MAX_VSEL) |
||||
return -EINVAL; |
||||
|
||||
ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_SELECT_REG, vsel); |
||||
if (ret < 0) |
||||
dev_err(tps->dev, "reg write failed, err %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev, |
||||
int ramp_delay) |
||||
{ |
||||
struct tps51632_chip *tps = rdev_get_drvdata(rdev); |
||||
int bit = ramp_delay/6000; |
||||
int ret; |
||||
|
||||
if (bit) |
||||
bit--; |
||||
ret = regmap_write(tps->regmap, TPS51632_SLEW_REGS, BIT(bit)); |
||||
if (ret < 0) |
||||
dev_err(tps->dev, "SLEW reg write failed, err %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
static struct regulator_ops tps51632_dcdc_ops = { |
||||
.get_voltage_sel = tps51632_dcdc_get_voltage_sel, |
||||
.set_voltage_sel = tps51632_dcdc_set_voltage_sel, |
||||
.list_voltage = regulator_list_voltage_linear, |
||||
.set_voltage_time_sel = regulator_set_voltage_time_sel, |
||||
.set_ramp_delay = tps51632_dcdc_set_ramp_delay, |
||||
}; |
||||
|
||||
static int tps51632_init_dcdc(struct tps51632_chip *tps, |
||||
struct tps51632_regulator_platform_data *pdata) |
||||
{ |
||||
int ret; |
||||
uint8_t control = 0; |
||||
int vsel; |
||||
|
||||
if (!pdata->enable_pwm_dvfs) |
||||
goto skip_pwm_config; |
||||
|
||||
control |= TPS51632_DVFS_PWMEN; |
||||
tps->enable_pwm_dvfs = pdata->enable_pwm_dvfs; |
||||
vsel = TPS51632_VOLT_VSEL(pdata->base_voltage_uV); |
||||
ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG, vsel); |
||||
if (ret < 0) { |
||||
dev_err(tps->dev, "BASE reg write failed, err %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
if (pdata->dvfs_step_20mV) |
||||
control |= TPS51632_DVFS_STEP_20; |
||||
|
||||
if (pdata->max_voltage_uV) { |
||||
unsigned int vmax; |
||||
/**
|
||||
* TPS51632 hw behavior: VMAX register can be write only |
||||
* once as it get locked after first write. The lock get |
||||
* reset only when device is power-reset. |
||||
* Write register only when lock bit is not enabled. |
||||
*/ |
||||
ret = regmap_read(tps->regmap, TPS51632_VMAX_REG, &vmax); |
||||
if (ret < 0) { |
||||
dev_err(tps->dev, "VMAX read failed, err %d\n", ret); |
||||
return ret; |
||||
} |
||||
if (!(vmax & TPS51632_VMAX_LOCK)) { |
||||
vsel = TPS51632_VOLT_VSEL(pdata->max_voltage_uV); |
||||
ret = regmap_write(tps->regmap, TPS51632_VMAX_REG, |
||||
vsel); |
||||
if (ret < 0) { |
||||
dev_err(tps->dev, |
||||
"VMAX write failed, err %d\n", ret); |
||||
return ret; |
||||
} |
||||
} |
||||
} |
||||
|
||||
skip_pwm_config: |
||||
ret = regmap_write(tps->regmap, TPS51632_DVFS_CONTROL_REG, control); |
||||
if (ret < 0) |
||||
dev_err(tps->dev, "DVFS reg write failed, err %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
static bool rd_wr_reg(struct device *dev, unsigned int reg) |
||||
{ |
||||
if ((reg >= 0x8) && (reg <= 0x10)) |
||||
return false; |
||||
return true; |
||||
} |
||||
|
||||
static const struct regmap_config tps51632_regmap_config = { |
||||
.reg_bits = 8, |
||||
.val_bits = 8, |
||||
.writeable_reg = rd_wr_reg, |
||||
.readable_reg = rd_wr_reg, |
||||
.max_register = TPS51632_MAX_REG - 1, |
||||
.cache_type = REGCACHE_RBTREE, |
||||
}; |
||||
|
||||
static int tps51632_probe(struct i2c_client *client, |
||||
const struct i2c_device_id *id) |
||||
{ |
||||
struct tps51632_regulator_platform_data *pdata; |
||||
struct regulator_dev *rdev; |
||||
struct tps51632_chip *tps; |
||||
int ret; |
||||
struct regulator_config config = { }; |
||||
|
||||
pdata = client->dev.platform_data; |
||||
if (!pdata) { |
||||
dev_err(&client->dev, "No Platform data\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); |
||||
if (!tps) { |
||||
dev_err(&client->dev, "Memory allocation failed\n"); |
||||
return -ENOMEM; |
||||
} |
||||
|
||||
tps->dev = &client->dev; |
||||
tps->desc.name = id->name; |
||||
tps->desc.id = 0; |
||||
tps->desc.ramp_delay = TPS51632_DEFAULT_RAMP_DELAY; |
||||
tps->desc.min_uV = TPS51632_MIN_VOLATGE; |
||||
tps->desc.uV_step = TPS51632_VOLATGE_STEP_10mV; |
||||
tps->desc.n_voltages = (TPS51632_MAX_VSEL - TPS51632_MIN_VSEL) + 1; |
||||
tps->desc.ops = &tps51632_dcdc_ops; |
||||
tps->desc.type = REGULATOR_VOLTAGE; |
||||
tps->desc.owner = THIS_MODULE; |
||||
|
||||
tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config); |
||||
if (IS_ERR(tps->regmap)) { |
||||
ret = PTR_ERR(tps->regmap); |
||||
dev_err(&client->dev, "regmap init failed, err %d\n", ret); |
||||
return ret; |
||||
} |
||||
i2c_set_clientdata(client, tps); |
||||
|
||||
ret = tps51632_init_dcdc(tps, pdata); |
||||
if (ret < 0) { |
||||
dev_err(tps->dev, "Init failed, err = %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
/* Register the regulators */ |
||||
config.dev = &client->dev; |
||||
config.init_data = pdata->reg_init_data; |
||||
config.driver_data = tps; |
||||
config.regmap = tps->regmap; |
||||
config.of_node = client->dev.of_node; |
||||
|
||||
rdev = regulator_register(&tps->desc, &config); |
||||
if (IS_ERR(rdev)) { |
||||
dev_err(tps->dev, "regulator register failed\n"); |
||||
return PTR_ERR(rdev); |
||||
} |
||||
|
||||
tps->rdev = rdev; |
||||
return 0; |
||||
} |
||||
|
||||
static int tps51632_remove(struct i2c_client *client) |
||||
{ |
||||
struct tps51632_chip *tps = i2c_get_clientdata(client); |
||||
|
||||
regulator_unregister(tps->rdev); |
||||
return 0; |
||||
} |
||||
|
||||
static const struct i2c_device_id tps51632_id[] = { |
||||
{.name = "tps51632",}, |
||||
{}, |
||||
}; |
||||
|
||||
MODULE_DEVICE_TABLE(i2c, tps51632_id); |
||||
|
||||
static struct i2c_driver tps51632_i2c_driver = { |
||||
.driver = { |
||||
.name = "tps51632", |
||||
.owner = THIS_MODULE, |
||||
}, |
||||
.probe = tps51632_probe, |
||||
.remove = tps51632_remove, |
||||
.id_table = tps51632_id, |
||||
}; |
||||
|
||||
static int __init tps51632_init(void) |
||||
{ |
||||
return i2c_add_driver(&tps51632_i2c_driver); |
||||
} |
||||
subsys_initcall(tps51632_init); |
||||
|
||||
static void __exit tps51632_cleanup(void) |
||||
{ |
||||
i2c_del_driver(&tps51632_i2c_driver); |
||||
} |
||||
module_exit(tps51632_cleanup); |
||||
|
||||
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); |
||||
MODULE_DESCRIPTION("TPS51632 voltage regulator driver"); |
||||
MODULE_LICENSE("GPL v2"); |
@ -0,0 +1,793 @@ |
||||
/*
|
||||
* tps80031-regulator.c -- TI TPS80031 regulator driver. |
||||
* |
||||
* Regulator driver for TITPS80031/TPS80032 Fully Integrated Power |
||||
* Management with Power Path and Battery Charger. |
||||
* |
||||
* Copyright (c) 2012, NVIDIA Corporation. |
||||
* |
||||
* Author: Laxman Dewangan <ldewangan@nvidia.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 version 2. |
||||
* |
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, |
||||
* whether express or implied; 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, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
||||
* 02111-1307, USA |
||||
*/ |
||||
|
||||
#include <linux/delay.h> |
||||
#include <linux/err.h> |
||||
#include <linux/init.h> |
||||
#include <linux/kernel.h> |
||||
#include <linux/mfd/tps80031.h> |
||||
#include <linux/module.h> |
||||
#include <linux/platform_device.h> |
||||
#include <linux/regulator/driver.h> |
||||
#include <linux/regulator/machine.h> |
||||
#include <linux/slab.h> |
||||
|
||||
/* Flags for DCDC Voltage reading */ |
||||
#define DCDC_OFFSET_EN BIT(0) |
||||
#define DCDC_EXTENDED_EN BIT(1) |
||||
#define TRACK_MODE_ENABLE BIT(2) |
||||
|
||||
#define SMPS_MULTOFFSET_VIO BIT(1) |
||||
#define SMPS_MULTOFFSET_SMPS1 BIT(3) |
||||
#define SMPS_MULTOFFSET_SMPS2 BIT(4) |
||||
#define SMPS_MULTOFFSET_SMPS3 BIT(6) |
||||
#define SMPS_MULTOFFSET_SMPS4 BIT(0) |
||||
|
||||
#define SMPS_CMD_MASK 0xC0 |
||||
#define SMPS_VSEL_MASK 0x3F |
||||
#define LDO_VSEL_MASK 0x1F |
||||
#define LDO_TRACK_VSEL_MASK 0x3F |
||||
|
||||
#define MISC2_LDOUSB_IN_VSYS BIT(4) |
||||
#define MISC2_LDOUSB_IN_PMID BIT(3) |
||||
#define MISC2_LDOUSB_IN_MASK 0x18 |
||||
|
||||
#define MISC2_LDO3_SEL_VIB_VAL BIT(0) |
||||
#define MISC2_LDO3_SEL_VIB_MASK 0x1 |
||||
|
||||
#define BOOST_HW_PWR_EN BIT(5) |
||||
#define BOOST_HW_PWR_EN_MASK BIT(5) |
||||
|
||||
#define OPA_MODE_EN BIT(6) |
||||
#define OPA_MODE_EN_MASK BIT(6) |
||||
|
||||
#define USB_VBUS_CTRL_SET 0x04 |
||||
#define USB_VBUS_CTRL_CLR 0x05 |
||||
#define VBUS_DISCHRG 0x20 |
||||
|
||||
struct tps80031_regulator_info { |
||||
/* Regulator register address.*/ |
||||
u8 trans_reg; |
||||
u8 state_reg; |
||||
u8 force_reg; |
||||
u8 volt_reg; |
||||
u8 volt_id; |
||||
|
||||
/*Power request bits */ |
||||
int preq_bit; |
||||
|
||||
/* used by regulator core */ |
||||
struct regulator_desc desc; |
||||
|
||||
}; |
||||
|
||||
struct tps80031_regulator { |
||||
struct device *dev; |
||||
struct regulator_dev *rdev; |
||||
struct tps80031_regulator_info *rinfo; |
||||
|
||||
u8 device_flags; |
||||
unsigned int config_flags; |
||||
unsigned int ext_ctrl_flag; |
||||
}; |
||||
|
||||
static inline struct device *to_tps80031_dev(struct regulator_dev *rdev) |
||||
{ |
||||
return rdev_get_dev(rdev)->parent->parent; |
||||
} |
||||
|
||||
static int tps80031_reg_is_enabled(struct regulator_dev *rdev) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
struct device *parent = to_tps80031_dev(rdev); |
||||
u8 reg_val; |
||||
int ret; |
||||
|
||||
if (ri->ext_ctrl_flag & TPS80031_EXT_PWR_REQ) |
||||
return true; |
||||
|
||||
ret = tps80031_read(parent, TPS80031_SLAVE_ID1, ri->rinfo->state_reg, |
||||
®_val); |
||||
if (ret < 0) { |
||||
dev_err(&rdev->dev, "Reg 0x%02x read failed, err = %d\n", |
||||
ri->rinfo->state_reg, ret); |
||||
return ret; |
||||
} |
||||
return ((reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON); |
||||
} |
||||
|
||||
static int tps80031_reg_enable(struct regulator_dev *rdev) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
struct device *parent = to_tps80031_dev(rdev); |
||||
int ret; |
||||
|
||||
if (ri->ext_ctrl_flag & TPS80031_EXT_PWR_REQ) |
||||
return 0; |
||||
|
||||
ret = tps80031_update(parent, TPS80031_SLAVE_ID1, ri->rinfo->state_reg, |
||||
TPS80031_STATE_ON, TPS80031_STATE_MASK); |
||||
if (ret < 0) { |
||||
dev_err(&rdev->dev, "Reg 0x%02x update failed, err = %d\n", |
||||
ri->rinfo->state_reg, ret); |
||||
return ret; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
static int tps80031_reg_disable(struct regulator_dev *rdev) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
struct device *parent = to_tps80031_dev(rdev); |
||||
int ret; |
||||
|
||||
if (ri->ext_ctrl_flag & TPS80031_EXT_PWR_REQ) |
||||
return 0; |
||||
|
||||
ret = tps80031_update(parent, TPS80031_SLAVE_ID1, ri->rinfo->state_reg, |
||||
TPS80031_STATE_OFF, TPS80031_STATE_MASK); |
||||
if (ret < 0) |
||||
dev_err(&rdev->dev, "Reg 0x%02x update failed, err = %d\n", |
||||
ri->rinfo->state_reg, ret); |
||||
return ret; |
||||
} |
||||
|
||||
/* DCDC voltages for the selector of 58 to 63 */ |
||||
static int tps80031_dcdc_voltages[4][5] = { |
||||
{ 1350, 1500, 1800, 1900, 2100}, |
||||
{ 1350, 1500, 1800, 1900, 2100}, |
||||
{ 2084, 2315, 2778, 2932, 3241}, |
||||
{ 4167, 2315, 2778, 2932, 3241}, |
||||
}; |
||||
|
||||
static int tps80031_dcdc_list_voltage(struct regulator_dev *rdev, unsigned sel) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
int volt_index = ri->device_flags & 0x3; |
||||
|
||||
if (sel == 0) |
||||
return 0; |
||||
else if (sel < 58) |
||||
return regulator_list_voltage_linear(rdev, sel - 1); |
||||
else |
||||
return tps80031_dcdc_voltages[volt_index][sel - 58] * 1000; |
||||
} |
||||
|
||||
static int tps80031_dcdc_set_voltage_sel(struct regulator_dev *rdev, |
||||
unsigned vsel) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
struct device *parent = to_tps80031_dev(rdev); |
||||
int ret; |
||||
u8 reg_val; |
||||
|
||||
if (ri->rinfo->force_reg) { |
||||
ret = tps80031_read(parent, ri->rinfo->volt_id, |
||||
ri->rinfo->force_reg, ®_val); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", |
||||
ri->rinfo->force_reg, ret); |
||||
return ret; |
||||
} |
||||
if (!(reg_val & SMPS_CMD_MASK)) { |
||||
ret = tps80031_update(parent, ri->rinfo->volt_id, |
||||
ri->rinfo->force_reg, vsel, SMPS_VSEL_MASK); |
||||
if (ret < 0) |
||||
dev_err(ri->dev, |
||||
"reg 0x%02x update failed, e = %d\n", |
||||
ri->rinfo->force_reg, ret); |
||||
return ret; |
||||
} |
||||
} |
||||
ret = tps80031_update(parent, ri->rinfo->volt_id, |
||||
ri->rinfo->volt_reg, vsel, SMPS_VSEL_MASK); |
||||
if (ret < 0) |
||||
dev_err(ri->dev, "reg 0x%02x update failed, e = %d\n", |
||||
ri->rinfo->volt_reg, ret); |
||||
return ret; |
||||
} |
||||
|
||||
static int tps80031_dcdc_get_voltage_sel(struct regulator_dev *rdev) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
struct device *parent = to_tps80031_dev(rdev); |
||||
uint8_t vsel = 0; |
||||
int ret; |
||||
|
||||
if (ri->rinfo->force_reg) { |
||||
ret = tps80031_read(parent, ri->rinfo->volt_id, |
||||
ri->rinfo->force_reg, &vsel); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", |
||||
ri->rinfo->force_reg, ret); |
||||
return ret; |
||||
} |
||||
|
||||
if (!(vsel & SMPS_CMD_MASK)) |
||||
return vsel & SMPS_VSEL_MASK; |
||||
} |
||||
ret = tps80031_read(parent, ri->rinfo->volt_id, |
||||
ri->rinfo->volt_reg, &vsel); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", |
||||
ri->rinfo->volt_reg, ret); |
||||
return ret; |
||||
} |
||||
return vsel & SMPS_VSEL_MASK; |
||||
} |
||||
|
||||
static int tps80031_ldo_set_voltage_sel(struct regulator_dev *rdev, |
||||
unsigned sel) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
struct device *parent = to_tps80031_dev(rdev); |
||||
int ret; |
||||
|
||||
/* Check for valid setting for TPS80031 or TPS80032-ES1.0 */ |
||||
if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) && |
||||
(ri->device_flags & TRACK_MODE_ENABLE)) { |
||||
unsigned nvsel = (sel) & 0x1F; |
||||
if (((tps80031_get_chip_info(parent) == TPS80031) || |
||||
((tps80031_get_chip_info(parent) == TPS80032) && |
||||
(tps80031_get_pmu_version(parent) == 0x0))) && |
||||
((nvsel == 0x0) || (nvsel >= 0x19 && nvsel <= 0x1F))) { |
||||
dev_err(ri->dev, |
||||
"Invalid sel %d in track mode LDO2\n", |
||||
nvsel); |
||||
return -EINVAL; |
||||
} |
||||
} |
||||
|
||||
ret = tps80031_write(parent, ri->rinfo->volt_id, |
||||
ri->rinfo->volt_reg, sel); |
||||
if (ret < 0) |
||||
dev_err(ri->dev, "Error in writing reg 0x%02x, e = %d\n", |
||||
ri->rinfo->volt_reg, ret); |
||||
return ret; |
||||
} |
||||
|
||||
static int tps80031_ldo_get_voltage_sel(struct regulator_dev *rdev) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
struct device *parent = to_tps80031_dev(rdev); |
||||
uint8_t vsel; |
||||
int ret; |
||||
|
||||
ret = tps80031_read(parent, ri->rinfo->volt_id, |
||||
ri->rinfo->volt_reg, &vsel); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "Error in writing the Voltage register\n"); |
||||
return ret; |
||||
} |
||||
return vsel & rdev->desc->vsel_mask; |
||||
} |
||||
|
||||
static int tps80031_ldo_list_voltage(struct regulator_dev *rdev, unsigned sel) |
||||
{ |
||||
if (sel == 0) |
||||
return 0; |
||||
else |
||||
return regulator_list_voltage_linear(rdev, sel - 1); |
||||
} |
||||
|
||||
static int tps80031_vbus_is_enabled(struct regulator_dev *rdev) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
struct device *parent = to_tps80031_dev(rdev); |
||||
int ret = -EIO; |
||||
uint8_t ctrl1 = 0; |
||||
uint8_t ctrl3 = 0; |
||||
|
||||
ret = tps80031_read(parent, TPS80031_SLAVE_ID2, |
||||
TPS80031_CHARGERUSB_CTRL1, &ctrl1); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", |
||||
TPS80031_CHARGERUSB_CTRL1, ret); |
||||
return ret; |
||||
} |
||||
ret = tps80031_read(parent, TPS80031_SLAVE_ID2, |
||||
TPS80031_CHARGERUSB_CTRL3, &ctrl3); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", |
||||
TPS80031_CHARGERUSB_CTRL1, ret); |
||||
return ret; |
||||
} |
||||
if ((ctrl1 & OPA_MODE_EN) && (ctrl3 & BOOST_HW_PWR_EN)) |
||||
return 1; |
||||
return ret; |
||||
} |
||||
|
||||
static int tps80031_vbus_enable(struct regulator_dev *rdev) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
struct device *parent = to_tps80031_dev(rdev); |
||||
int ret; |
||||
|
||||
ret = tps80031_set_bits(parent, TPS80031_SLAVE_ID2, |
||||
TPS80031_CHARGERUSB_CTRL1, OPA_MODE_EN); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", |
||||
TPS80031_CHARGERUSB_CTRL1, ret); |
||||
return ret; |
||||
} |
||||
|
||||
ret = tps80031_set_bits(parent, TPS80031_SLAVE_ID2, |
||||
TPS80031_CHARGERUSB_CTRL3, BOOST_HW_PWR_EN); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x read failed, e = %d\n", |
||||
TPS80031_CHARGERUSB_CTRL3, ret); |
||||
return ret; |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
static int tps80031_vbus_disable(struct regulator_dev *rdev) |
||||
{ |
||||
struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
||||
struct device *parent = to_tps80031_dev(rdev); |
||||
int ret = 0; |
||||
|
||||
if (ri->config_flags & TPS80031_VBUS_DISCHRG_EN_PDN) { |
||||
ret = tps80031_write(parent, TPS80031_SLAVE_ID2, |
||||
USB_VBUS_CTRL_SET, VBUS_DISCHRG); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x write failed, e = %d\n", |
||||
USB_VBUS_CTRL_SET, ret); |
||||
return ret; |
||||
} |
||||
} |
||||
|
||||
ret = tps80031_clr_bits(parent, TPS80031_SLAVE_ID2, |
||||
TPS80031_CHARGERUSB_CTRL1, OPA_MODE_EN); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x clearbit failed, e = %d\n", |
||||
TPS80031_CHARGERUSB_CTRL1, ret); |
||||
return ret; |
||||
} |
||||
|
||||
ret = tps80031_clr_bits(parent, TPS80031_SLAVE_ID2, |
||||
TPS80031_CHARGERUSB_CTRL3, BOOST_HW_PWR_EN); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x clearbit failed, e = %d\n", |
||||
TPS80031_CHARGERUSB_CTRL3, ret); |
||||
return ret; |
||||
} |
||||
|
||||
mdelay(DIV_ROUND_UP(ri->rinfo->desc.enable_time, 1000)); |
||||
if (ri->config_flags & TPS80031_VBUS_DISCHRG_EN_PDN) { |
||||
ret = tps80031_write(parent, TPS80031_SLAVE_ID2, |
||||
USB_VBUS_CTRL_CLR, VBUS_DISCHRG); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "reg 0x%02x write failed, e = %d\n", |
||||
USB_VBUS_CTRL_CLR, ret); |
||||
return ret; |
||||
} |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
static struct regulator_ops tps80031_dcdc_ops = { |
||||
.list_voltage = tps80031_dcdc_list_voltage, |
||||
.set_voltage_sel = tps80031_dcdc_set_voltage_sel, |
||||
.get_voltage_sel = tps80031_dcdc_get_voltage_sel, |
||||
.enable = tps80031_reg_enable, |
||||
.disable = tps80031_reg_disable, |
||||
.is_enabled = tps80031_reg_is_enabled, |
||||
}; |
||||
|
||||
static struct regulator_ops tps80031_ldo_ops = { |
||||
.list_voltage = tps80031_ldo_list_voltage, |
||||
.set_voltage_sel = tps80031_ldo_set_voltage_sel, |
||||
.get_voltage_sel = tps80031_ldo_get_voltage_sel, |
||||
.enable = tps80031_reg_enable, |
||||
.disable = tps80031_reg_disable, |
||||
.is_enabled = tps80031_reg_is_enabled, |
||||
}; |
||||
|
||||
static struct regulator_ops tps80031_vbus_sw_ops = { |
||||
.enable = tps80031_vbus_enable, |
||||
.disable = tps80031_vbus_disable, |
||||
.is_enabled = tps80031_vbus_is_enabled, |
||||
}; |
||||
|
||||
static struct regulator_ops tps80031_vbus_hw_ops = { |
||||
}; |
||||
|
||||
static struct regulator_ops tps80031_ext_reg_ops = { |
||||
.enable = tps80031_reg_enable, |
||||
.disable = tps80031_reg_disable, |
||||
.is_enabled = tps80031_reg_is_enabled, |
||||
}; |
||||
|
||||
/* Non-exiting default definition for some register */ |
||||
#define TPS80031_SMPS3_CFG_FORCE 0 |
||||
#define TPS80031_SMPS4_CFG_FORCE 0 |
||||
|
||||
#define TPS80031_VBUS_CFG_TRANS 0 |
||||
#define TPS80031_VBUS_CFG_STATE 0 |
||||
|
||||
#define TPS80031_REG_SMPS(_id, _volt_id, _pbit) \ |
||||
{ \
|
||||
.trans_reg = TPS80031_##_id##_CFG_TRANS, \
|
||||
.state_reg = TPS80031_##_id##_CFG_STATE, \
|
||||
.force_reg = TPS80031_##_id##_CFG_FORCE, \
|
||||
.volt_reg = TPS80031_##_id##_CFG_VOLTAGE, \
|
||||
.volt_id = TPS80031_SLAVE_##_volt_id, \
|
||||
.preq_bit = _pbit, \
|
||||
.desc = { \
|
||||
.name = "tps80031_"#_id, \
|
||||
.id = TPS80031_REGULATOR_##_id, \
|
||||
.n_voltages = 63, \
|
||||
.ops = &tps80031_dcdc_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.enable_time = 500, \
|
||||
}, \
|
||||
} |
||||
|
||||
#define TPS80031_REG_LDO(_id, _preq_bit) \ |
||||
{ \
|
||||
.trans_reg = TPS80031_##_id##_CFG_TRANS, \
|
||||
.state_reg = TPS80031_##_id##_CFG_STATE, \
|
||||
.volt_reg = TPS80031_##_id##_CFG_VOLTAGE, \
|
||||
.volt_id = TPS80031_SLAVE_ID1, \
|
||||
.preq_bit = _preq_bit, \
|
||||
.desc = { \
|
||||
.owner = THIS_MODULE, \
|
||||
.name = "tps80031_"#_id, \
|
||||
.id = TPS80031_REGULATOR_##_id, \
|
||||
.ops = &tps80031_ldo_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.min_uV = 1000000, \
|
||||
.uV_step = 100000, \
|
||||
.n_voltages = 25, \
|
||||
.vsel_mask = LDO_VSEL_MASK, \
|
||||
.enable_time = 500, \
|
||||
}, \
|
||||
} |
||||
|
||||
#define TPS80031_REG_FIXED(_id, max_mV, _ops, _delay, _pbit) \ |
||||
{ \
|
||||
.trans_reg = TPS80031_##_id##_CFG_TRANS, \
|
||||
.state_reg = TPS80031_##_id##_CFG_STATE, \
|
||||
.volt_id = TPS80031_SLAVE_ID1, \
|
||||
.preq_bit = _pbit, \
|
||||
.desc = { \
|
||||
.name = "tps80031_"#_id, \
|
||||
.id = TPS80031_REGULATOR_##_id, \
|
||||
.n_voltages = 2, \
|
||||
.ops = &_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.enable_time = _delay, \
|
||||
}, \
|
||||
} |
||||
|
||||
static struct tps80031_regulator_info tps80031_rinfo[TPS80031_REGULATOR_MAX] = { |
||||
TPS80031_REG_SMPS(VIO, ID0, 4), |
||||
TPS80031_REG_SMPS(SMPS1, ID0, 0), |
||||
TPS80031_REG_SMPS(SMPS2, ID0, 1), |
||||
TPS80031_REG_SMPS(SMPS3, ID1, 2), |
||||
TPS80031_REG_SMPS(SMPS4, ID1, 3), |
||||
TPS80031_REG_LDO(VANA, -1), |
||||
TPS80031_REG_LDO(LDO1, 8), |
||||
TPS80031_REG_LDO(LDO2, 9), |
||||
TPS80031_REG_LDO(LDO3, 10), |
||||
TPS80031_REG_LDO(LDO4, 11), |
||||
TPS80031_REG_LDO(LDO5, 12), |
||||
TPS80031_REG_LDO(LDO6, 13), |
||||
TPS80031_REG_LDO(LDO7, 14), |
||||
TPS80031_REG_LDO(LDOLN, 15), |
||||
TPS80031_REG_LDO(LDOUSB, 5), |
||||
TPS80031_REG_FIXED(VBUS, 5000, tps80031_vbus_hw_ops, 100000, -1), |
||||
TPS80031_REG_FIXED(REGEN1, 3300, tps80031_ext_reg_ops, 0, 16), |
||||
TPS80031_REG_FIXED(REGEN2, 3300, tps80031_ext_reg_ops, 0, 17), |
||||
TPS80031_REG_FIXED(SYSEN, 3300, tps80031_ext_reg_ops, 0, 18), |
||||
}; |
||||
|
||||
static int tps80031_power_req_config(struct device *parent, |
||||
struct tps80031_regulator *ri, |
||||
struct tps80031_regulator_platform_data *tps80031_pdata) |
||||
{ |
||||
int ret = 0; |
||||
|
||||
if (ri->rinfo->preq_bit < 0) |
||||
goto skip_pwr_req_config; |
||||
|
||||
ret = tps80031_ext_power_req_config(parent, ri->ext_ctrl_flag, |
||||
ri->rinfo->preq_bit, ri->rinfo->state_reg, |
||||
ri->rinfo->trans_reg); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "ext powerreq config failed, err = %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
skip_pwr_req_config: |
||||
if (tps80031_pdata->ext_ctrl_flag & TPS80031_PWR_ON_ON_SLEEP) { |
||||
ret = tps80031_update(parent, TPS80031_SLAVE_ID1, |
||||
ri->rinfo->trans_reg, TPS80031_TRANS_SLEEP_ON, |
||||
TPS80031_TRANS_SLEEP_MASK); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "Reg 0x%02x update failed, e %d\n", |
||||
ri->rinfo->trans_reg, ret); |
||||
return ret; |
||||
} |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
static int tps80031_regulator_config(struct device *parent, |
||||
struct tps80031_regulator *ri, |
||||
struct tps80031_regulator_platform_data *tps80031_pdata) |
||||
{ |
||||
int ret = 0; |
||||
|
||||
switch (ri->rinfo->desc.id) { |
||||
case TPS80031_REGULATOR_LDOUSB: |
||||
if (ri->config_flags & (TPS80031_USBLDO_INPUT_VSYS | |
||||
TPS80031_USBLDO_INPUT_PMID)) { |
||||
unsigned val = 0; |
||||
if (ri->config_flags & TPS80031_USBLDO_INPUT_VSYS) |
||||
val = MISC2_LDOUSB_IN_VSYS; |
||||
else |
||||
val = MISC2_LDOUSB_IN_PMID; |
||||
|
||||
ret = tps80031_update(parent, TPS80031_SLAVE_ID1, |
||||
TPS80031_MISC2, val, |
||||
MISC2_LDOUSB_IN_MASK); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, |
||||
"LDOUSB config failed, e= %d\n", ret); |
||||
return ret; |
||||
} |
||||
} |
||||
break; |
||||
|
||||
case TPS80031_REGULATOR_LDO3: |
||||
if (ri->config_flags & TPS80031_LDO3_OUTPUT_VIB) { |
||||
ret = tps80031_update(parent, TPS80031_SLAVE_ID1, |
||||
TPS80031_MISC2, MISC2_LDO3_SEL_VIB_VAL, |
||||
MISC2_LDO3_SEL_VIB_MASK); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, |
||||
"LDO3 config failed, e = %d\n", ret); |
||||
return ret; |
||||
} |
||||
} |
||||
break; |
||||
|
||||
case TPS80031_REGULATOR_VBUS: |
||||
/* Provide SW control Ops if VBUS is SW control */ |
||||
if (!(ri->config_flags & TPS80031_VBUS_SW_ONLY)) |
||||
ri->rinfo->desc.ops = &tps80031_vbus_sw_ops; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
/* Configure Active state to ON, SLEEP to OFF and OFF_state to OFF */ |
||||
ret = tps80031_update(parent, TPS80031_SLAVE_ID1, ri->rinfo->trans_reg, |
||||
TPS80031_TRANS_ACTIVE_ON | TPS80031_TRANS_SLEEP_OFF | |
||||
TPS80031_TRANS_OFF_OFF, TPS80031_TRANS_ACTIVE_MASK | |
||||
TPS80031_TRANS_SLEEP_MASK | TPS80031_TRANS_OFF_MASK); |
||||
if (ret < 0) { |
||||
dev_err(ri->dev, "trans reg update failed, e %d\n", ret); |
||||
return ret; |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
static int check_smps_mode_mult(struct device *parent, |
||||
struct tps80031_regulator *ri) |
||||
{ |
||||
int mult_offset; |
||||
int ret; |
||||
u8 smps_offset; |
||||
u8 smps_mult; |
||||
|
||||
ret = tps80031_read(parent, TPS80031_SLAVE_ID1, |
||||
TPS80031_SMPS_OFFSET, &smps_offset); |
||||
if (ret < 0) { |
||||
dev_err(parent, "Error in reading smps offset register\n"); |
||||
return ret; |
||||
} |
||||
|
||||
ret = tps80031_read(parent, TPS80031_SLAVE_ID1, |
||||
TPS80031_SMPS_MULT, &smps_mult); |
||||
if (ret < 0) { |
||||
dev_err(parent, "Error in reading smps mult register\n"); |
||||
return ret; |
||||
} |
||||
|
||||
switch (ri->rinfo->desc.id) { |
||||
case TPS80031_REGULATOR_VIO: |
||||
mult_offset = SMPS_MULTOFFSET_VIO; |
||||
break; |
||||
case TPS80031_REGULATOR_SMPS1: |
||||
mult_offset = SMPS_MULTOFFSET_SMPS1; |
||||
break; |
||||
case TPS80031_REGULATOR_SMPS2: |
||||
mult_offset = SMPS_MULTOFFSET_SMPS2; |
||||
break; |
||||
case TPS80031_REGULATOR_SMPS3: |
||||
mult_offset = SMPS_MULTOFFSET_SMPS3; |
||||
break; |
||||
case TPS80031_REGULATOR_SMPS4: |
||||
mult_offset = SMPS_MULTOFFSET_SMPS4; |
||||
break; |
||||
case TPS80031_REGULATOR_LDO2: |
||||
ri->device_flags = smps_mult & BIT(5) ? TRACK_MODE_ENABLE : 0; |
||||
/* TRACK mode the ldo2 varies from 600mV to 1300mV */ |
||||
if (ri->device_flags & TRACK_MODE_ENABLE) { |
||||
ri->rinfo->desc.min_uV = 600000; |
||||
ri->rinfo->desc.uV_step = 12500; |
||||
ri->rinfo->desc.n_voltages = 57; |
||||
ri->rinfo->desc.vsel_mask = LDO_TRACK_VSEL_MASK; |
||||
} |
||||
return 0; |
||||
default: |
||||
return 0; |
||||
} |
||||
|
||||
ri->device_flags = (smps_offset & mult_offset) ? DCDC_OFFSET_EN : 0; |
||||
ri->device_flags |= (smps_mult & mult_offset) ? DCDC_EXTENDED_EN : 0; |
||||
switch (ri->device_flags) { |
||||
case 0: |
||||
ri->rinfo->desc.min_uV = 607700; |
||||
ri->rinfo->desc.uV_step = 12660; |
||||
break; |
||||
case DCDC_OFFSET_EN: |
||||
ri->rinfo->desc.min_uV = 700000; |
||||
ri->rinfo->desc.uV_step = 12500; |
||||
break; |
||||
case DCDC_EXTENDED_EN: |
||||
ri->rinfo->desc.min_uV = 1852000; |
||||
ri->rinfo->desc.uV_step = 38600; |
||||
break; |
||||
case DCDC_OFFSET_EN | DCDC_EXTENDED_EN: |
||||
ri->rinfo->desc.min_uV = 2161000; |
||||
ri->rinfo->desc.uV_step = 38600; |
||||
break; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int tps80031_regulator_probe(struct platform_device *pdev) |
||||
{ |
||||
struct tps80031_platform_data *pdata; |
||||
struct tps80031_regulator_platform_data *tps_pdata; |
||||
struct tps80031_regulator_info *rinfo; |
||||
struct tps80031_regulator *ri; |
||||
struct tps80031_regulator *pmic; |
||||
struct regulator_dev *rdev; |
||||
struct regulator_config config = { }; |
||||
int ret; |
||||
int num; |
||||
|
||||
pdata = dev_get_platdata(pdev->dev.parent); |
||||
|
||||
if (!pdata) { |
||||
dev_err(&pdev->dev, "No platform data\n"); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
pmic = devm_kzalloc(&pdev->dev, |
||||
TPS80031_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL); |
||||
if (!pmic) { |
||||
dev_err(&pdev->dev, "mem alloc for pmic failed\n"); |
||||
return -ENOMEM; |
||||
} |
||||
|
||||
for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) { |
||||
tps_pdata = pdata->regulator_pdata[num]; |
||||
rinfo = &tps80031_rinfo[num]; |
||||
ri = &pmic[num]; |
||||
ri->rinfo = rinfo; |
||||
ri->dev = &pdev->dev; |
||||
|
||||
check_smps_mode_mult(pdev->dev.parent, ri); |
||||
config.dev = &pdev->dev; |
||||
config.init_data = NULL; |
||||
config.driver_data = ri; |
||||
if (tps_pdata) { |
||||
config.init_data = tps_pdata->reg_init_data; |
||||
ri->config_flags = tps_pdata->config_flags; |
||||
ri->ext_ctrl_flag = tps_pdata->ext_ctrl_flag; |
||||
ret = tps80031_regulator_config(pdev->dev.parent, |
||||
ri, tps_pdata); |
||||
if (ret < 0) { |
||||
dev_err(&pdev->dev, |
||||
"regulator config failed, e %d\n", ret); |
||||
goto fail; |
||||
} |
||||
|
||||
ret = tps80031_power_req_config(pdev->dev.parent, |
||||
ri, tps_pdata); |
||||
if (ret < 0) { |
||||
dev_err(&pdev->dev, |
||||
"pwr_req config failed, err %d\n", ret); |
||||
goto fail; |
||||
} |
||||
} |
||||
rdev = regulator_register(&ri->rinfo->desc, &config); |
||||
if (IS_ERR_OR_NULL(rdev)) { |
||||
dev_err(&pdev->dev, |
||||
"register regulator failed %s\n", |
||||
ri->rinfo->desc.name); |
||||
ret = PTR_ERR(rdev); |
||||
goto fail; |
||||
} |
||||
ri->rdev = rdev; |
||||
} |
||||
|
||||
platform_set_drvdata(pdev, pmic); |
||||
return 0; |
||||
fail: |
||||
while (--num >= 0) { |
||||
ri = &pmic[num]; |
||||
regulator_unregister(ri->rdev); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
static int tps80031_regulator_remove(struct platform_device *pdev) |
||||
{ |
||||
struct tps80031_regulator *pmic = platform_get_drvdata(pdev); |
||||
struct tps80031_regulator *ri = NULL; |
||||
int num; |
||||
|
||||
for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) { |
||||
ri = &pmic[num]; |
||||
regulator_unregister(ri->rdev); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static struct platform_driver tps80031_regulator_driver = { |
||||
.driver = { |
||||
.name = "tps80031-pmic", |
||||
.owner = THIS_MODULE, |
||||
}, |
||||
.probe = tps80031_regulator_probe, |
||||
.remove = tps80031_regulator_remove, |
||||
}; |
||||
|
||||
static int __init tps80031_regulator_init(void) |
||||
{ |
||||
return platform_driver_register(&tps80031_regulator_driver); |
||||
} |
||||
subsys_initcall(tps80031_regulator_init); |
||||
|
||||
static void __exit tps80031_regulator_exit(void) |
||||
{ |
||||
platform_driver_unregister(&tps80031_regulator_driver); |
||||
} |
||||
module_exit(tps80031_regulator_exit); |
||||
|
||||
MODULE_ALIAS("platform:tps80031-regulator"); |
||||
MODULE_DESCRIPTION("Regulator Driver for TI TPS80031 PMIC"); |
||||
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); |
||||
MODULE_LICENSE("GPL v2"); |
@ -0,0 +1,147 @@ |
||||
/*
|
||||
* 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. |
||||
* |
||||
* Copyright (C) 2012 ARM Limited |
||||
*/ |
||||
|
||||
#define DRVNAME "vexpress-regulator" |
||||
#define pr_fmt(fmt) DRVNAME ": " fmt |
||||
|
||||
#include <linux/device.h> |
||||
#include <linux/err.h> |
||||
#include <linux/module.h> |
||||
#include <linux/of_device.h> |
||||
#include <linux/regulator/driver.h> |
||||
#include <linux/regulator/machine.h> |
||||
#include <linux/regulator/of_regulator.h> |
||||
#include <linux/vexpress.h> |
||||
|
||||
struct vexpress_regulator { |
||||
struct regulator_desc desc; |
||||
struct regulator_dev *regdev; |
||||
struct vexpress_config_func *func; |
||||
}; |
||||
|
||||
static int vexpress_regulator_get_voltage(struct regulator_dev *regdev) |
||||
{ |
||||
struct vexpress_regulator *reg = rdev_get_drvdata(regdev); |
||||
u32 uV; |
||||
int err = vexpress_config_read(reg->func, 0, &uV); |
||||
|
||||
return err ? err : uV; |
||||
} |
||||
|
||||
static int vexpress_regulator_set_voltage(struct regulator_dev *regdev, |
||||
int min_uV, int max_uV, unsigned *selector) |
||||
{ |
||||
struct vexpress_regulator *reg = rdev_get_drvdata(regdev); |
||||
|
||||
return vexpress_config_write(reg->func, 0, min_uV); |
||||
} |
||||
|
||||
static struct regulator_ops vexpress_regulator_ops_ro = { |
||||
.get_voltage = vexpress_regulator_get_voltage, |
||||
}; |
||||
|
||||
static struct regulator_ops vexpress_regulator_ops = { |
||||
.get_voltage = vexpress_regulator_get_voltage, |
||||
.set_voltage = vexpress_regulator_set_voltage, |
||||
}; |
||||
|
||||
static int vexpress_regulator_probe(struct platform_device *pdev) |
||||
{ |
||||
int err; |
||||
struct vexpress_regulator *reg; |
||||
struct regulator_init_data *init_data; |
||||
struct regulator_config config = { }; |
||||
|
||||
reg = devm_kzalloc(&pdev->dev, sizeof(*reg), GFP_KERNEL); |
||||
if (!reg) { |
||||
err = -ENOMEM; |
||||
goto error_kzalloc; |
||||
} |
||||
|
||||
reg->func = vexpress_config_func_get_by_dev(&pdev->dev); |
||||
if (!reg->func) { |
||||
err = -ENXIO; |
||||
goto error_get_func; |
||||
} |
||||
|
||||
reg->desc.name = dev_name(&pdev->dev); |
||||
reg->desc.type = REGULATOR_VOLTAGE; |
||||
reg->desc.owner = THIS_MODULE; |
||||
reg->desc.continuous_voltage_range = true; |
||||
|
||||
init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); |
||||
if (!init_data) { |
||||
err = -EINVAL; |
||||
goto error_get_regulator_init_data; |
||||
} |
||||
|
||||
init_data->constraints.apply_uV = 0; |
||||
if (init_data->constraints.min_uV && init_data->constraints.max_uV) |
||||
reg->desc.ops = &vexpress_regulator_ops; |
||||
else |
||||
reg->desc.ops = &vexpress_regulator_ops_ro; |
||||
|
||||
config.dev = &pdev->dev; |
||||
config.init_data = init_data; |
||||
config.driver_data = reg; |
||||
config.of_node = pdev->dev.of_node; |
||||
|
||||
reg->regdev = regulator_register(®->desc, &config); |
||||
if (IS_ERR(reg->regdev)) { |
||||
err = PTR_ERR(reg->regdev); |
||||
goto error_regulator_register; |
||||
} |
||||
|
||||
platform_set_drvdata(pdev, reg); |
||||
|
||||
return 0; |
||||
|
||||
error_regulator_register: |
||||
error_get_regulator_init_data: |
||||
vexpress_config_func_put(reg->func); |
||||
error_get_func: |
||||
error_kzalloc: |
||||
return err; |
||||
} |
||||
|
||||
static int vexpress_regulator_remove(struct platform_device *pdev) |
||||
{ |
||||
struct vexpress_regulator *reg = platform_get_drvdata(pdev); |
||||
|
||||
vexpress_config_func_put(reg->func); |
||||
regulator_unregister(reg->regdev); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static struct of_device_id vexpress_regulator_of_match[] = { |
||||
{ .compatible = "arm,vexpress-volt", }, |
||||
{ } |
||||
}; |
||||
|
||||
static struct platform_driver vexpress_regulator_driver = { |
||||
.probe = vexpress_regulator_probe, |
||||
.remove = vexpress_regulator_remove, |
||||
.driver = { |
||||
.name = DRVNAME, |
||||
.owner = THIS_MODULE, |
||||
.of_match_table = vexpress_regulator_of_match, |
||||
}, |
||||
}; |
||||
|
||||
module_platform_driver(vexpress_regulator_driver); |
||||
|
||||
MODULE_AUTHOR("Pawel Moll <pawel.moll@arm.com>"); |
||||
MODULE_DESCRIPTION("Versatile Express regulator"); |
||||
MODULE_LICENSE("GPL"); |
||||
MODULE_ALIAS("platform:vexpress-regulator"); |
@ -0,0 +1,47 @@ |
||||
/*
|
||||
* tps51632-regulator.h -- TPS51632 regulator |
||||
* |
||||
* Interface for regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down |
||||
* Driverless Controller with serial VID control and DVFS. |
||||
* |
||||
* Copyright (C) 2012 NVIDIA Corporation |
||||
|
||||
* Author: Laxman Dewangan <ldewangan@nvidia.com> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
||||
* more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License along |
||||
* with this program; if not, write to the Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __LINUX_REGULATOR_TPS51632_H |
||||
#define __LINUX_REGULATOR_TPS51632_H |
||||
|
||||
/*
|
||||
* struct tps51632_regulator_platform_data - tps51632 regulator platform data. |
||||
* |
||||
* @reg_init_data: The regulator init data. |
||||
* @enable_pwm_dvfs: Enable PWM DVFS or not. |
||||
* @dvfs_step_20mV: Step for DVFS is 20mV or 10mV. |
||||
* @max_voltage_uV: Maximum possible voltage in PWM-DVFS mode. |
||||
* @base_voltage_uV: Base voltage when PWM-DVFS enabled. |
||||
*/ |
||||
struct tps51632_regulator_platform_data { |
||||
struct regulator_init_data *reg_init_data; |
||||
bool enable_pwm_dvfs; |
||||
bool dvfs_step_20mV; |
||||
int max_voltage_uV; |
||||
int base_voltage_uV; |
||||
}; |
||||
|
||||
#endif /* __LINUX_REGULATOR_TPS51632_H */ |
@ -1,50 +0,0 @@ |
||||
/*
|
||||
* Regulator driver interface for TI TPS65090 PMIC family |
||||
* |
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. |
||||
|
||||
* This program is free software; you can redistribute it and/or modify it |
||||
* under the terms and conditions of the GNU General Public License, |
||||
* version 2, as published by the Free Software Foundation. |
||||
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
||||
* more details. |
||||
|
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#ifndef __REGULATOR_TPS65090_H |
||||
#define __REGULATOR_TPS65090_H |
||||
|
||||
#include <linux/regulator/machine.h> |
||||
|
||||
#define tps65090_rails(_name) "tps65090_"#_name |
||||
|
||||
enum { |
||||
TPS65090_ID_DCDC1, |
||||
TPS65090_ID_DCDC2, |
||||
TPS65090_ID_DCDC3, |
||||
TPS65090_ID_FET1, |
||||
TPS65090_ID_FET2, |
||||
TPS65090_ID_FET3, |
||||
TPS65090_ID_FET4, |
||||
TPS65090_ID_FET5, |
||||
TPS65090_ID_FET6, |
||||
TPS65090_ID_FET7, |
||||
}; |
||||
|
||||
/*
|
||||
* struct tps65090_regulator_platform_data |
||||
* |
||||
* @regulator: The regulator init data. |
||||
* @slew_rate_uV_per_us: Slew rate microvolt per microsec. |
||||
*/ |
||||
|
||||
struct tps65090_regulator_platform_data { |
||||
struct regulator_init_data regulator; |
||||
}; |
||||
|
||||
#endif /* __REGULATOR_TPS65090_H */ |
Loading…
Reference in new issue