diff options
| author | Philipp Zabel <philipp.zabel@gmail.com> | 2009-06-15 06:10:24 -0400 |
|---|---|---|
| committer | Samuel Ortiz <sameol@linux.intel.com> | 2009-06-17 13:41:48 -0400 |
| commit | 9461f65a85e17926ee88878049e6b5de366a483d (patch) | |
| tree | a234d33d6623625b844664d9829a46fbcbcdf342 | |
| parent | 1b89040c3aa4500c97859bad714e010441e9c477 (diff) | |
mfd: asic3: enable DS1WM cell
This enables the ASIC3's DS1WM MFD cell, supported by the ds1wm driver.
Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
| -rw-r--r-- | drivers/mfd/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/mfd/asic3.c | 99 |
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 | |||
| 30 | config MFD_ASIC3 | 30 | config 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 | ||
| 28 | enum { | 31 | enum { |
| 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) */ | ||
| 623 | static struct ds1wm_driver_data ds1wm_pdata = { | ||
| 624 | .active_high = 1, | ||
| 625 | }; | ||
| 626 | |||
| 627 | static 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 | |||
| 640 | static 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 | |||
| 664 | static 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 | |||
| 678 | static 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 | |||
| 687 | static 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 | |||
| 709 | static void asic3_mfd_remove(struct platform_device *pdev) | ||
| 710 | { | ||
| 711 | mfd_remove_devices(&pdev->dev); | ||
| 712 | } | ||
| 713 | |||
| 619 | /* Core */ | 714 | /* Core */ |
| 620 | static int __init asic3_probe(struct platform_device *pdev) | 715 | static 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; |
