diff options
Diffstat (limited to 'drivers/mfd/twl6040-core.c')
-rw-r--r-- | drivers/mfd/twl6040-core.c | 114 |
1 files changed, 68 insertions, 46 deletions
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index b2d8e512d3cb..2d6bedadca09 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c | |||
@@ -30,7 +30,9 @@ | |||
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/gpio.h> | 31 | #include <linux/gpio.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/i2c/twl.h> | 33 | #include <linux/i2c.h> |
34 | #include <linux/regmap.h> | ||
35 | #include <linux/err.h> | ||
34 | #include <linux/mfd/core.h> | 36 | #include <linux/mfd/core.h> |
35 | #include <linux/mfd/twl6040.h> | 37 | #include <linux/mfd/twl6040.h> |
36 | 38 | ||
@@ -39,7 +41,7 @@ | |||
39 | int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) | 41 | int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) |
40 | { | 42 | { |
41 | int ret; | 43 | int ret; |
42 | u8 val = 0; | 44 | unsigned int val; |
43 | 45 | ||
44 | mutex_lock(&twl6040->io_mutex); | 46 | mutex_lock(&twl6040->io_mutex); |
45 | /* Vibra control registers from cache */ | 47 | /* Vibra control registers from cache */ |
@@ -47,7 +49,7 @@ int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) | |||
47 | reg == TWL6040_REG_VIBCTLR)) { | 49 | reg == TWL6040_REG_VIBCTLR)) { |
48 | val = twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)]; | 50 | val = twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)]; |
49 | } else { | 51 | } else { |
50 | ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg); | 52 | ret = regmap_read(twl6040->regmap, reg, &val); |
51 | if (ret < 0) { | 53 | if (ret < 0) { |
52 | mutex_unlock(&twl6040->io_mutex); | 54 | mutex_unlock(&twl6040->io_mutex); |
53 | return ret; | 55 | return ret; |
@@ -64,7 +66,7 @@ int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val) | |||
64 | int ret; | 66 | int ret; |
65 | 67 | ||
66 | mutex_lock(&twl6040->io_mutex); | 68 | mutex_lock(&twl6040->io_mutex); |
67 | ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg); | 69 | ret = regmap_write(twl6040->regmap, reg, val); |
68 | /* Cache the vibra control registers */ | 70 | /* Cache the vibra control registers */ |
69 | if (reg == TWL6040_REG_VIBCTLL || reg == TWL6040_REG_VIBCTLR) | 71 | if (reg == TWL6040_REG_VIBCTLL || reg == TWL6040_REG_VIBCTLR) |
70 | twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)] = val; | 72 | twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)] = val; |
@@ -77,16 +79,9 @@ EXPORT_SYMBOL(twl6040_reg_write); | |||
77 | int twl6040_set_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask) | 79 | int twl6040_set_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask) |
78 | { | 80 | { |
79 | int ret; | 81 | int ret; |
80 | u8 val; | ||
81 | 82 | ||
82 | mutex_lock(&twl6040->io_mutex); | 83 | mutex_lock(&twl6040->io_mutex); |
83 | ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg); | 84 | ret = regmap_update_bits(twl6040->regmap, reg, mask, mask); |
84 | if (ret) | ||
85 | goto out; | ||
86 | |||
87 | val |= mask; | ||
88 | ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg); | ||
89 | out: | ||
90 | mutex_unlock(&twl6040->io_mutex); | 85 | mutex_unlock(&twl6040->io_mutex); |
91 | return ret; | 86 | return ret; |
92 | } | 87 | } |
@@ -95,16 +90,9 @@ EXPORT_SYMBOL(twl6040_set_bits); | |||
95 | int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask) | 90 | int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask) |
96 | { | 91 | { |
97 | int ret; | 92 | int ret; |
98 | u8 val; | ||
99 | 93 | ||
100 | mutex_lock(&twl6040->io_mutex); | 94 | mutex_lock(&twl6040->io_mutex); |
101 | ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg); | 95 | ret = regmap_update_bits(twl6040->regmap, reg, mask, 0); |
102 | if (ret) | ||
103 | goto out; | ||
104 | |||
105 | val &= ~mask; | ||
106 | ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg); | ||
107 | out: | ||
108 | mutex_unlock(&twl6040->io_mutex); | 96 | mutex_unlock(&twl6040->io_mutex); |
109 | return ret; | 97 | return ret; |
110 | } | 98 | } |
@@ -494,32 +482,58 @@ static struct resource twl6040_codec_rsrc[] = { | |||
494 | }, | 482 | }, |
495 | }; | 483 | }; |
496 | 484 | ||
497 | static int __devinit twl6040_probe(struct platform_device *pdev) | 485 | static bool twl6040_readable_reg(struct device *dev, unsigned int reg) |
498 | { | 486 | { |
499 | struct twl4030_audio_data *pdata = pdev->dev.platform_data; | 487 | /* Register 0 is not readable */ |
488 | if (!reg) | ||
489 | return false; | ||
490 | return true; | ||
491 | } | ||
492 | |||
493 | static struct regmap_config twl6040_regmap_config = { | ||
494 | .reg_bits = 8, | ||
495 | .val_bits = 8, | ||
496 | .max_register = TWL6040_REG_STATUS, /* 0x2e */ | ||
497 | |||
498 | .readable_reg = twl6040_readable_reg, | ||
499 | }; | ||
500 | |||
501 | static int __devinit twl6040_probe(struct i2c_client *client, | ||
502 | const struct i2c_device_id *id) | ||
503 | { | ||
504 | struct twl6040_platform_data *pdata = client->dev.platform_data; | ||
500 | struct twl6040 *twl6040; | 505 | struct twl6040 *twl6040; |
501 | struct mfd_cell *cell = NULL; | 506 | struct mfd_cell *cell = NULL; |
502 | int ret, children = 0; | 507 | int ret, children = 0; |
503 | 508 | ||
504 | if (!pdata) { | 509 | if (!pdata) { |
505 | dev_err(&pdev->dev, "Platform data is missing\n"); | 510 | dev_err(&client->dev, "Platform data is missing\n"); |
506 | return -EINVAL; | 511 | return -EINVAL; |
507 | } | 512 | } |
508 | 513 | ||
509 | /* In order to operate correctly we need valid interrupt config */ | 514 | /* In order to operate correctly we need valid interrupt config */ |
510 | if (!pdata->naudint_irq || !pdata->irq_base) { | 515 | if (!client->irq || !pdata->irq_base) { |
511 | dev_err(&pdev->dev, "Invalid IRQ configuration\n"); | 516 | dev_err(&client->dev, "Invalid IRQ configuration\n"); |
512 | return -EINVAL; | 517 | return -EINVAL; |
513 | } | 518 | } |
514 | 519 | ||
515 | twl6040 = kzalloc(sizeof(struct twl6040), GFP_KERNEL); | 520 | twl6040 = devm_kzalloc(&client->dev, sizeof(struct twl6040), |
516 | if (!twl6040) | 521 | GFP_KERNEL); |
517 | return -ENOMEM; | 522 | if (!twl6040) { |
523 | ret = -ENOMEM; | ||
524 | goto err; | ||
525 | } | ||
526 | |||
527 | twl6040->regmap = regmap_init_i2c(client, &twl6040_regmap_config); | ||
528 | if (IS_ERR(twl6040->regmap)) { | ||
529 | ret = PTR_ERR(twl6040->regmap); | ||
530 | goto err; | ||
531 | } | ||
518 | 532 | ||
519 | platform_set_drvdata(pdev, twl6040); | 533 | i2c_set_clientdata(client, twl6040); |
520 | 534 | ||
521 | twl6040->dev = &pdev->dev; | 535 | twl6040->dev = &client->dev; |
522 | twl6040->irq = pdata->naudint_irq; | 536 | twl6040->irq = client->irq; |
523 | twl6040->irq_base = pdata->irq_base; | 537 | twl6040->irq_base = pdata->irq_base; |
524 | 538 | ||
525 | mutex_init(&twl6040->mutex); | 539 | mutex_init(&twl6040->mutex); |
@@ -588,12 +602,12 @@ static int __devinit twl6040_probe(struct platform_device *pdev) | |||
588 | } | 602 | } |
589 | 603 | ||
590 | if (children) { | 604 | if (children) { |
591 | ret = mfd_add_devices(&pdev->dev, pdev->id, twl6040->cells, | 605 | ret = mfd_add_devices(&client->dev, -1, twl6040->cells, |
592 | children, NULL, 0); | 606 | children, NULL, 0); |
593 | if (ret) | 607 | if (ret) |
594 | goto mfd_err; | 608 | goto mfd_err; |
595 | } else { | 609 | } else { |
596 | dev_err(&pdev->dev, "No platform data found for children\n"); | 610 | dev_err(&client->dev, "No platform data found for children\n"); |
597 | ret = -ENODEV; | 611 | ret = -ENODEV; |
598 | goto mfd_err; | 612 | goto mfd_err; |
599 | } | 613 | } |
@@ -608,14 +622,15 @@ gpio2_err: | |||
608 | if (gpio_is_valid(twl6040->audpwron)) | 622 | if (gpio_is_valid(twl6040->audpwron)) |
609 | gpio_free(twl6040->audpwron); | 623 | gpio_free(twl6040->audpwron); |
610 | gpio1_err: | 624 | gpio1_err: |
611 | platform_set_drvdata(pdev, NULL); | 625 | i2c_set_clientdata(client, NULL); |
612 | kfree(twl6040); | 626 | regmap_exit(twl6040->regmap); |
627 | err: | ||
613 | return ret; | 628 | return ret; |
614 | } | 629 | } |
615 | 630 | ||
616 | static int __devexit twl6040_remove(struct platform_device *pdev) | 631 | static int __devexit twl6040_remove(struct i2c_client *client) |
617 | { | 632 | { |
618 | struct twl6040 *twl6040 = platform_get_drvdata(pdev); | 633 | struct twl6040 *twl6040 = i2c_get_clientdata(client); |
619 | 634 | ||
620 | if (twl6040->power_count) | 635 | if (twl6040->power_count) |
621 | twl6040_power(twl6040, 0); | 636 | twl6040_power(twl6040, 0); |
@@ -626,23 +641,30 @@ static int __devexit twl6040_remove(struct platform_device *pdev) | |||
626 | free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040); | 641 | free_irq(twl6040->irq_base + TWL6040_IRQ_READY, twl6040); |
627 | twl6040_irq_exit(twl6040); | 642 | twl6040_irq_exit(twl6040); |
628 | 643 | ||
629 | mfd_remove_devices(&pdev->dev); | 644 | mfd_remove_devices(&client->dev); |
630 | platform_set_drvdata(pdev, NULL); | 645 | i2c_set_clientdata(client, NULL); |
631 | kfree(twl6040); | 646 | regmap_exit(twl6040->regmap); |
632 | 647 | ||
633 | return 0; | 648 | return 0; |
634 | } | 649 | } |
635 | 650 | ||
636 | static struct platform_driver twl6040_driver = { | 651 | static const struct i2c_device_id twl6040_i2c_id[] = { |
652 | { "twl6040", 0, }, | ||
653 | { }, | ||
654 | }; | ||
655 | MODULE_DEVICE_TABLE(i2c, twl6040_i2c_id); | ||
656 | |||
657 | static struct i2c_driver twl6040_driver = { | ||
658 | .driver = { | ||
659 | .name = "twl6040", | ||
660 | .owner = THIS_MODULE, | ||
661 | }, | ||
637 | .probe = twl6040_probe, | 662 | .probe = twl6040_probe, |
638 | .remove = __devexit_p(twl6040_remove), | 663 | .remove = __devexit_p(twl6040_remove), |
639 | .driver = { | 664 | .id_table = twl6040_i2c_id, |
640 | .owner = THIS_MODULE, | ||
641 | .name = "twl6040", | ||
642 | }, | ||
643 | }; | 665 | }; |
644 | 666 | ||
645 | module_platform_driver(twl6040_driver); | 667 | module_i2c_driver(twl6040_driver); |
646 | 668 | ||
647 | MODULE_DESCRIPTION("TWL6040 MFD"); | 669 | MODULE_DESCRIPTION("TWL6040 MFD"); |
648 | MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); | 670 | MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); |