diff options
Diffstat (limited to 'drivers/mfd/twl6040.c')
-rw-r--r-- | drivers/mfd/twl6040.c | 133 |
1 files changed, 58 insertions, 75 deletions
diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 492ee2cd3400..daf66942071c 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c | |||
@@ -44,17 +44,12 @@ | |||
44 | #define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1) | 44 | #define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1) |
45 | #define TWL6040_NUM_SUPPLIES (2) | 45 | #define TWL6040_NUM_SUPPLIES (2) |
46 | 46 | ||
47 | static bool twl6040_has_vibra(struct twl6040_platform_data *pdata, | 47 | static bool twl6040_has_vibra(struct device_node *node) |
48 | struct device_node *node) | ||
49 | { | 48 | { |
50 | if (pdata && pdata->vibra) | ||
51 | return true; | ||
52 | |||
53 | #ifdef CONFIG_OF | 49 | #ifdef CONFIG_OF |
54 | if (of_find_node_by_name(node, "vibra")) | 50 | if (of_find_node_by_name(node, "vibra")) |
55 | return true; | 51 | return true; |
56 | #endif | 52 | #endif |
57 | |||
58 | return false; | 53 | return false; |
59 | } | 54 | } |
60 | 55 | ||
@@ -63,15 +58,9 @@ int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) | |||
63 | int ret; | 58 | int ret; |
64 | unsigned int val; | 59 | unsigned int val; |
65 | 60 | ||
66 | /* Vibra control registers from cache */ | 61 | ret = regmap_read(twl6040->regmap, reg, &val); |
67 | if (unlikely(reg == TWL6040_REG_VIBCTLL || | 62 | if (ret < 0) |
68 | reg == TWL6040_REG_VIBCTLR)) { | 63 | return ret; |
69 | val = twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)]; | ||
70 | } else { | ||
71 | ret = regmap_read(twl6040->regmap, reg, &val); | ||
72 | if (ret < 0) | ||
73 | return ret; | ||
74 | } | ||
75 | 64 | ||
76 | return val; | 65 | return val; |
77 | } | 66 | } |
@@ -82,9 +71,6 @@ int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val) | |||
82 | int ret; | 71 | int ret; |
83 | 72 | ||
84 | ret = regmap_write(twl6040->regmap, reg, val); | 73 | ret = regmap_write(twl6040->regmap, reg, val); |
85 | /* Cache the vibra control registers */ | ||
86 | if (reg == TWL6040_REG_VIBCTLL || reg == TWL6040_REG_VIBCTLR) | ||
87 | twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)] = val; | ||
88 | 74 | ||
89 | return ret; | 75 | return ret; |
90 | } | 76 | } |
@@ -461,9 +447,20 @@ EXPORT_SYMBOL(twl6040_get_sysclk); | |||
461 | /* Get the combined status of the vibra control register */ | 447 | /* Get the combined status of the vibra control register */ |
462 | int twl6040_get_vibralr_status(struct twl6040 *twl6040) | 448 | int twl6040_get_vibralr_status(struct twl6040 *twl6040) |
463 | { | 449 | { |
450 | unsigned int reg; | ||
451 | int ret; | ||
464 | u8 status; | 452 | u8 status; |
465 | 453 | ||
466 | status = twl6040->vibra_ctrl_cache[0] | twl6040->vibra_ctrl_cache[1]; | 454 | ret = regmap_read(twl6040->regmap, TWL6040_REG_VIBCTLL, ®); |
455 | if (ret != 0) | ||
456 | return ret; | ||
457 | status = reg; | ||
458 | |||
459 | ret = regmap_read(twl6040->regmap, TWL6040_REG_VIBCTLR, ®); | ||
460 | if (ret != 0) | ||
461 | return ret; | ||
462 | status |= reg; | ||
463 | |||
467 | status &= (TWL6040_VIBENA | TWL6040_VIBSEL); | 464 | status &= (TWL6040_VIBENA | TWL6040_VIBSEL); |
468 | 465 | ||
469 | return status; | 466 | return status; |
@@ -490,12 +487,27 @@ static bool twl6040_readable_reg(struct device *dev, unsigned int reg) | |||
490 | return true; | 487 | return true; |
491 | } | 488 | } |
492 | 489 | ||
490 | static bool twl6040_volatile_reg(struct device *dev, unsigned int reg) | ||
491 | { | ||
492 | switch (reg) { | ||
493 | case TWL6040_REG_VIBCTLL: | ||
494 | case TWL6040_REG_VIBCTLR: | ||
495 | case TWL6040_REG_INTMR: | ||
496 | return false; | ||
497 | default: | ||
498 | return true; | ||
499 | } | ||
500 | } | ||
501 | |||
493 | static struct regmap_config twl6040_regmap_config = { | 502 | static struct regmap_config twl6040_regmap_config = { |
494 | .reg_bits = 8, | 503 | .reg_bits = 8, |
495 | .val_bits = 8, | 504 | .val_bits = 8, |
496 | .max_register = TWL6040_REG_STATUS, /* 0x2e */ | 505 | .max_register = TWL6040_REG_STATUS, /* 0x2e */ |
497 | 506 | ||
498 | .readable_reg = twl6040_readable_reg, | 507 | .readable_reg = twl6040_readable_reg, |
508 | .volatile_reg = twl6040_volatile_reg, | ||
509 | |||
510 | .cache_type = REGCACHE_RBTREE, | ||
499 | }; | 511 | }; |
500 | 512 | ||
501 | static const struct regmap_irq twl6040_irqs[] = { | 513 | static const struct regmap_irq twl6040_irqs[] = { |
@@ -520,14 +532,13 @@ static struct regmap_irq_chip twl6040_irq_chip = { | |||
520 | static int twl6040_probe(struct i2c_client *client, | 532 | static int twl6040_probe(struct i2c_client *client, |
521 | const struct i2c_device_id *id) | 533 | const struct i2c_device_id *id) |
522 | { | 534 | { |
523 | struct twl6040_platform_data *pdata = client->dev.platform_data; | ||
524 | struct device_node *node = client->dev.of_node; | 535 | struct device_node *node = client->dev.of_node; |
525 | struct twl6040 *twl6040; | 536 | struct twl6040 *twl6040; |
526 | struct mfd_cell *cell = NULL; | 537 | struct mfd_cell *cell = NULL; |
527 | int irq, ret, children = 0; | 538 | int irq, ret, children = 0; |
528 | 539 | ||
529 | if (!pdata && !node) { | 540 | if (!node) { |
530 | dev_err(&client->dev, "Platform data is missing\n"); | 541 | dev_err(&client->dev, "of node is missing\n"); |
531 | return -EINVAL; | 542 | return -EINVAL; |
532 | } | 543 | } |
533 | 544 | ||
@@ -539,23 +550,19 @@ static int twl6040_probe(struct i2c_client *client, | |||
539 | 550 | ||
540 | twl6040 = devm_kzalloc(&client->dev, sizeof(struct twl6040), | 551 | twl6040 = devm_kzalloc(&client->dev, sizeof(struct twl6040), |
541 | GFP_KERNEL); | 552 | GFP_KERNEL); |
542 | if (!twl6040) { | 553 | if (!twl6040) |
543 | ret = -ENOMEM; | 554 | return -ENOMEM; |
544 | goto err; | ||
545 | } | ||
546 | 555 | ||
547 | twl6040->regmap = devm_regmap_init_i2c(client, &twl6040_regmap_config); | 556 | twl6040->regmap = devm_regmap_init_i2c(client, &twl6040_regmap_config); |
548 | if (IS_ERR(twl6040->regmap)) { | 557 | if (IS_ERR(twl6040->regmap)) |
549 | ret = PTR_ERR(twl6040->regmap); | 558 | return PTR_ERR(twl6040->regmap); |
550 | goto err; | ||
551 | } | ||
552 | 559 | ||
553 | i2c_set_clientdata(client, twl6040); | 560 | i2c_set_clientdata(client, twl6040); |
554 | 561 | ||
555 | twl6040->supplies[0].supply = "vio"; | 562 | twl6040->supplies[0].supply = "vio"; |
556 | twl6040->supplies[1].supply = "v2v1"; | 563 | twl6040->supplies[1].supply = "v2v1"; |
557 | ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, | 564 | ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, |
558 | twl6040->supplies); | 565 | twl6040->supplies); |
559 | if (ret != 0) { | 566 | if (ret != 0) { |
560 | dev_err(&client->dev, "Failed to get supplies: %d\n", ret); | 567 | dev_err(&client->dev, "Failed to get supplies: %d\n", ret); |
561 | goto regulator_get_err; | 568 | goto regulator_get_err; |
@@ -576,44 +583,40 @@ static int twl6040_probe(struct i2c_client *client, | |||
576 | twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); | 583 | twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); |
577 | 584 | ||
578 | /* ERRATA: Automatic power-up is not possible in ES1.0 */ | 585 | /* ERRATA: Automatic power-up is not possible in ES1.0 */ |
579 | if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) { | 586 | if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) |
580 | if (pdata) | 587 | twl6040->audpwron = of_get_named_gpio(node, |
581 | twl6040->audpwron = pdata->audpwron_gpio; | 588 | "ti,audpwron-gpio", 0); |
582 | else | 589 | else |
583 | twl6040->audpwron = of_get_named_gpio(node, | ||
584 | "ti,audpwron-gpio", 0); | ||
585 | } else | ||
586 | twl6040->audpwron = -EINVAL; | 590 | twl6040->audpwron = -EINVAL; |
587 | 591 | ||
588 | if (gpio_is_valid(twl6040->audpwron)) { | 592 | if (gpio_is_valid(twl6040->audpwron)) { |
589 | ret = devm_gpio_request_one(&client->dev, twl6040->audpwron, | 593 | ret = devm_gpio_request_one(&client->dev, twl6040->audpwron, |
590 | GPIOF_OUT_INIT_LOW, "audpwron"); | 594 | GPIOF_OUT_INIT_LOW, "audpwron"); |
591 | if (ret) | 595 | if (ret) |
592 | goto gpio_err; | 596 | goto gpio_err; |
593 | } | 597 | } |
594 | 598 | ||
595 | ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, | 599 | ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, IRQF_ONESHOT, |
596 | IRQF_ONESHOT, 0, &twl6040_irq_chip, | 600 | 0, &twl6040_irq_chip,&twl6040->irq_data); |
597 | &twl6040->irq_data); | ||
598 | if (ret < 0) | 601 | if (ret < 0) |
599 | goto gpio_err; | 602 | goto gpio_err; |
600 | 603 | ||
601 | twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data, | 604 | twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data, |
602 | TWL6040_IRQ_READY); | 605 | TWL6040_IRQ_READY); |
603 | twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data, | 606 | twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data, |
604 | TWL6040_IRQ_TH); | 607 | TWL6040_IRQ_TH); |
605 | 608 | ||
606 | ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_ready, NULL, | 609 | ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_ready, NULL, |
607 | twl6040_readyint_handler, IRQF_ONESHOT, | 610 | twl6040_readyint_handler, IRQF_ONESHOT, |
608 | "twl6040_irq_ready", twl6040); | 611 | "twl6040_irq_ready", twl6040); |
609 | if (ret) { | 612 | if (ret) { |
610 | dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret); | 613 | dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret); |
611 | goto readyirq_err; | 614 | goto readyirq_err; |
612 | } | 615 | } |
613 | 616 | ||
614 | ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_th, NULL, | 617 | ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_th, NULL, |
615 | twl6040_thint_handler, IRQF_ONESHOT, | 618 | twl6040_thint_handler, IRQF_ONESHOT, |
616 | "twl6040_irq_th", twl6040); | 619 | "twl6040_irq_th", twl6040); |
617 | if (ret) { | 620 | if (ret) { |
618 | dev_err(twl6040->dev, "Thermal IRQ request failed: %d\n", ret); | 621 | dev_err(twl6040->dev, "Thermal IRQ request failed: %d\n", ret); |
619 | goto thirq_err; | 622 | goto thirq_err; |
@@ -625,8 +628,6 @@ static int twl6040_probe(struct i2c_client *client, | |||
625 | /* | 628 | /* |
626 | * The main functionality of twl6040 to provide audio on OMAP4+ systems. | 629 | * The main functionality of twl6040 to provide audio on OMAP4+ systems. |
627 | * We can add the ASoC codec child whenever this driver has been loaded. | 630 | * We can add the ASoC codec child whenever this driver has been loaded. |
628 | * The ASoC codec can work without pdata, pass the platform_data only if | ||
629 | * it has been provided. | ||
630 | */ | 631 | */ |
631 | irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_PLUG); | 632 | irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_PLUG); |
632 | cell = &twl6040->cells[children]; | 633 | cell = &twl6040->cells[children]; |
@@ -635,13 +636,10 @@ static int twl6040_probe(struct i2c_client *client, | |||
635 | twl6040_codec_rsrc[0].end = irq; | 636 | twl6040_codec_rsrc[0].end = irq; |
636 | cell->resources = twl6040_codec_rsrc; | 637 | cell->resources = twl6040_codec_rsrc; |
637 | cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc); | 638 | cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc); |
638 | if (pdata && pdata->codec) { | ||
639 | cell->platform_data = pdata->codec; | ||
640 | cell->pdata_size = sizeof(*pdata->codec); | ||
641 | } | ||
642 | children++; | 639 | children++; |
643 | 640 | ||
644 | if (twl6040_has_vibra(pdata, node)) { | 641 | /* Vibra input driver support */ |
642 | if (twl6040_has_vibra(node)) { | ||
645 | irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_VIB); | 643 | irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_VIB); |
646 | 644 | ||
647 | cell = &twl6040->cells[children]; | 645 | cell = &twl6040->cells[children]; |
@@ -650,28 +648,13 @@ static int twl6040_probe(struct i2c_client *client, | |||
650 | twl6040_vibra_rsrc[0].end = irq; | 648 | twl6040_vibra_rsrc[0].end = irq; |
651 | cell->resources = twl6040_vibra_rsrc; | 649 | cell->resources = twl6040_vibra_rsrc; |
652 | cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc); | 650 | cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc); |
653 | |||
654 | if (pdata && pdata->vibra) { | ||
655 | cell->platform_data = pdata->vibra; | ||
656 | cell->pdata_size = sizeof(*pdata->vibra); | ||
657 | } | ||
658 | children++; | 651 | children++; |
659 | } | 652 | } |
660 | 653 | ||
661 | /* | 654 | /* GPO support */ |
662 | * Enable the GPO driver in the following cases: | 655 | cell = &twl6040->cells[children]; |
663 | * DT booted kernel or legacy boot with valid gpo platform_data | 656 | cell->name = "twl6040-gpo"; |
664 | */ | 657 | children++; |
665 | if (!pdata || (pdata && pdata->gpo)) { | ||
666 | cell = &twl6040->cells[children]; | ||
667 | cell->name = "twl6040-gpo"; | ||
668 | |||
669 | if (pdata) { | ||
670 | cell->platform_data = pdata->gpo; | ||
671 | cell->pdata_size = sizeof(*pdata->gpo); | ||
672 | } | ||
673 | children++; | ||
674 | } | ||
675 | 658 | ||
676 | ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, | 659 | ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, |
677 | NULL, 0, NULL); | 660 | NULL, 0, NULL); |
@@ -690,7 +673,7 @@ gpio_err: | |||
690 | regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); | 673 | regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); |
691 | regulator_get_err: | 674 | regulator_get_err: |
692 | i2c_set_clientdata(client, NULL); | 675 | i2c_set_clientdata(client, NULL); |
693 | err: | 676 | |
694 | return ret; | 677 | return ret; |
695 | } | 678 | } |
696 | 679 | ||