18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Regulator driver for TPS6524x PMIC
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2010 Texas Instruments
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
78c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as
88c2ecf20Sopenharmony_ci * published by the Free Software Foundation version 2.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
118c2ecf20Sopenharmony_ci * whether express or implied; without even the implied warranty of
128c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
138c2ecf20Sopenharmony_ci * General Public License for more details.
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/module.h>
188c2ecf20Sopenharmony_ci#include <linux/err.h>
198c2ecf20Sopenharmony_ci#include <linux/errno.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
228c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h>
238c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define REG_LDO_SET		0x0
268c2ecf20Sopenharmony_ci#define LDO_ILIM_MASK		1	/* 0 = 400-800, 1 = 900-1500 */
278c2ecf20Sopenharmony_ci#define LDO_VSEL_MASK		0x0f
288c2ecf20Sopenharmony_ci#define LDO2_ILIM_SHIFT		12
298c2ecf20Sopenharmony_ci#define LDO2_VSEL_SHIFT		4
308c2ecf20Sopenharmony_ci#define LDO1_ILIM_SHIFT		8
318c2ecf20Sopenharmony_ci#define LDO1_VSEL_SHIFT		0
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define REG_BLOCK_EN		0x1
348c2ecf20Sopenharmony_ci#define BLOCK_MASK		1
358c2ecf20Sopenharmony_ci#define BLOCK_LDO1_SHIFT	0
368c2ecf20Sopenharmony_ci#define BLOCK_LDO2_SHIFT	1
378c2ecf20Sopenharmony_ci#define BLOCK_LCD_SHIFT		2
388c2ecf20Sopenharmony_ci#define BLOCK_USB_SHIFT		3
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define REG_DCDC_SET		0x2
418c2ecf20Sopenharmony_ci#define DCDC_VDCDC_MASK		0x1f
428c2ecf20Sopenharmony_ci#define DCDC_VDCDC1_SHIFT	0
438c2ecf20Sopenharmony_ci#define DCDC_VDCDC2_SHIFT	5
448c2ecf20Sopenharmony_ci#define DCDC_VDCDC3_SHIFT	10
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define REG_DCDC_EN		0x3
478c2ecf20Sopenharmony_ci#define DCDCDCDC_EN_MASK	0x1
488c2ecf20Sopenharmony_ci#define DCDCDCDC1_EN_SHIFT	0
498c2ecf20Sopenharmony_ci#define DCDCDCDC1_PG_MSK	BIT(1)
508c2ecf20Sopenharmony_ci#define DCDCDCDC2_EN_SHIFT	2
518c2ecf20Sopenharmony_ci#define DCDCDCDC2_PG_MSK	BIT(3)
528c2ecf20Sopenharmony_ci#define DCDCDCDC3_EN_SHIFT	4
538c2ecf20Sopenharmony_ci#define DCDCDCDC3_PG_MSK	BIT(5)
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define REG_USB			0x4
568c2ecf20Sopenharmony_ci#define USB_ILIM_SHIFT		0
578c2ecf20Sopenharmony_ci#define USB_ILIM_MASK		0x3
588c2ecf20Sopenharmony_ci#define USB_TSD_SHIFT		2
598c2ecf20Sopenharmony_ci#define USB_TSD_MASK		0x3
608c2ecf20Sopenharmony_ci#define USB_TWARN_SHIFT		4
618c2ecf20Sopenharmony_ci#define USB_TWARN_MASK		0x3
628c2ecf20Sopenharmony_ci#define USB_IWARN_SD		BIT(6)
638c2ecf20Sopenharmony_ci#define USB_FAST_LOOP		BIT(7)
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define REG_ALARM		0x5
668c2ecf20Sopenharmony_ci#define ALARM_LDO1		BIT(0)
678c2ecf20Sopenharmony_ci#define ALARM_DCDC1		BIT(1)
688c2ecf20Sopenharmony_ci#define ALARM_DCDC2		BIT(2)
698c2ecf20Sopenharmony_ci#define ALARM_DCDC3		BIT(3)
708c2ecf20Sopenharmony_ci#define ALARM_LDO2		BIT(4)
718c2ecf20Sopenharmony_ci#define ALARM_USB_WARN		BIT(5)
728c2ecf20Sopenharmony_ci#define ALARM_USB_ALARM		BIT(6)
738c2ecf20Sopenharmony_ci#define ALARM_LCD		BIT(9)
748c2ecf20Sopenharmony_ci#define ALARM_TEMP_WARM		BIT(10)
758c2ecf20Sopenharmony_ci#define ALARM_TEMP_HOT		BIT(11)
768c2ecf20Sopenharmony_ci#define ALARM_NRST		BIT(14)
778c2ecf20Sopenharmony_ci#define ALARM_POWERUP		BIT(15)
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define REG_INT_ENABLE		0x6
808c2ecf20Sopenharmony_ci#define INT_LDO1		BIT(0)
818c2ecf20Sopenharmony_ci#define INT_DCDC1		BIT(1)
828c2ecf20Sopenharmony_ci#define INT_DCDC2		BIT(2)
838c2ecf20Sopenharmony_ci#define INT_DCDC3		BIT(3)
848c2ecf20Sopenharmony_ci#define INT_LDO2		BIT(4)
858c2ecf20Sopenharmony_ci#define INT_USB_WARN		BIT(5)
868c2ecf20Sopenharmony_ci#define INT_USB_ALARM		BIT(6)
878c2ecf20Sopenharmony_ci#define INT_LCD			BIT(9)
888c2ecf20Sopenharmony_ci#define INT_TEMP_WARM		BIT(10)
898c2ecf20Sopenharmony_ci#define INT_TEMP_HOT		BIT(11)
908c2ecf20Sopenharmony_ci#define INT_GLOBAL_EN		BIT(15)
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define REG_INT_STATUS		0x7
938c2ecf20Sopenharmony_ci#define STATUS_LDO1		BIT(0)
948c2ecf20Sopenharmony_ci#define STATUS_DCDC1		BIT(1)
958c2ecf20Sopenharmony_ci#define STATUS_DCDC2		BIT(2)
968c2ecf20Sopenharmony_ci#define STATUS_DCDC3		BIT(3)
978c2ecf20Sopenharmony_ci#define STATUS_LDO2		BIT(4)
988c2ecf20Sopenharmony_ci#define STATUS_USB_WARN		BIT(5)
998c2ecf20Sopenharmony_ci#define STATUS_USB_ALARM	BIT(6)
1008c2ecf20Sopenharmony_ci#define STATUS_LCD		BIT(9)
1018c2ecf20Sopenharmony_ci#define STATUS_TEMP_WARM	BIT(10)
1028c2ecf20Sopenharmony_ci#define STATUS_TEMP_HOT		BIT(11)
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#define REG_SOFTWARE_RESET	0xb
1058c2ecf20Sopenharmony_ci#define REG_WRITE_ENABLE	0xd
1068c2ecf20Sopenharmony_ci#define REG_REV_ID		0xf
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci#define N_DCDC			3
1098c2ecf20Sopenharmony_ci#define N_LDO			2
1108c2ecf20Sopenharmony_ci#define N_SWITCH		2
1118c2ecf20Sopenharmony_ci#define N_REGULATORS		(N_DCDC + N_LDO + N_SWITCH)
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci#define CMD_READ(reg)		((reg) << 6)
1148c2ecf20Sopenharmony_ci#define CMD_WRITE(reg)		(BIT(5) | (reg) << 6)
1158c2ecf20Sopenharmony_ci#define STAT_CLK		BIT(3)
1168c2ecf20Sopenharmony_ci#define STAT_WRITE		BIT(2)
1178c2ecf20Sopenharmony_ci#define STAT_INVALID		BIT(1)
1188c2ecf20Sopenharmony_ci#define STAT_WP			BIT(0)
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistruct field {
1218c2ecf20Sopenharmony_ci	int		reg;
1228c2ecf20Sopenharmony_ci	int		shift;
1238c2ecf20Sopenharmony_ci	int		mask;
1248c2ecf20Sopenharmony_ci};
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistruct supply_info {
1278c2ecf20Sopenharmony_ci	const char	*name;
1288c2ecf20Sopenharmony_ci	int		n_voltages;
1298c2ecf20Sopenharmony_ci	const unsigned int *voltages;
1308c2ecf20Sopenharmony_ci	int		n_ilimsels;
1318c2ecf20Sopenharmony_ci	const unsigned int *ilimsels;
1328c2ecf20Sopenharmony_ci	struct field	enable, voltage, ilimsel;
1338c2ecf20Sopenharmony_ci};
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistruct tps6524x {
1368c2ecf20Sopenharmony_ci	struct device		*dev;
1378c2ecf20Sopenharmony_ci	struct spi_device	*spi;
1388c2ecf20Sopenharmony_ci	struct mutex		lock;
1398c2ecf20Sopenharmony_ci	struct regulator_desc	desc[N_REGULATORS];
1408c2ecf20Sopenharmony_ci};
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic int __read_reg(struct tps6524x *hw, int reg)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	int error = 0;
1458c2ecf20Sopenharmony_ci	u16 cmd = CMD_READ(reg), in;
1468c2ecf20Sopenharmony_ci	u8 status;
1478c2ecf20Sopenharmony_ci	struct spi_message m;
1488c2ecf20Sopenharmony_ci	struct spi_transfer t[3];
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	spi_message_init(&m);
1518c2ecf20Sopenharmony_ci	memset(t, 0, sizeof(t));
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	t[0].tx_buf = &cmd;
1548c2ecf20Sopenharmony_ci	t[0].len = 2;
1558c2ecf20Sopenharmony_ci	t[0].bits_per_word = 12;
1568c2ecf20Sopenharmony_ci	spi_message_add_tail(&t[0], &m);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	t[1].rx_buf = &in;
1598c2ecf20Sopenharmony_ci	t[1].len = 2;
1608c2ecf20Sopenharmony_ci	t[1].bits_per_word = 16;
1618c2ecf20Sopenharmony_ci	spi_message_add_tail(&t[1], &m);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	t[2].rx_buf = &status;
1648c2ecf20Sopenharmony_ci	t[2].len = 1;
1658c2ecf20Sopenharmony_ci	t[2].bits_per_word = 4;
1668c2ecf20Sopenharmony_ci	spi_message_add_tail(&t[2], &m);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	error = spi_sync(hw->spi, &m);
1698c2ecf20Sopenharmony_ci	if (error < 0)
1708c2ecf20Sopenharmony_ci		return error;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	dev_dbg(hw->dev, "read reg %d, data %x, status %x\n",
1738c2ecf20Sopenharmony_ci		reg, in, status);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (!(status & STAT_CLK) || (status & STAT_WRITE))
1768c2ecf20Sopenharmony_ci		return -EIO;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (status & STAT_INVALID)
1798c2ecf20Sopenharmony_ci		return -EINVAL;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	return in;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic int read_reg(struct tps6524x *hw, int reg)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	int ret;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	mutex_lock(&hw->lock);
1898c2ecf20Sopenharmony_ci	ret = __read_reg(hw, reg);
1908c2ecf20Sopenharmony_ci	mutex_unlock(&hw->lock);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return ret;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int __write_reg(struct tps6524x *hw, int reg, int val)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	int error = 0;
1988c2ecf20Sopenharmony_ci	u16 cmd = CMD_WRITE(reg), out = val;
1998c2ecf20Sopenharmony_ci	u8 status;
2008c2ecf20Sopenharmony_ci	struct spi_message m;
2018c2ecf20Sopenharmony_ci	struct spi_transfer t[3];
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	spi_message_init(&m);
2048c2ecf20Sopenharmony_ci	memset(t, 0, sizeof(t));
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	t[0].tx_buf = &cmd;
2078c2ecf20Sopenharmony_ci	t[0].len = 2;
2088c2ecf20Sopenharmony_ci	t[0].bits_per_word = 12;
2098c2ecf20Sopenharmony_ci	spi_message_add_tail(&t[0], &m);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	t[1].tx_buf = &out;
2128c2ecf20Sopenharmony_ci	t[1].len = 2;
2138c2ecf20Sopenharmony_ci	t[1].bits_per_word = 16;
2148c2ecf20Sopenharmony_ci	spi_message_add_tail(&t[1], &m);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	t[2].rx_buf = &status;
2178c2ecf20Sopenharmony_ci	t[2].len = 1;
2188c2ecf20Sopenharmony_ci	t[2].bits_per_word = 4;
2198c2ecf20Sopenharmony_ci	spi_message_add_tail(&t[2], &m);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	error = spi_sync(hw->spi, &m);
2228c2ecf20Sopenharmony_ci	if (error < 0)
2238c2ecf20Sopenharmony_ci		return error;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n",
2268c2ecf20Sopenharmony_ci		reg, out, status);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (!(status & STAT_CLK) || !(status & STAT_WRITE))
2298c2ecf20Sopenharmony_ci		return -EIO;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if (status & (STAT_INVALID | STAT_WP))
2328c2ecf20Sopenharmony_ci		return -EINVAL;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return error;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	int ret;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	ret = __read_reg(hw, reg);
2428c2ecf20Sopenharmony_ci	if (ret < 0)
2438c2ecf20Sopenharmony_ci		return ret;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	ret &= ~mask;
2468c2ecf20Sopenharmony_ci	ret |= val;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	ret = __write_reg(hw, reg, ret);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return (ret < 0) ? ret : 0;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int rmw_protect(struct tps6524x *hw, int reg, int mask, int val)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	int ret;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	mutex_lock(&hw->lock);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	ret = __write_reg(hw, REG_WRITE_ENABLE, 1);
2608c2ecf20Sopenharmony_ci	if (ret) {
2618c2ecf20Sopenharmony_ci		dev_err(hw->dev, "failed to set write enable\n");
2628c2ecf20Sopenharmony_ci		goto error;
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	ret = __rmw_reg(hw, reg, mask, val);
2668c2ecf20Sopenharmony_ci	if (ret)
2678c2ecf20Sopenharmony_ci		dev_err(hw->dev, "failed to rmw register %d\n", reg);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	ret = __write_reg(hw, REG_WRITE_ENABLE, 0);
2708c2ecf20Sopenharmony_ci	if (ret) {
2718c2ecf20Sopenharmony_ci		dev_err(hw->dev, "failed to clear write enable\n");
2728c2ecf20Sopenharmony_ci		goto error;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cierror:
2768c2ecf20Sopenharmony_ci	mutex_unlock(&hw->lock);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	return ret;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic int read_field(struct tps6524x *hw, const struct field *field)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	int tmp;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	tmp = read_reg(hw, field->reg);
2868c2ecf20Sopenharmony_ci	if (tmp < 0)
2878c2ecf20Sopenharmony_ci		return tmp;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return (tmp >> field->shift) & field->mask;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int write_field(struct tps6524x *hw, const struct field *field,
2938c2ecf20Sopenharmony_ci		       int val)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	if (val & ~field->mask)
2968c2ecf20Sopenharmony_ci		return -EOVERFLOW;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return rmw_protect(hw, field->reg,
2998c2ecf20Sopenharmony_ci				    field->mask << field->shift,
3008c2ecf20Sopenharmony_ci				    val << field->shift);
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic const unsigned int dcdc1_voltages[] = {
3048c2ecf20Sopenharmony_ci	 800000,  825000,  850000,  875000,
3058c2ecf20Sopenharmony_ci	 900000,  925000,  950000,  975000,
3068c2ecf20Sopenharmony_ci	1000000, 1025000, 1050000, 1075000,
3078c2ecf20Sopenharmony_ci	1100000, 1125000, 1150000, 1175000,
3088c2ecf20Sopenharmony_ci	1200000, 1225000, 1250000, 1275000,
3098c2ecf20Sopenharmony_ci	1300000, 1325000, 1350000, 1375000,
3108c2ecf20Sopenharmony_ci	1400000, 1425000, 1450000, 1475000,
3118c2ecf20Sopenharmony_ci	1500000, 1525000, 1550000, 1575000,
3128c2ecf20Sopenharmony_ci};
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic const unsigned int dcdc2_voltages[] = {
3158c2ecf20Sopenharmony_ci	1400000, 1450000, 1500000, 1550000,
3168c2ecf20Sopenharmony_ci	1600000, 1650000, 1700000, 1750000,
3178c2ecf20Sopenharmony_ci	1800000, 1850000, 1900000, 1950000,
3188c2ecf20Sopenharmony_ci	2000000, 2050000, 2100000, 2150000,
3198c2ecf20Sopenharmony_ci	2200000, 2250000, 2300000, 2350000,
3208c2ecf20Sopenharmony_ci	2400000, 2450000, 2500000, 2550000,
3218c2ecf20Sopenharmony_ci	2600000, 2650000, 2700000, 2750000,
3228c2ecf20Sopenharmony_ci	2800000, 2850000, 2900000, 2950000,
3238c2ecf20Sopenharmony_ci};
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic const unsigned int dcdc3_voltages[] = {
3268c2ecf20Sopenharmony_ci	2400000, 2450000, 2500000, 2550000, 2600000,
3278c2ecf20Sopenharmony_ci	2650000, 2700000, 2750000, 2800000, 2850000,
3288c2ecf20Sopenharmony_ci	2900000, 2950000, 3000000, 3050000, 3100000,
3298c2ecf20Sopenharmony_ci	3150000, 3200000, 3250000, 3300000, 3350000,
3308c2ecf20Sopenharmony_ci	3400000, 3450000, 3500000, 3550000, 3600000,
3318c2ecf20Sopenharmony_ci};
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic const unsigned int ldo1_voltages[] = {
3348c2ecf20Sopenharmony_ci	4300000, 4350000, 4400000, 4450000,
3358c2ecf20Sopenharmony_ci	4500000, 4550000, 4600000, 4650000,
3368c2ecf20Sopenharmony_ci	4700000, 4750000, 4800000, 4850000,
3378c2ecf20Sopenharmony_ci	4900000, 4950000, 5000000, 5050000,
3388c2ecf20Sopenharmony_ci};
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic const unsigned int ldo2_voltages[] = {
3418c2ecf20Sopenharmony_ci	1100000, 1150000, 1200000, 1250000,
3428c2ecf20Sopenharmony_ci	1300000, 1700000, 1750000, 1800000,
3438c2ecf20Sopenharmony_ci	1850000, 1900000, 3150000, 3200000,
3448c2ecf20Sopenharmony_ci	3250000, 3300000, 3350000, 3400000,
3458c2ecf20Sopenharmony_ci};
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic const unsigned int fixed_5000000_voltage[] = {
3488c2ecf20Sopenharmony_ci	5000000
3498c2ecf20Sopenharmony_ci};
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic const unsigned int ldo_ilimsel[] = {
3528c2ecf20Sopenharmony_ci	400000, 1500000
3538c2ecf20Sopenharmony_ci};
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic const unsigned int usb_ilimsel[] = {
3568c2ecf20Sopenharmony_ci	200000, 400000, 800000, 1000000
3578c2ecf20Sopenharmony_ci};
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic const unsigned int fixed_2400000_ilimsel[] = {
3608c2ecf20Sopenharmony_ci	2400000
3618c2ecf20Sopenharmony_ci};
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic const unsigned int fixed_1200000_ilimsel[] = {
3648c2ecf20Sopenharmony_ci	1200000
3658c2ecf20Sopenharmony_ci};
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic const unsigned int fixed_400000_ilimsel[] = {
3688c2ecf20Sopenharmony_ci	400000
3698c2ecf20Sopenharmony_ci};
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci#define __MK_FIELD(_reg, _mask, _shift) \
3728c2ecf20Sopenharmony_ci	{ .reg = (_reg), .mask = (_mask), .shift = (_shift), }
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic const struct supply_info supply_info[N_REGULATORS] = {
3758c2ecf20Sopenharmony_ci	{
3768c2ecf20Sopenharmony_ci		.name		= "DCDC1",
3778c2ecf20Sopenharmony_ci		.n_voltages	= ARRAY_SIZE(dcdc1_voltages),
3788c2ecf20Sopenharmony_ci		.voltages	= dcdc1_voltages,
3798c2ecf20Sopenharmony_ci		.n_ilimsels	= ARRAY_SIZE(fixed_2400000_ilimsel),
3808c2ecf20Sopenharmony_ci		.ilimsels	= fixed_2400000_ilimsel,
3818c2ecf20Sopenharmony_ci		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
3828c2ecf20Sopenharmony_ci					     DCDCDCDC1_EN_SHIFT),
3838c2ecf20Sopenharmony_ci		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
3848c2ecf20Sopenharmony_ci					     DCDC_VDCDC1_SHIFT),
3858c2ecf20Sopenharmony_ci	},
3868c2ecf20Sopenharmony_ci	{
3878c2ecf20Sopenharmony_ci		.name		= "DCDC2",
3888c2ecf20Sopenharmony_ci		.n_voltages	= ARRAY_SIZE(dcdc2_voltages),
3898c2ecf20Sopenharmony_ci		.voltages	= dcdc2_voltages,
3908c2ecf20Sopenharmony_ci		.n_ilimsels	= ARRAY_SIZE(fixed_1200000_ilimsel),
3918c2ecf20Sopenharmony_ci		.ilimsels	= fixed_1200000_ilimsel,
3928c2ecf20Sopenharmony_ci		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
3938c2ecf20Sopenharmony_ci					     DCDCDCDC2_EN_SHIFT),
3948c2ecf20Sopenharmony_ci		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
3958c2ecf20Sopenharmony_ci					     DCDC_VDCDC2_SHIFT),
3968c2ecf20Sopenharmony_ci	},
3978c2ecf20Sopenharmony_ci	{
3988c2ecf20Sopenharmony_ci		.name		= "DCDC3",
3998c2ecf20Sopenharmony_ci		.n_voltages	= ARRAY_SIZE(dcdc3_voltages),
4008c2ecf20Sopenharmony_ci		.voltages	= dcdc3_voltages,
4018c2ecf20Sopenharmony_ci		.n_ilimsels	= ARRAY_SIZE(fixed_1200000_ilimsel),
4028c2ecf20Sopenharmony_ci		.ilimsels	= fixed_1200000_ilimsel,
4038c2ecf20Sopenharmony_ci		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
4048c2ecf20Sopenharmony_ci					DCDCDCDC3_EN_SHIFT),
4058c2ecf20Sopenharmony_ci		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
4068c2ecf20Sopenharmony_ci					     DCDC_VDCDC3_SHIFT),
4078c2ecf20Sopenharmony_ci	},
4088c2ecf20Sopenharmony_ci	{
4098c2ecf20Sopenharmony_ci		.name		= "LDO1",
4108c2ecf20Sopenharmony_ci		.n_voltages	= ARRAY_SIZE(ldo1_voltages),
4118c2ecf20Sopenharmony_ci		.voltages	= ldo1_voltages,
4128c2ecf20Sopenharmony_ci		.n_ilimsels	= ARRAY_SIZE(ldo_ilimsel),
4138c2ecf20Sopenharmony_ci		.ilimsels	= ldo_ilimsel,
4148c2ecf20Sopenharmony_ci		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
4158c2ecf20Sopenharmony_ci					     BLOCK_LDO1_SHIFT),
4168c2ecf20Sopenharmony_ci		.voltage	= __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK,
4178c2ecf20Sopenharmony_ci					     LDO1_VSEL_SHIFT),
4188c2ecf20Sopenharmony_ci		.ilimsel	= __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK,
4198c2ecf20Sopenharmony_ci					     LDO1_ILIM_SHIFT),
4208c2ecf20Sopenharmony_ci	},
4218c2ecf20Sopenharmony_ci	{
4228c2ecf20Sopenharmony_ci		.name		= "LDO2",
4238c2ecf20Sopenharmony_ci		.n_voltages	= ARRAY_SIZE(ldo2_voltages),
4248c2ecf20Sopenharmony_ci		.voltages	= ldo2_voltages,
4258c2ecf20Sopenharmony_ci		.n_ilimsels	= ARRAY_SIZE(ldo_ilimsel),
4268c2ecf20Sopenharmony_ci		.ilimsels	= ldo_ilimsel,
4278c2ecf20Sopenharmony_ci		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
4288c2ecf20Sopenharmony_ci					     BLOCK_LDO2_SHIFT),
4298c2ecf20Sopenharmony_ci		.voltage	= __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK,
4308c2ecf20Sopenharmony_ci					     LDO2_VSEL_SHIFT),
4318c2ecf20Sopenharmony_ci		.ilimsel	= __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK,
4328c2ecf20Sopenharmony_ci					     LDO2_ILIM_SHIFT),
4338c2ecf20Sopenharmony_ci	},
4348c2ecf20Sopenharmony_ci	{
4358c2ecf20Sopenharmony_ci		.name		= "USB",
4368c2ecf20Sopenharmony_ci		.n_voltages	= ARRAY_SIZE(fixed_5000000_voltage),
4378c2ecf20Sopenharmony_ci		.voltages	= fixed_5000000_voltage,
4388c2ecf20Sopenharmony_ci		.n_ilimsels	= ARRAY_SIZE(usb_ilimsel),
4398c2ecf20Sopenharmony_ci		.ilimsels	= usb_ilimsel,
4408c2ecf20Sopenharmony_ci		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
4418c2ecf20Sopenharmony_ci					     BLOCK_USB_SHIFT),
4428c2ecf20Sopenharmony_ci		.ilimsel	= __MK_FIELD(REG_USB, USB_ILIM_MASK,
4438c2ecf20Sopenharmony_ci					     USB_ILIM_SHIFT),
4448c2ecf20Sopenharmony_ci	},
4458c2ecf20Sopenharmony_ci	{
4468c2ecf20Sopenharmony_ci		.name		= "LCD",
4478c2ecf20Sopenharmony_ci		.n_voltages	= ARRAY_SIZE(fixed_5000000_voltage),
4488c2ecf20Sopenharmony_ci		.voltages	= fixed_5000000_voltage,
4498c2ecf20Sopenharmony_ci		.n_ilimsels	= ARRAY_SIZE(fixed_400000_ilimsel),
4508c2ecf20Sopenharmony_ci		.ilimsels	= fixed_400000_ilimsel,
4518c2ecf20Sopenharmony_ci		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
4528c2ecf20Sopenharmony_ci					     BLOCK_LCD_SHIFT),
4538c2ecf20Sopenharmony_ci	},
4548c2ecf20Sopenharmony_ci};
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic int set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	const struct supply_info *info;
4598c2ecf20Sopenharmony_ci	struct tps6524x *hw;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	hw	= rdev_get_drvdata(rdev);
4628c2ecf20Sopenharmony_ci	info	= &supply_info[rdev_get_id(rdev)];
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	if (rdev->desc->n_voltages == 1)
4658c2ecf20Sopenharmony_ci		return -EINVAL;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	return write_field(hw, &info->voltage, selector);
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic int get_voltage_sel(struct regulator_dev *rdev)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	const struct supply_info *info;
4738c2ecf20Sopenharmony_ci	struct tps6524x *hw;
4748c2ecf20Sopenharmony_ci	int ret;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	hw	= rdev_get_drvdata(rdev);
4778c2ecf20Sopenharmony_ci	info	= &supply_info[rdev_get_id(rdev)];
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (rdev->desc->n_voltages == 1)
4808c2ecf20Sopenharmony_ci		return 0;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	ret = read_field(hw, &info->voltage);
4838c2ecf20Sopenharmony_ci	if (ret < 0)
4848c2ecf20Sopenharmony_ci		return ret;
4858c2ecf20Sopenharmony_ci	if (WARN_ON(ret >= info->n_voltages))
4868c2ecf20Sopenharmony_ci		return -EIO;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	return ret;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic int set_current_limit(struct regulator_dev *rdev, int min_uA,
4928c2ecf20Sopenharmony_ci			     int max_uA)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	const struct supply_info *info;
4958c2ecf20Sopenharmony_ci	struct tps6524x *hw;
4968c2ecf20Sopenharmony_ci	int i;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	hw	= rdev_get_drvdata(rdev);
4998c2ecf20Sopenharmony_ci	info	= &supply_info[rdev_get_id(rdev)];
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (info->n_ilimsels == 1)
5028c2ecf20Sopenharmony_ci		return -EINVAL;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	for (i = info->n_ilimsels - 1; i >= 0; i--) {
5058c2ecf20Sopenharmony_ci		if (min_uA <= info->ilimsels[i] &&
5068c2ecf20Sopenharmony_ci		    max_uA >= info->ilimsels[i])
5078c2ecf20Sopenharmony_ci			return write_field(hw, &info->ilimsel, i);
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	return -EINVAL;
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic int get_current_limit(struct regulator_dev *rdev)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	const struct supply_info *info;
5168c2ecf20Sopenharmony_ci	struct tps6524x *hw;
5178c2ecf20Sopenharmony_ci	int ret;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	hw	= rdev_get_drvdata(rdev);
5208c2ecf20Sopenharmony_ci	info	= &supply_info[rdev_get_id(rdev)];
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if (info->n_ilimsels == 1)
5238c2ecf20Sopenharmony_ci		return info->ilimsels[0];
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	ret = read_field(hw, &info->ilimsel);
5268c2ecf20Sopenharmony_ci	if (ret < 0)
5278c2ecf20Sopenharmony_ci		return ret;
5288c2ecf20Sopenharmony_ci	if (WARN_ON(ret >= info->n_ilimsels))
5298c2ecf20Sopenharmony_ci		return -EIO;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	return info->ilimsels[ret];
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic int enable_supply(struct regulator_dev *rdev)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	const struct supply_info *info;
5378c2ecf20Sopenharmony_ci	struct tps6524x *hw;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	hw	= rdev_get_drvdata(rdev);
5408c2ecf20Sopenharmony_ci	info	= &supply_info[rdev_get_id(rdev)];
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	return write_field(hw, &info->enable, 1);
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_cistatic int disable_supply(struct regulator_dev *rdev)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	const struct supply_info *info;
5488c2ecf20Sopenharmony_ci	struct tps6524x *hw;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	hw	= rdev_get_drvdata(rdev);
5518c2ecf20Sopenharmony_ci	info	= &supply_info[rdev_get_id(rdev)];
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	return write_field(hw, &info->enable, 0);
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_cistatic int is_supply_enabled(struct regulator_dev *rdev)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	const struct supply_info *info;
5598c2ecf20Sopenharmony_ci	struct tps6524x *hw;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	hw	= rdev_get_drvdata(rdev);
5628c2ecf20Sopenharmony_ci	info	= &supply_info[rdev_get_id(rdev)];
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	return read_field(hw, &info->enable);
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic const struct regulator_ops regulator_ops = {
5688c2ecf20Sopenharmony_ci	.is_enabled		= is_supply_enabled,
5698c2ecf20Sopenharmony_ci	.enable			= enable_supply,
5708c2ecf20Sopenharmony_ci	.disable		= disable_supply,
5718c2ecf20Sopenharmony_ci	.get_voltage_sel	= get_voltage_sel,
5728c2ecf20Sopenharmony_ci	.set_voltage_sel	= set_voltage_sel,
5738c2ecf20Sopenharmony_ci	.list_voltage		= regulator_list_voltage_table,
5748c2ecf20Sopenharmony_ci	.map_voltage		= regulator_map_voltage_ascend,
5758c2ecf20Sopenharmony_ci	.set_current_limit	= set_current_limit,
5768c2ecf20Sopenharmony_ci	.get_current_limit	= get_current_limit,
5778c2ecf20Sopenharmony_ci};
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic int pmic_probe(struct spi_device *spi)
5808c2ecf20Sopenharmony_ci{
5818c2ecf20Sopenharmony_ci	struct tps6524x *hw;
5828c2ecf20Sopenharmony_ci	struct device *dev = &spi->dev;
5838c2ecf20Sopenharmony_ci	const struct supply_info *info = supply_info;
5848c2ecf20Sopenharmony_ci	struct regulator_init_data *init_data;
5858c2ecf20Sopenharmony_ci	struct regulator_config config = { };
5868c2ecf20Sopenharmony_ci	struct regulator_dev *rdev;
5878c2ecf20Sopenharmony_ci	int i;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	init_data = dev_get_platdata(dev);
5908c2ecf20Sopenharmony_ci	if (!init_data) {
5918c2ecf20Sopenharmony_ci		dev_err(dev, "could not find regulator platform data\n");
5928c2ecf20Sopenharmony_ci		return -EINVAL;
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL);
5968c2ecf20Sopenharmony_ci	if (!hw)
5978c2ecf20Sopenharmony_ci		return -ENOMEM;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	spi_set_drvdata(spi, hw);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	memset(hw, 0, sizeof(struct tps6524x));
6028c2ecf20Sopenharmony_ci	hw->dev = dev;
6038c2ecf20Sopenharmony_ci	hw->spi = spi;
6048c2ecf20Sopenharmony_ci	mutex_init(&hw->lock);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	for (i = 0; i < N_REGULATORS; i++, info++, init_data++) {
6078c2ecf20Sopenharmony_ci		hw->desc[i].name	= info->name;
6088c2ecf20Sopenharmony_ci		hw->desc[i].id		= i;
6098c2ecf20Sopenharmony_ci		hw->desc[i].n_voltages	= info->n_voltages;
6108c2ecf20Sopenharmony_ci		hw->desc[i].volt_table	= info->voltages;
6118c2ecf20Sopenharmony_ci		hw->desc[i].ops		= &regulator_ops;
6128c2ecf20Sopenharmony_ci		hw->desc[i].type	= REGULATOR_VOLTAGE;
6138c2ecf20Sopenharmony_ci		hw->desc[i].owner	= THIS_MODULE;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		config.dev = dev;
6168c2ecf20Sopenharmony_ci		config.init_data = init_data;
6178c2ecf20Sopenharmony_ci		config.driver_data = hw;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		rdev = devm_regulator_register(dev, &hw->desc[i], &config);
6208c2ecf20Sopenharmony_ci		if (IS_ERR(rdev))
6218c2ecf20Sopenharmony_ci			return PTR_ERR(rdev);
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	return 0;
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_cistatic struct spi_driver pmic_driver = {
6288c2ecf20Sopenharmony_ci	.probe		= pmic_probe,
6298c2ecf20Sopenharmony_ci	.driver		= {
6308c2ecf20Sopenharmony_ci		.name	= "tps6524x",
6318c2ecf20Sopenharmony_ci	},
6328c2ecf20Sopenharmony_ci};
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_cimodule_spi_driver(pmic_driver);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TPS6524X PMIC Driver");
6378c2ecf20Sopenharmony_ciMODULE_AUTHOR("Cyril Chemparathy");
6388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
6398c2ecf20Sopenharmony_ciMODULE_ALIAS("spi:tps6524x");
640