diff options
| -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 | ||
