This source file includes following definitions.
- mcp16502_of_map_mode
- mcp16502_gpio_set_mode
- mcp16502_get_reg
- mcp16502_get_mode
- _mcp16502_set_mode
- mcp16502_set_mode
- mcp16502_get_status
- mcp16502_suspend_get_target_reg
- mcp16502_set_suspend_voltage
- mcp16502_set_suspend_mode
- mcp16502_set_suspend_enable
- mcp16502_set_suspend_disable
- mcp16502_probe
- mcp16502_suspend_noirq
- mcp16502_resume_noirq
1
2
3
4
5
6
7
8
9
10
11 #include <linux/gpio.h>
12 #include <linux/i2c.h>
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/regmap.h>
18 #include <linux/regulator/driver.h>
19 #include <linux/suspend.h>
20 #include <linux/gpio/consumer.h>
21
22 #define VDD_LOW_SEL 0x0D
23 #define VDD_HIGH_SEL 0x3F
24
25 #define MCP16502_FLT BIT(7)
26 #define MCP16502_ENS BIT(0)
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 #define MCP16502_BASE(i) (((i) + 1) << 4)
58 #define MCP16502_STAT_BASE(i) ((i) + 5)
59
60 #define MCP16502_OFFSET_MODE_A 0
61 #define MCP16502_OFFSET_MODE_LPM 1
62 #define MCP16502_OFFSET_MODE_HIB 2
63
64 #define MCP16502_OPMODE_ACTIVE REGULATOR_MODE_NORMAL
65 #define MCP16502_OPMODE_LPM REGULATOR_MODE_IDLE
66 #define MCP16502_OPMODE_HIB REGULATOR_MODE_STANDBY
67
68 #define MCP16502_MODE_AUTO_PFM 0
69 #define MCP16502_MODE_FPWM BIT(6)
70
71 #define MCP16502_VSEL 0x3F
72 #define MCP16502_EN BIT(7)
73 #define MCP16502_MODE BIT(6)
74
75 #define MCP16502_MIN_REG 0x0
76 #define MCP16502_MAX_REG 0x65
77
78 static unsigned int mcp16502_of_map_mode(unsigned int mode)
79 {
80 if (mode == REGULATOR_MODE_NORMAL || mode == REGULATOR_MODE_IDLE)
81 return mode;
82
83 return REGULATOR_MODE_INVALID;
84 }
85
86 #define MCP16502_REGULATOR(_name, _id, _ranges, _ops) \
87 [_id] = { \
88 .name = _name, \
89 .regulators_node = of_match_ptr("regulators"), \
90 .id = _id, \
91 .ops = &(_ops), \
92 .type = REGULATOR_VOLTAGE, \
93 .owner = THIS_MODULE, \
94 .n_voltages = MCP16502_VSEL + 1, \
95 .linear_ranges = _ranges, \
96 .n_linear_ranges = ARRAY_SIZE(_ranges), \
97 .of_match = of_match_ptr(_name), \
98 .of_map_mode = mcp16502_of_map_mode, \
99 .vsel_reg = (((_id) + 1) << 4), \
100 .vsel_mask = MCP16502_VSEL, \
101 .enable_reg = (((_id) + 1) << 4), \
102 .enable_mask = MCP16502_EN, \
103 }
104
105 enum {
106 BUCK1 = 0,
107 BUCK2,
108 BUCK3,
109 BUCK4,
110 LDO1,
111 LDO2,
112 NUM_REGULATORS
113 };
114
115
116
117
118
119
120
121 struct mcp16502 {
122 struct gpio_desc *lpm;
123 };
124
125
126
127
128
129
130 static void mcp16502_gpio_set_mode(struct mcp16502 *mcp, int mode)
131 {
132 switch (mode) {
133 case MCP16502_OPMODE_ACTIVE:
134 gpiod_set_value(mcp->lpm, 0);
135 break;
136 case MCP16502_OPMODE_LPM:
137 case MCP16502_OPMODE_HIB:
138 gpiod_set_value(mcp->lpm, 1);
139 break;
140 default:
141 pr_err("%s: %d invalid\n", __func__, mode);
142 }
143 }
144
145
146
147
148
149
150
151 static int mcp16502_get_reg(struct regulator_dev *rdev, int opmode)
152 {
153 int reg = MCP16502_BASE(rdev_get_id(rdev));
154
155 switch (opmode) {
156 case MCP16502_OPMODE_ACTIVE:
157 return reg + MCP16502_OFFSET_MODE_A;
158 case MCP16502_OPMODE_LPM:
159 return reg + MCP16502_OFFSET_MODE_LPM;
160 case MCP16502_OPMODE_HIB:
161 return reg + MCP16502_OFFSET_MODE_HIB;
162 default:
163 return -EINVAL;
164 }
165 }
166
167
168
169
170
171
172
173
174
175
176 static unsigned int mcp16502_get_mode(struct regulator_dev *rdev)
177 {
178 unsigned int val;
179 int ret, reg;
180
181 reg = mcp16502_get_reg(rdev, MCP16502_OPMODE_ACTIVE);
182 if (reg < 0)
183 return reg;
184
185 ret = regmap_read(rdev->regmap, reg, &val);
186 if (ret)
187 return ret;
188
189 switch (val & MCP16502_MODE) {
190 case MCP16502_MODE_FPWM:
191 return REGULATOR_MODE_NORMAL;
192 case MCP16502_MODE_AUTO_PFM:
193 return REGULATOR_MODE_IDLE;
194 default:
195 return REGULATOR_MODE_INVALID;
196 }
197 }
198
199
200
201
202
203
204
205
206 static int _mcp16502_set_mode(struct regulator_dev *rdev, unsigned int mode,
207 unsigned int op_mode)
208 {
209 int val;
210 int reg;
211
212 reg = mcp16502_get_reg(rdev, op_mode);
213 if (reg < 0)
214 return reg;
215
216 switch (mode) {
217 case REGULATOR_MODE_NORMAL:
218 val = MCP16502_MODE_FPWM;
219 break;
220 case REGULATOR_MODE_IDLE:
221 val = MCP16502_MODE_AUTO_PFM;
222 break;
223 default:
224 return -EINVAL;
225 }
226
227 reg = regmap_update_bits(rdev->regmap, reg, MCP16502_MODE, val);
228 return reg;
229 }
230
231
232
233
234 static int mcp16502_set_mode(struct regulator_dev *rdev, unsigned int mode)
235 {
236 return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_ACTIVE);
237 }
238
239
240
241
242 static int mcp16502_get_status(struct regulator_dev *rdev)
243 {
244 int ret;
245 unsigned int val;
246
247 ret = regmap_read(rdev->regmap, MCP16502_STAT_BASE(rdev_get_id(rdev)),
248 &val);
249 if (ret)
250 return ret;
251
252 if (val & MCP16502_FLT)
253 return REGULATOR_STATUS_ERROR;
254 else if (val & MCP16502_ENS)
255 return REGULATOR_STATUS_ON;
256 else if (!(val & MCP16502_ENS))
257 return REGULATOR_STATUS_OFF;
258
259 return REGULATOR_STATUS_UNDEFINED;
260 }
261
262 #ifdef CONFIG_SUSPEND
263
264
265
266
267 static int mcp16502_suspend_get_target_reg(struct regulator_dev *rdev)
268 {
269 switch (pm_suspend_target_state) {
270 case PM_SUSPEND_STANDBY:
271 return mcp16502_get_reg(rdev, MCP16502_OPMODE_LPM);
272 case PM_SUSPEND_ON:
273 case PM_SUSPEND_MEM:
274 return mcp16502_get_reg(rdev, MCP16502_OPMODE_HIB);
275 default:
276 dev_err(&rdev->dev, "invalid suspend target: %d\n",
277 pm_suspend_target_state);
278 }
279
280 return -EINVAL;
281 }
282
283
284
285
286 static int mcp16502_set_suspend_voltage(struct regulator_dev *rdev, int uV)
287 {
288 int sel = regulator_map_voltage_linear_range(rdev, uV, uV);
289 int reg = mcp16502_suspend_get_target_reg(rdev);
290
291 if (sel < 0)
292 return sel;
293
294 if (reg < 0)
295 return reg;
296
297 return regmap_update_bits(rdev->regmap, reg, MCP16502_VSEL, sel);
298 }
299
300
301
302
303 static int mcp16502_set_suspend_mode(struct regulator_dev *rdev,
304 unsigned int mode)
305 {
306 switch (pm_suspend_target_state) {
307 case PM_SUSPEND_STANDBY:
308 return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_LPM);
309 case PM_SUSPEND_ON:
310 case PM_SUSPEND_MEM:
311 return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_HIB);
312 default:
313 dev_err(&rdev->dev, "invalid suspend target: %d\n",
314 pm_suspend_target_state);
315 }
316
317 return -EINVAL;
318 }
319
320
321
322
323 static int mcp16502_set_suspend_enable(struct regulator_dev *rdev)
324 {
325 int reg = mcp16502_suspend_get_target_reg(rdev);
326
327 if (reg < 0)
328 return reg;
329
330 return regmap_update_bits(rdev->regmap, reg, MCP16502_EN, MCP16502_EN);
331 }
332
333
334
335
336 static int mcp16502_set_suspend_disable(struct regulator_dev *rdev)
337 {
338 int reg = mcp16502_suspend_get_target_reg(rdev);
339
340 if (reg < 0)
341 return reg;
342
343 return regmap_update_bits(rdev->regmap, reg, MCP16502_EN, 0);
344 }
345 #endif
346
347 static const struct regulator_ops mcp16502_buck_ops = {
348 .list_voltage = regulator_list_voltage_linear_range,
349 .map_voltage = regulator_map_voltage_linear_range,
350 .get_voltage_sel = regulator_get_voltage_sel_regmap,
351 .set_voltage_sel = regulator_set_voltage_sel_regmap,
352 .enable = regulator_enable_regmap,
353 .disable = regulator_disable_regmap,
354 .is_enabled = regulator_is_enabled_regmap,
355 .get_status = mcp16502_get_status,
356
357 .set_mode = mcp16502_set_mode,
358 .get_mode = mcp16502_get_mode,
359
360 #ifdef CONFIG_SUSPEND
361 .set_suspend_voltage = mcp16502_set_suspend_voltage,
362 .set_suspend_mode = mcp16502_set_suspend_mode,
363 .set_suspend_enable = mcp16502_set_suspend_enable,
364 .set_suspend_disable = mcp16502_set_suspend_disable,
365 #endif
366 };
367
368
369
370
371 static const struct regulator_ops mcp16502_ldo_ops = {
372 .list_voltage = regulator_list_voltage_linear_range,
373 .map_voltage = regulator_map_voltage_linear_range,
374 .get_voltage_sel = regulator_get_voltage_sel_regmap,
375 .set_voltage_sel = regulator_set_voltage_sel_regmap,
376 .enable = regulator_enable_regmap,
377 .disable = regulator_disable_regmap,
378 .is_enabled = regulator_is_enabled_regmap,
379 .get_status = mcp16502_get_status,
380
381 #ifdef CONFIG_SUSPEND
382 .set_suspend_voltage = mcp16502_set_suspend_voltage,
383 .set_suspend_enable = mcp16502_set_suspend_enable,
384 .set_suspend_disable = mcp16502_set_suspend_disable,
385 #endif
386 };
387
388 static const struct of_device_id mcp16502_ids[] = {
389 { .compatible = "microchip,mcp16502", },
390 {}
391 };
392 MODULE_DEVICE_TABLE(of, mcp16502_ids);
393
394 static const struct regulator_linear_range b1l12_ranges[] = {
395 REGULATOR_LINEAR_RANGE(1200000, VDD_LOW_SEL, VDD_HIGH_SEL, 50000),
396 };
397
398 static const struct regulator_linear_range b234_ranges[] = {
399 REGULATOR_LINEAR_RANGE(600000, VDD_LOW_SEL, VDD_HIGH_SEL, 25000),
400 };
401
402 static const struct regulator_desc mcp16502_desc[] = {
403
404 MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops),
405 MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops),
406 MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops),
407 MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops),
408 MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops),
409 MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops)
410 };
411
412 static const struct regmap_range mcp16502_ranges[] = {
413 regmap_reg_range(MCP16502_MIN_REG, MCP16502_MAX_REG)
414 };
415
416 static const struct regmap_access_table mcp16502_yes_reg_table = {
417 .yes_ranges = mcp16502_ranges,
418 .n_yes_ranges = ARRAY_SIZE(mcp16502_ranges),
419 };
420
421 static const struct regmap_config mcp16502_regmap_config = {
422 .reg_bits = 8,
423 .val_bits = 8,
424 .max_register = MCP16502_MAX_REG,
425 .cache_type = REGCACHE_NONE,
426 .rd_table = &mcp16502_yes_reg_table,
427 .wr_table = &mcp16502_yes_reg_table,
428 };
429
430 static int mcp16502_probe(struct i2c_client *client,
431 const struct i2c_device_id *id)
432 {
433 struct regulator_config config = { };
434 struct regulator_dev *rdev;
435 struct device *dev;
436 struct mcp16502 *mcp;
437 struct regmap *rmap;
438 int i, ret;
439
440 dev = &client->dev;
441 config.dev = dev;
442
443 mcp = devm_kzalloc(dev, sizeof(*mcp), GFP_KERNEL);
444 if (!mcp)
445 return -ENOMEM;
446
447 rmap = devm_regmap_init_i2c(client, &mcp16502_regmap_config);
448 if (IS_ERR(rmap)) {
449 ret = PTR_ERR(rmap);
450 dev_err(dev, "regmap init failed: %d\n", ret);
451 return ret;
452 }
453
454 i2c_set_clientdata(client, mcp);
455 config.regmap = rmap;
456 config.driver_data = mcp;
457
458 mcp->lpm = devm_gpiod_get(dev, "lpm", GPIOD_OUT_LOW);
459 if (IS_ERR(mcp->lpm)) {
460 dev_err(dev, "failed to get lpm pin: %ld\n", PTR_ERR(mcp->lpm));
461 return PTR_ERR(mcp->lpm);
462 }
463
464 for (i = 0; i < NUM_REGULATORS; i++) {
465 rdev = devm_regulator_register(dev, &mcp16502_desc[i], &config);
466 if (IS_ERR(rdev)) {
467 dev_err(dev,
468 "failed to register %s regulator %ld\n",
469 mcp16502_desc[i].name, PTR_ERR(rdev));
470 return PTR_ERR(rdev);
471 }
472 }
473
474 mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_ACTIVE);
475
476 return 0;
477 }
478
479 #ifdef CONFIG_PM_SLEEP
480 static int mcp16502_suspend_noirq(struct device *dev)
481 {
482 struct i2c_client *client = to_i2c_client(dev);
483 struct mcp16502 *mcp = i2c_get_clientdata(client);
484
485 mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_LPM);
486
487 return 0;
488 }
489
490 static int mcp16502_resume_noirq(struct device *dev)
491 {
492 struct i2c_client *client = to_i2c_client(dev);
493 struct mcp16502 *mcp = i2c_get_clientdata(client);
494
495 mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_ACTIVE);
496
497 return 0;
498 }
499 #endif
500
501 #ifdef CONFIG_PM
502 static const struct dev_pm_ops mcp16502_pm_ops = {
503 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mcp16502_suspend_noirq,
504 mcp16502_resume_noirq)
505 };
506 #endif
507 static const struct i2c_device_id mcp16502_i2c_id[] = {
508 { "mcp16502", 0 },
509 { }
510 };
511 MODULE_DEVICE_TABLE(i2c, mcp16502_i2c_id);
512
513 static struct i2c_driver mcp16502_drv = {
514 .probe = mcp16502_probe,
515 .driver = {
516 .name = "mcp16502-regulator",
517 .of_match_table = of_match_ptr(mcp16502_ids),
518 #ifdef CONFIG_PM
519 .pm = &mcp16502_pm_ops,
520 #endif
521 },
522 .id_table = mcp16502_i2c_id,
523 };
524
525 module_i2c_driver(mcp16502_drv);
526
527 MODULE_LICENSE("GPL v2");
528 MODULE_DESCRIPTION("MCP16502 PMIC driver");
529 MODULE_AUTHOR("Andrei Stefanescu andrei.stefanescu@microchip.com");