tps65023-regulator.c revision fc999b83799074832367d3cfd724c341c849a7da
130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/*
230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * tps65023-regulator.c
330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal *
430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * Supports TPS65023 Regulator
530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal *
630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/
730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal *
830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * This program is free software; you can redistribute it and/or
930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * modify it under the terms of the GNU General Public License as
1030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * published by the Free Software Foundation version 2.
1130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal *
1230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
1330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * whether express or implied; without even the implied warranty of
1430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * General Public License for more details.
1630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal */
1730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
1830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/kernel.h>
1930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/module.h>
2030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/init.h>
2130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/err.h>
2230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/platform_device.h>
2330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/regulator/driver.h>
2430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/regulator/machine.h>
2530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/i2c.h>
2630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#include <linux/delay.h>
275a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
2890923351d480fffd0d24646db83f6f8315eed0d9Mark Brown#include <linux/regmap.h>
2930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
3030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Register definitions */
3130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_REG_VERSION		0
3230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_REG_PGOODZ		1
3330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_REG_MASK		2
3430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_REG_REG_CTRL		3
3530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_REG_CON_CTRL		4
3630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_REG_CON_CTRL2		5
3730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_REG_DEF_CORE		6
3830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_REG_DEFSLEW		7
3930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_REG_LDO_CTRL		8
4030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
4130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* PGOODZ bitfields */
4230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_PGOODZ_PWRFAILZ	BIT(7)
4330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_PGOODZ_LOWBATTZ	BIT(6)
4430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_PGOODZ_VDCDC1		BIT(5)
4530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_PGOODZ_VDCDC2		BIT(4)
4630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_PGOODZ_VDCDC3		BIT(3)
4730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_PGOODZ_LDO2		BIT(2)
4830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_PGOODZ_LDO1		BIT(1)
4930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
5030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* MASK bitfields */
5130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_MASK_PWRFAILZ		BIT(7)
5230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_MASK_LOWBATTZ		BIT(6)
5330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_MASK_VDCDC1		BIT(5)
5430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_MASK_VDCDC2		BIT(4)
5530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_MASK_VDCDC3		BIT(3)
5630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_MASK_LDO2		BIT(2)
5730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define	TPS65023_MASK_LDO1		BIT(1)
5830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
5930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* REG_CTRL bitfields */
6030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CTRL_VDCDC1_EN	BIT(5)
6130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CTRL_VDCDC2_EN	BIT(4)
6230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CTRL_VDCDC3_EN	BIT(3)
6330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CTRL_LDO2_EN	BIT(2)
6430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_REG_CTRL_LDO1_EN	BIT(1)
6530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
66fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson/* REG_CTRL2 bitfields */
67fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson#define TPS65023_REG_CTRL2_GO		BIT(7)
68fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson#define TPS65023_REG_CTRL2_CORE_ADJ	BIT(6)
69fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson#define TPS65023_REG_CTRL2_DCDC2	BIT(2)
70fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson#define TPS65023_REG_CTRL2_DCDC1	BIT(2)
71fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson#define TPS65023_REG_CTRL2_DCDC3	BIT(0)
72fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson
7330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* LDO_CTRL bitfields */
7430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id)	((ldo_id)*4)
7530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id)	(0xF0 >> ((ldo_id)*4))
7630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
7730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Number of step-down converters available */
7830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_NUM_DCDC		3
7930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Number of LDO voltage regulators  available */
8030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_NUM_LDO		2
8130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Number of total regulators available */
8230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_NUM_REGULATOR	(TPS65023_NUM_DCDC + TPS65023_NUM_LDO)
8330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
8430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* DCDCs */
8530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_DCDC_1			0
8630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_DCDC_2			1
8730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_DCDC_3			2
8830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* LDOs */
8930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_LDO_1			3
9030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_LDO_2			4
9130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
9230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal#define TPS65023_MAX_REG_ID		TPS65023_LDO_2
9330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
9430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Supported voltage values for regulators */
9530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic const u16 VDCDC1_VSEL_table[] = {
9630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	800, 825, 850, 875,
9730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	900, 925, 950, 975,
9830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	1000, 1025, 1050, 1075,
9930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	1100, 1125, 1150, 1175,
10030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	1200, 1225, 1250, 1275,
10130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	1300, 1325, 1350, 1375,
10230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	1400, 1425, 1450, 1475,
10330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	1500, 1525, 1550, 1600,
10430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal};
10530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
10630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic const u16 LDO1_VSEL_table[] = {
10730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	1000, 1100, 1300, 1800,
10830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	2200, 2600, 2800, 3150,
10930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal};
11030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
11130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic const u16 LDO2_VSEL_table[] = {
11230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	1050, 1200, 1300, 1800,
11330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	2500, 2800, 3000, 3300,
11430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal};
11530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
11630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic unsigned int num_voltages[] = {ARRAY_SIZE(VDCDC1_VSEL_table),
11730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal				0, 0, ARRAY_SIZE(LDO1_VSEL_table),
11830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal				ARRAY_SIZE(LDO2_VSEL_table)};
11930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
12030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Regulator specific details */
12130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstruct tps_info {
12230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	const char *name;
12330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	unsigned min_uV;
12430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	unsigned max_uV;
12530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	bool fixed;
12630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	u8 table_len;
12730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	const u16 *table;
12830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal};
12930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
13030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* PMIC details */
13130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstruct tps_pmic {
13230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct regulator_desc desc[TPS65023_NUM_REGULATOR];
13330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct i2c_client *client;
13430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
13530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	const struct tps_info *info[TPS65023_NUM_REGULATOR];
13690923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	struct regmap *regmap;
13730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal};
13830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
13930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps_65023_set_bits(struct tps_pmic *tps, u8 reg, u8 mask)
14030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
14190923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	return regmap_update_bits(tps->regmap, reg, mask, mask);
14230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
14330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
14430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps_65023_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask)
14530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
14690923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	return regmap_update_bits(tps->regmap, reg, mask, 0);
14730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
14830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
14930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps_65023_reg_read(struct tps_pmic *tps, u8 reg)
15030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
15190923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	unsigned int val;
15290923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	int ret;
15330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
15490923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	ret = regmap_read(tps->regmap, reg, &val);
15530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
15690923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	if (ret != 0)
15790923351d480fffd0d24646db83f6f8315eed0d9Mark Brown		return ret;
15890923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	else
15990923351d480fffd0d24646db83f6f8315eed0d9Mark Brown		return val;
16030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
16130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
16230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps_65023_reg_write(struct tps_pmic *tps, u8 reg, u8 val)
16330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
16490923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	return regmap_write(tps->regmap, reg, val);
16530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
16630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
16730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_is_enabled(struct regulator_dev *dev)
16830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
16930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
17030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int data, dcdc = rdev_get_id(dev);
17130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	u8 shift;
17230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
17330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
17430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
17530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
17630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	shift = TPS65023_NUM_REGULATOR - dcdc;
17730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	data = tps_65023_reg_read(tps, TPS65023_REG_REG_CTRL);
17830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
17930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (data < 0)
18030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return data;
18130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	else
18230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return (data & 1<<shift) ? 1 : 0;
18330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
18430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
18530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_is_enabled(struct regulator_dev *dev)
18630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
18730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
18830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int data, ldo = rdev_get_id(dev);
18930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	u8 shift;
19030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
19130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
19230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
19330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
19430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
19530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	data = tps_65023_reg_read(tps, TPS65023_REG_REG_CTRL);
19630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
19730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (data < 0)
19830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return data;
19930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	else
20030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return (data & 1<<shift) ? 1 : 0;
20130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
20230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
20330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_enable(struct regulator_dev *dev)
20430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
20530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
20630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int dcdc = rdev_get_id(dev);
20730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	u8 shift;
20830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
20930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
21030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
21130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
21230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	shift = TPS65023_NUM_REGULATOR - dcdc;
21330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	return tps_65023_set_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift);
21430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
21530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
21630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_disable(struct regulator_dev *dev)
21730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
21830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
21930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int dcdc = rdev_get_id(dev);
22030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	u8 shift;
22130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
22230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
22330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
22430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
22530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	shift = TPS65023_NUM_REGULATOR - dcdc;
22630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	return tps_65023_clear_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift);
22730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
22830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
22930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_enable(struct regulator_dev *dev)
23030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
23130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
23230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int ldo = rdev_get_id(dev);
23330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	u8 shift;
23430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
23530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
23630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
23730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
23830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
23930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	return tps_65023_set_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift);
24030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
24130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
24230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_disable(struct regulator_dev *dev)
24330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
24430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
24530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int ldo = rdev_get_id(dev);
24630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	u8 shift;
24730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
24830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
24930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
25030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
25130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
25230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	return tps_65023_clear_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift);
25330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
25430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
25530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
25630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
25730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
25830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int data, dcdc = rdev_get_id(dev);
25930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
26030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
26130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
26230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
26330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (dcdc == TPS65023_DCDC_1) {
26430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		data = tps_65023_reg_read(tps, TPS65023_REG_DEF_CORE);
26530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		if (data < 0)
26630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal			return data;
26730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		data &= (tps->info[dcdc]->table_len - 1);
26830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return tps->info[dcdc]->table[data] * 1000;
26930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	} else
27030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return tps->info[dcdc]->min_uV;
27130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
27230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
27330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
2743a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown				     int min_uV, int max_uV,
2753a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown				     unsigned *selector)
27630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
27730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
27830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int dcdc = rdev_get_id(dev);
27930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int vsel;
28030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
28130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (dcdc != TPS65023_DCDC_1)
28230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
28330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
28430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (min_uV < tps->info[dcdc]->min_uV
28530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal			|| min_uV > tps->info[dcdc]->max_uV)
28630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
28730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (max_uV < tps->info[dcdc]->min_uV
28830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal			|| max_uV > tps->info[dcdc]->max_uV)
28930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
29030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
29130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
29230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		int mV = tps->info[dcdc]->table[vsel];
29330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		int uV = mV * 1000;
29430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
29530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		/* Break at the first in-range value */
29630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		if (min_uV <= uV && uV <= max_uV)
29730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal			break;
29830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	}
29930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
3003a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown	*selector = vsel;
3013a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown
30230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	/* write to the register in case we found a match */
30330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (vsel == tps->info[dcdc]->table_len)
30430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
30530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	else
30630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return tps_65023_reg_write(tps, TPS65023_REG_DEF_CORE, vsel);
30730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
30830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
30930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_get_voltage(struct regulator_dev *dev)
31030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
31130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
31230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int data, ldo = rdev_get_id(dev);
31330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
31430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
31530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
31630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
31730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL);
31830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (data < 0)
31930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return data;
32030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
32130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1));
32230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	data &= (tps->info[ldo]->table_len - 1);
32330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	return tps->info[ldo]->table[data] * 1000;
32430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
32530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
32630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_set_voltage(struct regulator_dev *dev,
3273a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown				    int min_uV, int max_uV, unsigned *selector)
32830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
32930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
33030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int data, vsel, ldo = rdev_get_id(dev);
33130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
33230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
33330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
33430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
33530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV)
33630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
33730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV)
33830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
33930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
34030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) {
34130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		int mV = tps->info[ldo]->table[vsel];
34230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		int uV = mV * 1000;
34330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
34430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		/* Break at the first in-range value */
34530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		if (min_uV <= uV && uV <= max_uV)
34630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal			break;
34730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	}
34830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
34930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (vsel == tps->info[ldo]->table_len)
35030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
35130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
3523a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown	*selector = vsel;
3533a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown
35430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL);
35530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (data < 0)
35630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return data;
35730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
35830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	data &= TPS65023_LDO_CTRL_LDOx_MASK(ldo - TPS65023_LDO_1);
35930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	data |= (vsel << (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1)));
36030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	return tps_65023_reg_write(tps, TPS65023_REG_LDO_CTRL, data);
36130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
36230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
36330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
36430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal					unsigned selector)
36530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
36630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
36730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int dcdc = rdev_get_id(dev);
36830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
36930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
37030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
37130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
37230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (dcdc == TPS65023_DCDC_1) {
37330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		if (selector >= tps->info[dcdc]->table_len)
37430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal			return -EINVAL;
37530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		else
37630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal			return tps->info[dcdc]->table[selector] * 1000;
37730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	} else
37830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return tps->info[dcdc]->min_uV;
37930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
38030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
38130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int tps65023_ldo_list_voltage(struct regulator_dev *dev,
38230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal					unsigned selector)
38330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
38430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = rdev_get_drvdata(dev);
38530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int ldo = rdev_get_id(dev);
38630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
38730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
38830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
38930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
39030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (selector >= tps->info[ldo]->table_len)
39130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EINVAL;
39230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	else
39330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return tps->info[ldo]->table[selector] * 1000;
39430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
39530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
39630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Operations permitted on VDCDCx */
39730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic struct regulator_ops tps65023_dcdc_ops = {
39830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.is_enabled = tps65023_dcdc_is_enabled,
39930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.enable = tps65023_dcdc_enable,
40030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.disable = tps65023_dcdc_disable,
40130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.get_voltage = tps65023_dcdc_get_voltage,
40230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.set_voltage = tps65023_dcdc_set_voltage,
40330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.list_voltage = tps65023_dcdc_list_voltage,
40430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal};
40530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
40630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/* Operations permitted on LDOx */
40730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic struct regulator_ops tps65023_ldo_ops = {
40830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.is_enabled = tps65023_ldo_is_enabled,
40930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.enable = tps65023_ldo_enable,
41030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.disable = tps65023_ldo_disable,
41130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.get_voltage = tps65023_ldo_get_voltage,
41230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.set_voltage = tps65023_ldo_set_voltage,
41330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.list_voltage = tps65023_ldo_list_voltage,
41430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal};
41530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
41690923351d480fffd0d24646db83f6f8315eed0d9Mark Brownstatic struct regmap_config tps65023_regmap_config = {
41790923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	.reg_bits = 8,
41890923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	.val_bits = 8,
41990923351d480fffd0d24646db83f6f8315eed0d9Mark Brown};
42090923351d480fffd0d24646db83f6f8315eed0d9Mark Brown
42154d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhovstatic int __devinit tps_65023_probe(struct i2c_client *client,
42254d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov				     const struct i2c_device_id *id)
42330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
42430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	const struct tps_info *info = (void *)id->driver_data;
42530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct regulator_init_data *init_data;
42630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct regulator_dev *rdev;
42730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps;
42830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int i;
42954d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov	int error;
43030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
43130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
43230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EIO;
43330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
43430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	/**
43530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	 * init_data points to array of regulator_init structures
43630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	 * coming from the board-evm file.
43730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	 */
43830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	init_data = client->dev.platform_data;
43930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (!init_data)
44030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -EIO;
44130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
44230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	tps = kzalloc(sizeof(*tps), GFP_KERNEL);
44330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	if (!tps)
44430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		return -ENOMEM;
44530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
44690923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	tps->regmap = regmap_init_i2c(client, &tps65023_regmap_config);
44790923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	if (IS_ERR(tps->regmap)) {
44890923351d480fffd0d24646db83f6f8315eed0d9Mark Brown		error = PTR_ERR(tps->regmap);
44990923351d480fffd0d24646db83f6f8315eed0d9Mark Brown		dev_err(&client->dev, "Failed to allocate register map: %d\n",
45090923351d480fffd0d24646db83f6f8315eed0d9Mark Brown			error);
45190923351d480fffd0d24646db83f6f8315eed0d9Mark Brown		goto fail_alloc;
45290923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	}
45330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
45430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	/* common for all regulators */
45530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	tps->client = client;
45630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
45730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
45830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		/* Store regulator specific information */
45930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		tps->info[i] = info;
46030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
46130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		tps->desc[i].name = info->name;
46277fa44d0e10711e899788c58fe53f8f7b18c7f67Axel Lin		tps->desc[i].id = i;
46330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		tps->desc[i].n_voltages = num_voltages[i];
46430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
46530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal					&tps65023_ldo_ops : &tps65023_dcdc_ops);
46630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		tps->desc[i].type = REGULATOR_VOLTAGE;
46730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		tps->desc[i].owner = THIS_MODULE;
46830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
46930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		/* Register the regulators */
47030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		rdev = regulator_register(&tps->desc[i], &client->dev,
47154d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov					  init_data, tps);
47230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		if (IS_ERR(rdev)) {
47330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal			dev_err(&client->dev, "failed to register %s\n",
47430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal				id->name);
47554d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov			error = PTR_ERR(rdev);
47654d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov			goto fail;
47730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		}
47830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
47930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		/* Save regulator for cleanup */
48030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		tps->rdev[i] = rdev;
48130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	}
48230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
48330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	i2c_set_clientdata(client, tps);
48430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
485fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson	/* Enable setting output voltage by I2C */
486fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson	tps_65023_clear_bits(tps, TPS65023_REG_CON_CTRL2,
487fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson						TPS65023_REG_CTRL2_CORE_ADJ);
488fc999b83799074832367d3cfd724c341c849a7daMarcus Folkesson
48930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	return 0;
49054d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov
49154d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov fail:
49254d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov	while (--i >= 0)
49354d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov		regulator_unregister(tps->rdev[i]);
49454d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov
49590923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	regmap_exit(tps->regmap);
49690923351d480fffd0d24646db83f6f8315eed0d9Mark Brown fail_alloc:
49754d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov	kfree(tps);
49854d13ab1038911249fc5769efee87fed000623c0Dmitry Torokhov	return error;
49930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
50030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
50130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/**
50230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * tps_65023_remove - TPS65023 driver i2c remove handler
50330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * @client: i2c driver client device structure
50430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal *
50530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * Unregister TPS driver as an i2c client device driver
50630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal */
50730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int __devexit tps_65023_remove(struct i2c_client *client)
50830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
50930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	struct tps_pmic *tps = i2c_get_clientdata(client);
51030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	int i;
51130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
51230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	for (i = 0; i < TPS65023_NUM_REGULATOR; i++)
51330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		regulator_unregister(tps->rdev[i]);
51430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
51590923351d480fffd0d24646db83f6f8315eed0d9Mark Brown	regmap_exit(tps->regmap);
51630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	kfree(tps);
51730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
51830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	return 0;
51930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
52030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
52130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic const struct tps_info tps65023_regs[] = {
52230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	{
52330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.name = "VDCDC1",
52430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.min_uV =  800000,
52530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.max_uV = 1600000,
52630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.table_len = ARRAY_SIZE(VDCDC1_VSEL_table),
52730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.table = VDCDC1_VSEL_table,
52830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	},
52930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	{
53030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.name = "VDCDC2",
53130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.min_uV =  3300000,
53230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.max_uV = 3300000,
53330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.fixed = 1,
53430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	},
53530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	{
53630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.name = "VDCDC3",
53730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.min_uV =  1800000,
53830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.max_uV = 1800000,
53930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.fixed = 1,
54030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	},
54130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	{
54230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.name = "LDO1",
54330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.min_uV = 1000000,
54430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.max_uV = 3150000,
54530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
54630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.table = LDO1_VSEL_table,
54730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	},
54830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	{
54930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.name = "LDO2",
55030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.min_uV = 1050000,
55130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.max_uV = 3300000,
55230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
55330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.table = LDO2_VSEL_table,
55430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	},
55530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal};
55630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
5579e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam Girdwoodstatic const struct i2c_device_id tps_65023_id[] = {
5589e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam Girdwood	{.name = "tps65023",
5599e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam Girdwood	.driver_data = (unsigned long) tps65023_regs,},
5601880a2fc59d2afabc142a311497cf7c320d64506Marek Vasut	{.name = "tps65021",
5611880a2fc59d2afabc142a311497cf7c320d64506Marek Vasut	.driver_data = (unsigned long) tps65023_regs,},
5629e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam Girdwood	{ },
56330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal};
56430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
56530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj AggarwalMODULE_DEVICE_TABLE(i2c, tps_65023_id);
56630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
56730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic struct i2c_driver tps_65023_i2c_driver = {
56830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.driver = {
56930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.name = "tps65023",
57030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal		.owner = THIS_MODULE,
57130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	},
57230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.probe = tps_65023_probe,
57330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	.remove = __devexit_p(tps_65023_remove),
5749e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam Girdwood	.id_table = tps_65023_id,
57530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal};
57630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
57730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/**
57830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * tps_65023_init
57930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal *
58030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * Module init function
58130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal */
58230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic int __init tps_65023_init(void)
58330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
58430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	return i2c_add_driver(&tps_65023_i2c_driver);
58530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
58630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalsubsys_initcall(tps_65023_init);
58730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
58830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal/**
58930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * tps_65023_cleanup
59030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal *
59130e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal * Module exit function
59230e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal */
59330e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalstatic void __exit tps_65023_cleanup(void)
59430e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal{
59530e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal	i2c_del_driver(&tps_65023_i2c_driver);
59630e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal}
59730e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwalmodule_exit(tps_65023_cleanup);
59830e6599d317ec83c664f341f18b5b2b57b831a6dAnuj Aggarwal
59930e6599d317ec83c664f341f18b5b2b57b831a6dAnuj AggarwalMODULE_AUTHOR("Texas Instruments");
60030e6599d317ec83c664f341f18b5b2b57b831a6dAnuj AggarwalMODULE_DESCRIPTION("TPS65023 voltage regulator driver");
6019e108d33edcb88bac3db39ba1683fc2c0591d7d4Liam GirdwoodMODULE_LICENSE("GPL v2");
602