[go: nahoru, domu]

16219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan/*
26219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * tps62360.c -- TI tps62360
36219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *
4d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin * Driver for processor core supply tps62360, tps62361B, tps62362 and tps62363.
56219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *
66219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * Copyright (c) 2012, NVIDIA Corporation.
76219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *
86219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * Author: Laxman Dewangan <ldewangan@nvidia.com>
96219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *
106219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * This program is free software; you can redistribute it and/or
116219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * modify it under the terms of the GNU General Public License as
126219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * published by the Free Software Foundation version 2.
136219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *
146219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
156219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * whether express or implied; without even the implied warranty of
166219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
176219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * General Public License for more details.
186219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *
196219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * You should have received a copy of the GNU General Public License
206219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * along with this program; if not, write to the Free Software
216219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
226219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * 02111-1307, USA
236219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan */
246219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
256219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/kernel.h>
266219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/module.h>
276219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/init.h>
286219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/err.h>
29684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan#include <linux/of.h>
30684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan#include <linux/of_device.h>
31684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan#include <linux/of_gpio.h>
32684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan#include <linux/regulator/of_regulator.h>
336219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/platform_device.h>
346219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/regulator/driver.h>
356219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/regulator/machine.h>
366219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/regulator/tps62360.h>
376219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/gpio.h>
386219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/i2c.h>
396219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/slab.h>
406219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#include <linux/regmap.h>
416219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
426219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan/* Register definitions */
436219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#define REG_VSET0		0
446219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#define REG_VSET1		1
456219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#define REG_VSET2		2
466219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#define REG_VSET3		3
476219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#define REG_CONTROL		4
486219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#define REG_TEMP		5
496219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#define REG_RAMPCTRL		6
506219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#define REG_CHIPID		8
516219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
529a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan#define FORCE_PWM_ENABLE	BIT(7)
539a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan
54d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Linenum chips {TPS62360, TPS62361, TPS62362, TPS62363};
556219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
562935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan#define TPS62360_BASE_VOLTAGE	770000
576219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#define TPS62360_N_VOLTAGES	64
586219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
592935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan#define TPS62361_BASE_VOLTAGE	500000
606219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan#define TPS62361_N_VOLTAGES	128
616219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
626219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan/* tps 62360 chip information */
636219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganstruct tps62360_chip {
646219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	struct device *dev;
656219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	struct regulator_desc desc;
666219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	struct regulator_dev *rdev;
676219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	struct regmap *regmap;
686219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int vsel0_gpio;
696219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int vsel1_gpio;
706219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	u8 voltage_reg_mask;
716219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	bool en_internal_pulldn;
726219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	bool en_discharge;
736219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	bool valid_gpios;
746219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int lru_index[4];
756219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int curr_vset_vsel[4];
766219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int curr_vset_id;
776219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan};
786219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
796219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan/*
806219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * find_voltage_set_register: Find new voltage configuration register
816219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * (VSET) id.
826219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * The finding of the new VSET register will be based on the LRU mechanism.
836219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * Each VSET register will have different voltage configured . This
846219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * Function will look if any of the VSET register have requested voltage set
856219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan * or not.
866219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *     - If it is already there then it will make that register as most
876219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *       recently used and return as found so that caller need not to set
886219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *       the VSET register but need to set the proper gpios to select this
896219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *       VSET register.
906219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *     - If requested voltage is not found then it will use the least
916219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *       recently mechanism to get new VSET register for new configuration
926219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *       and will return not_found so that caller need to set new VSET
936219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan *       register and then gpios (both).
946219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan */
956219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganstatic bool find_voltage_set_register(struct tps62360_chip *tps,
966219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		int req_vsel, int *vset_reg_id)
976219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan{
986219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int i;
996219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	bool found = false;
1006219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int new_vset_reg = tps->lru_index[3];
1016219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int found_index = 3;
1022935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan
1036219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	for (i = 0; i < 4; ++i) {
1046219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) {
1056219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan			new_vset_reg = tps->lru_index[i];
1066219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan			found_index = i;
1076219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan			found = true;
1086219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan			goto update_lru_index;
1096219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		}
1106219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	}
1116219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
1126219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganupdate_lru_index:
1136219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	for (i = found_index; i > 0; i--)
1146219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		tps->lru_index[i] = tps->lru_index[i - 1];
1156219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
1166219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->lru_index[0] = new_vset_reg;
1176219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	*vset_reg_id = new_vset_reg;
1186219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	return found;
1196219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan}
1206219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
121a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewanganstatic int tps62360_dcdc_get_voltage_sel(struct regulator_dev *dev)
1226219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan{
1236219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	struct tps62360_chip *tps = rdev_get_drvdata(dev);
1246219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int vsel;
1256219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	unsigned int data;
1266219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int ret;
1276219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
1286219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
1296219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (ret < 0) {
1302935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		dev_err(tps->dev, "%s(): register %d read failed with err %d\n",
1312935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			__func__, REG_VSET0 + tps->curr_vset_id, ret);
1326219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		return ret;
1336219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	}
1346219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	vsel = (int)data & tps->voltage_reg_mask;
135a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan	return vsel;
1366219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan}
1376219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
13841097afd64108348a935c658c78662bce1ea6355Axel Linstatic int tps62360_dcdc_set_voltage_sel(struct regulator_dev *dev,
13941097afd64108348a935c658c78662bce1ea6355Axel Lin					 unsigned selector)
1406219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan{
1416219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	struct tps62360_chip *tps = rdev_get_drvdata(dev);
1426219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int ret;
1436219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	bool found = false;
1446219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int new_vset_id = tps->curr_vset_id;
1456219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
1466219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	/*
1476219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	 * If gpios are available to select the VSET register then least
1486219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	 * recently used register for new configuration.
1496219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	 */
1506219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (tps->valid_gpios)
15141097afd64108348a935c658c78662bce1ea6355Axel Lin		found = find_voltage_set_register(tps, selector, &new_vset_id);
1526219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
1536219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (!found) {
1546219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id,
15541097afd64108348a935c658c78662bce1ea6355Axel Lin				tps->voltage_reg_mask, selector);
1566219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		if (ret < 0) {
1572935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			dev_err(tps->dev,
1582935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan				"%s(): register %d update failed with err %d\n",
1592935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan				 __func__, REG_VSET0 + new_vset_id, ret);
1606219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan			return ret;
1616219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		}
1626219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		tps->curr_vset_id = new_vset_id;
16341097afd64108348a935c658c78662bce1ea6355Axel Lin		tps->curr_vset_vsel[new_vset_id] = selector;
1646219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	}
1656219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
1666219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	/* Select proper VSET register vio gpios */
1676219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (tps->valid_gpios) {
1682935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		gpio_set_value_cansleep(tps->vsel0_gpio, new_vset_id & 0x1);
1696219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		gpio_set_value_cansleep(tps->vsel1_gpio,
1706219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan					(new_vset_id >> 1) & 0x1);
1716219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	}
1726219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	return 0;
1736219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan}
1746219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
1759a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewanganstatic int tps62360_set_mode(struct regulator_dev *rdev, unsigned int mode)
1769a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan{
1779a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	struct tps62360_chip *tps = rdev_get_drvdata(rdev);
1789a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	int i;
1799a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	int val;
1809a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	int ret;
1819a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan
1829a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	/* Enable force PWM mode in FAST mode only. */
1839a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	switch (mode) {
1849a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	case REGULATOR_MODE_FAST:
1859a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		val = FORCE_PWM_ENABLE;
1869a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		break;
1879a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan
1889a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	case REGULATOR_MODE_NORMAL:
1899a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		val = 0;
1909a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		break;
1919a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan
1929a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	default:
1939a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		return -EINVAL;
1949a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	}
1959a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan
1969a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	if (!tps->valid_gpios) {
1979a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		ret = regmap_update_bits(tps->regmap,
1989a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan			REG_VSET0 + tps->curr_vset_id, FORCE_PWM_ENABLE, val);
1999a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		if (ret < 0)
2009a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan			dev_err(tps->dev,
2019a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan				"%s(): register %d update failed with err %d\n",
2029a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan				__func__, REG_VSET0 + tps->curr_vset_id, ret);
2039a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		return ret;
2049a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	}
2059a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan
2069a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	/* If gpios are valid then all register set need to be control */
2079a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	for (i = 0; i < 4; ++i) {
2089a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		ret = regmap_update_bits(tps->regmap,
2099a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan					REG_VSET0 + i, FORCE_PWM_ENABLE, val);
2109a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		if (ret < 0) {
2119a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan			dev_err(tps->dev,
2129a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan				"%s(): register %d update failed with err %d\n",
2139a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan				__func__, REG_VSET0 + i, ret);
2149a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan			return ret;
2159a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		}
2169a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	}
2179a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	return ret;
2189a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan}
2199a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan
2209a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewanganstatic unsigned int tps62360_get_mode(struct regulator_dev *rdev)
2219a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan{
2229a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	struct tps62360_chip *tps = rdev_get_drvdata(rdev);
2239a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	unsigned int data;
2249a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	int ret;
2259a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan
2269a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
2279a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	if (ret < 0) {
2289a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		dev_err(tps->dev, "%s(): register %d read failed with err %d\n",
2299a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan			__func__, REG_VSET0 + tps->curr_vset_id, ret);
2309a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan		return ret;
2319a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	}
2329a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	return (data & FORCE_PWM_ENABLE) ?
2339a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan				REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
2349a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan}
2359a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan
2366219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganstatic struct regulator_ops tps62360_dcdc_ops = {
237a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan	.get_voltage_sel	= tps62360_dcdc_get_voltage_sel,
23841097afd64108348a935c658c78662bce1ea6355Axel Lin	.set_voltage_sel	= tps62360_dcdc_set_voltage_sel,
2397f225ba5850886b9834f3473c6e584a94c5fc53bAxel Lin	.list_voltage		= regulator_list_voltage_linear,
24041097afd64108348a935c658c78662bce1ea6355Axel Lin	.map_voltage		= regulator_map_voltage_linear,
2410072f0a82ce78ceb634f00a57d80c9b421b061d4Axel Lin	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
2429a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	.set_mode		= tps62360_set_mode,
2439a00630c3db8ca064a8904dbcd9632fb81244bc0Laxman Dewangan	.get_mode		= tps62360_get_mode,
2446219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan};
2456219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
246a5023574d120ca3b9337cedd4e27de90cae9aff7Bill Pembertonstatic int tps62360_init_dcdc(struct tps62360_chip *tps,
2476219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		struct tps62360_regulator_platform_data *pdata)
2486219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan{
2496219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int ret;
250a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan	unsigned int ramp_ctrl;
2516219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
2522935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan	/* Initialize internal pull up/down control */
2536219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (tps->en_internal_pulldn)
2546219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		ret = regmap_write(tps->regmap, REG_CONTROL, 0xE0);
2556219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	else
2566219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		ret = regmap_write(tps->regmap, REG_CONTROL, 0x0);
2576219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (ret < 0) {
2582935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		dev_err(tps->dev,
2592935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			"%s(): register %d write failed with err %d\n",
2602935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			__func__, REG_CONTROL, ret);
2616219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		return ret;
2626219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	}
2636219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
2646219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	/* Reset output discharge path to reduce power consumption */
2656219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0);
266a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan	if (ret < 0) {
2672935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		dev_err(tps->dev,
2682935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			"%s(): register %d update failed with err %d\n",
2692935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			__func__, REG_RAMPCTRL, ret);
270a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan		return ret;
271a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan	}
272a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan
273a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan	/* Get ramp value from ramp control register */
274a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan	ret = regmap_read(tps->regmap, REG_RAMPCTRL, &ramp_ctrl);
275a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan	if (ret < 0) {
2762935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		dev_err(tps->dev,
2772935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			"%s(): register %d read failed with err %d\n",
2782935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			__func__, REG_RAMPCTRL, ret);
279a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan		return ret;
280a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan	}
2811864b670902260d1c239f37e984f26de8fbad319Axel Lin	ramp_ctrl = (ramp_ctrl >> 5) & 0x7;
282a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan
283a60cfce051dd5e22329df1018d278bf3e52d82bcLaxman Dewangan	/* ramp mV/us = 32/(2^ramp_ctrl) */
2840072f0a82ce78ceb634f00a57d80c9b421b061d4Axel Lin	tps->desc.ramp_delay = DIV_ROUND_UP(32000, BIT(ramp_ctrl));
2856219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	return ret;
2866219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan}
2876219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
2886219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganstatic const struct regmap_config tps62360_regmap_config = {
28916ea003bd1c95ea55a0b88187ce7cbeaca760fcfLaxman Dewangan	.reg_bits		= 8,
29016ea003bd1c95ea55a0b88187ce7cbeaca760fcfLaxman Dewangan	.val_bits		= 8,
29116ea003bd1c95ea55a0b88187ce7cbeaca760fcfLaxman Dewangan	.max_register		= REG_CHIPID,
29216ea003bd1c95ea55a0b88187ce7cbeaca760fcfLaxman Dewangan	.cache_type		= REGCACHE_RBTREE,
2936219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan};
2946219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
295684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewanganstatic struct tps62360_regulator_platform_data *
296684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	of_get_tps62360_platform_data(struct device *dev)
297684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan{
298684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	struct tps62360_regulator_platform_data *pdata;
299684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	struct device_node *np = dev->of_node;
300684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
301684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
30233e63ba6c698740bebc49dc9a7e652526ca005ccSachin Kamat	if (!pdata)
303684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		return NULL;
304684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
305684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
306684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	if (!pdata->reg_init_data) {
307684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		dev_err(dev, "Not able to get OF regulator init data\n");
308684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		return NULL;
309684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	}
310684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
311684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	pdata->vsel0_gpio = of_get_named_gpio(np, "vsel0-gpio", 0);
312684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	pdata->vsel1_gpio = of_get_named_gpio(np, "vsel1-gpio", 0);
313684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
314684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	if (of_find_property(np, "ti,vsel0-state-high", NULL))
315684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		pdata->vsel0_def_state = 1;
316684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
317684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	if (of_find_property(np, "ti,vsel1-state-high", NULL))
318684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		pdata->vsel1_def_state = 1;
319684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
320684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	if (of_find_property(np, "ti,enable-pull-down", NULL))
321684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		pdata->en_internal_pulldn = true;
322684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
323684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	if (of_find_property(np, "ti,enable-vout-discharge", NULL))
324684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		pdata->en_discharge = true;
325684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
326684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	return pdata;
327684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan}
328684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
329684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan#if defined(CONFIG_OF)
330684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewanganstatic const struct of_device_id tps62360_of_match[] = {
331684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	 { .compatible = "ti,tps62360", .data = (void *)TPS62360},
332684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	 { .compatible = "ti,tps62361", .data = (void *)TPS62361},
333684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	 { .compatible = "ti,tps62362", .data = (void *)TPS62362},
334684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	 { .compatible = "ti,tps62363", .data = (void *)TPS62363},
335684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	{},
336be15411d97b6b9b2883b7f1ec52ef03bc770a6d4Axel Lin};
337684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman DewanganMODULE_DEVICE_TABLE(of, tps62360_of_match);
338684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan#endif
339684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
340a5023574d120ca3b9337cedd4e27de90cae9aff7Bill Pembertonstatic int tps62360_probe(struct i2c_client *client,
3416219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan				     const struct i2c_device_id *id)
3426219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan{
343c172708d38a401b2f3f841dfcd862b469fa0b670Mark Brown	struct regulator_config config = { };
3446219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	struct tps62360_regulator_platform_data *pdata;
3456219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	struct regulator_dev *rdev;
3466219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	struct tps62360_chip *tps;
3476219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int ret;
3486219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int i;
349684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	int chip_id;
3506219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
351dff91d0b721bf8f036c1071a8f16a7effaa87514Jingoo Han	pdata = dev_get_platdata(&client->dev);
352684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
353684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	if (client->dev.of_node) {
354684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		const struct of_device_id *match;
355684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		match = of_match_device(of_match_ptr(tps62360_of_match),
356684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan				&client->dev);
357684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		if (!match) {
358684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan			dev_err(&client->dev, "Error: No device match found\n");
359684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan			return -ENODEV;
360684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		}
361541f597f1080ee615534cb6ccb2253891a29535cDavid Howells		chip_id = (int)(long)match->data;
362684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		if (!pdata)
363684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan			pdata = of_get_tps62360_platform_data(&client->dev);
3640a62d03b4844988c5477f13bd17c3553f816ce87Tuomas Tynkkynen	} else if (id) {
3650a62d03b4844988c5477f13bd17c3553f816ce87Tuomas Tynkkynen		chip_id = id->driver_data;
3660a62d03b4844988c5477f13bd17c3553f816ce87Tuomas Tynkkynen	} else {
3670a62d03b4844988c5477f13bd17c3553f816ce87Tuomas Tynkkynen		dev_err(&client->dev, "No device tree match or id table match found\n");
3680a62d03b4844988c5477f13bd17c3553f816ce87Tuomas Tynkkynen		return -ENODEV;
369684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	}
370684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan
3716219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (!pdata) {
3722935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		dev_err(&client->dev, "%s(): Platform data not found\n",
3736219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan						__func__);
3746219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		return -EIO;
3756219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	}
3766219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
3776219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
37833e63ba6c698740bebc49dc9a7e652526ca005ccSachin Kamat	if (!tps)
3796219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		return -ENOMEM;
3806219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
3816219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->en_discharge = pdata->en_discharge;
3826219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->en_internal_pulldn = pdata->en_internal_pulldn;
3836219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->vsel0_gpio = pdata->vsel0_gpio;
3846219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->vsel1_gpio = pdata->vsel1_gpio;
3856219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->dev = &client->dev;
386d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin
387684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan	switch (chip_id) {
388d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin	case TPS62360:
389d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin	case TPS62362:
390b5152415225ba0d489939778f3b85217b25036dbAxel Lin		tps->desc.min_uV = TPS62360_BASE_VOLTAGE;
391d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin		tps->voltage_reg_mask = 0x3F;
392d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin		tps->desc.n_voltages = TPS62360_N_VOLTAGES;
393d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin		break;
394d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin	case TPS62361:
395d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin	case TPS62363:
396b5152415225ba0d489939778f3b85217b25036dbAxel Lin		tps->desc.min_uV = TPS62361_BASE_VOLTAGE;
397d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin		tps->voltage_reg_mask = 0x7F;
398d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin		tps->desc.n_voltages = TPS62361_N_VOLTAGES;
399d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin		break;
400d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin	default:
401d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin		return -ENODEV;
402d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin	}
4036219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
4040a62d03b4844988c5477f13bd17c3553f816ce87Tuomas Tynkkynen	tps->desc.name = client->name;
4056219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->desc.id = 0;
4066219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->desc.ops = &tps62360_dcdc_ops;
4076219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->desc.type = REGULATOR_VOLTAGE;
4086219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->desc.owner = THIS_MODULE;
4097f225ba5850886b9834f3473c6e584a94c5fc53bAxel Lin	tps->desc.uV_step = 10000;
4107f225ba5850886b9834f3473c6e584a94c5fc53bAxel Lin
4119a4bdd87a29bf297d9046410b011d726d51c3999Axel Lin	tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config);
4126219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (IS_ERR(tps->regmap)) {
4136219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		ret = PTR_ERR(tps->regmap);
4142935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		dev_err(&client->dev,
4152935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			"%s(): regmap allocation failed with err %d\n",
4162935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			__func__, ret);
4176219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		return ret;
4186219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	}
4196219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	i2c_set_clientdata(client, tps);
4206219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
4216219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->curr_vset_id = (pdata->vsel1_def_state & 1) * 2 +
4226219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan				(pdata->vsel0_def_state & 1);
4236219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->lru_index[0] = tps->curr_vset_id;
4246219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->valid_gpios = false;
4256219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
4266219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (gpio_is_valid(tps->vsel0_gpio) && gpio_is_valid(tps->vsel1_gpio)) {
4272935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		int gpio_flags;
4282935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		gpio_flags = (pdata->vsel0_def_state) ?
4292935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan				GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
4308a8e3d5915b3b40a64a5e7dc5aeb208594917a15Laxman Dewangan		ret = devm_gpio_request_one(&client->dev, tps->vsel0_gpio,
4312935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan				gpio_flags, "tps62360-vsel0");
4326219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		if (ret) {
4336219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan			dev_err(&client->dev,
4342935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan				"%s(): Could not obtain vsel0 GPIO %d: %d\n",
4352935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan				__func__, tps->vsel0_gpio, ret);
4368a8e3d5915b3b40a64a5e7dc5aeb208594917a15Laxman Dewangan			return ret;
4376219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		}
4386219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
4392935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		gpio_flags = (pdata->vsel1_def_state) ?
4402935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan				GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
4418a8e3d5915b3b40a64a5e7dc5aeb208594917a15Laxman Dewangan		ret = devm_gpio_request_one(&client->dev, tps->vsel1_gpio,
4422935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan				gpio_flags, "tps62360-vsel1");
4436219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		if (ret) {
4446219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan			dev_err(&client->dev,
4452935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan				"%s(): Could not obtain vsel1 GPIO %d: %d\n",
4462935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan				__func__, tps->vsel1_gpio, ret);
4478a8e3d5915b3b40a64a5e7dc5aeb208594917a15Laxman Dewangan			return ret;
4486219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		}
4496219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		tps->valid_gpios = true;
4506219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
4516219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		/*
4526219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		 * Initialize the lru index with vset_reg id
4536219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		 * The index 0 will be most recently used and
4546219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		 * set with the tps->curr_vset_id */
4556219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		for (i = 0; i < 4; ++i)
4566219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan			tps->lru_index[i] = i;
4576219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		tps->lru_index[0] = tps->curr_vset_id;
4586219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		tps->lru_index[tps->curr_vset_id] = 0;
4596219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	}
4606219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
4616219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	ret = tps62360_init_dcdc(tps, pdata);
4626219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (ret < 0) {
4632935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		dev_err(tps->dev, "%s(): Init failed with err = %d\n",
4646219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan				__func__, ret);
4658a8e3d5915b3b40a64a5e7dc5aeb208594917a15Laxman Dewangan		return ret;
4666219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	}
4676219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
468c172708d38a401b2f3f841dfcd862b469fa0b670Mark Brown	config.dev = &client->dev;
4698bdca009e66bb18a990a4be1830c73acacfce331Laxman Dewangan	config.init_data = pdata->reg_init_data;
470c172708d38a401b2f3f841dfcd862b469fa0b670Mark Brown	config.driver_data = tps;
4719fc3815e26efd044c1a1d0770b4335cd00c833c0Laxman Dewangan	config.of_node = client->dev.of_node;
472c172708d38a401b2f3f841dfcd862b469fa0b670Mark Brown
4736219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	/* Register the regulators */
47458c6e938c00de744d52f739aa426a4b1b13ef22bSachin Kamat	rdev = devm_regulator_register(&client->dev, &tps->desc, &config);
4756219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (IS_ERR(rdev)) {
4762935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		dev_err(tps->dev,
4772935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			"%s(): regulator register failed with err %s\n",
4782935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			__func__, id->name);
4798a8e3d5915b3b40a64a5e7dc5aeb208594917a15Laxman Dewangan		return PTR_ERR(rdev);
4806219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	}
4816219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
4826219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	tps->rdev = rdev;
4836219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	return 0;
4846219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan}
4856219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
4866219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganstatic void tps62360_shutdown(struct i2c_client *client)
4876219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan{
4886219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	struct tps62360_chip *tps = i2c_get_clientdata(client);
4896219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	int st;
4906219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
4916219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (!tps->en_discharge)
4926219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		return;
4936219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
4946219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	/* Configure the output discharge path */
4956219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2));
4966219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	if (st < 0)
4972935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan		dev_err(tps->dev,
4982935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			"%s(): register %d update failed with err %d\n",
4992935fb18aa1e75e6afaab3303cdd1a4ac62be63eLaxman Dewangan			__func__, REG_RAMPCTRL, st);
5006219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan}
5016219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
5026219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganstatic const struct i2c_device_id tps62360_id[] = {
5036219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	{.name = "tps62360", .driver_data = TPS62360},
5046219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	{.name = "tps62361", .driver_data = TPS62361},
505d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin	{.name = "tps62362", .driver_data = TPS62362},
506d1cf4f65e1eb17bc8768d822755780588e42cf37Axel Lin	{.name = "tps62363", .driver_data = TPS62363},
5076219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	{},
5086219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan};
5096219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
5106219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman DewanganMODULE_DEVICE_TABLE(i2c, tps62360_id);
5116219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
5126219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganstatic struct i2c_driver tps62360_i2c_driver = {
5136219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	.driver = {
5146219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		.name = "tps62360",
5156219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan		.owner = THIS_MODULE,
516684ae39b91ee7fd2855c35be7f3bf226d42516a5Laxman Dewangan		.of_match_table = of_match_ptr(tps62360_of_match),
5176219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	},
5186219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	.probe = tps62360_probe,
5196219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	.shutdown = tps62360_shutdown,
5206219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	.id_table = tps62360_id,
5216219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan};
5226219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
5236219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganstatic int __init tps62360_init(void)
5246219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan{
5256219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	return i2c_add_driver(&tps62360_i2c_driver);
5266219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan}
5276219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangansubsys_initcall(tps62360_init);
5286219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
5296219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganstatic void __exit tps62360_cleanup(void)
5306219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan{
5316219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan	i2c_del_driver(&tps62360_i2c_driver);
5326219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan}
5336219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewanganmodule_exit(tps62360_cleanup);
5346219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman Dewangan
5356219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman DewanganMODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
536d1cf4f65e1eb17bc8768d822755780588e42cf37Axel LinMODULE_DESCRIPTION("TPS6236x voltage regulator driver");
5376219929f5f82708309b3054ec7db6cb6e3ee47d5Laxman DewanganMODULE_LICENSE("GPL v2");
538