18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * TI TPS65132 Regulator driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Author: Venkat Reddy Talla <vreddytalla@nvidia.com>
78c2ecf20Sopenharmony_ci *		Laxman Dewangan <ldewangan@nvidia.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
108c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as
118c2ecf20Sopenharmony_ci * published by the Free Software Foundation; either version 2 of the
128c2ecf20Sopenharmony_ci * License, or (at your option) any later version.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
158c2ecf20Sopenharmony_ci * whether express or implied; without even the implied warranty of
168c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
178c2ecf20Sopenharmony_ci * General Public License for more details.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/delay.h>
218c2ecf20Sopenharmony_ci#include <linux/err.h>
228c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
238c2ecf20Sopenharmony_ci#include <linux/i2c.h>
248c2ecf20Sopenharmony_ci#include <linux/module.h>
258c2ecf20Sopenharmony_ci#include <linux/regmap.h>
268c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h>
278c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define TPS65132_REG_VPOS		0x00
308c2ecf20Sopenharmony_ci#define TPS65132_REG_VNEG		0x01
318c2ecf20Sopenharmony_ci#define TPS65132_REG_APPS_DISP_DISN	0x03
328c2ecf20Sopenharmony_ci#define TPS65132_REG_CONTROL		0x0FF
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define TPS65132_VOUT_MASK		0x1F
358c2ecf20Sopenharmony_ci#define TPS65132_VOUT_N_VOLTAGE		0x15
368c2ecf20Sopenharmony_ci#define TPS65132_VOUT_VMIN		4000000
378c2ecf20Sopenharmony_ci#define TPS65132_VOUT_VMAX		6000000
388c2ecf20Sopenharmony_ci#define TPS65132_VOUT_STEP		100000
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define TPS65132_REG_APPS_DIS_VPOS		BIT(0)
418c2ecf20Sopenharmony_ci#define TPS65132_REG_APPS_DIS_VNEG		BIT(1)
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define TPS65132_REGULATOR_ID_VPOS	0
448c2ecf20Sopenharmony_ci#define TPS65132_REGULATOR_ID_VNEG	1
458c2ecf20Sopenharmony_ci#define TPS65132_MAX_REGULATORS		2
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define TPS65132_ACT_DIS_TIME_SLACK		1000
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct tps65132_reg_pdata {
508c2ecf20Sopenharmony_ci	struct gpio_desc *en_gpiod;
518c2ecf20Sopenharmony_ci	struct gpio_desc *act_dis_gpiod;
528c2ecf20Sopenharmony_ci	unsigned int act_dis_time_us;
538c2ecf20Sopenharmony_ci	int ena_gpio_state;
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistruct tps65132_regulator {
578c2ecf20Sopenharmony_ci	struct device *dev;
588c2ecf20Sopenharmony_ci	struct tps65132_reg_pdata reg_pdata[TPS65132_MAX_REGULATORS];
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int tps65132_regulator_enable(struct regulator_dev *rdev)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct tps65132_regulator *tps = rdev_get_drvdata(rdev);
648c2ecf20Sopenharmony_ci	int id = rdev_get_id(rdev);
658c2ecf20Sopenharmony_ci	struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id];
668c2ecf20Sopenharmony_ci	int ret;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (!IS_ERR(rpdata->en_gpiod)) {
698c2ecf20Sopenharmony_ci		gpiod_set_value_cansleep(rpdata->en_gpiod, 1);
708c2ecf20Sopenharmony_ci		rpdata->ena_gpio_state = 1;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	/* Hardware automatically enable discharge bit in enable */
748c2ecf20Sopenharmony_ci	if (rdev->constraints->active_discharge ==
758c2ecf20Sopenharmony_ci			REGULATOR_ACTIVE_DISCHARGE_DISABLE) {
768c2ecf20Sopenharmony_ci		ret = regulator_set_active_discharge_regmap(rdev, false);
778c2ecf20Sopenharmony_ci		if (ret < 0) {
788c2ecf20Sopenharmony_ci			dev_err(tps->dev, "Failed to disable active discharge: %d\n",
798c2ecf20Sopenharmony_ci				ret);
808c2ecf20Sopenharmony_ci			return ret;
818c2ecf20Sopenharmony_ci		}
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	return 0;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic int tps65132_regulator_disable(struct regulator_dev *rdev)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	struct tps65132_regulator *tps = rdev_get_drvdata(rdev);
908c2ecf20Sopenharmony_ci	int id = rdev_get_id(rdev);
918c2ecf20Sopenharmony_ci	struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id];
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	if (!IS_ERR(rpdata->en_gpiod)) {
948c2ecf20Sopenharmony_ci		gpiod_set_value_cansleep(rpdata->en_gpiod, 0);
958c2ecf20Sopenharmony_ci		rpdata->ena_gpio_state = 0;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (!IS_ERR(rpdata->act_dis_gpiod)) {
998c2ecf20Sopenharmony_ci		gpiod_set_value_cansleep(rpdata->act_dis_gpiod, 1);
1008c2ecf20Sopenharmony_ci		usleep_range(rpdata->act_dis_time_us, rpdata->act_dis_time_us +
1018c2ecf20Sopenharmony_ci			     TPS65132_ACT_DIS_TIME_SLACK);
1028c2ecf20Sopenharmony_ci		gpiod_set_value_cansleep(rpdata->act_dis_gpiod, 0);
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic int tps65132_regulator_is_enabled(struct regulator_dev *rdev)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct tps65132_regulator *tps = rdev_get_drvdata(rdev);
1118c2ecf20Sopenharmony_ci	int id = rdev_get_id(rdev);
1128c2ecf20Sopenharmony_ci	struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[id];
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (!IS_ERR(rpdata->en_gpiod))
1158c2ecf20Sopenharmony_ci		return rpdata->ena_gpio_state;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return 1;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic const struct regulator_ops tps65132_regulator_ops = {
1218c2ecf20Sopenharmony_ci	.enable = tps65132_regulator_enable,
1228c2ecf20Sopenharmony_ci	.disable = tps65132_regulator_disable,
1238c2ecf20Sopenharmony_ci	.is_enabled = tps65132_regulator_is_enabled,
1248c2ecf20Sopenharmony_ci	.list_voltage = regulator_list_voltage_linear,
1258c2ecf20Sopenharmony_ci	.map_voltage = regulator_map_voltage_linear,
1268c2ecf20Sopenharmony_ci	.get_voltage_sel = regulator_get_voltage_sel_regmap,
1278c2ecf20Sopenharmony_ci	.set_voltage_sel = regulator_set_voltage_sel_regmap,
1288c2ecf20Sopenharmony_ci	.set_active_discharge = regulator_set_active_discharge_regmap,
1298c2ecf20Sopenharmony_ci};
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic int tps65132_of_parse_cb(struct device_node *np,
1328c2ecf20Sopenharmony_ci				const struct regulator_desc *desc,
1338c2ecf20Sopenharmony_ci				struct regulator_config *config)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct tps65132_regulator *tps = config->driver_data;
1368c2ecf20Sopenharmony_ci	struct tps65132_reg_pdata *rpdata = &tps->reg_pdata[desc->id];
1378c2ecf20Sopenharmony_ci	int ret;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	rpdata->en_gpiod = devm_fwnode_gpiod_get(tps->dev, of_fwnode_handle(np),
1408c2ecf20Sopenharmony_ci						 "enable", GPIOD_ASIS,
1418c2ecf20Sopenharmony_ci						 "enable");
1428c2ecf20Sopenharmony_ci	if (IS_ERR(rpdata->en_gpiod)) {
1438c2ecf20Sopenharmony_ci		ret = PTR_ERR(rpdata->en_gpiod);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci		/* Ignore the error other than probe defer */
1468c2ecf20Sopenharmony_ci		if (ret == -EPROBE_DEFER)
1478c2ecf20Sopenharmony_ci			return ret;
1488c2ecf20Sopenharmony_ci		return 0;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	rpdata->act_dis_gpiod = devm_fwnode_gpiod_get(tps->dev,
1528c2ecf20Sopenharmony_ci						      of_fwnode_handle(np),
1538c2ecf20Sopenharmony_ci						      "active-discharge",
1548c2ecf20Sopenharmony_ci						      GPIOD_ASIS,
1558c2ecf20Sopenharmony_ci						      "active-discharge");
1568c2ecf20Sopenharmony_ci	if (IS_ERR(rpdata->act_dis_gpiod)) {
1578c2ecf20Sopenharmony_ci		ret = PTR_ERR(rpdata->act_dis_gpiod);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci		/* Ignore the error other than probe defer */
1608c2ecf20Sopenharmony_ci		if (ret == -EPROBE_DEFER)
1618c2ecf20Sopenharmony_ci			return ret;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		return 0;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	ret = of_property_read_u32(np, "ti,active-discharge-time-us",
1678c2ecf20Sopenharmony_ci				   &rpdata->act_dis_time_us);
1688c2ecf20Sopenharmony_ci	if (ret < 0) {
1698c2ecf20Sopenharmony_ci		dev_err(tps->dev, "Failed to read active discharge time:%d\n",
1708c2ecf20Sopenharmony_ci			ret);
1718c2ecf20Sopenharmony_ci		return ret;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	return 0;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci#define TPS65132_REGULATOR_DESC(_id, _name)		\
1788c2ecf20Sopenharmony_ci	[TPS65132_REGULATOR_ID_##_id] = {		\
1798c2ecf20Sopenharmony_ci		.name = "tps65132-"#_name,		\
1808c2ecf20Sopenharmony_ci		.supply_name = "vin",			\
1818c2ecf20Sopenharmony_ci		.id = TPS65132_REGULATOR_ID_##_id,	\
1828c2ecf20Sopenharmony_ci		.of_match = of_match_ptr(#_name),	\
1838c2ecf20Sopenharmony_ci		.of_parse_cb	= tps65132_of_parse_cb,	\
1848c2ecf20Sopenharmony_ci		.ops = &tps65132_regulator_ops,		\
1858c2ecf20Sopenharmony_ci		.n_voltages = TPS65132_VOUT_N_VOLTAGE,	\
1868c2ecf20Sopenharmony_ci		.min_uV = TPS65132_VOUT_VMIN,		\
1878c2ecf20Sopenharmony_ci		.uV_step = TPS65132_VOUT_STEP,		\
1888c2ecf20Sopenharmony_ci		.enable_time = 500,			\
1898c2ecf20Sopenharmony_ci		.vsel_mask = TPS65132_VOUT_MASK,	\
1908c2ecf20Sopenharmony_ci		.vsel_reg = TPS65132_REG_##_id,		\
1918c2ecf20Sopenharmony_ci		.active_discharge_off = 0,			\
1928c2ecf20Sopenharmony_ci		.active_discharge_on = TPS65132_REG_APPS_DIS_##_id, \
1938c2ecf20Sopenharmony_ci		.active_discharge_mask = TPS65132_REG_APPS_DIS_##_id, \
1948c2ecf20Sopenharmony_ci		.active_discharge_reg = TPS65132_REG_APPS_DISP_DISN, \
1958c2ecf20Sopenharmony_ci		.type = REGULATOR_VOLTAGE,		\
1968c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,			\
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic const struct regulator_desc tps_regs_desc[TPS65132_MAX_REGULATORS] = {
2008c2ecf20Sopenharmony_ci	TPS65132_REGULATOR_DESC(VPOS, outp),
2018c2ecf20Sopenharmony_ci	TPS65132_REGULATOR_DESC(VNEG, outn),
2028c2ecf20Sopenharmony_ci};
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic const struct regmap_range tps65132_no_reg_ranges[] = {
2058c2ecf20Sopenharmony_ci	regmap_reg_range(TPS65132_REG_APPS_DISP_DISN + 1,
2068c2ecf20Sopenharmony_ci			 TPS65132_REG_CONTROL - 1),
2078c2ecf20Sopenharmony_ci};
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic const struct regmap_access_table tps65132_no_reg_table = {
2108c2ecf20Sopenharmony_ci	.no_ranges = tps65132_no_reg_ranges,
2118c2ecf20Sopenharmony_ci	.n_no_ranges = ARRAY_SIZE(tps65132_no_reg_ranges),
2128c2ecf20Sopenharmony_ci};
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic const struct regmap_config tps65132_regmap_config = {
2158c2ecf20Sopenharmony_ci	.reg_bits	= 8,
2168c2ecf20Sopenharmony_ci	.val_bits	= 8,
2178c2ecf20Sopenharmony_ci	.max_register	= TPS65132_REG_CONTROL,
2188c2ecf20Sopenharmony_ci	.cache_type	= REGCACHE_NONE,
2198c2ecf20Sopenharmony_ci	.rd_table	= &tps65132_no_reg_table,
2208c2ecf20Sopenharmony_ci	.wr_table	= &tps65132_no_reg_table,
2218c2ecf20Sopenharmony_ci};
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic int tps65132_probe(struct i2c_client *client)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
2268c2ecf20Sopenharmony_ci	struct tps65132_regulator *tps;
2278c2ecf20Sopenharmony_ci	struct regulator_dev *rdev;
2288c2ecf20Sopenharmony_ci	struct regmap *rmap;
2298c2ecf20Sopenharmony_ci	struct regulator_config config = { };
2308c2ecf20Sopenharmony_ci	int id;
2318c2ecf20Sopenharmony_ci	int ret;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	tps = devm_kzalloc(dev, sizeof(*tps), GFP_KERNEL);
2348c2ecf20Sopenharmony_ci	if (!tps)
2358c2ecf20Sopenharmony_ci		return -ENOMEM;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	rmap = devm_regmap_init_i2c(client, &tps65132_regmap_config);
2388c2ecf20Sopenharmony_ci	if (IS_ERR(rmap)) {
2398c2ecf20Sopenharmony_ci		ret = PTR_ERR(rmap);
2408c2ecf20Sopenharmony_ci		dev_err(dev, "regmap init failed: %d\n", ret);
2418c2ecf20Sopenharmony_ci		return ret;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, tps);
2458c2ecf20Sopenharmony_ci	tps->dev = dev;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	for (id = 0; id < TPS65132_MAX_REGULATORS; ++id) {
2488c2ecf20Sopenharmony_ci		config.regmap = rmap;
2498c2ecf20Sopenharmony_ci		config.dev = dev;
2508c2ecf20Sopenharmony_ci		config.driver_data = tps;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		rdev = devm_regulator_register(dev, &tps_regs_desc[id],
2538c2ecf20Sopenharmony_ci					       &config);
2548c2ecf20Sopenharmony_ci		if (IS_ERR(rdev)) {
2558c2ecf20Sopenharmony_ci			ret = PTR_ERR(rdev);
2568c2ecf20Sopenharmony_ci			dev_err(dev, "regulator %s register failed: %d\n",
2578c2ecf20Sopenharmony_ci				tps_regs_desc[id].name, ret);
2588c2ecf20Sopenharmony_ci			return ret;
2598c2ecf20Sopenharmony_ci		}
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci	return 0;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic const struct i2c_device_id tps65132_id[] = {
2658c2ecf20Sopenharmony_ci	{.name = "tps65132",},
2668c2ecf20Sopenharmony_ci	{},
2678c2ecf20Sopenharmony_ci};
2688c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tps65132_id);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic struct i2c_driver tps65132_i2c_driver = {
2718c2ecf20Sopenharmony_ci	.driver = {
2728c2ecf20Sopenharmony_ci		.name = "tps65132",
2738c2ecf20Sopenharmony_ci	},
2748c2ecf20Sopenharmony_ci	.probe_new = tps65132_probe,
2758c2ecf20Sopenharmony_ci	.id_table = tps65132_id,
2768c2ecf20Sopenharmony_ci};
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cimodule_i2c_driver(tps65132_i2c_driver);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("tps65132 regulator driver");
2818c2ecf20Sopenharmony_ciMODULE_AUTHOR("Venkat Reddy Talla <vreddytalla@nvidia.com>");
2828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
2838c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
284