blob: 5ca6d21305935ae42f4abf88c1aab92df93a50f2 [file] [log] [blame]
Anuj Aggarwal30e65992009-08-21 00:39:31 +05301/*
2 * tps65023-regulator.c
3 *
4 * Supports TPS65023 Regulator
5 *
6 * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation version 2.
11 *
12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
13 * whether express or implied; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/err.h>
22#include <linux/platform_device.h>
23#include <linux/regulator/driver.h>
24#include <linux/regulator/machine.h>
25#include <linux/i2c.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Mark Brown90923352011-06-18 01:18:51 +010027#include <linux/regmap.h>
Anuj Aggarwal30e65992009-08-21 00:39:31 +053028
29/* Register definitions */
30#define TPS65023_REG_VERSION 0
31#define TPS65023_REG_PGOODZ 1
32#define TPS65023_REG_MASK 2
33#define TPS65023_REG_REG_CTRL 3
34#define TPS65023_REG_CON_CTRL 4
35#define TPS65023_REG_CON_CTRL2 5
36#define TPS65023_REG_DEF_CORE 6
37#define TPS65023_REG_DEFSLEW 7
38#define TPS65023_REG_LDO_CTRL 8
39
40/* PGOODZ bitfields */
41#define TPS65023_PGOODZ_PWRFAILZ BIT(7)
42#define TPS65023_PGOODZ_LOWBATTZ BIT(6)
43#define TPS65023_PGOODZ_VDCDC1 BIT(5)
44#define TPS65023_PGOODZ_VDCDC2 BIT(4)
45#define TPS65023_PGOODZ_VDCDC3 BIT(3)
46#define TPS65023_PGOODZ_LDO2 BIT(2)
47#define TPS65023_PGOODZ_LDO1 BIT(1)
48
49/* MASK bitfields */
50#define TPS65023_MASK_PWRFAILZ BIT(7)
51#define TPS65023_MASK_LOWBATTZ BIT(6)
52#define TPS65023_MASK_VDCDC1 BIT(5)
53#define TPS65023_MASK_VDCDC2 BIT(4)
54#define TPS65023_MASK_VDCDC3 BIT(3)
55#define TPS65023_MASK_LDO2 BIT(2)
56#define TPS65023_MASK_LDO1 BIT(1)
57
58/* REG_CTRL bitfields */
59#define TPS65023_REG_CTRL_VDCDC1_EN BIT(5)
60#define TPS65023_REG_CTRL_VDCDC2_EN BIT(4)
61#define TPS65023_REG_CTRL_VDCDC3_EN BIT(3)
62#define TPS65023_REG_CTRL_LDO2_EN BIT(2)
63#define TPS65023_REG_CTRL_LDO1_EN BIT(1)
64
Marcus Folkessonfc999b82011-08-04 13:33:49 +020065/* REG_CTRL2 bitfields */
66#define TPS65023_REG_CTRL2_GO BIT(7)
67#define TPS65023_REG_CTRL2_CORE_ADJ BIT(6)
68#define TPS65023_REG_CTRL2_DCDC2 BIT(2)
Marcus Folkessonf068ad82011-08-08 20:29:32 +020069#define TPS65023_REG_CTRL2_DCDC1 BIT(1)
70#define TPS65023_REG_CTRL2_DCDC3 BIT(0)
71
Anuj Aggarwal30e65992009-08-21 00:39:31 +053072/* Number of step-down converters available */
73#define TPS65023_NUM_DCDC 3
74/* Number of LDO voltage regulators available */
75#define TPS65023_NUM_LDO 2
76/* Number of total regulators available */
77#define TPS65023_NUM_REGULATOR (TPS65023_NUM_DCDC + TPS65023_NUM_LDO)
78
79/* DCDCs */
80#define TPS65023_DCDC_1 0
81#define TPS65023_DCDC_2 1
82#define TPS65023_DCDC_3 2
83/* LDOs */
84#define TPS65023_LDO_1 3
85#define TPS65023_LDO_2 4
86
87#define TPS65023_MAX_REG_ID TPS65023_LDO_2
88
Thomas Elste2d3eda62015-09-21 16:30:47 +020089#define TPS65023_REGULATOR_DCDC(_num, _t, _em) \
90 { \
91 .name = "VDCDC"#_num, \
92 .of_match = of_match_ptr("VDCDC"#_num), \
93 .regulators_node = of_match_ptr("regulators"), \
94 .id = TPS65023_DCDC_##_num, \
95 .n_voltages = ARRAY_SIZE(_t), \
96 .ops = &tps65023_dcdc_ops, \
97 .type = REGULATOR_VOLTAGE, \
98 .owner = THIS_MODULE, \
99 .volt_table = _t, \
100 .vsel_reg = TPS65023_REG_DEF_CORE, \
101 .vsel_mask = ARRAY_SIZE(_t) - 1, \
102 .enable_mask = _em, \
103 .enable_reg = TPS65023_REG_REG_CTRL, \
104 .apply_reg = TPS65023_REG_CON_CTRL2, \
105 .apply_bit = TPS65023_REG_CTRL2_GO, \
106 } \
107
108#define TPS65023_REGULATOR_LDO(_num, _t, _vm) \
109 { \
110 .name = "LDO"#_num, \
111 .of_match = of_match_ptr("LDO"#_num), \
112 .regulators_node = of_match_ptr("regulators"), \
113 .id = TPS65023_LDO_##_num, \
114 .n_voltages = ARRAY_SIZE(_t), \
115 .ops = &tps65023_ldo_ops, \
116 .type = REGULATOR_VOLTAGE, \
117 .owner = THIS_MODULE, \
118 .volt_table = _t, \
119 .vsel_reg = TPS65023_REG_LDO_CTRL, \
120 .vsel_mask = _vm, \
121 .enable_mask = 1 << (_num), \
122 .enable_reg = TPS65023_REG_REG_CTRL, \
123 } \
124
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530125/* Supported voltage values for regulators */
Axel Linba3bd8a2012-06-19 17:12:18 +0800126static const unsigned int VCORE_VSEL_table[] = {
127 800000, 825000, 850000, 875000,
128 900000, 925000, 950000, 975000,
129 1000000, 1025000, 1050000, 1075000,
130 1100000, 1125000, 1150000, 1175000,
131 1200000, 1225000, 1250000, 1275000,
132 1300000, 1325000, 1350000, 1375000,
133 1400000, 1425000, 1450000, 1475000,
134 1500000, 1525000, 1550000, 1600000,
135};
136
137static const unsigned int DCDC_FIXED_3300000_VSEL_table[] = {
138 3300000,
139};
140
141static const unsigned int DCDC_FIXED_1800000_VSEL_table[] = {
142 1800000,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530143};
144
Marcus Folkesson437afd22011-08-08 20:29:35 +0200145/* Supported voltage values for LDO regulators for tps65020 */
Axel Lin20405412013-04-25 11:31:42 +0800146static const unsigned int TPS65020_LDO_VSEL_table[] = {
Axel Linba3bd8a2012-06-19 17:12:18 +0800147 1000000, 1050000, 1100000, 1300000,
148 1800000, 2500000, 3000000, 3300000,
Marcus Folkesson437afd22011-08-08 20:29:35 +0200149};
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200150
151/* Supported voltage values for LDO regulators
152 * for tps65021 and tps65023 */
Axel Linba3bd8a2012-06-19 17:12:18 +0800153static const unsigned int TPS65023_LDO1_VSEL_table[] = {
154 1000000, 1100000, 1300000, 1800000,
155 2200000, 2600000, 2800000, 3150000,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530156};
157
Axel Linba3bd8a2012-06-19 17:12:18 +0800158static const unsigned int TPS65023_LDO2_VSEL_table[] = {
159 1050000, 1200000, 1300000, 1800000,
160 2500000, 2800000, 3000000, 3300000,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530161};
162
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530163/* PMIC details */
164struct tps_pmic {
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530165 struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
Thomas Elste2d3eda62015-09-21 16:30:47 +0200166 const struct tps_driver_data *driver_data;
Mark Brown90923352011-06-18 01:18:51 +0100167 struct regmap *regmap;
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200168};
169
170/* Struct passed as driver data */
171struct tps_driver_data {
Thomas Elste2d3eda62015-09-21 16:30:47 +0200172 const struct regulator_desc *desc;
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200173 u8 core_regulator;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530174};
175
Axel Lina1338292012-06-19 17:13:13 +0800176static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530177{
178 struct tps_pmic *tps = rdev_get_drvdata(dev);
Axel Lin46bcb002013-04-23 11:54:48 +0800179 int dcdc = rdev_get_id(dev);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530180
181 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
182 return -EINVAL;
183
Thomas Elste2d3eda62015-09-21 16:30:47 +0200184 if (dcdc != tps->driver_data->core_regulator)
Axel Lina1338292012-06-19 17:13:13 +0800185 return 0;
Axel Lin46bcb002013-04-23 11:54:48 +0800186
187 return regulator_get_voltage_sel_regmap(dev);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530188}
189
Axel Lin70618732012-03-26 13:46:44 +0800190static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
191 unsigned selector)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530192{
193 struct tps_pmic *tps = rdev_get_drvdata(dev);
194 int dcdc = rdev_get_id(dev);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530195
Thomas Elste2d3eda62015-09-21 16:30:47 +0200196 if (dcdc != tps->driver_data->core_regulator)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530197 return -EINVAL;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530198
Axel Lin46bcb002013-04-23 11:54:48 +0800199 return regulator_set_voltage_sel_regmap(dev, selector);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530200}
201
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530202/* Operations permitted on VDCDCx */
Krzysztof Kozlowski4604a062015-01-05 10:05:48 +0100203static const struct regulator_ops tps65023_dcdc_ops = {
Axel Linee7b1912012-04-16 19:03:09 +0800204 .is_enabled = regulator_is_enabled_regmap,
205 .enable = regulator_enable_regmap,
206 .disable = regulator_disable_regmap,
Axel Lina1338292012-06-19 17:13:13 +0800207 .get_voltage_sel = tps65023_dcdc_get_voltage_sel,
Axel Lin70618732012-03-26 13:46:44 +0800208 .set_voltage_sel = tps65023_dcdc_set_voltage_sel,
Axel Linba3bd8a2012-06-19 17:12:18 +0800209 .list_voltage = regulator_list_voltage_table,
Axel Linc4bbfbd2013-04-25 11:32:40 +0800210 .map_voltage = regulator_map_voltage_ascend,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530211};
212
213/* Operations permitted on LDOx */
Krzysztof Kozlowski4604a062015-01-05 10:05:48 +0100214static const struct regulator_ops tps65023_ldo_ops = {
Axel Linee7b1912012-04-16 19:03:09 +0800215 .is_enabled = regulator_is_enabled_regmap,
216 .enable = regulator_enable_regmap,
217 .disable = regulator_disable_regmap,
Axel Line90a8442012-06-19 17:14:31 +0800218 .get_voltage_sel = regulator_get_voltage_sel_regmap,
219 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Axel Linba3bd8a2012-06-19 17:12:18 +0800220 .list_voltage = regulator_list_voltage_table,
Axel Linc4bbfbd2013-04-25 11:32:40 +0800221 .map_voltage = regulator_map_voltage_ascend,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530222};
223
Krzysztof Kozlowski4604a062015-01-05 10:05:48 +0100224static const struct regmap_config tps65023_regmap_config = {
Mark Brown90923352011-06-18 01:18:51 +0100225 .reg_bits = 8,
226 .val_bits = 8,
227};
228
Thomas Elste2d3eda62015-09-21 16:30:47 +0200229static const struct regulator_desc tps65020_regulators[] = {
230 TPS65023_REGULATOR_DCDC(1, DCDC_FIXED_3300000_VSEL_table, 0x20),
231 TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_1800000_VSEL_table, 0x10),
232 TPS65023_REGULATOR_DCDC(3, VCORE_VSEL_table, 0x08),
233 TPS65023_REGULATOR_LDO(1, TPS65020_LDO_VSEL_table, 0x07),
234 TPS65023_REGULATOR_LDO(2, TPS65020_LDO_VSEL_table, 0x70),
235};
236
237static const struct regulator_desc tps65021_regulators[] = {
238 TPS65023_REGULATOR_DCDC(1, DCDC_FIXED_3300000_VSEL_table, 0x20),
239 TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_1800000_VSEL_table, 0x10),
240 TPS65023_REGULATOR_DCDC(3, VCORE_VSEL_table, 0x08),
241 TPS65023_REGULATOR_LDO(1, TPS65023_LDO1_VSEL_table, 0x07),
242 TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70),
243};
244
245static const struct regulator_desc tps65023_regulators[] = {
246 TPS65023_REGULATOR_DCDC(1, VCORE_VSEL_table, 0x20),
247 TPS65023_REGULATOR_DCDC(2, DCDC_FIXED_3300000_VSEL_table, 0x10),
248 TPS65023_REGULATOR_DCDC(3, DCDC_FIXED_1800000_VSEL_table, 0x08),
249 TPS65023_REGULATOR_LDO(1, TPS65023_LDO1_VSEL_table, 0x07),
250 TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70),
251};
252
253static struct tps_driver_data tps65020_drv_data = {
254 .desc = tps65020_regulators,
255 .core_regulator = TPS65023_DCDC_3,
256};
257
258static struct tps_driver_data tps65021_drv_data = {
259 .desc = tps65021_regulators,
260 .core_regulator = TPS65023_DCDC_3,
261};
262
263static struct tps_driver_data tps65023_drv_data = {
264 .desc = tps65023_regulators,
265 .core_regulator = TPS65023_DCDC_1,
266};
267
Bill Pembertona5023572012-11-19 13:22:22 -0500268static int tps_65023_probe(struct i2c_client *client,
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800269 const struct i2c_device_id *id)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530270{
Thomas Elste2d3eda62015-09-21 16:30:47 +0200271 struct regulator_init_data *init_data = dev_get_platdata(&client->dev);
Mark Brownc1727082012-04-04 00:50:22 +0100272 struct regulator_config config = { };
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530273 struct tps_pmic *tps;
274 int i;
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800275 int error;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530276
Axel Lin19a8da22012-04-07 23:31:44 +0800277 tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530278 if (!tps)
279 return -ENOMEM;
280
Thomas Elste2d3eda62015-09-21 16:30:47 +0200281 tps->driver_data = (struct tps_driver_data *)id->driver_data;
282
Axel Lin19a8da22012-04-07 23:31:44 +0800283 tps->regmap = devm_regmap_init_i2c(client, &tps65023_regmap_config);
Mark Brown90923352011-06-18 01:18:51 +0100284 if (IS_ERR(tps->regmap)) {
285 error = PTR_ERR(tps->regmap);
286 dev_err(&client->dev, "Failed to allocate register map: %d\n",
287 error);
Axel Lin19a8da22012-04-07 23:31:44 +0800288 return error;
Mark Brown90923352011-06-18 01:18:51 +0100289 }
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530290
291 /* common for all regulators */
Thomas Elste2d3eda62015-09-21 16:30:47 +0200292 config.dev = &client->dev;
293 config.driver_data = tps;
294 config.regmap = tps->regmap;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530295
Thomas Elste2d3eda62015-09-21 16:30:47 +0200296 for (i = 0; i < TPS65023_NUM_REGULATOR; i++) {
297 if (init_data)
298 config.init_data = &init_data[i];
Mark Brownc1727082012-04-04 00:50:22 +0100299
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530300 /* Register the regulators */
Thomas Elste2d3eda62015-09-21 16:30:47 +0200301 tps->rdev[i] = devm_regulator_register(&client->dev,
302 &tps->driver_data->desc[i], &config);
303 if (IS_ERR(tps->rdev[i])) {
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530304 dev_err(&client->dev, "failed to register %s\n",
305 id->name);
Thomas Elste2d3eda62015-09-21 16:30:47 +0200306 return PTR_ERR(tps->rdev[i]);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530307 }
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530308 }
309
310 i2c_set_clientdata(client, tps);
311
Marcus Folkessonfc999b82011-08-04 13:33:49 +0200312 /* Enable setting output voltage by I2C */
Jonghwan Choi43530b62011-11-07 08:16:04 +0900313 regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
Richard Cochranc849b4f2017-04-17 10:23:36 +0200314 TPS65023_REG_CTRL2_CORE_ADJ, 0);
Marcus Folkessonfc999b82011-08-04 13:33:49 +0200315
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530316 return 0;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530317}
318
Thomas Elste2d3eda62015-09-21 16:30:47 +0200319static const struct of_device_id tps65023_of_match[] = {
320 { .compatible = "ti,tps65020", .data = &tps65020_drv_data},
321 { .compatible = "ti,tps65021", .data = &tps65021_drv_data},
322 { .compatible = "ti,tps65023", .data = &tps65023_drv_data},
323 {},
Marcus Folkesson437afd22011-08-08 20:29:35 +0200324};
Thomas Elste2d3eda62015-09-21 16:30:47 +0200325MODULE_DEVICE_TABLE(of, tps65023_of_match);
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200326
Liam Girdwood9e108d32009-08-24 10:31:34 +0100327static const struct i2c_device_id tps_65023_id[] = {
Thomas Elste2d3eda62015-09-21 16:30:47 +0200328 {
329 .name = "tps65023",
330 .driver_data = (kernel_ulong_t)&tps65023_drv_data
331 }, {
332 .name = "tps65021",
333 .driver_data = (kernel_ulong_t)&tps65021_drv_data
334 }, {
335 .name = "tps65020",
336 .driver_data = (kernel_ulong_t)&tps65020_drv_data
337 },
Liam Girdwood9e108d32009-08-24 10:31:34 +0100338 { },
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530339};
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530340MODULE_DEVICE_TABLE(i2c, tps_65023_id);
341
342static struct i2c_driver tps_65023_i2c_driver = {
343 .driver = {
344 .name = "tps65023",
Thomas Elste2d3eda62015-09-21 16:30:47 +0200345 .of_match_table = of_match_ptr(tps65023_of_match),
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530346 },
347 .probe = tps_65023_probe,
Liam Girdwood9e108d32009-08-24 10:31:34 +0100348 .id_table = tps_65023_id,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530349};
350
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530351static int __init tps_65023_init(void)
352{
353 return i2c_add_driver(&tps_65023_i2c_driver);
354}
355subsys_initcall(tps_65023_init);
356
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530357static void __exit tps_65023_cleanup(void)
358{
359 i2c_del_driver(&tps_65023_i2c_driver);
360}
361module_exit(tps_65023_cleanup);
362
363MODULE_AUTHOR("Texas Instruments");
364MODULE_DESCRIPTION("TPS65023 voltage regulator driver");
Liam Girdwood9e108d32009-08-24 10:31:34 +0100365MODULE_LICENSE("GPL v2");