11394fd28SCyril Chemparathy /*
21394fd28SCyril Chemparathy  * Regulator driver for TPS6524x PMIC
31394fd28SCyril Chemparathy  *
41394fd28SCyril Chemparathy  * Copyright (C) 2010 Texas Instruments
51394fd28SCyril Chemparathy  *
61394fd28SCyril Chemparathy  * This program is free software; you can redistribute it and/or
71394fd28SCyril Chemparathy  * modify it under the terms of the GNU General Public License as
81394fd28SCyril Chemparathy  * published by the Free Software Foundation version 2.
91394fd28SCyril Chemparathy  *
101394fd28SCyril Chemparathy  * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
111394fd28SCyril Chemparathy  * whether express or implied; without even the implied warranty of
121394fd28SCyril Chemparathy  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
131394fd28SCyril Chemparathy  * General Public License for more details.
141394fd28SCyril Chemparathy  */
151394fd28SCyril Chemparathy 
161394fd28SCyril Chemparathy #include <linux/kernel.h>
171394fd28SCyril Chemparathy #include <linux/module.h>
181394fd28SCyril Chemparathy #include <linux/err.h>
191394fd28SCyril Chemparathy #include <linux/errno.h>
201394fd28SCyril Chemparathy #include <linux/slab.h>
211394fd28SCyril Chemparathy #include <linux/spi/spi.h>
221394fd28SCyril Chemparathy #include <linux/regulator/driver.h>
231394fd28SCyril Chemparathy #include <linux/regulator/machine.h>
241394fd28SCyril Chemparathy 
251394fd28SCyril Chemparathy #define REG_LDO_SET		0x0
261394fd28SCyril Chemparathy #define LDO_ILIM_MASK		1	/* 0 = 400-800, 1 = 900-1500 */
271394fd28SCyril Chemparathy #define LDO_VSEL_MASK		0x0f
281394fd28SCyril Chemparathy #define LDO2_ILIM_SHIFT		12
291394fd28SCyril Chemparathy #define LDO2_VSEL_SHIFT		4
301394fd28SCyril Chemparathy #define LDO1_ILIM_SHIFT		8
311394fd28SCyril Chemparathy #define LDO1_VSEL_SHIFT		0
321394fd28SCyril Chemparathy 
331394fd28SCyril Chemparathy #define REG_BLOCK_EN		0x1
341394fd28SCyril Chemparathy #define BLOCK_MASK		1
351394fd28SCyril Chemparathy #define BLOCK_LDO1_SHIFT	0
361394fd28SCyril Chemparathy #define BLOCK_LDO2_SHIFT	1
371394fd28SCyril Chemparathy #define BLOCK_LCD_SHIFT		2
381394fd28SCyril Chemparathy #define BLOCK_USB_SHIFT		3
391394fd28SCyril Chemparathy 
401394fd28SCyril Chemparathy #define REG_DCDC_SET		0x2
411394fd28SCyril Chemparathy #define DCDC_VDCDC_MASK		0x1f
421394fd28SCyril Chemparathy #define DCDC_VDCDC1_SHIFT	0
431394fd28SCyril Chemparathy #define DCDC_VDCDC2_SHIFT	5
441394fd28SCyril Chemparathy #define DCDC_VDCDC3_SHIFT	10
451394fd28SCyril Chemparathy 
461394fd28SCyril Chemparathy #define REG_DCDC_EN		0x3
471394fd28SCyril Chemparathy #define DCDCDCDC_EN_MASK	0x1
481394fd28SCyril Chemparathy #define DCDCDCDC1_EN_SHIFT	0
491394fd28SCyril Chemparathy #define DCDCDCDC1_PG_MSK	BIT(1)
501394fd28SCyril Chemparathy #define DCDCDCDC2_EN_SHIFT	2
511394fd28SCyril Chemparathy #define DCDCDCDC2_PG_MSK	BIT(3)
521394fd28SCyril Chemparathy #define DCDCDCDC3_EN_SHIFT	4
531394fd28SCyril Chemparathy #define DCDCDCDC3_PG_MSK	BIT(5)
541394fd28SCyril Chemparathy 
551394fd28SCyril Chemparathy #define REG_USB			0x4
561394fd28SCyril Chemparathy #define USB_ILIM_SHIFT		0
571394fd28SCyril Chemparathy #define USB_ILIM_MASK		0x3
581394fd28SCyril Chemparathy #define USB_TSD_SHIFT		2
591394fd28SCyril Chemparathy #define USB_TSD_MASK		0x3
601394fd28SCyril Chemparathy #define USB_TWARN_SHIFT		4
611394fd28SCyril Chemparathy #define USB_TWARN_MASK		0x3
621394fd28SCyril Chemparathy #define USB_IWARN_SD		BIT(6)
631394fd28SCyril Chemparathy #define USB_FAST_LOOP		BIT(7)
641394fd28SCyril Chemparathy 
651394fd28SCyril Chemparathy #define REG_ALARM		0x5
661394fd28SCyril Chemparathy #define ALARM_LDO1		BIT(0)
671394fd28SCyril Chemparathy #define ALARM_DCDC1		BIT(1)
681394fd28SCyril Chemparathy #define ALARM_DCDC2		BIT(2)
691394fd28SCyril Chemparathy #define ALARM_DCDC3		BIT(3)
701394fd28SCyril Chemparathy #define ALARM_LDO2		BIT(4)
711394fd28SCyril Chemparathy #define ALARM_USB_WARN		BIT(5)
721394fd28SCyril Chemparathy #define ALARM_USB_ALARM		BIT(6)
731394fd28SCyril Chemparathy #define ALARM_LCD		BIT(9)
741394fd28SCyril Chemparathy #define ALARM_TEMP_WARM		BIT(10)
751394fd28SCyril Chemparathy #define ALARM_TEMP_HOT		BIT(11)
761394fd28SCyril Chemparathy #define ALARM_NRST		BIT(14)
771394fd28SCyril Chemparathy #define ALARM_POWERUP		BIT(15)
781394fd28SCyril Chemparathy 
791394fd28SCyril Chemparathy #define REG_INT_ENABLE		0x6
801394fd28SCyril Chemparathy #define INT_LDO1		BIT(0)
811394fd28SCyril Chemparathy #define INT_DCDC1		BIT(1)
821394fd28SCyril Chemparathy #define INT_DCDC2		BIT(2)
831394fd28SCyril Chemparathy #define INT_DCDC3		BIT(3)
841394fd28SCyril Chemparathy #define INT_LDO2		BIT(4)
851394fd28SCyril Chemparathy #define INT_USB_WARN		BIT(5)
861394fd28SCyril Chemparathy #define INT_USB_ALARM		BIT(6)
871394fd28SCyril Chemparathy #define INT_LCD			BIT(9)
881394fd28SCyril Chemparathy #define INT_TEMP_WARM		BIT(10)
891394fd28SCyril Chemparathy #define INT_TEMP_HOT		BIT(11)
901394fd28SCyril Chemparathy #define INT_GLOBAL_EN		BIT(15)
911394fd28SCyril Chemparathy 
921394fd28SCyril Chemparathy #define REG_INT_STATUS		0x7
931394fd28SCyril Chemparathy #define STATUS_LDO1		BIT(0)
941394fd28SCyril Chemparathy #define STATUS_DCDC1		BIT(1)
951394fd28SCyril Chemparathy #define STATUS_DCDC2		BIT(2)
961394fd28SCyril Chemparathy #define STATUS_DCDC3		BIT(3)
971394fd28SCyril Chemparathy #define STATUS_LDO2		BIT(4)
981394fd28SCyril Chemparathy #define STATUS_USB_WARN		BIT(5)
991394fd28SCyril Chemparathy #define STATUS_USB_ALARM	BIT(6)
1001394fd28SCyril Chemparathy #define STATUS_LCD		BIT(9)
1011394fd28SCyril Chemparathy #define STATUS_TEMP_WARM	BIT(10)
1021394fd28SCyril Chemparathy #define STATUS_TEMP_HOT		BIT(11)
1031394fd28SCyril Chemparathy 
1041394fd28SCyril Chemparathy #define REG_SOFTWARE_RESET	0xb
1051394fd28SCyril Chemparathy #define REG_WRITE_ENABLE	0xd
1061394fd28SCyril Chemparathy #define REG_REV_ID		0xf
1071394fd28SCyril Chemparathy 
1081394fd28SCyril Chemparathy #define N_DCDC			3
1091394fd28SCyril Chemparathy #define N_LDO			2
1101394fd28SCyril Chemparathy #define N_SWITCH		2
1114d984d1cSAxel Lin #define N_REGULATORS		(N_DCDC + N_LDO + N_SWITCH)
1121394fd28SCyril Chemparathy 
1131394fd28SCyril Chemparathy #define CMD_READ(reg)		((reg) << 6)
1141394fd28SCyril Chemparathy #define CMD_WRITE(reg)		(BIT(5) | (reg) << 6)
1151394fd28SCyril Chemparathy #define STAT_CLK		BIT(3)
1161394fd28SCyril Chemparathy #define STAT_WRITE		BIT(2)
1171394fd28SCyril Chemparathy #define STAT_INVALID		BIT(1)
1181394fd28SCyril Chemparathy #define STAT_WP			BIT(0)
1191394fd28SCyril Chemparathy 
1201394fd28SCyril Chemparathy struct field {
1211394fd28SCyril Chemparathy 	int		reg;
1221394fd28SCyril Chemparathy 	int		shift;
1231394fd28SCyril Chemparathy 	int		mask;
1241394fd28SCyril Chemparathy };
1251394fd28SCyril Chemparathy 
1261394fd28SCyril Chemparathy struct supply_info {
1271394fd28SCyril Chemparathy 	const char	*name;
1281394fd28SCyril Chemparathy 	int		n_voltages;
129cac87fd3SAxel Lin 	const unsigned int *voltages;
1301394fd28SCyril Chemparathy 	int		n_ilimsels;
1311e12dfc9SAxel Lin 	const unsigned int *ilimsels;
1321394fd28SCyril Chemparathy 	struct field	enable, voltage, ilimsel;
1331394fd28SCyril Chemparathy };
1341394fd28SCyril Chemparathy 
1351394fd28SCyril Chemparathy struct tps6524x {
1361394fd28SCyril Chemparathy 	struct device		*dev;
1371394fd28SCyril Chemparathy 	struct spi_device	*spi;
1381394fd28SCyril Chemparathy 	struct mutex		lock;
1391394fd28SCyril Chemparathy 	struct regulator_desc	desc[N_REGULATORS];
1401394fd28SCyril Chemparathy };
1411394fd28SCyril Chemparathy 
__read_reg(struct tps6524x * hw,int reg)1421394fd28SCyril Chemparathy static int __read_reg(struct tps6524x *hw, int reg)
1431394fd28SCyril Chemparathy {
1441394fd28SCyril Chemparathy 	int error = 0;
1451394fd28SCyril Chemparathy 	u16 cmd = CMD_READ(reg), in;
1461394fd28SCyril Chemparathy 	u8 status;
1471394fd28SCyril Chemparathy 	struct spi_message m;
1481394fd28SCyril Chemparathy 	struct spi_transfer t[3];
1491394fd28SCyril Chemparathy 
1501394fd28SCyril Chemparathy 	spi_message_init(&m);
1511394fd28SCyril Chemparathy 	memset(t, 0, sizeof(t));
1521394fd28SCyril Chemparathy 
1531394fd28SCyril Chemparathy 	t[0].tx_buf = &cmd;
1541394fd28SCyril Chemparathy 	t[0].len = 2;
1551394fd28SCyril Chemparathy 	t[0].bits_per_word = 12;
1561394fd28SCyril Chemparathy 	spi_message_add_tail(&t[0], &m);
1571394fd28SCyril Chemparathy 
1581394fd28SCyril Chemparathy 	t[1].rx_buf = &in;
1591394fd28SCyril Chemparathy 	t[1].len = 2;
1601394fd28SCyril Chemparathy 	t[1].bits_per_word = 16;
1611394fd28SCyril Chemparathy 	spi_message_add_tail(&t[1], &m);
1621394fd28SCyril Chemparathy 
1631394fd28SCyril Chemparathy 	t[2].rx_buf = &status;
1641394fd28SCyril Chemparathy 	t[2].len = 1;
1651394fd28SCyril Chemparathy 	t[2].bits_per_word = 4;
1661394fd28SCyril Chemparathy 	spi_message_add_tail(&t[2], &m);
1671394fd28SCyril Chemparathy 
1681394fd28SCyril Chemparathy 	error = spi_sync(hw->spi, &m);
1691394fd28SCyril Chemparathy 	if (error < 0)
1701394fd28SCyril Chemparathy 		return error;
1711394fd28SCyril Chemparathy 
1721394fd28SCyril Chemparathy 	dev_dbg(hw->dev, "read reg %d, data %x, status %x\n",
1731394fd28SCyril Chemparathy 		reg, in, status);
1741394fd28SCyril Chemparathy 
1751394fd28SCyril Chemparathy 	if (!(status & STAT_CLK) || (status & STAT_WRITE))
1761394fd28SCyril Chemparathy 		return -EIO;
1771394fd28SCyril Chemparathy 
1781394fd28SCyril Chemparathy 	if (status & STAT_INVALID)
1791394fd28SCyril Chemparathy 		return -EINVAL;
1801394fd28SCyril Chemparathy 
1811394fd28SCyril Chemparathy 	return in;
1821394fd28SCyril Chemparathy }
1831394fd28SCyril Chemparathy 
read_reg(struct tps6524x * hw,int reg)1841394fd28SCyril Chemparathy static int read_reg(struct tps6524x *hw, int reg)
1851394fd28SCyril Chemparathy {
1861394fd28SCyril Chemparathy 	int ret;
1871394fd28SCyril Chemparathy 
1881394fd28SCyril Chemparathy 	mutex_lock(&hw->lock);
1891394fd28SCyril Chemparathy 	ret = __read_reg(hw, reg);
1901394fd28SCyril Chemparathy 	mutex_unlock(&hw->lock);
1911394fd28SCyril Chemparathy 
1921394fd28SCyril Chemparathy 	return ret;
1931394fd28SCyril Chemparathy }
1941394fd28SCyril Chemparathy 
__write_reg(struct tps6524x * hw,int reg,int val)1951394fd28SCyril Chemparathy static int __write_reg(struct tps6524x *hw, int reg, int val)
1961394fd28SCyril Chemparathy {
1971394fd28SCyril Chemparathy 	int error = 0;
1981394fd28SCyril Chemparathy 	u16 cmd = CMD_WRITE(reg), out = val;
1991394fd28SCyril Chemparathy 	u8 status;
2001394fd28SCyril Chemparathy 	struct spi_message m;
2011394fd28SCyril Chemparathy 	struct spi_transfer t[3];
2021394fd28SCyril Chemparathy 
2031394fd28SCyril Chemparathy 	spi_message_init(&m);
2041394fd28SCyril Chemparathy 	memset(t, 0, sizeof(t));
2051394fd28SCyril Chemparathy 
2061394fd28SCyril Chemparathy 	t[0].tx_buf = &cmd;
2071394fd28SCyril Chemparathy 	t[0].len = 2;
2081394fd28SCyril Chemparathy 	t[0].bits_per_word = 12;
2091394fd28SCyril Chemparathy 	spi_message_add_tail(&t[0], &m);
2101394fd28SCyril Chemparathy 
2111394fd28SCyril Chemparathy 	t[1].tx_buf = &out;
2121394fd28SCyril Chemparathy 	t[1].len = 2;
2131394fd28SCyril Chemparathy 	t[1].bits_per_word = 16;
2141394fd28SCyril Chemparathy 	spi_message_add_tail(&t[1], &m);
2151394fd28SCyril Chemparathy 
2161394fd28SCyril Chemparathy 	t[2].rx_buf = &status;
2171394fd28SCyril Chemparathy 	t[2].len = 1;
2181394fd28SCyril Chemparathy 	t[2].bits_per_word = 4;
2191394fd28SCyril Chemparathy 	spi_message_add_tail(&t[2], &m);
2201394fd28SCyril Chemparathy 
2211394fd28SCyril Chemparathy 	error = spi_sync(hw->spi, &m);
2221394fd28SCyril Chemparathy 	if (error < 0)
2231394fd28SCyril Chemparathy 		return error;
2241394fd28SCyril Chemparathy 
2251394fd28SCyril Chemparathy 	dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n",
2261394fd28SCyril Chemparathy 		reg, out, status);
2271394fd28SCyril Chemparathy 
2281394fd28SCyril Chemparathy 	if (!(status & STAT_CLK) || !(status & STAT_WRITE))
2291394fd28SCyril Chemparathy 		return -EIO;
2301394fd28SCyril Chemparathy 
2311394fd28SCyril Chemparathy 	if (status & (STAT_INVALID | STAT_WP))
2321394fd28SCyril Chemparathy 		return -EINVAL;
2331394fd28SCyril Chemparathy 
2341394fd28SCyril Chemparathy 	return error;
2351394fd28SCyril Chemparathy }
2361394fd28SCyril Chemparathy 
__rmw_reg(struct tps6524x * hw,int reg,int mask,int val)2371394fd28SCyril Chemparathy static int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val)
2381394fd28SCyril Chemparathy {
2391394fd28SCyril Chemparathy 	int ret;
2401394fd28SCyril Chemparathy 
2411394fd28SCyril Chemparathy 	ret = __read_reg(hw, reg);
2421394fd28SCyril Chemparathy 	if (ret < 0)
2431394fd28SCyril Chemparathy 		return ret;
2441394fd28SCyril Chemparathy 
2451394fd28SCyril Chemparathy 	ret &= ~mask;
2461394fd28SCyril Chemparathy 	ret |= val;
2471394fd28SCyril Chemparathy 
2481394fd28SCyril Chemparathy 	ret = __write_reg(hw, reg, ret);
2491394fd28SCyril Chemparathy 
2501394fd28SCyril Chemparathy 	return (ret < 0) ? ret : 0;
2511394fd28SCyril Chemparathy }
2521394fd28SCyril Chemparathy 
rmw_protect(struct tps6524x * hw,int reg,int mask,int val)2531394fd28SCyril Chemparathy static int rmw_protect(struct tps6524x *hw, int reg, int mask, int val)
2541394fd28SCyril Chemparathy {
2551394fd28SCyril Chemparathy 	int ret;
2561394fd28SCyril Chemparathy 
2571394fd28SCyril Chemparathy 	mutex_lock(&hw->lock);
2581394fd28SCyril Chemparathy 
2591394fd28SCyril Chemparathy 	ret = __write_reg(hw, REG_WRITE_ENABLE, 1);
2601394fd28SCyril Chemparathy 	if (ret) {
2611394fd28SCyril Chemparathy 		dev_err(hw->dev, "failed to set write enable\n");
2621394fd28SCyril Chemparathy 		goto error;
2631394fd28SCyril Chemparathy 	}
2641394fd28SCyril Chemparathy 
2651394fd28SCyril Chemparathy 	ret = __rmw_reg(hw, reg, mask, val);
2661394fd28SCyril Chemparathy 	if (ret)
2671394fd28SCyril Chemparathy 		dev_err(hw->dev, "failed to rmw register %d\n", reg);
2681394fd28SCyril Chemparathy 
2691394fd28SCyril Chemparathy 	ret = __write_reg(hw, REG_WRITE_ENABLE, 0);
2701394fd28SCyril Chemparathy 	if (ret) {
2711394fd28SCyril Chemparathy 		dev_err(hw->dev, "failed to clear write enable\n");
2721394fd28SCyril Chemparathy 		goto error;
2731394fd28SCyril Chemparathy 	}
2741394fd28SCyril Chemparathy 
2751394fd28SCyril Chemparathy error:
2761394fd28SCyril Chemparathy 	mutex_unlock(&hw->lock);
2771394fd28SCyril Chemparathy 
2781394fd28SCyril Chemparathy 	return ret;
2791394fd28SCyril Chemparathy }
2801394fd28SCyril Chemparathy 
read_field(struct tps6524x * hw,const struct field * field)2811394fd28SCyril Chemparathy static int read_field(struct tps6524x *hw, const struct field *field)
2821394fd28SCyril Chemparathy {
2831394fd28SCyril Chemparathy 	int tmp;
2841394fd28SCyril Chemparathy 
2851394fd28SCyril Chemparathy 	tmp = read_reg(hw, field->reg);
2861394fd28SCyril Chemparathy 	if (tmp < 0)
2871394fd28SCyril Chemparathy 		return tmp;
2881394fd28SCyril Chemparathy 
2891394fd28SCyril Chemparathy 	return (tmp >> field->shift) & field->mask;
2901394fd28SCyril Chemparathy }
2911394fd28SCyril Chemparathy 
write_field(struct tps6524x * hw,const struct field * field,int val)2921394fd28SCyril Chemparathy static int write_field(struct tps6524x *hw, const struct field *field,
2931394fd28SCyril Chemparathy 		       int val)
2941394fd28SCyril Chemparathy {
2951394fd28SCyril Chemparathy 	if (val & ~field->mask)
2961394fd28SCyril Chemparathy 		return -EOVERFLOW;
2971394fd28SCyril Chemparathy 
2981394fd28SCyril Chemparathy 	return rmw_protect(hw, field->reg,
2991394fd28SCyril Chemparathy 				    field->mask << field->shift,
3001394fd28SCyril Chemparathy 				    val << field->shift);
3011394fd28SCyril Chemparathy }
3021394fd28SCyril Chemparathy 
303cac87fd3SAxel Lin static const unsigned int dcdc1_voltages[] = {
3041394fd28SCyril Chemparathy 	 800000,  825000,  850000,  875000,
3051394fd28SCyril Chemparathy 	 900000,  925000,  950000,  975000,
3061394fd28SCyril Chemparathy 	1000000, 1025000, 1050000, 1075000,
3071394fd28SCyril Chemparathy 	1100000, 1125000, 1150000, 1175000,
3081394fd28SCyril Chemparathy 	1200000, 1225000, 1250000, 1275000,
3091394fd28SCyril Chemparathy 	1300000, 1325000, 1350000, 1375000,
3101394fd28SCyril Chemparathy 	1400000, 1425000, 1450000, 1475000,
3111394fd28SCyril Chemparathy 	1500000, 1525000, 1550000, 1575000,
3121394fd28SCyril Chemparathy };
3131394fd28SCyril Chemparathy 
314cac87fd3SAxel Lin static const unsigned int dcdc2_voltages[] = {
3151394fd28SCyril Chemparathy 	1400000, 1450000, 1500000, 1550000,
3161394fd28SCyril Chemparathy 	1600000, 1650000, 1700000, 1750000,
3171394fd28SCyril Chemparathy 	1800000, 1850000, 1900000, 1950000,
3181394fd28SCyril Chemparathy 	2000000, 2050000, 2100000, 2150000,
3191394fd28SCyril Chemparathy 	2200000, 2250000, 2300000, 2350000,
3201394fd28SCyril Chemparathy 	2400000, 2450000, 2500000, 2550000,
3211394fd28SCyril Chemparathy 	2600000, 2650000, 2700000, 2750000,
3221394fd28SCyril Chemparathy 	2800000, 2850000, 2900000, 2950000,
3231394fd28SCyril Chemparathy };
3241394fd28SCyril Chemparathy 
325cac87fd3SAxel Lin static const unsigned int dcdc3_voltages[] = {
3261394fd28SCyril Chemparathy 	2400000, 2450000, 2500000, 2550000, 2600000,
3271394fd28SCyril Chemparathy 	2650000, 2700000, 2750000, 2800000, 2850000,
3281394fd28SCyril Chemparathy 	2900000, 2950000, 3000000, 3050000, 3100000,
3291394fd28SCyril Chemparathy 	3150000, 3200000, 3250000, 3300000, 3350000,
3301394fd28SCyril Chemparathy 	3400000, 3450000, 3500000, 3550000, 3600000,
3311394fd28SCyril Chemparathy };
3321394fd28SCyril Chemparathy 
333cac87fd3SAxel Lin static const unsigned int ldo1_voltages[] = {
3341394fd28SCyril Chemparathy 	4300000, 4350000, 4400000, 4450000,
3351394fd28SCyril Chemparathy 	4500000, 4550000, 4600000, 4650000,
3361394fd28SCyril Chemparathy 	4700000, 4750000, 4800000, 4850000,
3371394fd28SCyril Chemparathy 	4900000, 4950000, 5000000, 5050000,
3381394fd28SCyril Chemparathy };
3391394fd28SCyril Chemparathy 
340cac87fd3SAxel Lin static const unsigned int ldo2_voltages[] = {
3411394fd28SCyril Chemparathy 	1100000, 1150000, 1200000, 1250000,
3421394fd28SCyril Chemparathy 	1300000, 1700000, 1750000, 1800000,
3431394fd28SCyril Chemparathy 	1850000, 1900000, 3150000, 3200000,
3441394fd28SCyril Chemparathy 	3250000, 3300000, 3350000, 3400000,
3451394fd28SCyril Chemparathy };
3461394fd28SCyril Chemparathy 
347cac87fd3SAxel Lin static const unsigned int fixed_5000000_voltage[] = {
348cac87fd3SAxel Lin 	5000000
349cac87fd3SAxel Lin };
350cac87fd3SAxel Lin 
3511e12dfc9SAxel Lin static const unsigned int ldo_ilimsel[] = {
3521394fd28SCyril Chemparathy 	400000, 1500000
3531394fd28SCyril Chemparathy };
3541394fd28SCyril Chemparathy 
3551e12dfc9SAxel Lin static const unsigned int usb_ilimsel[] = {
3561394fd28SCyril Chemparathy 	200000, 400000, 800000, 1000000
3571394fd28SCyril Chemparathy };
3581394fd28SCyril Chemparathy 
3591e12dfc9SAxel Lin static const unsigned int fixed_2400000_ilimsel[] = {
3601e12dfc9SAxel Lin 	2400000
3611e12dfc9SAxel Lin };
3621e12dfc9SAxel Lin 
3631e12dfc9SAxel Lin static const unsigned int fixed_1200000_ilimsel[] = {
3641e12dfc9SAxel Lin 	1200000
3651e12dfc9SAxel Lin };
3661e12dfc9SAxel Lin 
3671e12dfc9SAxel Lin static const unsigned int fixed_400000_ilimsel[] = {
3681e12dfc9SAxel Lin 	400000
3691e12dfc9SAxel Lin };
3701e12dfc9SAxel Lin 
3711394fd28SCyril Chemparathy #define __MK_FIELD(_reg, _mask, _shift) \
3721394fd28SCyril Chemparathy 	{ .reg = (_reg), .mask = (_mask), .shift = (_shift), }
3731394fd28SCyril Chemparathy 
3741394fd28SCyril Chemparathy static const struct supply_info supply_info[N_REGULATORS] = {
3751394fd28SCyril Chemparathy 	{
3761394fd28SCyril Chemparathy 		.name		= "DCDC1",
3771394fd28SCyril Chemparathy 		.n_voltages	= ARRAY_SIZE(dcdc1_voltages),
3781394fd28SCyril Chemparathy 		.voltages	= dcdc1_voltages,
3791e12dfc9SAxel Lin 		.n_ilimsels	= ARRAY_SIZE(fixed_2400000_ilimsel),
3801e12dfc9SAxel Lin 		.ilimsels	= fixed_2400000_ilimsel,
3811394fd28SCyril Chemparathy 		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
3821394fd28SCyril Chemparathy 					     DCDCDCDC1_EN_SHIFT),
3831394fd28SCyril Chemparathy 		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
3841394fd28SCyril Chemparathy 					     DCDC_VDCDC1_SHIFT),
3851394fd28SCyril Chemparathy 	},
3861394fd28SCyril Chemparathy 	{
3871394fd28SCyril Chemparathy 		.name		= "DCDC2",
3881394fd28SCyril Chemparathy 		.n_voltages	= ARRAY_SIZE(dcdc2_voltages),
3891394fd28SCyril Chemparathy 		.voltages	= dcdc2_voltages,
3901e12dfc9SAxel Lin 		.n_ilimsels	= ARRAY_SIZE(fixed_1200000_ilimsel),
3911e12dfc9SAxel Lin 		.ilimsels	= fixed_1200000_ilimsel,
3921394fd28SCyril Chemparathy 		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
3931394fd28SCyril Chemparathy 					     DCDCDCDC2_EN_SHIFT),
3941394fd28SCyril Chemparathy 		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
3951394fd28SCyril Chemparathy 					     DCDC_VDCDC2_SHIFT),
3961394fd28SCyril Chemparathy 	},
3971394fd28SCyril Chemparathy 	{
3981394fd28SCyril Chemparathy 		.name		= "DCDC3",
3991394fd28SCyril Chemparathy 		.n_voltages	= ARRAY_SIZE(dcdc3_voltages),
4001394fd28SCyril Chemparathy 		.voltages	= dcdc3_voltages,
4011e12dfc9SAxel Lin 		.n_ilimsels	= ARRAY_SIZE(fixed_1200000_ilimsel),
4021e12dfc9SAxel Lin 		.ilimsels	= fixed_1200000_ilimsel,
4031394fd28SCyril Chemparathy 		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
4041394fd28SCyril Chemparathy 					DCDCDCDC3_EN_SHIFT),
4051394fd28SCyril Chemparathy 		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
4061394fd28SCyril Chemparathy 					     DCDC_VDCDC3_SHIFT),
4071394fd28SCyril Chemparathy 	},
4081394fd28SCyril Chemparathy 	{
4091394fd28SCyril Chemparathy 		.name		= "LDO1",
4101394fd28SCyril Chemparathy 		.n_voltages	= ARRAY_SIZE(ldo1_voltages),
4111394fd28SCyril Chemparathy 		.voltages	= ldo1_voltages,
4121394fd28SCyril Chemparathy 		.n_ilimsels	= ARRAY_SIZE(ldo_ilimsel),
4131394fd28SCyril Chemparathy 		.ilimsels	= ldo_ilimsel,
4141394fd28SCyril Chemparathy 		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
4151394fd28SCyril Chemparathy 					     BLOCK_LDO1_SHIFT),
4161394fd28SCyril Chemparathy 		.voltage	= __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK,
4171394fd28SCyril Chemparathy 					     LDO1_VSEL_SHIFT),
4181394fd28SCyril Chemparathy 		.ilimsel	= __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK,
4191394fd28SCyril Chemparathy 					     LDO1_ILIM_SHIFT),
4201394fd28SCyril Chemparathy 	},
4211394fd28SCyril Chemparathy 	{
4221394fd28SCyril Chemparathy 		.name		= "LDO2",
4231394fd28SCyril Chemparathy 		.n_voltages	= ARRAY_SIZE(ldo2_voltages),
4241394fd28SCyril Chemparathy 		.voltages	= ldo2_voltages,
4251394fd28SCyril Chemparathy 		.n_ilimsels	= ARRAY_SIZE(ldo_ilimsel),
4261394fd28SCyril Chemparathy 		.ilimsels	= ldo_ilimsel,
4271394fd28SCyril Chemparathy 		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
4281394fd28SCyril Chemparathy 					     BLOCK_LDO2_SHIFT),
4291394fd28SCyril Chemparathy 		.voltage	= __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK,
4301394fd28SCyril Chemparathy 					     LDO2_VSEL_SHIFT),
4311394fd28SCyril Chemparathy 		.ilimsel	= __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK,
4321394fd28SCyril Chemparathy 					     LDO2_ILIM_SHIFT),
4331394fd28SCyril Chemparathy 	},
4341394fd28SCyril Chemparathy 	{
4351394fd28SCyril Chemparathy 		.name		= "USB",
436cac87fd3SAxel Lin 		.n_voltages	= ARRAY_SIZE(fixed_5000000_voltage),
437cac87fd3SAxel Lin 		.voltages	= fixed_5000000_voltage,
4381394fd28SCyril Chemparathy 		.n_ilimsels	= ARRAY_SIZE(usb_ilimsel),
4391394fd28SCyril Chemparathy 		.ilimsels	= usb_ilimsel,
4401394fd28SCyril Chemparathy 		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
4411394fd28SCyril Chemparathy 					     BLOCK_USB_SHIFT),
4421394fd28SCyril Chemparathy 		.ilimsel	= __MK_FIELD(REG_USB, USB_ILIM_MASK,
4431394fd28SCyril Chemparathy 					     USB_ILIM_SHIFT),
4441394fd28SCyril Chemparathy 	},
4451394fd28SCyril Chemparathy 	{
4461394fd28SCyril Chemparathy 		.name		= "LCD",
447cac87fd3SAxel Lin 		.n_voltages	= ARRAY_SIZE(fixed_5000000_voltage),
448cac87fd3SAxel Lin 		.voltages	= fixed_5000000_voltage,
4491e12dfc9SAxel Lin 		.n_ilimsels	= ARRAY_SIZE(fixed_400000_ilimsel),
4501e12dfc9SAxel Lin 		.ilimsels	= fixed_400000_ilimsel,
4511394fd28SCyril Chemparathy 		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
4521394fd28SCyril Chemparathy 					     BLOCK_LCD_SHIFT),
4531394fd28SCyril Chemparathy 	},
4541394fd28SCyril Chemparathy };
4551394fd28SCyril Chemparathy 
set_voltage_sel(struct regulator_dev * rdev,unsigned selector)456f8ee3393SAxel Lin static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
4571394fd28SCyril Chemparathy {
4581394fd28SCyril Chemparathy 	const struct supply_info *info;
4591394fd28SCyril Chemparathy 	struct tps6524x *hw;
4601394fd28SCyril Chemparathy 
4611394fd28SCyril Chemparathy 	hw	= rdev_get_drvdata(rdev);
4621394fd28SCyril Chemparathy 	info	= &supply_info[rdev_get_id(rdev)];
4631394fd28SCyril Chemparathy 
464cac87fd3SAxel Lin 	if (rdev->desc->n_voltages == 1)
4651394fd28SCyril Chemparathy 		return -EINVAL;
4661394fd28SCyril Chemparathy 
467f8ee3393SAxel Lin 	return write_field(hw, &info->voltage, selector);
4681394fd28SCyril Chemparathy }
4691394fd28SCyril Chemparathy 
get_voltage_sel(struct regulator_dev * rdev)4704af7c1d3SAxel Lin static int get_voltage_sel(struct regulator_dev *rdev)
4711394fd28SCyril Chemparathy {
4721394fd28SCyril Chemparathy 	const struct supply_info *info;
4731394fd28SCyril Chemparathy 	struct tps6524x *hw;
4741394fd28SCyril Chemparathy 	int ret;
4751394fd28SCyril Chemparathy 
4761394fd28SCyril Chemparathy 	hw	= rdev_get_drvdata(rdev);
4771394fd28SCyril Chemparathy 	info	= &supply_info[rdev_get_id(rdev)];
4781394fd28SCyril Chemparathy 
479cac87fd3SAxel Lin 	if (rdev->desc->n_voltages == 1)
4808386a00fSAxel Lin 		return 0;
4811394fd28SCyril Chemparathy 
4821394fd28SCyril Chemparathy 	ret = read_field(hw, &info->voltage);
4831394fd28SCyril Chemparathy 	if (ret < 0)
4841394fd28SCyril Chemparathy 		return ret;
4851394fd28SCyril Chemparathy 	if (WARN_ON(ret >= info->n_voltages))
4861394fd28SCyril Chemparathy 		return -EIO;
4871394fd28SCyril Chemparathy 
4884af7c1d3SAxel Lin 	return ret;
4891394fd28SCyril Chemparathy }
4901394fd28SCyril Chemparathy 
set_current_limit(struct regulator_dev * rdev,int min_uA,int max_uA)4911394fd28SCyril Chemparathy static int set_current_limit(struct regulator_dev *rdev, int min_uA,
4921394fd28SCyril Chemparathy 			     int max_uA)
4931394fd28SCyril Chemparathy {
4941394fd28SCyril Chemparathy 	const struct supply_info *info;
4951394fd28SCyril Chemparathy 	struct tps6524x *hw;
4961394fd28SCyril Chemparathy 	int i;
4971394fd28SCyril Chemparathy 
4981394fd28SCyril Chemparathy 	hw	= rdev_get_drvdata(rdev);
4991394fd28SCyril Chemparathy 	info	= &supply_info[rdev_get_id(rdev)];
5001394fd28SCyril Chemparathy 
5011e12dfc9SAxel Lin 	if (info->n_ilimsels == 1)
5021394fd28SCyril Chemparathy 		return -EINVAL;
5031394fd28SCyril Chemparathy 
50473f4f3d3SAxel Lin 	for (i = info->n_ilimsels - 1; i >= 0; i--) {
5051394fd28SCyril Chemparathy 		if (min_uA <= info->ilimsels[i] &&
5061394fd28SCyril Chemparathy 		    max_uA >= info->ilimsels[i])
5071394fd28SCyril Chemparathy 			return write_field(hw, &info->ilimsel, i);
5081394fd28SCyril Chemparathy 	}
5091394fd28SCyril Chemparathy 
51073f4f3d3SAxel Lin 	return -EINVAL;
51173f4f3d3SAxel Lin }
51273f4f3d3SAxel Lin 
get_current_limit(struct regulator_dev * rdev)5131394fd28SCyril Chemparathy static int get_current_limit(struct regulator_dev *rdev)
5141394fd28SCyril Chemparathy {
5151394fd28SCyril Chemparathy 	const struct supply_info *info;
5161394fd28SCyril Chemparathy 	struct tps6524x *hw;
5171394fd28SCyril Chemparathy 	int ret;
5181394fd28SCyril Chemparathy 
5191394fd28SCyril Chemparathy 	hw	= rdev_get_drvdata(rdev);
5201394fd28SCyril Chemparathy 	info	= &supply_info[rdev_get_id(rdev)];
5211394fd28SCyril Chemparathy 
5221e12dfc9SAxel Lin 	if (info->n_ilimsels == 1)
5231e12dfc9SAxel Lin 		return info->ilimsels[0];
5241394fd28SCyril Chemparathy 
5251394fd28SCyril Chemparathy 	ret = read_field(hw, &info->ilimsel);
5261394fd28SCyril Chemparathy 	if (ret < 0)
5271394fd28SCyril Chemparathy 		return ret;
5281394fd28SCyril Chemparathy 	if (WARN_ON(ret >= info->n_ilimsels))
5291394fd28SCyril Chemparathy 		return -EIO;
5301394fd28SCyril Chemparathy 
5311394fd28SCyril Chemparathy 	return info->ilimsels[ret];
5321394fd28SCyril Chemparathy }
5331394fd28SCyril Chemparathy 
enable_supply(struct regulator_dev * rdev)5341394fd28SCyril Chemparathy static int enable_supply(struct regulator_dev *rdev)
5351394fd28SCyril Chemparathy {
5361394fd28SCyril Chemparathy 	const struct supply_info *info;
5371394fd28SCyril Chemparathy 	struct tps6524x *hw;
5381394fd28SCyril Chemparathy 
5391394fd28SCyril Chemparathy 	hw	= rdev_get_drvdata(rdev);
5401394fd28SCyril Chemparathy 	info	= &supply_info[rdev_get_id(rdev)];
5411394fd28SCyril Chemparathy 
5421394fd28SCyril Chemparathy 	return write_field(hw, &info->enable, 1);
5431394fd28SCyril Chemparathy }
5441394fd28SCyril Chemparathy 
disable_supply(struct regulator_dev * rdev)5451394fd28SCyril Chemparathy static int disable_supply(struct regulator_dev *rdev)
5461394fd28SCyril Chemparathy {
5471394fd28SCyril Chemparathy 	const struct supply_info *info;
5481394fd28SCyril Chemparathy 	struct tps6524x *hw;
5491394fd28SCyril Chemparathy 
5501394fd28SCyril Chemparathy 	hw	= rdev_get_drvdata(rdev);
5511394fd28SCyril Chemparathy 	info	= &supply_info[rdev_get_id(rdev)];
5521394fd28SCyril Chemparathy 
5531394fd28SCyril Chemparathy 	return write_field(hw, &info->enable, 0);
5541394fd28SCyril Chemparathy }
5551394fd28SCyril Chemparathy 
is_supply_enabled(struct regulator_dev * rdev)5561394fd28SCyril Chemparathy static int is_supply_enabled(struct regulator_dev *rdev)
5571394fd28SCyril Chemparathy {
5581394fd28SCyril Chemparathy 	const struct supply_info *info;
5591394fd28SCyril Chemparathy 	struct tps6524x *hw;
5601394fd28SCyril Chemparathy 
5611394fd28SCyril Chemparathy 	hw	= rdev_get_drvdata(rdev);
5621394fd28SCyril Chemparathy 	info	= &supply_info[rdev_get_id(rdev)];
5631394fd28SCyril Chemparathy 
5641394fd28SCyril Chemparathy 	return read_field(hw, &info->enable);
5651394fd28SCyril Chemparathy }
5661394fd28SCyril Chemparathy 
567357db027SAxel Lin static const struct regulator_ops regulator_ops = {
5681394fd28SCyril Chemparathy 	.is_enabled		= is_supply_enabled,
5691394fd28SCyril Chemparathy 	.enable			= enable_supply,
5701394fd28SCyril Chemparathy 	.disable		= disable_supply,
5714af7c1d3SAxel Lin 	.get_voltage_sel	= get_voltage_sel,
572f8ee3393SAxel Lin 	.set_voltage_sel	= set_voltage_sel,
573cac87fd3SAxel Lin 	.list_voltage		= regulator_list_voltage_table,
574b92f567dSAxel Lin 	.map_voltage		= regulator_map_voltage_ascend,
5751394fd28SCyril Chemparathy 	.set_current_limit	= set_current_limit,
5761394fd28SCyril Chemparathy 	.get_current_limit	= get_current_limit,
5771394fd28SCyril Chemparathy };
5781394fd28SCyril Chemparathy 
pmic_probe(struct spi_device * spi)579a5023574SBill Pemberton static int pmic_probe(struct spi_device *spi)
5801394fd28SCyril Chemparathy {
5811394fd28SCyril Chemparathy 	struct tps6524x *hw;
5821394fd28SCyril Chemparathy 	struct device *dev = &spi->dev;
5831394fd28SCyril Chemparathy 	const struct supply_info *info = supply_info;
5841394fd28SCyril Chemparathy 	struct regulator_init_data *init_data;
585c172708dSMark Brown 	struct regulator_config config = { };
5867a8b0e66SAxel Lin 	struct regulator_dev *rdev;
5875e085575SJingoo Han 	int i;
5881394fd28SCyril Chemparathy 
589dff91d0bSJingoo Han 	init_data = dev_get_platdata(dev);
5901394fd28SCyril Chemparathy 	if (!init_data) {
5911394fd28SCyril Chemparathy 		dev_err(dev, "could not find regulator platform data\n");
5921394fd28SCyril Chemparathy 		return -EINVAL;
5931394fd28SCyril Chemparathy 	}
5941394fd28SCyril Chemparathy 
5959eb0c421SAxel Lin 	hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL);
596516add1dSSachin Kamat 	if (!hw)
5971394fd28SCyril Chemparathy 		return -ENOMEM;
598516add1dSSachin Kamat 
5991394fd28SCyril Chemparathy 	spi_set_drvdata(spi, hw);
6001394fd28SCyril Chemparathy 
6011394fd28SCyril Chemparathy 	memset(hw, 0, sizeof(struct tps6524x));
6021394fd28SCyril Chemparathy 	hw->dev = dev;
603ae714c3bSMark Brown 	hw->spi = spi;
6041394fd28SCyril Chemparathy 	mutex_init(&hw->lock);
6051394fd28SCyril Chemparathy 
6061394fd28SCyril Chemparathy 	for (i = 0; i < N_REGULATORS; i++, info++, init_data++) {
6071394fd28SCyril Chemparathy 		hw->desc[i].name	= info->name;
6081394fd28SCyril Chemparathy 		hw->desc[i].id		= i;
6091394fd28SCyril Chemparathy 		hw->desc[i].n_voltages	= info->n_voltages;
610cac87fd3SAxel Lin 		hw->desc[i].volt_table	= info->voltages;
6111394fd28SCyril Chemparathy 		hw->desc[i].ops		= &regulator_ops;
6121394fd28SCyril Chemparathy 		hw->desc[i].type	= REGULATOR_VOLTAGE;
6131394fd28SCyril Chemparathy 		hw->desc[i].owner	= THIS_MODULE;
6141394fd28SCyril Chemparathy 
615c172708dSMark Brown 		config.dev = dev;
616c172708dSMark Brown 		config.init_data = init_data;
617c172708dSMark Brown 		config.driver_data = hw;
618c172708dSMark Brown 
6197a8b0e66SAxel Lin 		rdev = devm_regulator_register(dev, &hw->desc[i], &config);
6207a8b0e66SAxel Lin 		if (IS_ERR(rdev))
6217a8b0e66SAxel Lin 			return PTR_ERR(rdev);
6221394fd28SCyril Chemparathy 	}
6231394fd28SCyril Chemparathy 
6241394fd28SCyril Chemparathy 	return 0;
6251394fd28SCyril Chemparathy }
6261394fd28SCyril Chemparathy 
6271394fd28SCyril Chemparathy static struct spi_driver pmic_driver = {
6281394fd28SCyril Chemparathy 	.probe		= pmic_probe,
6291394fd28SCyril Chemparathy 	.driver		= {
6301394fd28SCyril Chemparathy 		.name	= "tps6524x",
631*259b93b2SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
6321394fd28SCyril Chemparathy 	},
6331394fd28SCyril Chemparathy };
6341394fd28SCyril Chemparathy 
635173f24d1SMark Brown module_spi_driver(pmic_driver);
6361394fd28SCyril Chemparathy 
6371394fd28SCyril Chemparathy MODULE_DESCRIPTION("TPS6524X PMIC Driver");
6381394fd28SCyril Chemparathy MODULE_AUTHOR("Cyril Chemparathy");
6391394fd28SCyril Chemparathy MODULE_LICENSE("GPL");
6401394fd28SCyril Chemparathy MODULE_ALIAS("spi:tps6524x");
641