aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2012-04-03 04:56:51 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-04-16 10:45:34 -0400
commit8eaeb9393397be8eb700ab38a69c450975463b77 (patch)
tree1f6b9d8d8197b16c19ed0ed03d55886e0c519ba5 /drivers/mfd
parent4accdff7a3e397b43e50f605ee561ba7994745c7 (diff)
mfd: Convert twl6040 to i2c driver, and separate it from twl core
Complete the separation of the twl6040 from the twl core since it is a separate chip, not part of the twl6030 PMIC. Make the needed Kconfig changes for the depending drivers at the same time to avoid breaking the kernel build (vibra, ASoC components). Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Reviewed-by: Mark Brown <broonie@opensource.wolfsonicro.com> Acked-by: Tony Lindgren <tony@atomide.com> Acked-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig11
-rw-r--r--drivers/mfd/twl6040-core.c114
2 files changed, 77 insertions, 48 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 29f463cc09cb..11e44386fa9b 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -268,10 +268,17 @@ config TWL6030_PWM
268 This is used to control charging LED brightness. 268 This is used to control charging LED brightness.
269 269
270config TWL6040_CORE 270config TWL6040_CORE
271 bool 271 bool "Support for TWL6040 audio codec"
272 depends on TWL4030_CORE && GENERIC_HARDIRQS 272 depends on I2C=y && GENERIC_HARDIRQS
273 select MFD_CORE 273 select MFD_CORE
274 select REGMAP_I2C
274 default n 275 default n
276 help
277 Say yes here if you want support for Texas Instruments TWL6040 audio
278 codec.
279 This driver provides common support for accessing the device,
280 additional drivers must be enabled in order to use the
281 functionality of the device (audio, vibra).
275 282
276config MFD_STMPE 283config MFD_STMPE
277 bool "Support STMicroelectronics STMPE" 284 bool "Support STMicroelectronics STMPE"
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 @@
39int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) 41int 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);
77int twl6040_set_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask) 79int 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);
89out:
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);
95int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask) 90int 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);
107out:
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
497static int __devinit twl6040_probe(struct platform_device *pdev) 485static 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
493static 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
501static 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);
610gpio1_err: 624gpio1_err:
611 platform_set_drvdata(pdev, NULL); 625 i2c_set_clientdata(client, NULL);
612 kfree(twl6040); 626 regmap_exit(twl6040->regmap);
627err:
613 return ret; 628 return ret;
614} 629}
615 630
616static int __devexit twl6040_remove(struct platform_device *pdev) 631static 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
636static struct platform_driver twl6040_driver = { 651static const struct i2c_device_id twl6040_i2c_id[] = {
652 { "twl6040", 0, },
653 { },
654};
655MODULE_DEVICE_TABLE(i2c, twl6040_i2c_id);
656
657static 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
645module_platform_driver(twl6040_driver); 667module_i2c_driver(twl6040_driver);
646 668
647MODULE_DESCRIPTION("TWL6040 MFD"); 669MODULE_DESCRIPTION("TWL6040 MFD");
648MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); 670MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");