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 */ |
