tegrakernel/kernel/kernel-4.9/drivers/regulator/tps61280-regulator.c

1035 lines
27 KiB
C
Raw Normal View History

2022-02-16 09:13:02 -06:00
/*
* Driver for TI,TP61280 DC/DC Boost Converter
*
* Copyright (c) 2014-2016, NVIDIA Corporation. All rights reserved.
*
* Author: Venkat Reddy Talla <vreddytalla@nvidia.com>
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/thermal.h>
#define TPS61280_CONFIG 0x01
#define TPS61280_VOUTFLOORSET 0x02
#define TPS61280_VOUTROOFSET 0x03
#define TPS61280_ILIMSET 0x04
#define TPS61280_STATUS 0x05
#define TPS61280_E2PROMCTRL 0xFF
#define TPS61280_ILIM_BASE 0x08
#define TPS61280_ILIM_OFFSET 1500
#define TPS61280_ILIM_STEP 500
#define TPS61280_ENABLE_ILIM 0x0
#define TPS61280_DISABLE_ILIM 0x20
#define TPS61280_VOUT_OFFSET 2850
#define TPS61280_VOUT_STEP 50
#define TPS61280_HOTDIE_TEMP 120
#define TPS61280_NORMAL_OPTEMP 40
#define TPS61280_CONFIG_MODE_MASK 0x03
#define TPS61280_CONFIG_MODE_VSEL 0x03
#define TPS61280_CONFIG_MODE_FORCE_PWM 0x02
#define TPS61280_CONFIG_MODE_AUTO_PWM 0x01
#define TPS61280_CONFIG_MODE_DEVICE 0x00
#define TPS61280_ILIM_MASK 0x0F
#define TPS61280_VOUT_MASK 0x1F
#define TPS61280_CONFIG_ENABLE_MASK 0x60
#define TPS61280_CONFIG_BYPASS_HW_CONTRL 0x00
#define TPS61280_CONFIG_BYPASS_AUTO_TRANS 0x20
#define TPS61280_CONFIG_BYPASS_PASS_TROUGH 0x40
#define TPS61280_CONFIG_BYPASS_SHUTDOWN 0x60
#define TPS61280_PGOOD_MASK BIT(0)
#define TPS61280_FAULT_MASK BIT(1)
#define TPS61280_ILIMBST_MASK BIT(2)
#define TPS61280_ILIMPT_MASK BIT(3)
#define TPS61280_OPMODE_MASK BIT(4)
#define TPS61280_DCDCMODE_MASK BIT(5)
#define TPS61280_HOTDIE_MASK BIT(6)
#define TPS61280_THERMALSD_MASK BIT(7)
#define TPS61280_MAX_VOUT_REG 2
#define TPS61280_VOUT_MASK 0x1F
#define TPS61280_VOUT_VMIN 2850000
#define TPS61280_VOUT_VMAX 4400000
#define TPS61280_VOUT_VSTEP 50000
struct tps61280_platform_data {
bool bypass_pin_ctrl;
int bypass_gpio;
bool vsel_controlled_mode;
bool vsel_controlled_dvs;
bool vsel_controlled_sleep;
int vsel_gpio;
int vsel_pin_default_state;
bool enable_pin_ctrl;
int enable_gpio;
};
struct tps61280_chip {
struct device *dev;
struct i2c_client *client;
struct regulator_dev *rdev;
struct regmap *rmap;
struct regulator_desc rdesc;
struct tps61280_platform_data pdata;
int lru_index[TPS61280_MAX_VOUT_REG];
int curr_vout_val[TPS61280_MAX_VOUT_REG];
int curr_vout_reg;
int curr_vsel_gpio_val;
int sleep_vout_reg;
struct thermal_zone_device *tz_device;
struct mutex mutex;
struct regulator_init_data *rinit_data;
int bypass_state;
int current_mode;
int enable_state;
};
static const struct regmap_config tps61280_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 5,
};
/*
* find_voltage_set_register: Find new voltage configuration register (VOUT).
* The finding of the new VOUT register will be based on the LRU mechanism.
* Each VOUT register will have different voltage configured . This
* Function will look if any of the VOUT register have requested voltage set
* or not.
* - If it is already there then it will make that register as most
* recently used and return as found so that caller need not to set
* the VOUT register but need to set the proper gpios to select this
* VOUT register.
* - If requested voltage is not found then it will use the least
* recently mechanism to get new VOUT register for new configuration
* and will return not_found so that caller need to set new VOUT
* register and then gpios (both).
*/
static bool find_voltage_set_register(struct tps61280_chip *tps,
int req_vsel, int *vout_reg, int *gpio_val)
{
int i;
bool found = false;
int new_vout_reg = tps->lru_index[TPS61280_MAX_VOUT_REG - 1];
int found_index = TPS61280_MAX_VOUT_REG - 1;
for (i = 0; i < TPS61280_MAX_VOUT_REG; ++i) {
if (tps->curr_vout_val[tps->lru_index[i]] == req_vsel) {
new_vout_reg = tps->lru_index[i];
found_index = i;
found = true;
goto update_lru_index;
}
}
update_lru_index:
for (i = found_index; i > 0; i--)
tps->lru_index[i] = tps->lru_index[i - 1];
tps->lru_index[0] = new_vout_reg;
*gpio_val = new_vout_reg;
*vout_reg = TPS61280_VOUTFLOORSET + new_vout_reg;
return found;
}
static int tps61280_dcdc_get_voltage_sel(struct regulator_dev *rdev)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
unsigned int data;
int ret;
ret = regmap_read(tps->rmap, tps->curr_vout_reg, &data);
if (ret < 0) {
dev_err(tps->dev, "register %d read failed: %d\n",
tps->curr_vout_reg, ret);
return ret;
}
return data & TPS61280_VOUT_MASK;
}
static int tps61280_dcdc_set_voltage_sel(struct regulator_dev *rdev,
unsigned vsel)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
int ret;
bool found = false;
int vout_reg = tps->curr_vout_reg;
int gpio_val = tps->curr_vsel_gpio_val;
/*
* If gpios are available to select the VOUT register then least
* recently used register for new configuration.
*/
if (tps->pdata.vsel_controlled_dvs &&
gpio_is_valid(tps->pdata.vsel_gpio))
found = find_voltage_set_register(tps, vsel,
&vout_reg, &gpio_val);
if (!found) {
ret = regmap_update_bits(tps->rmap, vout_reg,
TPS61280_VOUT_MASK, vsel);
if (ret < 0) {
dev_err(tps->dev, "register %d update failed: %d\n",
vout_reg, ret);
return ret;
}
tps->curr_vout_reg = vout_reg;
tps->curr_vout_val[gpio_val] = vsel;
}
/* Select proper VOUT register vio gpios */
if (tps->pdata.vsel_controlled_dvs &&
gpio_is_valid(tps->pdata.vsel_gpio)) {
gpio_set_value_cansleep(tps->pdata.vsel_gpio, gpio_val & 0x1);
tps->curr_vsel_gpio_val = gpio_val;
}
return 0;
}
static int tps61280_dcdc_set_sleep_voltage_sel(struct regulator_dev *rdev,
unsigned sel)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
int ret;
if (!tps->pdata.vsel_controlled_sleep ||
gpio_is_valid(tps->pdata.vsel_gpio)) {
dev_err(tps->dev, "Regulator has invalid configuration\n");
return -EINVAL;
}
ret = regmap_update_bits(tps->rmap, tps->sleep_vout_reg,
TPS61280_VOUT_MASK, sel);
if (ret < 0) {
dev_err(tps->dev, "register %d update failed: %d\n",
tps->sleep_vout_reg, ret);
return ret;
}
return 0;
}
static int tps61280_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
unsigned int val;
int ret = 0;
int curr_mode;
switch (mode) {
case REGULATOR_MODE_FAST:
case REGULATOR_MODE_NORMAL:
break;
default:
dev_err(tps->dev, "Mode is not supported\n");
return -EINVAL;
}
if (tps->current_mode == mode)
return 0;
curr_mode = mode;
if (curr_mode != REGULATOR_MODE_FAST)
curr_mode = REGULATOR_MODE_NORMAL;
if (tps->pdata.vsel_controlled_mode) {
if (!gpio_is_valid(tps->pdata.vsel_gpio))
return 0;
if (curr_mode == REGULATOR_MODE_FAST)
gpio_set_value_cansleep(tps->pdata.vsel_gpio, 1);
else
gpio_set_value_cansleep(tps->pdata.vsel_gpio, 0);
tps->current_mode = curr_mode;
return 0;
}
val = TPS61280_CONFIG_MODE_AUTO_PWM;
if (curr_mode != REGULATOR_MODE_FAST)
val = TPS61280_CONFIG_MODE_FORCE_PWM;
ret = regmap_update_bits(tps->rmap, TPS61280_CONFIG,
TPS61280_CONFIG_MODE_MASK, val);
if (ret < 0) {
dev_err(tps->dev, "CONFIG update failed %d\n", ret);
return ret;
}
tps->current_mode = curr_mode;
return 0;
}
static unsigned int tps61280_get_mode(struct regulator_dev *rdev)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
return tps->current_mode;
}
static int tps61280_val_to_reg(int val, int offset, int div, int nbits,
bool roundup)
{
int max_val = offset + (BIT(nbits) - 1) * div;
if (val <= offset)
return 0;
if (val >= max_val)
return BIT(nbits) - 1;
if (roundup)
return DIV_ROUND_UP(val - offset, div);
else
return (val - offset) / div;
}
static int tps61280_set_current_limit(struct regulator_dev *rdev, int min_ua,
int max_ua)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
int val;
int ret = 0;
if (!max_ua)
return -EINVAL;
dev_info(tps->dev, "Setting current limit %d\n", max_ua/1000);
val = tps61280_val_to_reg(max_ua/1000, TPS61280_ILIM_OFFSET,
TPS61280_ILIM_STEP, 3, 0);
if (val < 0)
return -EINVAL;
ret = regmap_update_bits(tps->rmap, TPS61280_ILIMSET,
TPS61280_ILIM_MASK, (val | TPS61280_ILIM_BASE));
if (ret < 0) {
dev_err(tps->dev, "ILIM REG update failed %d\n", ret);
return ret;
}
return ret;
}
static int tps61280_get_current_limit(struct regulator_dev *rdev)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
u32 val;
int ret;
ret = regmap_read(tps->rmap, TPS61280_ILIMSET, &val);
if (ret < 0) {
dev_err(tps->dev, "ILIM REG read failed %d\n", ret);
return ret;
}
val &= (TPS61280_ILIM_MASK & ~TPS61280_ILIM_BASE);
val = val * TPS61280_ILIM_STEP + TPS61280_ILIM_OFFSET;
return val;
}
static int tps61280_regulator_enable(struct regulator_dev *rdev)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
u32 val;
int ret;
if (tps->pdata.enable_pin_ctrl) {
gpio_set_value_cansleep(tps->pdata.enable_gpio, 1);
return 0;
}
val = TPS61280_CONFIG_BYPASS_PASS_TROUGH;
if (tps->bypass_state)
val = TPS61280_CONFIG_BYPASS_AUTO_TRANS;
ret = regmap_update_bits(tps->rmap, TPS61280_CONFIG,
TPS61280_CONFIG_ENABLE_MASK, val);
if (ret < 0) {
dev_err(tps->dev, "CONFIG update failed %d\n", ret);
return ret;
}
tps->enable_state = true;
return 0;
}
static int tps61280_regulator_disable(struct regulator_dev *rdev)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
int ret;
if (tps->pdata.enable_pin_ctrl) {
gpio_set_value_cansleep(tps->pdata.enable_gpio, 0);
return 0;
}
ret = regmap_update_bits(tps->rmap, TPS61280_CONFIG,
TPS61280_CONFIG_ENABLE_MASK,
TPS61280_CONFIG_BYPASS_SHUTDOWN);
if (ret < 0) {
dev_err(tps->dev, "CONFIG update failed %d\n", ret);
return ret;
}
tps->enable_state = false;
return 0;
}
static int tps61280_regulator_is_enabled(struct regulator_dev *rdev)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
return tps->enable_state;
}
static int tps61280_set_bypass(struct regulator_dev *rdev, bool enable)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
u32 val;
int ret;
if (tps->pdata.bypass_pin_ctrl) {
if (!gpio_is_valid(tps->pdata.bypass_gpio))
return 0;
if (enable)
gpio_set_value_cansleep(tps->pdata.bypass_gpio, 1);
else
gpio_set_value_cansleep(tps->pdata.bypass_gpio, 0);
tps->bypass_state = enable;
return 0;
}
if (!tps->enable_state) {
tps->bypass_state = enable;
return 0;
}
val = TPS61280_CONFIG_BYPASS_PASS_TROUGH;
if (enable)
val = TPS61280_CONFIG_BYPASS_AUTO_TRANS;
ret = regmap_update_bits(tps->rmap, TPS61280_CONFIG,
TPS61280_CONFIG_ENABLE_MASK, val);
if (ret < 0) {
dev_err(tps->dev, "CONFIG update failed %d\n", ret);
return ret;
}
tps->bypass_state = enable;
return 0;
}
static int tps61280_get_bypass(struct regulator_dev *rdev, bool *enable)
{
struct tps61280_chip *tps = rdev_get_drvdata(rdev);
*enable = tps->bypass_state;
return 0;
}
static struct regulator_ops tps61280_ops = {
.set_voltage_sel = tps61280_dcdc_set_voltage_sel,
.get_voltage_sel = tps61280_dcdc_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
.set_mode = tps61280_set_mode,
.get_mode = tps61280_get_mode,
.set_current_limit = tps61280_set_current_limit,
.get_current_limit = tps61280_get_current_limit,
.set_bypass = tps61280_set_bypass,
.get_bypass = tps61280_get_bypass,
.enable = tps61280_regulator_enable,
.disable = tps61280_regulator_disable,
.is_enabled = tps61280_regulator_is_enabled,
.set_sleep_voltage_sel = tps61280_dcdc_set_sleep_voltage_sel,
};
static int tps61280_thermal_read_temp(void *data, int *temp)
{
struct tps61280_chip *tps = data;
u32 val;
int ret;
ret = regmap_read(tps->rmap, TPS61280_STATUS, &val);
if (ret < 0) {
dev_err(tps->dev, "STATUS REG read failed %d\n", ret);
return -EINVAL;
}
if (val & TPS61280_HOTDIE_MASK)
*temp = TPS61280_HOTDIE_TEMP * 1000;
else
*temp = TPS61280_NORMAL_OPTEMP * 1000;
return 0;
}
static irqreturn_t tps61280_irq(int irq, void *dev)
{
struct tps61280_chip *tps = dev;
struct i2c_client *client = tps->client;
int val;
int ret;
ret = regmap_read(tps->rmap, TPS61280_STATUS, &val);
if (ret < 0) {
dev_err(&client->dev, "%s() STATUS REG read failed %d\n",
__func__, ret);
return -EINVAL;
}
dev_info(&client->dev, "%s() Irq %d status 0x%02x\n",
__func__, irq, val);
if (val & TPS61280_PGOOD_MASK)
dev_info(&client->dev,
"PG Status:output voltage is within normal range\n");
if (val & TPS61280_FAULT_MASK)
dev_err(&client->dev, "FAULT condition has occurred\n");
if (val & TPS61280_ILIMBST_MASK)
dev_err(&client->dev,
"Input current triggered for 1.5ms in boost mode\n");
if (val & TPS61280_ILIMPT_MASK)
dev_err(&client->dev, "Bypass FET Current has triggered\n");
if (val & TPS61280_OPMODE_MASK)
dev_err(&client->dev, "Device operates in dc/dc mode\n");
else
dev_err(&client->dev,
"Device operates in pass-through mode\n");
if (val & TPS61280_DCDCMODE_MASK)
dev_err(&client->dev, "Device operates in PFM mode\n");
else
dev_err(&client->dev, "Device operates in PWM mode\n");
if (val & TPS61280_HOTDIE_MASK) {
dev_info(&client->dev, "TPS61280 in thermal regulation\n");
if (tps->tz_device)
thermal_zone_device_update(tps->tz_device,
THERMAL_EVENT_UNSPECIFIED);
}
if (val & TPS61280_THERMALSD_MASK)
dev_err(&client->dev, "Thermal shutdown tripped\n");
return IRQ_HANDLED;
}
static int tps61280_bypass_init(struct tps61280_chip *tps61280)
{
struct device *dev = tps61280->dev;
unsigned int val;
int ret;
if (!tps61280->rinit_data)
return 0;
tps61280->rinit_data->constraints.valid_ops_mask |=
REGULATOR_CHANGE_BYPASS;
if (tps61280->pdata.bypass_pin_ctrl) {
int gpio_flag;
ret = regmap_update_bits(tps61280->rmap, TPS61280_CONFIG,
TPS61280_CONFIG_ENABLE_MASK,
TPS61280_CONFIG_BYPASS_HW_CONTRL);
if (ret < 0) {
dev_err(dev, "CONFIG update failed %d\n", ret);
return ret;
}
if (!gpio_is_valid(tps61280->pdata.bypass_gpio))
return 0;
if (tps61280->rinit_data->constraints.bypass_on)
gpio_flag = GPIOF_OUT_INIT_HIGH;
else
gpio_flag = GPIOF_OUT_INIT_LOW;
ret = devm_gpio_request_one(tps61280->dev,
tps61280->pdata.bypass_gpio,
gpio_flag, "tps61280-bypass-pin-gpio");
if (ret < 0) {
dev_err(dev, "Bypass GPIO request failed: %d\n", ret);
return ret;
}
tps61280->bypass_state =
tps61280->rinit_data->constraints.bypass_on;
return 0;
}
if (!tps61280->enable_state) {
tps61280->bypass_state =
tps61280->rinit_data->constraints.bypass_on;
return 0;
}
val = TPS61280_CONFIG_BYPASS_PASS_TROUGH;
if (tps61280->rinit_data->constraints.bypass_on)
val = TPS61280_CONFIG_BYPASS_AUTO_TRANS;
ret = regmap_update_bits(tps61280->rmap, TPS61280_CONFIG,
TPS61280_CONFIG_ENABLE_MASK, val);
if (ret < 0) {
dev_err(dev, "CONFIG update failed %d\n", ret);
return ret;
}
tps61280->bypass_state = tps61280->rinit_data->constraints.bypass_on;
return 0;
}
static int tps61280_mode_init(struct tps61280_chip *tps61280)
{
struct device *dev = tps61280->dev;
unsigned int val;
int ret;
int curr_mode;
if (!tps61280->rinit_data)
return 0;
tps61280->rinit_data->constraints.valid_ops_mask |=
REGULATOR_CHANGE_MODE;
tps61280->rinit_data->constraints.valid_modes_mask |=
REGULATOR_MODE_FAST |
REGULATOR_MODE_NORMAL;
curr_mode = tps61280->rinit_data->constraints.initial_mode;
if (curr_mode != REGULATOR_MODE_FAST)
curr_mode = REGULATOR_MODE_NORMAL;
if (tps61280->pdata.vsel_controlled_mode) {
int gpio_flag;
ret = regmap_update_bits(tps61280->rmap, TPS61280_CONFIG,
TPS61280_CONFIG_MODE_MASK,
TPS61280_CONFIG_MODE_VSEL);
if (ret < 0) {
dev_err(dev, "CONFIG update failed %d\n", ret);
return ret;
}
if (!gpio_is_valid(tps61280->pdata.vsel_gpio))
return 0;
if (curr_mode == REGULATOR_MODE_FAST)
gpio_flag = GPIOF_OUT_INIT_HIGH;
else
gpio_flag = GPIOF_OUT_INIT_LOW;
ret = devm_gpio_request_one(tps61280->dev,
tps61280->pdata.vsel_gpio,
gpio_flag, "tps61280-mode-vsel-gpio");
if (ret < 0) {
dev_err(dev, "VSEL-MODE GPIO request failed: %d\n",
ret);
return ret;
}
tps61280->current_mode = curr_mode;
return 0;
}
val = TPS61280_CONFIG_MODE_AUTO_PWM;
if (curr_mode != REGULATOR_MODE_FAST)
val = TPS61280_CONFIG_MODE_FORCE_PWM;
ret = regmap_update_bits(tps61280->rmap, TPS61280_CONFIG,
TPS61280_CONFIG_MODE_MASK, val);
if (ret < 0) {
dev_err(dev, "CONFIG update failed %d\n", ret);
return ret;
}
tps61280->current_mode = curr_mode;
return 0;
}
static int tps61280_regulator_enable_init(struct tps61280_chip *tps61280)
{
struct device *dev = tps61280->dev;
int ret;
int enable_state = 0;
if (!tps61280->rinit_data)
return 0;
tps61280->rinit_data->constraints.valid_ops_mask |=
REGULATOR_CHANGE_STATUS;
if (tps61280->rinit_data->constraints.always_on ||
tps61280->rinit_data->constraints.boot_on)
enable_state = 1;
if (tps61280->pdata.enable_pin_ctrl) {
int gpio_flag = GPIOF_OUT_INIT_LOW;
if (!gpio_is_valid(tps61280->pdata.enable_gpio))
return 0;
if (enable_state)
gpio_flag = GPIOF_OUT_INIT_HIGH;
ret = devm_gpio_request_one(tps61280->dev,
tps61280->pdata.enable_gpio,
gpio_flag, "tps61280-en-pin-gpio");
if (ret < 0) {
dev_err(dev, "Enable GPIO request failed: %d\n", ret);
return ret;
}
tps61280->enable_state = enable_state;
return 0;
}
if (!enable_state) {
ret = regmap_update_bits(tps61280->rmap, TPS61280_CONFIG,
TPS61280_CONFIG_ENABLE_MASK,
TPS61280_CONFIG_BYPASS_SHUTDOWN);
if (ret < 0) {
dev_err(dev, "CONFIG update failed %d\n", ret);
return ret;
}
}
tps61280->enable_state = enable_state;
return 0;
}
static int tps61280_dvs_init(struct tps61280_chip *tps61280)
{
struct device *dev = tps61280->dev;
unsigned int init_uv;
unsigned int vsel;
int ret;
if (!tps61280->rinit_data)
return 0;
tps61280->rinit_data->constraints.valid_ops_mask |=
REGULATOR_CHANGE_VOLTAGE;
tps61280->curr_vsel_gpio_val = tps61280->pdata.vsel_pin_default_state;
tps61280->curr_vout_reg = TPS61280_VOUTFLOORSET +
tps61280->pdata.vsel_pin_default_state;
tps61280->lru_index[0] = tps61280->curr_vout_reg;
tps61280->sleep_vout_reg = TPS61280_VOUTFLOORSET;
if (!tps61280->pdata.vsel_pin_default_state)
tps61280->sleep_vout_reg += 1;
if (tps61280->pdata.vsel_controlled_dvs &&
gpio_is_valid(tps61280->pdata.vsel_gpio)) {
int gpio_flags;
int i;
gpio_flags = (tps61280->pdata.vsel_pin_default_state) ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
ret = devm_gpio_request_one(dev, tps61280->pdata.vsel_gpio,
gpio_flags, "tps61280-vsel-dvs");
if (ret) {
dev_err(dev, "VSEL GPIO request failed: %d\n", ret);
return ret;
}
/*
* Initialize the lru index with vout_reg id
* The index 0 will be most recently used and
* set with the max->curr_vout_reg */
for (i = 0; i < TPS61280_MAX_VOUT_REG; ++i)
tps61280->lru_index[i] = i;
tps61280->lru_index[0] = tps61280->curr_vout_reg;
tps61280->lru_index[tps61280->curr_vout_reg] = 0;
}
init_uv = tps61280->rinit_data->constraints.min_uV;
if ((init_uv >= TPS61280_VOUT_VMIN) &&
(init_uv <= TPS61280_VOUT_VMAX)) {
vsel = DIV_ROUND_UP((init_uv - TPS61280_VOUT_VMIN),
TPS61280_VOUT_VSTEP);
ret = regmap_update_bits(tps61280->rmap, TPS61280_VOUTFLOORSET,
TPS61280_VOUT_MASK, vsel);
if (ret < 0) {
dev_err(dev, "VOUTFLOORSET update failed: %d\n", ret);
return ret;
}
ret = regmap_update_bits(tps61280->rmap, TPS61280_VOUTROOFSET,
TPS61280_VOUT_MASK, vsel);
if (ret < 0) {
dev_err(dev, "VOUTROOFSET update failed: %d\n", ret);
return ret;
}
}
return 0;
}
static const struct thermal_zone_of_device_ops tps61280_of_thermal_ops = {
.get_temp = tps61280_thermal_read_temp,
};
static int tps61280_parse_dt_data(struct i2c_client *client,
struct tps61280_platform_data *pdata)
{
struct device_node *np = client->dev.of_node;
u32 pval;
int ret;
pdata->vsel_controlled_mode = of_property_read_bool(np,
"ti,enable-vsel-controlled-mode");
pdata->vsel_controlled_dvs = of_property_read_bool(np,
"ti,enable-vsel-controlled-dvs");
pdata->vsel_controlled_sleep = of_property_read_bool(np,
"ti,enable-vsel-controlled-sleep");
pdata->vsel_gpio = -EINVAL;
if (pdata->vsel_controlled_mode || pdata->vsel_controlled_dvs) {
pdata->vsel_gpio = of_get_named_gpio(np,
"ti,vsel-pin-gpio", 0);
if ((pdata->vsel_gpio < 0) && (pdata->vsel_gpio != -EINVAL)) {
dev_err(&client->dev, "VSEL GPIO not available: %d\n",
pdata->vsel_gpio);
return pdata->vsel_gpio;
}
}
if (pdata->vsel_controlled_dvs || pdata->vsel_controlled_sleep) {
ret = of_property_read_u32(np, "ti,vsel-pin-default-state",
&pval);
if (ret < 0) {
dev_err(&client->dev, "VSEL default state not found\n");
return ret;
}
pdata->vsel_pin_default_state = pval;
}
pdata->enable_pin_ctrl = of_property_read_bool(np,
"ti,enable-en-pin-control");
if (pdata->enable_pin_ctrl) {
pdata->enable_gpio = of_get_named_gpio(np,
"ti,en-pin-gpio", 0);
if ((pdata->enable_gpio < 0) &&
(pdata->enable_gpio != -EINVAL)) {
dev_err(&client->dev, "EN GPIO not available: ^%d\n",
pdata->enable_gpio);
return pdata->enable_gpio;
}
}
pdata->bypass_pin_ctrl = of_property_read_bool(np,
"ti,enable-bypass-pin-control");
if (pdata->bypass_pin_ctrl) {
pdata->bypass_gpio = of_get_named_gpio(np,
"ti,bypass-pin-gpio", 0);
if ((pdata->bypass_gpio < 0) &&
(pdata->bypass_gpio != -EINVAL)) {
dev_err(&client->dev, "BYPASS GPIO not available: %d\n",
pdata->bypass_gpio);
return pdata->bypass_gpio;
}
}
return 0;
}
static int tps61280_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tps61280_chip *tps61280;
struct regulator_config rconfig = { };
int ret;
if (!client->dev.of_node) {
dev_err(&client->dev, "Only Supporting DT\n");
return -ENODEV;
}
tps61280 = devm_kzalloc(&client->dev, sizeof(*tps61280), GFP_KERNEL);
if (!tps61280)
return -ENOMEM;
ret = tps61280_parse_dt_data(client, &tps61280->pdata);
if (ret < 0) {
dev_err(&client->dev, "Platform data pasring failed: %d\n",
ret);
return ret;
}
tps61280->rmap = devm_regmap_init_i2c(client, &tps61280_regmap_config);
if (IS_ERR(tps61280->rmap)) {
ret = PTR_ERR(tps61280->rmap);
dev_err(&client->dev, "regmap init failed with err%d\n", ret);
return ret;
}
tps61280->client = client;
tps61280->dev = &client->dev;
i2c_set_clientdata(client, tps61280);
mutex_init(&tps61280->mutex);
tps61280->rdesc.name = "tps61280-dcdc";
tps61280->rdesc.ops = &tps61280_ops;
tps61280->rdesc.type = REGULATOR_VOLTAGE;
tps61280->rdesc.owner = THIS_MODULE;
tps61280->rdesc.linear_min_sel = 0;
tps61280->rdesc.min_uV = TPS61280_VOUT_VMIN;
tps61280->rdesc.uV_step = TPS61280_VOUT_VSTEP;
tps61280->rdesc.n_voltages = 0x20;
tps61280->rinit_data = of_get_regulator_init_data(tps61280->dev,
tps61280->dev->of_node, &tps61280->rdesc);
if (!tps61280->rinit_data) {
dev_err(&client->dev, "No Regulator init data\n");
return -EINVAL;
}
ret = tps61280_regulator_enable_init(tps61280);
if (ret < 0) {
dev_err(&client->dev, "Enable init failed: %d\n", ret);
return ret;
}
ret = tps61280_dvs_init(tps61280);
if (ret < 0) {
dev_err(&client->dev, "DVS init failed: %d\n", ret);
return ret;
}
ret = tps61280_bypass_init(tps61280);
if (ret < 0) {
dev_err(&client->dev, "Bypass init failed: %d\n", ret);
return ret;
}
ret = tps61280_mode_init(tps61280);
if (ret < 0) {
dev_err(&client->dev, "Mode init failed: %d\n", ret);
return ret;
}
rconfig.dev = tps61280->dev;
rconfig.of_node = tps61280->dev->of_node;
rconfig.driver_data = tps61280;
rconfig.regmap = tps61280->rmap;
rconfig.init_data = tps61280->rinit_data;
tps61280->rdev = devm_regulator_register(tps61280->dev,
&tps61280->rdesc, &rconfig);
if (IS_ERR(tps61280->rdev)) {
ret = PTR_ERR(tps61280->rdev);
dev_err(&client->dev, "regulator register failed %d\n", ret);
return ret;
}
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, tps61280_irq,
IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
dev_name(&client->dev), tps61280);
if (ret < 0) {
dev_err(&client->dev, "Request irq %d failed: %d\n",
client->irq, ret);
return ret;
}
}
device_set_wakeup_capable(&client->dev, 1);
device_wakeup_enable(&client->dev);
tps61280->tz_device = devm_thermal_zone_of_sensor_register(tps61280->dev, 0,
tps61280, &tps61280_of_thermal_ops);
if (IS_ERR(tps61280->tz_device)) {
ret = PTR_ERR(tps61280->tz_device);
dev_err(&client->dev, "TZ device register failed: %d\n", ret);
return ret;
}
dev_info(&client->dev, "DC-Boost probe successful\n");
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int tps61280_suspend(struct device *dev)
{
struct tps61280_chip *tps = dev_get_drvdata(dev);
if (device_may_wakeup(&tps->client->dev) && tps->client->irq)
enable_irq_wake(tps->client->irq);
return 0;
}
static int tps61280_resume(struct device *dev)
{
struct tps61280_chip *tps = dev_get_drvdata(dev);
if (device_may_wakeup(&tps->client->dev) && tps->client->irq)
disable_irq_wake(tps->client->irq);
return 0;
}
#endif /* CONFIG_PM */
static SIMPLE_DEV_PM_OPS(tps61280_pm_ops, tps61280_suspend, tps61280_resume);
static const struct of_device_id tps61280_dt_match[] = {
{ .compatible = "tps61280" },
{ },
};
MODULE_DEVICE_TABLE(of, tps61280_dt_match);
static const struct i2c_device_id tps61280_i2c_id[] = {
{ "tps61280", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tps61280_i2c_id);
static struct i2c_driver tps61280_driver = {
.driver = {
.name = "tps61280",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(tps61280_dt_match),
.pm = &tps61280_pm_ops,
},
.probe = tps61280_probe,
.id_table = tps61280_i2c_id,
};
static int __init tps61280_init(void)
{
return i2c_add_driver(&tps61280_driver);
}
fs_initcall_sync(tps61280_init);
static void __exit tps61280_exit(void)
{
i2c_del_driver(&tps61280_driver);
}
module_exit(tps61280_exit);
MODULE_DESCRIPTION("tps61280 driver");
MODULE_AUTHOR("Venkat Reddy Talla <vreddytalla@nvidia.com>");
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
MODULE_ALIAS("i2c:tps61280");
MODULE_LICENSE("GPL v2");