diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/regulator/Kconfig | 8 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/core.c | 4 | ||||
-rw-r--r-- | drivers/regulator/of_regulator.c | 4 | ||||
-rw-r--r-- | drivers/regulator/pfuze100-regulator.c | 24 | ||||
-rw-r--r-- | drivers/regulator/tps65132-regulator.c | 284 | ||||
-rw-r--r-- | drivers/regulator/twl6030-regulator.c | 2 |
7 files changed, 325 insertions, 2 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 9ecd70373f0b..d54044c03a6c 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -807,6 +807,14 @@ config REGULATOR_TPS65090 This driver provides support for the voltage regulators on the TI TPS65090 PMIC. +config REGULATOR_TPS65132 + tristate "TI TPS65132 Dual Output Power regulators" + depends on I2C && GPIOLIB + select REGMAP_I2C + help + This driver supports TPS65132 single inductor - dual output + power supply specifcally designed for display panels. + config REGULATOR_TPS65217 tristate "TI TPS65217 Power regulators" depends on MFD_TPS65217 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index ddbde708385d..f30cb0e2d6fb 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -107,6 +107,7 @@ obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o +obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-regulator.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 462e6e679ce1..c0d9ae8d0860 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2172,6 +2172,8 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret < 0) return ret; + _notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE, + NULL); } else if (ret < 0) { rdev_err(rdev, "is_enabled() failed: %d\n", ret); return ret; @@ -2763,6 +2765,8 @@ static int _regulator_set_voltage_time(struct regulator_dev *rdev, ramp_delay = rdev->constraints->ramp_delay; else if (rdev->desc->ramp_delay) ramp_delay = rdev->desc->ramp_delay; + else if (rdev->constraints->settling_time) + return rdev->constraints->settling_time; if (ramp_delay == 0) { rdev_dbg(rdev, "ramp_delay not set\n"); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 4f613ec99500..09d677d5d3f0 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -86,6 +86,10 @@ static void of_get_regulation_constraints(struct device_node *np, constraints->ramp_disable = true; } + ret = of_property_read_u32(np, "regulator-settling-time-us", &pval); + if (!ret) + constraints->settling_time = pval; + ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval); if (!ret) constraints->enable_time = pval; diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index e193bbbb8ffc..63922a2167e5 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -40,6 +40,7 @@ #define PFUZE100_REVID 0x3 #define PFUZE100_FABID 0x4 +#define PFUZE100_COINVOL 0x1a #define PFUZE100_SW1ABVOL 0x20 #define PFUZE100_SW1CVOL 0x2e #define PFUZE100_SW2VOL 0x35 @@ -81,6 +82,10 @@ static const int pfuze100_vsnvs[] = { 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000, }; +static const int pfuze100_coin[] = { + 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, +}; + static const int pfuze3000_sw2lo[] = { 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, }; @@ -230,6 +235,23 @@ static const struct regulator_ops pfuze100_swb_regulator_ops = { .stby_mask = 0x20, \ } +#define PFUZE100_COIN_REG(_chip, _name, base, mask, voltages) \ + [_chip ## _ ## _name] = { \ + .desc = { \ + .name = #_name, \ + .n_voltages = ARRAY_SIZE(voltages), \ + .ops = &pfuze100_swb_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .volt_table = voltages, \ + .vsel_reg = (base), \ + .vsel_mask = (mask), \ + .enable_reg = (base), \ + .enable_mask = 0x8, \ + }, \ + } + #define PFUZE3000_VCC_REG(_chip, _name, base, min, max, step) { \ .desc = { \ .name = #_name, \ @@ -317,6 +339,7 @@ static struct pfuze_regulator pfuze200_regulators[] = { PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), + PFUZE100_COIN_REG(PFUZE200, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin), }; static struct pfuze_regulator pfuze3000_regulators[] = { @@ -371,6 +394,7 @@ static struct of_regulator_match pfuze200_matches[] = { { .name = "vgen4", }, { .name = "vgen5", }, { .name = "vgen6", }, + { .name = "coin", }, }; /* PFUZE3000 */ diff --git a/drivers/regulator/tps65132-regulator.c b/drivers/regulator/tps65132-regulator.c new file mode 100644 index 000000000000..73978dd440f7 --- /dev/null +++ b/drivers/regulator/tps65132-regulator.c @@ -0,0 +1,284 @@ +/* + * TI TPS65132 Regulator driver + * + * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. + * + * Author: Venkat Reddy Talla <vreddytalla@nvidia.com> + * 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 "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. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#define TPS65132_REG_VPOS 0x00 +#define TPS65132_REG_VNEG 0x01 +#define TPS65132_REG_APPS_DISP_DISN 0x03 +#define TPS65132_REG_CONTROL 0x0FF + +#define TPS65132_VOUT_MASK 0x1F +#define TPS65132_VOUT_N_VOLTAGE 0x15 +#define TPS65132_VOUT_VMIN 4000000 +#define TPS65132_VOUT_VMAX 6000000 +#define TPS65132_VOUT_STEP 100000 + +#define TPS65132_REG_APPS_DIS_VPOS BIT(0) +#define TPS65132_REG_APPS_DIS_VNEG BIT(1) + +#define TPS65132_REGULATOR_ID_VPOS 0 +#define TPS65132_REGULATOR_ID_VNEG 1 +#define TPS65132_MAX_REGULATORS 2 + +#define TPS65132_ACT_DIS_TIME_SLACK 1000 + +struct tps65132_reg_pdata { + struct gpio_desc *en_gpiod; + struct gpio_desc *act_dis_gpiod; + unsigned int act_dis_time_us; + int ena_gpio_state; +}; + +struct tps65132_regulator { + struct device *dev; + struct regmap *rmap; + struct regulator_desc *rdesc[TPS65132_MAX_REGULATORS]; + struct tps65132_reg_pdata reg_pdata[TPS65132_MAX_REGULATORS]; + struct regulator_dev *rdev[TPS65132_MAX_REGULATORS]; +}; + +static int tps65132_regulator_enable(struct regulator_dev *rdev) +{ + struct tps65132_regulator *tps = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id]; + int ret; + + if (!IS_ERR(rpdata->en_gpiod)) { + gpiod_set_value_cansleep(rpdata->en_gpiod, 1); + rpdata->ena_gpio_state = 1; + } + + /* Hardware automatically enable discharge bit in enable */ + if (rdev->constraints->active_discharge == + REGULATOR_ACTIVE_DISCHARGE_DISABLE) { + ret = regulator_set_active_discharge_regmap(rdev, false); + if (ret < 0) { + dev_err(tps->dev, "Failed to disable active discharge: %d\n", + ret); + return ret; + } + } + + return 0; +} + +static int tps65132_regulator_disable(struct regulator_dev *rdev) +{ + struct tps65132_regulator *tps = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id]; + + if (!IS_ERR(rpdata->en_gpiod)) { + gpiod_set_value_cansleep(rpdata->en_gpiod, 0); + rpdata->ena_gpio_state = 0; + } + + if (!IS_ERR(rpdata->act_dis_gpiod)) { + gpiod_set_value_cansleep(rpdata->act_dis_gpiod, 1); + usleep_range(rpdata->act_dis_time_us, rpdata->act_dis_time_us + + TPS65132_ACT_DIS_TIME_SLACK); + gpiod_set_value_cansleep(rpdata->act_dis_gpiod, 0); + } + + return 0; +} + +static int tps65132_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct tps65132_regulator *tps = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id]; + + if (!IS_ERR(rpdata->en_gpiod)) + return rpdata->ena_gpio_state; + + return 1; +} + +static struct regulator_ops tps65132_regulator_ops = { + .enable = tps65132_regulator_enable, + .disable = tps65132_regulator_disable, + .is_enabled = tps65132_regulator_is_enabled, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +static int tps65132_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct tps65132_regulator *tps = config->driver_data; + struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[desc->id]; + int ret; + + rpdata->en_gpiod = devm_fwnode_get_index_gpiod_from_child(tps->dev, + "enable", 0, &np->fwnode, 0, "enable"); + if (IS_ERR(rpdata->en_gpiod)) { + ret = PTR_ERR(rpdata->en_gpiod); + + /* Ignore the error other than probe defer */ + if (ret == -EPROBE_DEFER) + return ret; + return 0; + } + + rpdata->act_dis_gpiod = devm_fwnode_get_index_gpiod_from_child( + tps->dev, "active-discharge", 0, + &np->fwnode, 0, "active-discharge"); + if (IS_ERR(rpdata->act_dis_gpiod)) { + ret = PTR_ERR(rpdata->act_dis_gpiod); + + /* Ignore the error other than probe defer */ + if (ret == -EPROBE_DEFER) + return ret; + + return 0; + } + + ret = of_property_read_u32(np, "ti,active-discharge-time-us", + &rpdata->act_dis_time_us); + if (ret < 0) { + dev_err(tps->dev, "Failed to read active discharge time:%d\n", + ret); + return ret; + } + + return 0; +} + +#define TPS65132_REGULATOR_DESC(_id, _name) \ + [TPS65132_REGULATOR_ID_##_id] = { \ + .name = "tps65132-"#_name, \ + .supply_name = "vin", \ + .id = TPS65132_REGULATOR_ID_##_id, \ + .of_match = of_match_ptr(#_name), \ + .of_parse_cb = tps65132_of_parse_cb, \ + .ops = &tps65132_regulator_ops, \ + .n_voltages = TPS65132_VOUT_N_VOLTAGE, \ + .min_uV = TPS65132_VOUT_VMIN, \ + .uV_step = TPS65132_VOUT_STEP, \ + .enable_time = 500, \ + .vsel_mask = TPS65132_VOUT_MASK, \ + .vsel_reg = TPS65132_REG_##_id, \ + .active_discharge_off = 0, \ + .active_discharge_on = TPS65132_REG_APPS_DIS_##_id, \ + .active_discharge_mask = TPS65132_REG_APPS_DIS_##_id, \ + .active_discharge_reg = TPS65132_REG_APPS_DISP_DISN, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +static struct regulator_desc tps_regs_desc[TPS65132_MAX_REGULATORS] = { + TPS65132_REGULATOR_DESC(VPOS, outp), + TPS65132_REGULATOR_DESC(VNEG, outn), +}; + +static const struct regmap_range tps65132_no_reg_ranges[] = { + regmap_reg_range(TPS65132_REG_APPS_DISP_DISN + 1, + TPS65132_REG_CONTROL - 1), +}; + +static const struct regmap_access_table tps65132_no_reg_table = { + .no_ranges = tps65132_no_reg_ranges, + .n_no_ranges = ARRAY_SIZE(tps65132_no_reg_ranges), +}; + +static const struct regmap_config tps65132_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = TPS65132_REG_CONTROL, + .cache_type = REGCACHE_NONE, + .rd_table = &tps65132_no_reg_table, + .wr_table = &tps65132_no_reg_table, +}; + +static int tps65132_probe(struct i2c_client *client, + const struct i2c_device_id *client_id) +{ + struct device *dev = &client->dev; + struct tps65132_regulator *tps; + struct regulator_config config = { }; + int id; + int ret; + + tps = devm_kzalloc(dev, sizeof(*tps), GFP_KERNEL); + if (!tps) + return -ENOMEM; + + tps->rmap = devm_regmap_init_i2c(client, &tps65132_regmap_config); + if (IS_ERR(tps->rmap)) { + ret = PTR_ERR(tps->rmap); + dev_err(dev, "regmap init failed: %d\n", ret); + return ret; + } + + i2c_set_clientdata(client, tps); + tps->dev = dev; + + for (id = 0; id < TPS65132_MAX_REGULATORS; ++id) { + tps->rdesc[id] = &tps_regs_desc[id]; + + config.regmap = tps->rmap; + config.dev = dev; + config.driver_data = tps; + + tps->rdev[id] = devm_regulator_register(dev, + tps->rdesc[id], &config); + if (IS_ERR(tps->rdev[id])) { + ret = PTR_ERR(tps->rdev[id]); + dev_err(dev, "regulator %s register failed: %d\n", + tps->rdesc[id]->name, ret); + return ret; + } + } + return 0; +} + +static const struct i2c_device_id tps65132_id[] = { + {.name = "tps65132",}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, tps65132_id); + +static struct i2c_driver tps65132_i2c_driver = { + .driver = { + .name = "tps65132", + }, + .probe = tps65132_probe, + .id_table = tps65132_id, +}; + +module_i2c_driver(tps65132_i2c_driver); + +MODULE_DESCRIPTION("tps65132 regulator driver"); +MODULE_AUTHOR("Venkat Reddy Talla <vreddytalla@nvidia.com>"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c index 716191046a70..56aada387887 100644 --- a/drivers/regulator/twl6030-regulator.c +++ b/drivers/regulator/twl6030-regulator.c @@ -456,8 +456,6 @@ static int twl6030smps_map_voltage(struct regulator_dev *rdev, int min_uV, vsel = 60; else if ((min_uV > 1350000) && (min_uV <= 1500000)) vsel = 59; - else if ((min_uV > 1300000) && (min_uV <= 1350000)) - vsel = 58; else return -EINVAL; break; |