aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/Kconfig1
-rw-r--r--drivers/mfd/asic3.c99
2 files changed, 100 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6ea325cc8d28..491ac0f800d2 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -30,6 +30,7 @@ config MFD_SM501_GPIO
30config MFD_ASIC3 30config MFD_ASIC3
31 bool "Support for Compaq ASIC3" 31 bool "Support for Compaq ASIC3"
32 depends on GENERIC_HARDIRQS && GPIOLIB && ARM 32 depends on GENERIC_HARDIRQS && GPIOLIB && ARM
33 select MFD_CORE
33 ---help--- 34 ---help---
34 This driver supports the ASIC3 multifunction chip found on many 35 This driver supports the ASIC3 multifunction chip found on many
35 PDAs (mainly iPAQ and HTC based ones) 36 PDAs (mainly iPAQ and HTC based ones)
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index d5dd0dfae872..a90658e86307 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -17,6 +17,7 @@
17 */ 17 */
18 18
19#include <linux/kernel.h> 19#include <linux/kernel.h>
20#include <linux/delay.h>
20#include <linux/irq.h> 21#include <linux/irq.h>
21#include <linux/gpio.h> 22#include <linux/gpio.h>
22#include <linux/io.h> 23#include <linux/io.h>
@@ -24,6 +25,8 @@
24#include <linux/platform_device.h> 25#include <linux/platform_device.h>
25 26
26#include <linux/mfd/asic3.h> 27#include <linux/mfd/asic3.h>
28#include <linux/mfd/core.h>
29#include <linux/mfd/ds1wm.h>
27 30
28enum { 31enum {
29 ASIC3_CLOCK_SPI, 32 ASIC3_CLOCK_SPI,
@@ -616,6 +619,98 @@ static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk)
616 spin_unlock_irqrestore(&asic->lock, flags); 619 spin_unlock_irqrestore(&asic->lock, flags);
617} 620}
618 621
622/* MFD cells (SPI, PWM, LED, DS1WM, MMC) */
623static struct ds1wm_driver_data ds1wm_pdata = {
624 .active_high = 1,
625};
626
627static struct resource ds1wm_resources[] = {
628 {
629 .start = ASIC3_OWM_BASE,
630 .end = ASIC3_OWM_BASE + 0x13,
631 .flags = IORESOURCE_MEM,
632 },
633 {
634 .start = ASIC3_IRQ_OWM,
635 .start = ASIC3_IRQ_OWM,
636 .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
637 },
638};
639
640static int ds1wm_enable(struct platform_device *pdev)
641{
642 struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
643
644 /* Turn on external clocks and the OWM clock */
645 asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]);
646 asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]);
647 asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_OWM]);
648 msleep(1);
649
650 /* Reset and enable DS1WM */
651 asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET),
652 ASIC3_EXTCF_OWM_RESET, 1);
653 msleep(1);
654 asic3_set_register(asic, ASIC3_OFFSET(EXTCF, RESET),
655 ASIC3_EXTCF_OWM_RESET, 0);
656 msleep(1);
657 asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT),
658 ASIC3_EXTCF_OWM_EN, 1);
659 msleep(1);
660
661 return 0;
662}
663
664static int ds1wm_disable(struct platform_device *pdev)
665{
666 struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
667
668 asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT),
669 ASIC3_EXTCF_OWM_EN, 0);
670
671 asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_OWM]);
672 asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]);
673 asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]);
674
675 return 0;
676}
677
678static struct mfd_cell asic3_cell_ds1wm = {
679 .name = "ds1wm",
680 .enable = ds1wm_enable,
681 .disable = ds1wm_disable,
682 .driver_data = &ds1wm_pdata,
683 .num_resources = ARRAY_SIZE(ds1wm_resources),
684 .resources = ds1wm_resources,
685};
686
687static int __init asic3_mfd_probe(struct platform_device *pdev,
688 struct resource *mem)
689{
690 struct asic3 *asic = platform_get_drvdata(pdev);
691 int ret;
692
693 /* DS1WM */
694 asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT),
695 ASIC3_EXTCF_OWM_SMB, 0);
696
697 ds1wm_resources[0].start >>= asic->bus_shift;
698 ds1wm_resources[0].end >>= asic->bus_shift;
699
700 asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm;
701 asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm);
702
703 ret = mfd_add_devices(&pdev->dev, pdev->id,
704 &asic3_cell_ds1wm, 1, mem, asic->irq_base);
705
706 return ret;
707}
708
709static void asic3_mfd_remove(struct platform_device *pdev)
710{
711 mfd_remove_devices(&pdev->dev);
712}
713
619/* Core */ 714/* Core */
620static int __init asic3_probe(struct platform_device *pdev) 715static int __init asic3_probe(struct platform_device *pdev)
621{ 716{
@@ -683,6 +778,8 @@ static int __init asic3_probe(struct platform_device *pdev)
683 */ 778 */
684 memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init)); 779 memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init));
685 780
781 asic3_mfd_probe(pdev, mem);
782
686 dev_info(asic->dev, "ASIC3 Core driver\n"); 783 dev_info(asic->dev, "ASIC3 Core driver\n");
687 784
688 return 0; 785 return 0;
@@ -704,6 +801,8 @@ static int asic3_remove(struct platform_device *pdev)
704 int ret; 801 int ret;
705 struct asic3 *asic = platform_get_drvdata(pdev); 802 struct asic3 *asic = platform_get_drvdata(pdev);
706 803
804 asic3_mfd_remove(pdev);
805
707 ret = asic3_gpio_remove(pdev); 806 ret = asic3_gpio_remove(pdev);
708 if (ret < 0) 807 if (ret < 0)
709 return ret; 808 return ret;