diff options
-rw-r--r-- | drivers/mfd/twl4030-core.c | 174 | ||||
-rw-r--r-- | include/linux/i2c/twl4030.h | 47 |
2 files changed, 211 insertions, 10 deletions
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c index f5486cce86f4..8ab9ee8543a6 100644 --- a/drivers/mfd/twl4030-core.c +++ b/drivers/mfd/twl4030-core.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include <linux/clk.h> | 33 | #include <linux/clk.h> |
34 | #include <linux/err.h> | 34 | #include <linux/err.h> |
35 | 35 | ||
36 | #include <linux/regulator/machine.h> | ||
37 | |||
36 | #include <linux/i2c.h> | 38 | #include <linux/i2c.h> |
37 | #include <linux/i2c/twl4030.h> | 39 | #include <linux/i2c/twl4030.h> |
38 | 40 | ||
@@ -71,6 +73,13 @@ | |||
71 | #define twl_has_gpio() false | 73 | #define twl_has_gpio() false |
72 | #endif | 74 | #endif |
73 | 75 | ||
76 | #if defined(CONFIG_REGULATOR_TWL4030) \ | ||
77 | || defined(CONFIG_REGULATOR_TWL4030_MODULE) | ||
78 | #define twl_has_regulator() true | ||
79 | #else | ||
80 | #define twl_has_regulator() false | ||
81 | #endif | ||
82 | |||
74 | #if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE) | 83 | #if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE) |
75 | #define twl_has_madc() true | 84 | #define twl_has_madc() true |
76 | #else | 85 | #else |
@@ -149,6 +158,10 @@ | |||
149 | #define HIGH_PERF_SQ (1 << 3) | 158 | #define HIGH_PERF_SQ (1 << 3) |
150 | 159 | ||
151 | 160 | ||
161 | /* chip-specific feature flags, for i2c_device_id.driver_data */ | ||
162 | #define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */ | ||
163 | #define TPS_SUBSET BIT(1) /* tps659[23]0 have fewer LDOs */ | ||
164 | |||
152 | /*----------------------------------------------------------------------*/ | 165 | /*----------------------------------------------------------------------*/ |
153 | 166 | ||
154 | /* is driver active, bound to a chip? */ | 167 | /* is driver active, bound to a chip? */ |
@@ -352,7 +365,8 @@ EXPORT_SYMBOL(twl4030_i2c_read_u8); | |||
352 | 365 | ||
353 | /*----------------------------------------------------------------------*/ | 366 | /*----------------------------------------------------------------------*/ |
354 | 367 | ||
355 | static struct device *add_child(unsigned chip, const char *name, | 368 | static struct device * |
369 | add_numbered_child(unsigned chip, const char *name, int num, | ||
356 | void *pdata, unsigned pdata_len, | 370 | void *pdata, unsigned pdata_len, |
357 | bool can_wakeup, int irq0, int irq1) | 371 | bool can_wakeup, int irq0, int irq1) |
358 | { | 372 | { |
@@ -360,7 +374,7 @@ static struct device *add_child(unsigned chip, const char *name, | |||
360 | struct twl4030_client *twl = &twl4030_modules[chip]; | 374 | struct twl4030_client *twl = &twl4030_modules[chip]; |
361 | int status; | 375 | int status; |
362 | 376 | ||
363 | pdev = platform_device_alloc(name, -1); | 377 | pdev = platform_device_alloc(name, num); |
364 | if (!pdev) { | 378 | if (!pdev) { |
365 | dev_dbg(&twl->client->dev, "can't alloc dev\n"); | 379 | dev_dbg(&twl->client->dev, "can't alloc dev\n"); |
366 | status = -ENOMEM; | 380 | status = -ENOMEM; |
@@ -402,17 +416,52 @@ err: | |||
402 | return &pdev->dev; | 416 | return &pdev->dev; |
403 | } | 417 | } |
404 | 418 | ||
419 | static inline struct device *add_child(unsigned chip, const char *name, | ||
420 | void *pdata, unsigned pdata_len, | ||
421 | bool can_wakeup, int irq0, int irq1) | ||
422 | { | ||
423 | return add_numbered_child(chip, name, -1, pdata, pdata_len, | ||
424 | can_wakeup, irq0, irq1); | ||
425 | } | ||
426 | |||
427 | static struct device * | ||
428 | add_regulator_linked(int num, struct regulator_init_data *pdata, | ||
429 | struct regulator_consumer_supply *consumers, | ||
430 | unsigned num_consumers) | ||
431 | { | ||
432 | /* regulator framework demands init_data ... */ | ||
433 | if (!pdata) | ||
434 | return NULL; | ||
435 | |||
436 | if (consumers && !pdata->consumer_supplies) { | ||
437 | pdata->consumer_supplies = consumers; | ||
438 | pdata->num_consumer_supplies = num_consumers; | ||
439 | } | ||
440 | |||
441 | /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ | ||
442 | return add_numbered_child(3, "twl4030_reg", num, | ||
443 | pdata, sizeof(*pdata), false, 0, 0); | ||
444 | } | ||
445 | |||
446 | static struct device * | ||
447 | add_regulator(int num, struct regulator_init_data *pdata) | ||
448 | { | ||
449 | return add_regulator_linked(num, pdata, NULL, 0); | ||
450 | } | ||
451 | |||
405 | /* | 452 | /* |
406 | * NOTE: We know the first 8 IRQs after pdata->base_irq are | 453 | * NOTE: We know the first 8 IRQs after pdata->base_irq are |
407 | * for the PIH, and the next are for the PWR_INT SIH, since | 454 | * for the PIH, and the next are for the PWR_INT SIH, since |
408 | * that's how twl_init_irq() sets things up. | 455 | * that's how twl_init_irq() sets things up. |
409 | */ | 456 | */ |
410 | 457 | ||
411 | static int add_children(struct twl4030_platform_data *pdata) | 458 | static int |
459 | add_children(struct twl4030_platform_data *pdata, unsigned long features) | ||
412 | { | 460 | { |
413 | struct device *child; | 461 | struct device *child; |
462 | struct device *usb_transceiver = NULL; | ||
414 | 463 | ||
415 | if (twl_has_bci() && pdata->bci) { | 464 | if (twl_has_bci() && pdata->bci && !(features & TPS_SUBSET)) { |
416 | child = add_child(3, "twl4030_bci", | 465 | child = add_child(3, "twl4030_bci", |
417 | pdata->bci, sizeof(*pdata->bci), | 466 | pdata->bci, sizeof(*pdata->bci), |
418 | false, | 467 | false, |
@@ -469,6 +518,111 @@ static int add_children(struct twl4030_platform_data *pdata) | |||
469 | pdata->irq_base + 8 + 2, pdata->irq_base + 4); | 518 | pdata->irq_base + 8 + 2, pdata->irq_base + 4); |
470 | if (IS_ERR(child)) | 519 | if (IS_ERR(child)) |
471 | return PTR_ERR(child); | 520 | return PTR_ERR(child); |
521 | |||
522 | /* we need to connect regulators to this transceiver */ | ||
523 | usb_transceiver = child; | ||
524 | } | ||
525 | |||
526 | if (twl_has_regulator()) { | ||
527 | /* | ||
528 | child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1); | ||
529 | if (IS_ERR(child)) | ||
530 | return PTR_ERR(child); | ||
531 | */ | ||
532 | |||
533 | child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1); | ||
534 | if (IS_ERR(child)) | ||
535 | return PTR_ERR(child); | ||
536 | |||
537 | child = add_regulator(TWL4030_REG_VDAC, pdata->vdac); | ||
538 | if (IS_ERR(child)) | ||
539 | return PTR_ERR(child); | ||
540 | |||
541 | child = add_regulator((features & TWL4030_VAUX2) | ||
542 | ? TWL4030_REG_VAUX2_4030 | ||
543 | : TWL4030_REG_VAUX2, | ||
544 | pdata->vaux2); | ||
545 | if (IS_ERR(child)) | ||
546 | return PTR_ERR(child); | ||
547 | } | ||
548 | |||
549 | if (twl_has_regulator() && usb_transceiver) { | ||
550 | static struct regulator_consumer_supply usb1v5 = { | ||
551 | .supply = "usb1v5", | ||
552 | }; | ||
553 | static struct regulator_consumer_supply usb1v8 = { | ||
554 | .supply = "usb1v8", | ||
555 | }; | ||
556 | static struct regulator_consumer_supply usb3v1 = { | ||
557 | .supply = "usb3v1", | ||
558 | }; | ||
559 | static struct regulator_consumer_supply usbcp = { | ||
560 | .supply = "usbcp", | ||
561 | }; | ||
562 | |||
563 | /* this is a template that gets copied */ | ||
564 | struct regulator_init_data usb_fixed = { | ||
565 | .constraints.valid_modes_mask = | ||
566 | REGULATOR_MODE_NORMAL | ||
567 | | REGULATOR_MODE_STANDBY, | ||
568 | .constraints.valid_ops_mask = | ||
569 | REGULATOR_CHANGE_MODE | ||
570 | | REGULATOR_CHANGE_STATUS, | ||
571 | }; | ||
572 | |||
573 | usb1v5.dev = usb_transceiver; | ||
574 | usb1v8.dev = usb_transceiver; | ||
575 | usb3v1.dev = usb_transceiver; | ||
576 | usbcp.dev = usb_transceiver; | ||
577 | |||
578 | child = add_regulator_linked(TWL4030_REG_VUSB1V5, &usb_fixed, | ||
579 | &usb1v5, 1); | ||
580 | if (IS_ERR(child)) | ||
581 | return PTR_ERR(child); | ||
582 | |||
583 | child = add_regulator_linked(TWL4030_REG_VUSB1V8, &usb_fixed, | ||
584 | &usb1v8, 1); | ||
585 | if (IS_ERR(child)) | ||
586 | return PTR_ERR(child); | ||
587 | |||
588 | child = add_regulator_linked(TWL4030_REG_VUSB3V1, &usb_fixed, | ||
589 | &usb3v1, 1); | ||
590 | if (IS_ERR(child)) | ||
591 | return PTR_ERR(child); | ||
592 | |||
593 | child = add_regulator_linked(TWL4030_REG_VUSBCP, &usb_fixed, | ||
594 | &usbcp, 1); | ||
595 | if (IS_ERR(child)) | ||
596 | return PTR_ERR(child); | ||
597 | } | ||
598 | |||
599 | /* maybe add LDOs that are omitted on cost-reduced parts */ | ||
600 | if (twl_has_regulator() && !(features & TPS_SUBSET)) { | ||
601 | /* | ||
602 | child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2); | ||
603 | if (IS_ERR(child)) | ||
604 | return PTR_ERR(child); | ||
605 | */ | ||
606 | |||
607 | child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2); | ||
608 | if (IS_ERR(child)) | ||
609 | return PTR_ERR(child); | ||
610 | |||
611 | child = add_regulator(TWL4030_REG_VSIM, pdata->vsim); | ||
612 | if (IS_ERR(child)) | ||
613 | return PTR_ERR(child); | ||
614 | |||
615 | child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1); | ||
616 | if (IS_ERR(child)) | ||
617 | return PTR_ERR(child); | ||
618 | |||
619 | child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3); | ||
620 | if (IS_ERR(child)) | ||
621 | return PTR_ERR(child); | ||
622 | |||
623 | child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4); | ||
624 | if (IS_ERR(child)) | ||
625 | return PTR_ERR(child); | ||
472 | } | 626 | } |
473 | 627 | ||
474 | return 0; | 628 | return 0; |
@@ -632,7 +786,7 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
632 | goto fail; | 786 | goto fail; |
633 | } | 787 | } |
634 | 788 | ||
635 | status = add_children(pdata); | 789 | status = add_children(pdata, id->driver_data); |
636 | fail: | 790 | fail: |
637 | if (status < 0) | 791 | if (status < 0) |
638 | twl4030_remove(client); | 792 | twl4030_remove(client); |
@@ -640,11 +794,11 @@ fail: | |||
640 | } | 794 | } |
641 | 795 | ||
642 | static const struct i2c_device_id twl4030_ids[] = { | 796 | static const struct i2c_device_id twl4030_ids[] = { |
643 | { "twl4030", 0 }, /* "Triton 2" */ | 797 | { "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */ |
644 | { "tps65950", 0 }, /* catalog version of twl4030 */ | 798 | { "twl5030", 0 }, /* T2 updated */ |
645 | { "tps65930", 0 }, /* fewer LDOs and DACs; no charger */ | 799 | { "tps65950", 0 }, /* catalog version of twl5030 */ |
646 | { "tps65920", 0 }, /* fewer LDOs; no codec or charger */ | 800 | { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ |
647 | { "twl5030", 0 }, /* T2 updated */ | 801 | { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ |
648 | { /* end of list */ }, | 802 | { /* end of list */ }, |
649 | }; | 803 | }; |
650 | MODULE_DEVICE_TABLE(i2c, twl4030_ids); | 804 | MODULE_DEVICE_TABLE(i2c, twl4030_ids); |
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h index d4846695bcd0..e06555d40d35 100644 --- a/include/linux/i2c/twl4030.h +++ b/include/linux/i2c/twl4030.h | |||
@@ -278,6 +278,18 @@ struct twl4030_platform_data { | |||
278 | struct twl4030_keypad_data *keypad; | 278 | struct twl4030_keypad_data *keypad; |
279 | struct twl4030_usb_data *usb; | 279 | struct twl4030_usb_data *usb; |
280 | 280 | ||
281 | /* LDO regulators */ | ||
282 | struct regulator_init_data *vdac; | ||
283 | struct regulator_init_data *vpll1; | ||
284 | struct regulator_init_data *vpll2; | ||
285 | struct regulator_init_data *vmmc1; | ||
286 | struct regulator_init_data *vmmc2; | ||
287 | struct regulator_init_data *vsim; | ||
288 | struct regulator_init_data *vaux1; | ||
289 | struct regulator_init_data *vaux2; | ||
290 | struct regulator_init_data *vaux3; | ||
291 | struct regulator_init_data *vaux4; | ||
292 | |||
281 | /* REVISIT more to come ... _nothing_ should be hard-wired */ | 293 | /* REVISIT more to come ... _nothing_ should be hard-wired */ |
282 | }; | 294 | }; |
283 | 295 | ||
@@ -309,4 +321,39 @@ int twl4030_set_gpio_debounce(int gpio, int enable); | |||
309 | static inline int twl4030charger_usb_en(int enable) { return 0; } | 321 | static inline int twl4030charger_usb_en(int enable) { return 0; } |
310 | #endif | 322 | #endif |
311 | 323 | ||
324 | /*----------------------------------------------------------------------*/ | ||
325 | |||
326 | /* Linux-specific regulator identifiers ... for now, we only support | ||
327 | * the LDOs, and leave the three buck converters alone. VDD1 and VDD2 | ||
328 | * need to tie into hardware based voltage scaling (cpufreq etc), while | ||
329 | * VIO is generally fixed. | ||
330 | */ | ||
331 | |||
332 | /* EXTERNAL dc-to-dc buck converters */ | ||
333 | #define TWL4030_REG_VDD1 0 | ||
334 | #define TWL4030_REG_VDD2 1 | ||
335 | #define TWL4030_REG_VIO 2 | ||
336 | |||
337 | /* EXTERNAL LDOs */ | ||
338 | #define TWL4030_REG_VDAC 3 | ||
339 | #define TWL4030_REG_VPLL1 4 | ||
340 | #define TWL4030_REG_VPLL2 5 /* not on all chips */ | ||
341 | #define TWL4030_REG_VMMC1 6 | ||
342 | #define TWL4030_REG_VMMC2 7 /* not on all chips */ | ||
343 | #define TWL4030_REG_VSIM 8 /* not on all chips */ | ||
344 | #define TWL4030_REG_VAUX1 9 /* not on all chips */ | ||
345 | #define TWL4030_REG_VAUX2_4030 10 /* (twl4030-specific) */ | ||
346 | #define TWL4030_REG_VAUX2 11 /* (twl5030 and newer) */ | ||
347 | #define TWL4030_REG_VAUX3 12 /* not on all chips */ | ||
348 | #define TWL4030_REG_VAUX4 13 /* not on all chips */ | ||
349 | |||
350 | /* INTERNAL LDOs */ | ||
351 | #define TWL4030_REG_VINTANA1 14 | ||
352 | #define TWL4030_REG_VINTANA2 15 | ||
353 | #define TWL4030_REG_VINTDIG 16 | ||
354 | #define TWL4030_REG_VUSB1V5 17 | ||
355 | #define TWL4030_REG_VUSB1V8 18 | ||
356 | #define TWL4030_REG_VUSB3V1 19 | ||
357 | #define TWL4030_REG_VUSBCP 20 | ||
358 | |||
312 | #endif /* End of __TWL4030_H */ | 359 | #endif /* End of __TWL4030_H */ |