diff options
author | Philipp Zabel <philipp.zabel@gmail.com> | 2009-06-15 06:10:25 -0400 |
---|---|---|
committer | Samuel Ortiz <sameol@linux.intel.com> | 2009-06-17 13:41:50 -0400 |
commit | 09f05ce8512c9873bda7f76273708753fdc5c698 (patch) | |
tree | e69bd1a41018ab492cf932c4b6e2df9c8c5aa00c /drivers/mfd | |
parent | 9461f65a85e17926ee88878049e6b5de366a483d (diff) |
mfd: asic3: enable SD/SDIO cell
This enables the ASIC3's SD/SDIO MFD cell, supported by the tmio_mmc driver.
Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/asic3.c | 114 |
1 files changed, 113 insertions, 1 deletions
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index a90658e86307..63a2a6632106 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/mfd/asic3.h> | 27 | #include <linux/mfd/asic3.h> |
28 | #include <linux/mfd/core.h> | 28 | #include <linux/mfd/core.h> |
29 | #include <linux/mfd/ds1wm.h> | 29 | #include <linux/mfd/ds1wm.h> |
30 | #include <linux/mfd/tmio.h> | ||
30 | 31 | ||
31 | enum { | 32 | enum { |
32 | ASIC3_CLOCK_SPI, | 33 | ASIC3_CLOCK_SPI, |
@@ -684,11 +685,106 @@ static struct mfd_cell asic3_cell_ds1wm = { | |||
684 | .resources = ds1wm_resources, | 685 | .resources = ds1wm_resources, |
685 | }; | 686 | }; |
686 | 687 | ||
688 | static struct tmio_mmc_data asic3_mmc_data = { | ||
689 | .hclk = 24576000, | ||
690 | }; | ||
691 | |||
692 | static struct resource asic3_mmc_resources[] = { | ||
693 | { | ||
694 | .start = ASIC3_SD_CTRL_BASE, | ||
695 | .end = ASIC3_SD_CTRL_BASE + 0x3ff, | ||
696 | .flags = IORESOURCE_MEM, | ||
697 | }, | ||
698 | { | ||
699 | .start = ASIC3_SD_CONFIG_BASE, | ||
700 | .end = ASIC3_SD_CONFIG_BASE + 0x1ff, | ||
701 | .flags = IORESOURCE_MEM, | ||
702 | }, | ||
703 | { | ||
704 | .start = 0, | ||
705 | .end = 0, | ||
706 | .flags = IORESOURCE_IRQ, | ||
707 | }, | ||
708 | }; | ||
709 | |||
710 | static int asic3_mmc_enable(struct platform_device *pdev) | ||
711 | { | ||
712 | struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); | ||
713 | |||
714 | /* Not sure if it must be done bit by bit, but leaving as-is */ | ||
715 | asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), | ||
716 | ASIC3_SDHWCTRL_LEVCD, 1); | ||
717 | asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), | ||
718 | ASIC3_SDHWCTRL_LEVWP, 1); | ||
719 | asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), | ||
720 | ASIC3_SDHWCTRL_SUSPEND, 0); | ||
721 | asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), | ||
722 | ASIC3_SDHWCTRL_PCLR, 0); | ||
723 | |||
724 | asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); | ||
725 | /* CLK32 used for card detection and for interruption detection | ||
726 | * when HCLK is stopped. | ||
727 | */ | ||
728 | asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); | ||
729 | msleep(1); | ||
730 | |||
731 | /* HCLK 24.576 MHz, BCLK 12.288 MHz: */ | ||
732 | asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), | ||
733 | CLOCK_SEL_CX | CLOCK_SEL_SD_HCLK_SEL); | ||
734 | |||
735 | asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]); | ||
736 | asic3_clk_enable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]); | ||
737 | msleep(1); | ||
738 | |||
739 | asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), | ||
740 | ASIC3_EXTCF_SD_MEM_ENABLE, 1); | ||
741 | |||
742 | /* Enable SD card slot 3.3V power supply */ | ||
743 | asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), | ||
744 | ASIC3_SDHWCTRL_SDPWR, 1); | ||
745 | |||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | static int asic3_mmc_disable(struct platform_device *pdev) | ||
750 | { | ||
751 | struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); | ||
752 | |||
753 | /* Put in suspend mode */ | ||
754 | asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), | ||
755 | ASIC3_SDHWCTRL_SUSPEND, 1); | ||
756 | |||
757 | /* Disable clocks */ | ||
758 | asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_HOST]); | ||
759 | asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_SD_BUS]); | ||
760 | asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX0]); | ||
761 | asic3_clk_disable(asic, &asic->clocks[ASIC3_CLOCK_EX1]); | ||
762 | return 0; | ||
763 | } | ||
764 | |||
765 | static struct mfd_cell asic3_cell_mmc = { | ||
766 | .name = "tmio-mmc", | ||
767 | .enable = asic3_mmc_enable, | ||
768 | .disable = asic3_mmc_disable, | ||
769 | .driver_data = &asic3_mmc_data, | ||
770 | .num_resources = ARRAY_SIZE(asic3_mmc_resources), | ||
771 | .resources = asic3_mmc_resources, | ||
772 | }; | ||
773 | |||
687 | static int __init asic3_mfd_probe(struct platform_device *pdev, | 774 | static int __init asic3_mfd_probe(struct platform_device *pdev, |
688 | struct resource *mem) | 775 | struct resource *mem) |
689 | { | 776 | { |
690 | struct asic3 *asic = platform_get_drvdata(pdev); | 777 | struct asic3 *asic = platform_get_drvdata(pdev); |
691 | int ret; | 778 | struct resource *mem_sdio; |
779 | int irq, ret; | ||
780 | |||
781 | mem_sdio = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
782 | if (!mem_sdio) | ||
783 | dev_dbg(asic->dev, "no SDIO MEM resource\n"); | ||
784 | |||
785 | irq = platform_get_irq(pdev, 1); | ||
786 | if (irq < 0) | ||
787 | dev_dbg(asic->dev, "no SDIO IRQ resource\n"); | ||
692 | 788 | ||
693 | /* DS1WM */ | 789 | /* DS1WM */ |
694 | asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), | 790 | asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), |
@@ -700,9 +796,25 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, | |||
700 | asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm; | 796 | asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm; |
701 | asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm); | 797 | asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm); |
702 | 798 | ||
799 | /* MMC */ | ||
800 | asic3_mmc_resources[0].start >>= asic->bus_shift; | ||
801 | asic3_mmc_resources[0].end >>= asic->bus_shift; | ||
802 | asic3_mmc_resources[1].start >>= asic->bus_shift; | ||
803 | asic3_mmc_resources[1].end >>= asic->bus_shift; | ||
804 | |||
805 | asic3_cell_mmc.platform_data = &asic3_cell_mmc; | ||
806 | asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc); | ||
807 | |||
703 | ret = mfd_add_devices(&pdev->dev, pdev->id, | 808 | ret = mfd_add_devices(&pdev->dev, pdev->id, |
704 | &asic3_cell_ds1wm, 1, mem, asic->irq_base); | 809 | &asic3_cell_ds1wm, 1, mem, asic->irq_base); |
810 | if (ret < 0) | ||
811 | goto out; | ||
812 | |||
813 | if (mem_sdio && (irq >= 0)) | ||
814 | ret = mfd_add_devices(&pdev->dev, pdev->id, | ||
815 | &asic3_cell_mmc, 1, mem_sdio, irq); | ||
705 | 816 | ||
817 | out: | ||
706 | return ret; | 818 | return ret; |
707 | } | 819 | } |
708 | 820 | ||