blob: 79b3eb3222c68d9cae327407ec5132938bbb1cb7 [file] [log] [blame]
Tony Lindgren0ad4c072017-02-02 15:43:57 -08001/*
2 * Motorola CPCAP PMIC regulator driver
3 *
4 * Based on cpcap-regulator.c from Motorola Linux kernel tree
5 * Copyright (C) 2009-2011 Motorola, Inc.
6 *
7 * Rewritten for mainline kernel to use device tree and regmap
8 * Copyright (C) 2017 Tony Lindgren <tony@atomide.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation version 2.
13 *
14 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
15 * kind, whether express or implied; without even the implied warranty
16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20#include <linux/err.h>
21#include <linux/module.h>
22#include <linux/of.h>
23#include <linux/of_platform.h>
24#include <linux/regmap.h>
25#include <linux/regulator/driver.h>
26#include <linux/regulator/machine.h>
27#include <linux/regulator/of_regulator.h>
28#include <linux/mfd/motorola-cpcap.h>
29
30/*
31 * Resource assignment register bits. These seem to control the state
32 * idle modes adn are used at least for omap4.
33 */
34
35/* CPCAP_REG_ASSIGN2 bits - Resource Assignment 2 */
36#define CPCAP_BIT_VSDIO_SEL BIT(15)
37#define CPCAP_BIT_VDIG_SEL BIT(14)
38#define CPCAP_BIT_VCAM_SEL BIT(13)
39#define CPCAP_BIT_SW6_SEL BIT(12)
40#define CPCAP_BIT_SW5_SEL BIT(11)
41#define CPCAP_BIT_SW4_SEL BIT(10)
42#define CPCAP_BIT_SW3_SEL BIT(9)
43#define CPCAP_BIT_SW2_SEL BIT(8)
44#define CPCAP_BIT_SW1_SEL BIT(7)
45
46/* CPCAP_REG_ASSIGN3 bits - Resource Assignment 3 */
47#define CPCAP_BIT_VUSBINT2_SEL BIT(15)
48#define CPCAP_BIT_VUSBINT1_SEL BIT(14)
49#define CPCAP_BIT_VVIB_SEL BIT(13)
50#define CPCAP_BIT_VWLAN1_SEL BIT(12)
51#define CPCAP_BIT_VRF1_SEL BIT(11)
52#define CPCAP_BIT_VHVIO_SEL BIT(10)
53#define CPCAP_BIT_VDAC_SEL BIT(9)
54#define CPCAP_BIT_VUSB_SEL BIT(8)
55#define CPCAP_BIT_VSIM_SEL BIT(7)
56#define CPCAP_BIT_VRFREF_SEL BIT(6)
57#define CPCAP_BIT_VPLL_SEL BIT(5)
58#define CPCAP_BIT_VFUSE_SEL BIT(4)
59#define CPCAP_BIT_VCSI_SEL BIT(3)
60#define CPCAP_BIT_SPARE_14_2 BIT(2)
61#define CPCAP_BIT_VWLAN2_SEL BIT(1)
62#define CPCAP_BIT_VRF2_SEL BIT(0)
63
64/* CPCAP_REG_ASSIGN4 bits - Resource Assignment 4 */
65#define CPCAP_BIT_VAUDIO_SEL BIT(0)
66
67/*
68 * Enable register bits. At least CPCAP_BIT_AUDIO_LOW_PWR is generic,
69 * and not limited to audio regulator. Let's use the Motorola kernel
70 * naming for now until we have a better understanding of the other
71 * enable register bits. No idea why BIT(3) is not defined.
72 */
73#define CPCAP_BIT_AUDIO_LOW_PWR BIT(6)
74#define CPCAP_BIT_AUD_LOWPWR_SPEED BIT(5)
75#define CPCAP_BIT_VAUDIOPRISTBY BIT(4)
76#define CPCAP_BIT_VAUDIO_MODE1 BIT(2)
77#define CPCAP_BIT_VAUDIO_MODE0 BIT(1)
78#define CPCAP_BIT_V_AUDIO_EN BIT(0)
79
Sebastian Reichel91a024e2017-07-10 16:33:39 +020080#define CPCAP_BIT_AUDIO_NORMAL_MODE 0x00
81
Tony Lindgren0ad4c072017-02-02 15:43:57 -080082/*
83 * Off mode configuration bit. Used currently only by SW5 on omap4. There's
84 * the following comment in Motorola Linux kernel tree for it:
85 *
86 * When set in the regulator mode, the regulator assignment will be changed
87 * to secondary when the regulator is disabled. The mode will be set back to
88 * primary when the regulator is turned on.
89 */
90#define CPCAP_REG_OFF_MODE_SEC BIT(15)
91
Lee Jones7b804ce2020-06-25 17:36:12 +010092/*
Geert Uytterhoeven25a7d032019-06-07 13:26:40 +020093 * SoC specific configuration for CPCAP regulator. There are at least three
Tony Lindgren0ad4c072017-02-02 15:43:57 -080094 * different SoCs each with their own parameters: omap3, omap4 and tegra2.
95 *
96 * The assign_reg and assign_mask seem to allow toggling between primary
97 * and secondary mode that at least omap4 uses for off mode.
98 */
99struct cpcap_regulator {
100 struct regulator_desc rdesc;
101 const u16 assign_reg;
102 const u16 assign_mask;
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800103};
104
105#define CPCAP_REG(_ID, reg, assignment_reg, assignment_mask, val_tbl, \
Axel Linde338732019-02-26 13:52:29 +0800106 mode_mask, volt_mask, mode_val, off_val, \
107 volt_trans_time) { \
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800108 .rdesc = { \
109 .name = #_ID, \
110 .of_match = of_match_ptr(#_ID), \
111 .ops = &cpcap_regulator_ops, \
112 .regulators_node = of_match_ptr("regulators"), \
113 .type = REGULATOR_VOLTAGE, \
114 .id = CPCAP_##_ID, \
115 .owner = THIS_MODULE, \
116 .n_voltages = ARRAY_SIZE(val_tbl), \
117 .volt_table = (val_tbl), \
118 .vsel_reg = (reg), \
119 .vsel_mask = (volt_mask), \
120 .enable_reg = (reg), \
121 .enable_mask = (mode_mask), \
122 .enable_val = (mode_val), \
123 .disable_val = (off_val), \
124 .ramp_delay = (volt_trans_time), \
Sebastian Reichel74ff8e02017-07-10 16:33:40 +0200125 .of_map_mode = cpcap_map_mode, \
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800126 }, \
127 .assign_reg = (assignment_reg), \
128 .assign_mask = (assignment_mask), \
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800129}
130
131struct cpcap_ddata {
132 struct regmap *reg;
133 struct device *dev;
134 const struct cpcap_regulator *soc;
135};
136
137enum cpcap_regulator_id {
138 CPCAP_SW1,
139 CPCAP_SW2,
140 CPCAP_SW3,
141 CPCAP_SW4,
142 CPCAP_SW5,
143 CPCAP_SW6,
144 CPCAP_VCAM,
145 CPCAP_VCSI,
146 CPCAP_VDAC,
147 CPCAP_VDIG,
148 CPCAP_VFUSE,
149 CPCAP_VHVIO,
150 CPCAP_VSDIO,
151 CPCAP_VPLL,
152 CPCAP_VRF1,
153 CPCAP_VRF2,
154 CPCAP_VRFREF,
155 CPCAP_VWLAN1,
156 CPCAP_VWLAN2,
157 CPCAP_VSIM,
158 CPCAP_VSIMCARD,
159 CPCAP_VVIB,
160 CPCAP_VUSB,
161 CPCAP_VAUDIO,
162 CPCAP_NR_REGULATORS,
163};
164
165/*
166 * We need to also configure regulator idle mode for SoC off mode if
167 * CPCAP_REG_OFF_MODE_SEC is set.
168 */
169static int cpcap_regulator_enable(struct regulator_dev *rdev)
170{
171 struct cpcap_regulator *regulator = rdev_get_drvdata(rdev);
Lee Jonesb89a5ef2020-06-25 17:36:11 +0100172 int error;
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800173
174 error = regulator_enable_regmap(rdev);
175 if (error)
176 return error;
177
178 if (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC) {
179 error = regmap_update_bits(rdev->regmap, regulator->assign_reg,
180 regulator->assign_mask,
181 regulator->assign_mask);
182 if (error)
Lee Jonesb89a5ef2020-06-25 17:36:11 +0100183 regulator_disable_regmap(rdev);
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800184 }
185
186 return error;
187}
188
189/*
190 * We need to also configure regulator idle mode for SoC off mode if
191 * CPCAP_REG_OFF_MODE_SEC is set.
192 */
193static int cpcap_regulator_disable(struct regulator_dev *rdev)
194{
195 struct cpcap_regulator *regulator = rdev_get_drvdata(rdev);
Lee Jonesb89a5ef2020-06-25 17:36:11 +0100196 int error;
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800197
198 if (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC) {
199 error = regmap_update_bits(rdev->regmap, regulator->assign_reg,
200 regulator->assign_mask, 0);
201 if (error)
202 return error;
203 }
204
205 error = regulator_disable_regmap(rdev);
206 if (error && (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC)) {
Lee Jonesb89a5ef2020-06-25 17:36:11 +0100207 regmap_update_bits(rdev->regmap, regulator->assign_reg,
208 regulator->assign_mask,
209 regulator->assign_mask);
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800210 }
211
212 return error;
213}
214
Sebastian Reichel74ff8e02017-07-10 16:33:40 +0200215static unsigned int cpcap_map_mode(unsigned int mode)
216{
217 switch (mode) {
218 case CPCAP_BIT_AUDIO_NORMAL_MODE:
219 return REGULATOR_MODE_NORMAL;
220 case CPCAP_BIT_AUDIO_LOW_PWR:
221 return REGULATOR_MODE_STANDBY;
222 default:
Douglas Anderson02f37032018-04-18 08:54:18 -0700223 return REGULATOR_MODE_INVALID;
Sebastian Reichel74ff8e02017-07-10 16:33:40 +0200224 }
225}
226
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800227static unsigned int cpcap_regulator_get_mode(struct regulator_dev *rdev)
228{
229 int value;
230
231 regmap_read(rdev->regmap, rdev->desc->enable_reg, &value);
232
Sebastian Reichel91a024e2017-07-10 16:33:39 +0200233 if (value & CPCAP_BIT_AUDIO_LOW_PWR)
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800234 return REGULATOR_MODE_STANDBY;
235
236 return REGULATOR_MODE_NORMAL;
237}
238
239static int cpcap_regulator_set_mode(struct regulator_dev *rdev,
240 unsigned int mode)
241{
242 int value;
243
244 switch (mode) {
245 case REGULATOR_MODE_NORMAL:
Sebastian Reichel91a024e2017-07-10 16:33:39 +0200246 value = CPCAP_BIT_AUDIO_NORMAL_MODE;
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800247 break;
248 case REGULATOR_MODE_STANDBY:
Sebastian Reichel91a024e2017-07-10 16:33:39 +0200249 value = CPCAP_BIT_AUDIO_LOW_PWR;
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800250 break;
251 default:
252 return -EINVAL;
253 }
254
255 return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
256 CPCAP_BIT_AUDIO_LOW_PWR, value);
257}
258
Rikard Falkebornbcf39c12020-06-18 00:32:44 +0200259static const struct regulator_ops cpcap_regulator_ops = {
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800260 .enable = cpcap_regulator_enable,
261 .disable = cpcap_regulator_disable,
262 .is_enabled = regulator_is_enabled_regmap,
263 .list_voltage = regulator_list_voltage_table,
264 .map_voltage = regulator_map_voltage_iterate,
265 .get_voltage_sel = regulator_get_voltage_sel_regmap,
266 .set_voltage_sel = regulator_set_voltage_sel_regmap,
267 .get_mode = cpcap_regulator_get_mode,
268 .set_mode = cpcap_regulator_set_mode,
269};
270
271static const unsigned int unknown_val_tbl[] = { 0, };
Peter Geisad662252018-07-24 09:25:40 -0400272static const unsigned int sw2_sw4_val_tbl[] = { 612500, 625000, 637500,
273 650000, 662500, 675000,
274 687500, 700000, 712500,
275 725000, 737500, 750000,
276 762500, 775000, 787500,
277 800000, 812500, 825000,
278 837500, 850000, 862500,
279 875000, 887500, 900000,
280 912500, 925000, 937500,
281 950000, 962500, 975000,
282 987500, 1000000, 1012500,
283 1025000, 1037500, 1050000,
284 1062500, 1075000, 1087500,
285 1100000, 1112500, 1125000,
286 1137500, 1150000, 1162500,
287 1175000, 1187500, 1200000,
288 1212500, 1225000, 1237500,
289 1250000, 1262500, 1275000,
290 1287500, 1300000, 1312500,
291 1325000, 1337500, 1350000,
292 1362500, 1375000, 1387500,
293 1400000, 1412500, 1425000,
294 1437500, 1450000, 1462500, };
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800295static const unsigned int sw5_val_tbl[] = { 0, 5050000, };
296static const unsigned int vcam_val_tbl[] = { 2600000, 2700000, 2800000,
297 2900000, };
298static const unsigned int vcsi_val_tbl[] = { 1200000, 1800000, };
299static const unsigned int vdac_val_tbl[] = { 1200000, 1500000, 1800000,
300 2500000,};
301static const unsigned int vdig_val_tbl[] = { 1200000, 1350000, 1500000,
302 1875000, };
303static const unsigned int vfuse_val_tbl[] = { 1500000, 1600000, 1700000,
304 1800000, 1900000, 2000000,
305 2100000, 2200000, 2300000,
306 2400000, 2500000, 2600000,
307 2700000, 3150000, };
308static const unsigned int vhvio_val_tbl[] = { 2775000, };
309static const unsigned int vsdio_val_tbl[] = { 1500000, 1600000, 1800000,
310 2600000, 2700000, 2800000,
311 2900000, 3000000, };
312static const unsigned int vpll_val_tbl[] = { 1200000, 1300000, 1400000,
313 1800000, };
314/* Quirk: 2775000 is before 2500000 for vrf1 regulator */
315static const unsigned int vrf1_val_tbl[] = { 2775000, 2500000, };
316static const unsigned int vrf2_val_tbl[] = { 0, 2775000, };
317static const unsigned int vrfref_val_tbl[] = { 2500000, 2775000, };
318static const unsigned int vwlan1_val_tbl[] = { 1800000, 1900000, };
319static const unsigned int vwlan2_val_tbl[] = { 2775000, 3000000, 3300000,
320 3300000, };
321static const unsigned int vsim_val_tbl[] = { 1800000, 2900000, };
322static const unsigned int vsimcard_val_tbl[] = { 1800000, 2900000, };
323static const unsigned int vvib_val_tbl[] = { 1300000, 1800000, 2000000,
324 3000000, };
325static const unsigned int vusb_val_tbl[] = { 0, 3300000, };
326static const unsigned int vaudio_val_tbl[] = { 0, 2775000, };
327
Lee Jones7b804ce2020-06-25 17:36:12 +0100328/*
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800329 * SoC specific configuration for omap4. The data below is comes from Motorola
330 * Linux kernel tree. It's basically the values of cpcap_regltr_data,
331 * cpcap_regulator_mode_values and cpcap_regulator_off_mode_values, see
332 * CPCAP_REG macro above.
333 *
334 * SW1 to SW4 and SW6 seems to be unused for mapphone. Note that VSIM and
335 * VSIMCARD have a shared resource assignment bit.
336 */
Axel Lin61456012019-02-26 13:52:30 +0800337static const struct cpcap_regulator omap4_regulators[] = {
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800338 CPCAP_REG(SW1, CPCAP_REG_S1C1, CPCAP_REG_ASSIGN2,
339 CPCAP_BIT_SW1_SEL, unknown_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800340 0, 0, 0, 0, 0),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800341 CPCAP_REG(SW2, CPCAP_REG_S2C1, CPCAP_REG_ASSIGN2,
342 CPCAP_BIT_SW2_SEL, unknown_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800343 0, 0, 0, 0, 0),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800344 CPCAP_REG(SW3, CPCAP_REG_S3C, CPCAP_REG_ASSIGN2,
345 CPCAP_BIT_SW3_SEL, unknown_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800346 0, 0, 0, 0, 0),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800347 CPCAP_REG(SW4, CPCAP_REG_S4C1, CPCAP_REG_ASSIGN2,
348 CPCAP_BIT_SW4_SEL, unknown_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800349 0, 0, 0, 0, 0),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800350 CPCAP_REG(SW5, CPCAP_REG_S5C, CPCAP_REG_ASSIGN2,
351 CPCAP_BIT_SW5_SEL, sw5_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800352 0x28, 0, 0x20 | CPCAP_REG_OFF_MODE_SEC, 0, 0),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800353 CPCAP_REG(SW6, CPCAP_REG_S6C, CPCAP_REG_ASSIGN2,
354 CPCAP_BIT_SW6_SEL, unknown_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800355 0, 0, 0, 0, 0),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800356 CPCAP_REG(VCAM, CPCAP_REG_VCAMC, CPCAP_REG_ASSIGN2,
357 CPCAP_BIT_VCAM_SEL, vcam_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800358 0x87, 0x30, 0x3, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800359 CPCAP_REG(VCSI, CPCAP_REG_VCSIC, CPCAP_REG_ASSIGN3,
360 CPCAP_BIT_VCSI_SEL, vcsi_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800361 0x47, 0x10, 0x43, 0x41, 350),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800362 CPCAP_REG(VDAC, CPCAP_REG_VDACC, CPCAP_REG_ASSIGN3,
363 CPCAP_BIT_VDAC_SEL, vdac_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800364 0x87, 0x30, 0x3, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800365 CPCAP_REG(VDIG, CPCAP_REG_VDIGC, CPCAP_REG_ASSIGN2,
366 CPCAP_BIT_VDIG_SEL, vdig_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800367 0x87, 0x30, 0x82, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800368 CPCAP_REG(VFUSE, CPCAP_REG_VFUSEC, CPCAP_REG_ASSIGN3,
369 CPCAP_BIT_VFUSE_SEL, vfuse_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800370 0x80, 0xf, 0x80, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800371 CPCAP_REG(VHVIO, CPCAP_REG_VHVIOC, CPCAP_REG_ASSIGN3,
372 CPCAP_BIT_VHVIO_SEL, vhvio_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800373 0x17, 0, 0, 0x12, 0),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800374 CPCAP_REG(VSDIO, CPCAP_REG_VSDIOC, CPCAP_REG_ASSIGN2,
375 CPCAP_BIT_VSDIO_SEL, vsdio_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800376 0x87, 0x38, 0x82, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800377 CPCAP_REG(VPLL, CPCAP_REG_VPLLC, CPCAP_REG_ASSIGN3,
378 CPCAP_BIT_VPLL_SEL, vpll_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800379 0x43, 0x18, 0x2, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800380 CPCAP_REG(VRF1, CPCAP_REG_VRF1C, CPCAP_REG_ASSIGN3,
381 CPCAP_BIT_VRF1_SEL, vrf1_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800382 0xac, 0x2, 0x4, 0, 10),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800383 CPCAP_REG(VRF2, CPCAP_REG_VRF2C, CPCAP_REG_ASSIGN3,
384 CPCAP_BIT_VRF2_SEL, vrf2_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800385 0x23, 0x8, 0, 0, 10),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800386 CPCAP_REG(VRFREF, CPCAP_REG_VRFREFC, CPCAP_REG_ASSIGN3,
387 CPCAP_BIT_VRFREF_SEL, vrfref_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800388 0x23, 0x8, 0, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800389 CPCAP_REG(VWLAN1, CPCAP_REG_VWLAN1C, CPCAP_REG_ASSIGN3,
390 CPCAP_BIT_VWLAN1_SEL, vwlan1_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800391 0x47, 0x10, 0, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800392 CPCAP_REG(VWLAN2, CPCAP_REG_VWLAN2C, CPCAP_REG_ASSIGN3,
393 CPCAP_BIT_VWLAN2_SEL, vwlan2_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800394 0x20c, 0xc0, 0x20c, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800395 CPCAP_REG(VSIM, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3,
396 0xffff, vsim_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800397 0x23, 0x8, 0x3, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800398 CPCAP_REG(VSIMCARD, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3,
399 0xffff, vsimcard_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800400 0x1e80, 0x8, 0x1e00, 0, 420),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800401 CPCAP_REG(VVIB, CPCAP_REG_VVIBC, CPCAP_REG_ASSIGN3,
402 CPCAP_BIT_VVIB_SEL, vvib_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800403 0x1, 0xc, 0x1, 0, 500),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800404 CPCAP_REG(VUSB, CPCAP_REG_VUSBC, CPCAP_REG_ASSIGN3,
405 CPCAP_BIT_VUSB_SEL, vusb_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800406 0x11c, 0x40, 0xc, 0, 0),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800407 CPCAP_REG(VAUDIO, CPCAP_REG_VAUDIOC, CPCAP_REG_ASSIGN4,
408 CPCAP_BIT_VAUDIO_SEL, vaudio_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800409 0x16, 0x1, 0x4, 0, 0),
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800410 { /* sentinel */ },
411};
412
Axel Lin61456012019-02-26 13:52:30 +0800413static const struct cpcap_regulator xoom_regulators[] = {
Peter Geis6c0b3192018-07-24 09:25:41 -0400414 CPCAP_REG(SW1, CPCAP_REG_S1C1, CPCAP_REG_ASSIGN2,
415 CPCAP_BIT_SW1_SEL, unknown_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800416 0, 0, 0, 0, 0),
Peter Geis6c0b3192018-07-24 09:25:41 -0400417 CPCAP_REG(SW2, CPCAP_REG_S2C1, CPCAP_REG_ASSIGN2,
418 CPCAP_BIT_SW2_SEL, sw2_sw4_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800419 0xf00, 0x7f, 0x800, 0, 120),
Peter Geis6c0b3192018-07-24 09:25:41 -0400420 CPCAP_REG(SW3, CPCAP_REG_S3C, CPCAP_REG_ASSIGN2,
421 CPCAP_BIT_SW3_SEL, unknown_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800422 0, 0, 0, 0, 0),
Peter Geis6c0b3192018-07-24 09:25:41 -0400423 CPCAP_REG(SW4, CPCAP_REG_S4C1, CPCAP_REG_ASSIGN2,
424 CPCAP_BIT_SW4_SEL, sw2_sw4_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800425 0xf00, 0x7f, 0x900, 0, 100),
Peter Geis6c0b3192018-07-24 09:25:41 -0400426 CPCAP_REG(SW5, CPCAP_REG_S5C, CPCAP_REG_ASSIGN2,
427 CPCAP_BIT_SW5_SEL, sw5_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800428 0x2a, 0, 0x22, 0, 0),
Peter Geis6c0b3192018-07-24 09:25:41 -0400429 CPCAP_REG(SW6, CPCAP_REG_S6C, CPCAP_REG_ASSIGN2,
430 CPCAP_BIT_SW6_SEL, unknown_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800431 0, 0, 0, 0, 0),
Peter Geis6c0b3192018-07-24 09:25:41 -0400432 CPCAP_REG(VCAM, CPCAP_REG_VCAMC, CPCAP_REG_ASSIGN2,
433 CPCAP_BIT_VCAM_SEL, vcam_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800434 0x87, 0x30, 0x7, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400435 CPCAP_REG(VCSI, CPCAP_REG_VCSIC, CPCAP_REG_ASSIGN3,
436 CPCAP_BIT_VCSI_SEL, vcsi_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800437 0x47, 0x10, 0x7, 0, 350),
Peter Geis6c0b3192018-07-24 09:25:41 -0400438 CPCAP_REG(VDAC, CPCAP_REG_VDACC, CPCAP_REG_ASSIGN3,
439 CPCAP_BIT_VDAC_SEL, vdac_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800440 0x87, 0x30, 0x3, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400441 CPCAP_REG(VDIG, CPCAP_REG_VDIGC, CPCAP_REG_ASSIGN2,
442 CPCAP_BIT_VDIG_SEL, vdig_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800443 0x87, 0x30, 0x5, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400444 CPCAP_REG(VFUSE, CPCAP_REG_VFUSEC, CPCAP_REG_ASSIGN3,
445 CPCAP_BIT_VFUSE_SEL, vfuse_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800446 0x80, 0xf, 0x80, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400447 CPCAP_REG(VHVIO, CPCAP_REG_VHVIOC, CPCAP_REG_ASSIGN3,
448 CPCAP_BIT_VHVIO_SEL, vhvio_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800449 0x17, 0, 0x2, 0, 0),
Peter Geis6c0b3192018-07-24 09:25:41 -0400450 CPCAP_REG(VSDIO, CPCAP_REG_VSDIOC, CPCAP_REG_ASSIGN2,
451 CPCAP_BIT_VSDIO_SEL, vsdio_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800452 0x87, 0x38, 0x2, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400453 CPCAP_REG(VPLL, CPCAP_REG_VPLLC, CPCAP_REG_ASSIGN3,
454 CPCAP_BIT_VPLL_SEL, vpll_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800455 0x43, 0x18, 0x1, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400456 CPCAP_REG(VRF1, CPCAP_REG_VRF1C, CPCAP_REG_ASSIGN3,
457 CPCAP_BIT_VRF1_SEL, vrf1_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800458 0xac, 0x2, 0xc, 0, 10),
Peter Geis6c0b3192018-07-24 09:25:41 -0400459 CPCAP_REG(VRF2, CPCAP_REG_VRF2C, CPCAP_REG_ASSIGN3,
460 CPCAP_BIT_VRF2_SEL, vrf2_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800461 0x23, 0x8, 0x3, 0, 10),
Peter Geis6c0b3192018-07-24 09:25:41 -0400462 CPCAP_REG(VRFREF, CPCAP_REG_VRFREFC, CPCAP_REG_ASSIGN3,
463 CPCAP_BIT_VRFREF_SEL, vrfref_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800464 0x23, 0x8, 0x3, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400465 CPCAP_REG(VWLAN1, CPCAP_REG_VWLAN1C, CPCAP_REG_ASSIGN3,
466 CPCAP_BIT_VWLAN1_SEL, vwlan1_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800467 0x47, 0x10, 0x5, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400468 CPCAP_REG(VWLAN2, CPCAP_REG_VWLAN2C, CPCAP_REG_ASSIGN3,
469 CPCAP_BIT_VWLAN2_SEL, vwlan2_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800470 0x20c, 0xc0, 0x8, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400471 CPCAP_REG(VSIM, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3,
472 0xffff, vsim_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800473 0x23, 0x8, 0x3, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400474 CPCAP_REG(VSIMCARD, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3,
475 0xffff, vsimcard_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800476 0x1e80, 0x8, 0x1e00, 0, 420),
Peter Geis6c0b3192018-07-24 09:25:41 -0400477 CPCAP_REG(VVIB, CPCAP_REG_VVIBC, CPCAP_REG_ASSIGN3,
478 CPCAP_BIT_VVIB_SEL, vvib_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800479 0x1, 0xc, 0, 0x1, 500),
Peter Geis6c0b3192018-07-24 09:25:41 -0400480 CPCAP_REG(VUSB, CPCAP_REG_VUSBC, CPCAP_REG_ASSIGN3,
481 CPCAP_BIT_VUSB_SEL, vusb_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800482 0x11c, 0x40, 0xc, 0, 0),
Peter Geis6c0b3192018-07-24 09:25:41 -0400483 CPCAP_REG(VAUDIO, CPCAP_REG_VAUDIOC, CPCAP_REG_ASSIGN4,
484 CPCAP_BIT_VAUDIO_SEL, vaudio_val_tbl,
Axel Linde338732019-02-26 13:52:29 +0800485 0x16, 0x1, 0x4, 0, 0),
Peter Geis6c0b3192018-07-24 09:25:41 -0400486 { /* sentinel */ },
487};
488
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800489static const struct of_device_id cpcap_regulator_id_table[] = {
490 {
491 .compatible = "motorola,cpcap-regulator",
492 },
493 {
494 .compatible = "motorola,mapphone-cpcap-regulator",
495 .data = omap4_regulators,
496 },
Peter Geis6c0b3192018-07-24 09:25:41 -0400497 {
498 .compatible = "motorola,xoom-cpcap-regulator",
499 .data = xoom_regulators,
500 },
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800501 {},
502};
503MODULE_DEVICE_TABLE(of, cpcap_regulator_id_table);
504
505static int cpcap_regulator_probe(struct platform_device *pdev)
506{
507 struct cpcap_ddata *ddata;
Axel Linf4192c22019-03-16 22:35:58 +0800508 const struct cpcap_regulator *match_data;
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800509 struct regulator_config config;
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800510 int i;
511
Axel Linf4192c22019-03-16 22:35:58 +0800512 match_data = of_device_get_match_data(&pdev->dev);
513 if (!match_data) {
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800514 dev_err(&pdev->dev, "no configuration data found\n");
515
516 return -ENODEV;
517 }
518
519 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
520 if (!ddata)
521 return -ENOMEM;
522
523 ddata->reg = dev_get_regmap(pdev->dev.parent, NULL);
524 if (!ddata->reg)
525 return -ENODEV;
526
527 ddata->dev = &pdev->dev;
Axel Linf4192c22019-03-16 22:35:58 +0800528 ddata->soc = match_data;
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800529 platform_set_drvdata(pdev, ddata);
530
531 memset(&config, 0, sizeof(config));
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800532 config.dev = &pdev->dev;
533 config.regmap = ddata->reg;
Tony Lindgren0ad4c072017-02-02 15:43:57 -0800534
535 for (i = 0; i < CPCAP_NR_REGULATORS; i++) {
536 const struct cpcap_regulator *regulator = &ddata->soc[i];
537 struct regulator_dev *rdev;
538
539 if (!regulator->rdesc.name)
540 break;
541
542 if (regulator->rdesc.volt_table == unknown_val_tbl)
543 continue;
544
545 config.driver_data = (void *)regulator;
546 rdev = devm_regulator_register(&pdev->dev,
547 &regulator->rdesc,
548 &config);
549 if (IS_ERR(rdev)) {
550 dev_err(&pdev->dev, "failed to register regulator %s\n",
551 regulator->rdesc.name);
552
553 return PTR_ERR(rdev);
554 }
555 }
556
557 return 0;
558}
559
560static struct platform_driver cpcap_regulator_driver = {
561 .probe = cpcap_regulator_probe,
562 .driver = {
563 .name = "cpcap-regulator",
564 .of_match_table = of_match_ptr(cpcap_regulator_id_table),
565 },
566};
567
568module_platform_driver(cpcap_regulator_driver);
569
570MODULE_ALIAS("platform:cpcap-regulator");
571MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
572MODULE_DESCRIPTION("CPCAP regulator driver");
573MODULE_LICENSE("GPL v2");