On Tue, May 24, 2011 at 2:10 AM, Philip Rakity <prakity@xxxxxxxxxxx> wrote: > > code is missing hooks for 74 clock generation. Could we add the hook later in another patch, or could you help submit one patch to handle this. We test on mmp2 and ttc_dkb with toshiba and sandisk emmc, do not find issues without adding hook for 74 clock generation. > > > On May 23, 2011, at 6:21 AM, Zhangfei Gao wrote: > >> Delete sdhci-pxa.c and replace with sdhci-mmp2.c specificlly for mmp2 >> >> Signed-off-by: Zhangfei Gao <zhangfei.gao@xxxxxxxxxxx> >> --- >> arch/arm/plat-pxa/include/plat/sdhci.h | 43 ++++- >> drivers/mmc/host/Kconfig | 9 +- >> drivers/mmc/host/Makefile | 2 +- >> drivers/mmc/host/sdhci-mmp2.c | 304 ++++++++++++++++++++++++++++++++ >> drivers/mmc/host/sdhci-pxa.c | 303 ------------------------------- >> 5 files changed, 349 insertions(+), 312 deletions(-) >> create mode 100644 drivers/mmc/host/sdhci-mmp2.c >> delete mode 100644 drivers/mmc/host/sdhci-pxa.c >> >> diff --git a/arch/arm/plat-pxa/include/plat/sdhci.h b/arch/arm/plat-pxa/include/plat/sdhci.h >> index 1ab332e..92becc0 100644 >> --- a/arch/arm/plat-pxa/include/plat/sdhci.h >> +++ b/arch/arm/plat-pxa/include/plat/sdhci.h >> @@ -13,23 +13,58 @@ >> #ifndef __PLAT_PXA_SDHCI_H >> #define __PLAT_PXA_SDHCI_H >> >> +#include <linux/mmc/sdhci.h> >> +#include <linux/platform_device.h> >> + >> /* pxa specific flag */ >> /* Require clock free running */ >> #define PXA_FLAG_DISABLE_CLOCK_GATING (1<<0) >> - >> +/* card alwayes wired to host, like on-chip emmc */ >> +#define PXA_FLAG_CARD_PERMANENT (1<<1) >> /* Board design supports 8-bit data on SD/SDIO BUS */ >> #define PXA_FLAG_SD_8_BIT_CAPABLE_SLOT (1<<2) >> +/* card not use wp, such as micro sd card */ >> +#define PXA_FLAG_CARD_NO_WP (3<<1) >> >> +struct sdhci_pxa; >> /* >> * struct pxa_sdhci_platdata() - Platform device data for PXA SDHCI >> - * @max_speed: the maximum speed supported >> - * @quirks: quirks of specific device >> * @flags: flags for platform requirement >> + * @clk_delay_cycles: >> + * mmp2: each step is roughly 100ps, 5bits width >> + * pxa910: each step is 1ns, 4bits width >> + * @clk_delay_sel: select clk_delay, used on pxa910 >> + * 0: choose feedback clk >> + * 1: choose feedback clk + delay value >> + * 2: choose internal clk >> + * @ext_cd_gpio: gpio pin used for external CD line >> + * @ext_cd_gpio_invert: invert values for external CD gpio line >> + * @clk_delay_enable: enable clk_delay or not, used on pxa910 >> + * @max_speed: the maximum speed supported >> + * @host_caps: Standard MMC host capabilities bit field. >> + * @quirks: quirks of platfrom >> + * @pm_caps: pm_caps of platfrom >> */ >> struct sdhci_pxa_platdata { >> + unsigned int flags; >> + unsigned int clk_delay_cycles; >> + unsigned int clk_delay_sel; >> + unsigned int ext_cd_gpio; >> + bool ext_cd_gpio_invert; >> + bool clk_delay_enable; >> unsigned int max_speed; >> + unsigned int host_caps; >> unsigned int quirks; >> - unsigned int flags; >> + unsigned int pm_caps; >> +}; >> + >> +struct sdhci_pxa { >> + struct sdhci_pxa_platdata *pdata; >> + struct clk *clk; >> + struct sdhci_ops *ops; >> + >> + u8 clk_enable; >> + u8 power_mode; >> }; >> >> #endif /* __PLAT_PXA_SDHCI_H */ >> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig >> index 862235e..1e520e3 100644 >> --- a/drivers/mmc/host/Kconfig >> +++ b/drivers/mmc/host/Kconfig >> @@ -181,14 +181,15 @@ config MMC_SDHCI_S3C >> >> If unsure, say N. >> >> -config MMC_SDHCI_PXA >> - tristate "Marvell PXA168/PXA910/MMP2 SD Host Controller support" >> +config MMC_SDHCI_MMP2 >> + tristate "Marvell MMP2 SD Host Controller support" >> depends on ARCH_PXA || ARCH_MMP >> select MMC_SDHCI >> + select MMC_SDHCI_PLTFM >> select MMC_SDHCI_IO_ACCESSORS >> help >> - This selects the Marvell(R) PXA168/PXA910/MMP2 SD Host Controller. >> - If you have a PXA168/PXA910/MMP2 platform with SD Host Controller >> + This selects the Marvell(R) MMP2 SD Host Controller. >> + If you have a MMP2 platform with SD Host Controller >> and a card slot, say Y or M here. >> >> If unsure, say N. >> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile >> index 4933004..f8650e0 100644 >> --- a/drivers/mmc/host/Makefile >> +++ b/drivers/mmc/host/Makefile >> @@ -9,7 +9,7 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o >> obj-$(CONFIG_MMC_MXS) += mxs-mmc.o >> obj-$(CONFIG_MMC_SDHCI) += sdhci.o >> obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o >> -obj-$(CONFIG_MMC_SDHCI_PXA) += sdhci-pxa.o >> +obj-$(CONFIG_MMC_SDHCI_MMP2) += sdhci-mmp2.o >> obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o >> obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o >> obj-$(CONFIG_MMC_WBSD) += wbsd.o >> diff --git a/drivers/mmc/host/sdhci-mmp2.c b/drivers/mmc/host/sdhci-mmp2.c >> new file mode 100644 >> index 0000000..566d525 >> --- /dev/null >> +++ b/drivers/mmc/host/sdhci-mmp2.c >> @@ -0,0 +1,304 @@ >> +/* >> + * Copyright (C) 2010 Marvell International Ltd. >> + * >> + * This software is licensed under the terms of the GNU General Public >> + * License version 2, as published by the Free Software Foundation, and >> + * may be copied, distributed, and modified under those terms. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + */ >> + >> +#include <linux/err.h> >> +#include <linux/init.h> >> +#include <linux/platform_device.h> >> +#include <linux/clk.h> >> +#include <linux/io.h> >> +#include <linux/gpio.h> >> +#include <linux/mmc/card.h> >> +#include <linux/mmc/host.h> >> +#include <plat/sdhci.h> >> +#include <linux/slab.h> >> +#include "sdhci.h" >> +#include "sdhci-pltfm.h" >> + >> +#define MMP2_SD_FIFO_PARAM 0x104 >> +#define MMP2_DIS_PAD_SD_CLK_GATE 0x400 >> + >> +#define MMP2_SD_CLOCK_AND_BURST_SIZE_SETUP 0x10A >> +#define MMP2_SDCLK_SEL 0x100 >> +#define MMP2_SDCLK_DELAY_SHIFT 9 >> +#define MMP2_SDCLK_DELAY_MASK 0x1f >> + >> +#define SD_CFG_FIFO_PARAM 0x100 >> +#define SDCFG_GEN_PAD_CLK_ON (1<<6) >> +#define SDCFG_GEN_PAD_CLK_CNT_MASK 0xFF >> +#define SDCFG_GEN_PAD_CLK_CNT_SHIFT 24 >> + >> +#define SD_SPI_MODE 0x108 >> +#define SD_CE_ATA_1 0x10C >> + >> +#define SD_CE_ATA_2 0x10E >> +#define SDCE_MISC_INT (1<<2) >> +#define SDCE_MISC_INT_EN (1<<1) >> + >> +static void mmp2_soc_set_timing(struct sdhci_host *host, >> + struct sdhci_pxa_platdata *pdata) >> +{ >> + /* >> + * tune timing of read data/command when crc error happen >> + * no performance impact >> + */ >> + if (pdata && 0 != pdata->clk_delay_cycles) { >> + u16 tmp; >> + >> + tmp = readw(host->ioaddr + MMP2_SD_CLOCK_AND_BURST_SIZE_SETUP); >> + tmp |= (pdata->clk_delay_cycles & MMP2_SDCLK_DELAY_MASK) >> + << MMP2_SDCLK_DELAY_SHIFT; >> + tmp |= MMP2_SDCLK_SEL; >> + writew(tmp, host->ioaddr + MMP2_SD_CLOCK_AND_BURST_SIZE_SETUP); >> + } >> + >> + /* >> + * disable clock gating per some cards requirement >> + */ >> + >> + if (pdata && pdata->flags & PXA_FLAG_DISABLE_CLOCK_GATING) { >> + u32 tmp = 0; >> + >> + tmp = readl(host->ioaddr + MMP2_SD_FIFO_PARAM); >> + tmp |= MMP2_DIS_PAD_SD_CLK_GATE; >> + writel(tmp, host->ioaddr + MMP2_SD_FIFO_PARAM); >> + } >> +} >> + >> +static unsigned int mmp2_get_ro(struct sdhci_host *host) >> +{ >> + /* Micro SD does not support write-protect feature */ >> + return 0; >> +} >> + >> +static void mmp2_set_clock(struct sdhci_host *host, unsigned int clock) >> +{ >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_pxa *pxa = pltfm_host->priv; >> + >> + if (clock) >> + mmp2_soc_set_timing(host, pxa->pdata); >> +} >> + >> +static int mmp2_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) >> +{ >> + u16 ctrl_2; >> + >> + /* >> + * Set V18_EN -- UHS modes do not work without this. >> + * does not change signaling voltage >> + */ >> + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); >> + >> + /* Select Bus Speed Mode for host */ >> + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; >> + switch (uhs) { >> + case MMC_TIMING_UHS_SDR12: >> + ctrl_2 |= SDHCI_CTRL_UHS_SDR12; >> + break; >> + case MMC_TIMING_UHS_SDR25: >> + ctrl_2 |= SDHCI_CTRL_UHS_SDR25; >> + break; >> + case MMC_TIMING_UHS_SDR50: >> + ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; >> + break; >> + case MMC_TIMING_UHS_SDR104: >> + ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; >> + break; >> + case MMC_TIMING_UHS_DDR50: >> + ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; >> + break; >> + } >> + >> + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); >> + dev_dbg(mmc_dev(host->mmc), >> + "%s:%s uhs = %d, ctrl_2 = %04X\n", >> + __func__, mmc_hostname(host->mmc), uhs, ctrl_2); >> + >> + return 0; >> +} >> + >> +static int __devinit sdhci_mmp2_probe(struct platform_device *pdev) >> +{ >> + struct sdhci_pltfm_host *pltfm_host; >> + struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; >> + struct device *dev = &pdev->dev; >> + struct sdhci_host *host = NULL; >> + struct sdhci_pxa *pxa = NULL; >> + int ret; >> + struct clk *clk; >> + >> + pxa = kzalloc(sizeof(struct sdhci_pxa), GFP_KERNEL); >> + if (!pxa) { >> + ret = -ENOMEM; >> + goto out; >> + } >> + pxa->ops = kzalloc(sizeof(struct sdhci_ops), GFP_KERNEL); >> + if (!pxa->ops) { >> + ret = -ENOMEM; >> + goto out; >> + } >> + pxa->pdata = pdata; >> + >> + clk = clk_get(dev, "PXA-SDHCLK"); >> + if (IS_ERR(clk)) { >> + dev_err(dev, "failed to get io clock\n"); >> + ret = PTR_ERR(clk); >> + goto out; >> + } >> + pxa->clk = clk; >> + clk_enable(clk); >> + >> + host = sdhci_pltfm_init(pdev, NULL); >> + if (IS_ERR(host)) >> + return PTR_ERR(host); >> + >> + pltfm_host = sdhci_priv(host); >> + pltfm_host->priv = pxa; >> + >> + host->quirks = SDHCI_QUIRK_BROKEN_ADMA >> + | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL >> + | SDHCI_QUIRK_32BIT_DMA_ADDR >> + | SDHCI_QUIRK_32BIT_DMA_SIZE >> + | SDHCI_QUIRK_32BIT_ADMA_SIZE >> + | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; >> + >> + /* enable 1/8V DDR capable */ >> + host->mmc->caps |= MMC_CAP_1_8V_DDR; >> + >> + if (pdata && pdata->flags & PXA_FLAG_CARD_PERMANENT) { >> + /* on-chip device */ >> + host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; >> + host->mmc->caps |= MMC_CAP_NONREMOVABLE; >> + } >> + >> + /* If slot design supports 8 bit data, indicate this to MMC. */ >> + if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) >> + host->mmc->caps |= MMC_CAP_8_BIT_DATA; >> + >> + if (pdata && pdata->quirks) >> + host->quirks |= pdata->quirks; >> + if (pdata && pdata->host_caps) >> + host->mmc->caps |= pdata->host_caps; >> + if (pdata && pdata->pm_caps) >> + host->mmc->pm_caps |= pdata->pm_caps; >> + >> + pxa->ops->set_clock = mmp2_set_clock; >> + pxa->ops->set_uhs_signaling = mmp2_set_uhs_signaling; >> + if (pdata && pdata->flags & PXA_FLAG_CARD_NO_WP) >> + pxa->ops->get_ro = mmp2_get_ro; >> + >> + host->ops = pxa->ops; >> + >> + ret = sdhci_add_host(host); >> + if (ret) { >> + dev_err(&pdev->dev, "failed to add host\n"); >> + goto out; >> + } >> + >> + platform_set_drvdata(pdev, host); >> + >> + return 0; >> +out: >> + if (host) { >> + clk_disable(pltfm_host->clk); >> + clk_put(pltfm_host->clk); >> + sdhci_pltfm_free(pdev); >> + } >> + >> + if (pxa) >> + kfree(pxa->ops); >> + kfree(pxa); >> + >> + return ret; >> +} >> + >> +static int __devexit sdhci_mmp2_remove(struct platform_device *pdev) >> +{ >> + struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; >> + struct sdhci_host *host = platform_get_drvdata(pdev); >> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); >> + struct sdhci_pxa *pxa = pltfm_host->priv; >> + int dead = 0; >> + u32 scratch; >> + >> + if (host) { >> + scratch = readl(host->ioaddr + SDHCI_INT_STATUS); >> + if (scratch == (u32)-1) >> + dead = 1; >> + >> + sdhci_remove_host(host, dead); >> + >> + clk_disable(pxa->clk); >> + clk_put(pxa->clk); >> + sdhci_pltfm_free(pdev); >> + >> + platform_set_drvdata(pdev, NULL); >> + } >> + >> + if (pxa) >> + kfree(pxa->ops); >> + kfree(pxa); >> + >> + return 0; >> +} >> + >> +#ifdef CONFIG_PM >> +static int sdhci_mmp2_suspend(struct platform_device *dev, pm_message_t state) >> +{ >> + struct sdhci_host *host = platform_get_drvdata(dev); >> + >> + return sdhci_suspend_host(host, state); >> +} >> + >> +static int sdhci_mmp2_resume(struct platform_device *dev) >> +{ >> + struct sdhci_host *host = platform_get_drvdata(dev); >> + >> + return sdhci_resume_host(host); >> +} >> +#else >> +#define sdhci_mmp2_suspend NULL >> +#define sdhci_mmp2_resume NULL >> +#endif >> + >> + >> +static struct platform_driver sdhci_mmp2_driver = { >> + .driver = { >> + .name = "sdhci-mmp2", >> + .owner = THIS_MODULE, >> + }, >> + .probe = sdhci_mmp2_probe, >> + .remove = __devexit_p(sdhci_mmp2_remove), >> +#ifdef CONFIG_PM >> + .suspend = sdhci_mmp2_suspend, >> + .resume = sdhci_mmp2_resume, >> +#endif >> +}; >> +static int __init sdhci_mmp2_init(void) >> +{ >> + return platform_driver_register(&sdhci_mmp2_driver); >> +} >> + >> +static void __exit sdhci_mmp2_exit(void) >> +{ >> + platform_driver_unregister(&sdhci_mmp2_driver); >> +} >> + >> +module_init(sdhci_mmp2_init); >> +module_exit(sdhci_mmp2_exit); >> + >> +MODULE_DESCRIPTION("SDHCI driver for mmp2"); >> +MODULE_AUTHOR("Marvell International Ltd."); >> +MODULE_LICENSE("GPL v2"); >> + >> diff --git a/drivers/mmc/host/sdhci-pxa.c b/drivers/mmc/host/sdhci-pxa.c >> deleted file mode 100644 >> index 089c9a6..0000000 >> --- a/drivers/mmc/host/sdhci-pxa.c >> +++ /dev/null >> @@ -1,303 +0,0 @@ >> -/* linux/drivers/mmc/host/sdhci-pxa.c >> - * >> - * Copyright (C) 2010 Marvell International Ltd. >> - * Zhangfei Gao <zhangfei.gao@xxxxxxxxxxx> >> - * Kevin Wang <dwang4@xxxxxxxxxxx> >> - * Mingwei Wang <mwwang@xxxxxxxxxxx> >> - * Philip Rakity <prakity@xxxxxxxxxxx> >> - * Mark Brown <markb@xxxxxxxxxxx> >> - * >> - * This program is free software; you can redistribute it and/or modify >> - * it under the terms of the GNU General Public License version 2 as >> - * published by the Free Software Foundation. >> - */ >> - >> -/* Supports: >> - * SDHCI support for MMP2/PXA910/PXA168 >> - * >> - * Refer to sdhci-s3c.c. >> - */ >> - >> -#include <linux/delay.h> >> -#include <linux/platform_device.h> >> -#include <linux/mmc/host.h> >> -#include <linux/clk.h> >> -#include <linux/io.h> >> -#include <linux/err.h> >> -#include <plat/sdhci.h> >> -#include "sdhci.h" >> - >> -#define DRIVER_NAME "sdhci-pxa" >> - >> -#define SD_FIFO_PARAM 0x104 >> -#define DIS_PAD_SD_CLK_GATE 0x400 >> - >> -struct sdhci_pxa { >> - struct sdhci_host *host; >> - struct sdhci_pxa_platdata *pdata; >> - struct clk *clk; >> - struct resource *res; >> - >> - u8 clk_enable; >> -}; >> - >> -/*****************************************************************************\ >> - * * >> - * SDHCI core callbacks * >> - * * >> -\*****************************************************************************/ >> -static void set_clock(struct sdhci_host *host, unsigned int clock) >> -{ >> - struct sdhci_pxa *pxa = sdhci_priv(host); >> - u32 tmp = 0; >> - >> - if (clock == 0) { >> - if (pxa->clk_enable) { >> - clk_disable(pxa->clk); >> - pxa->clk_enable = 0; >> - } >> - } else { >> - if (0 == pxa->clk_enable) { >> - if (pxa->pdata->flags & PXA_FLAG_DISABLE_CLOCK_GATING) { >> - tmp = readl(host->ioaddr + SD_FIFO_PARAM); >> - tmp |= DIS_PAD_SD_CLK_GATE; >> - writel(tmp, host->ioaddr + SD_FIFO_PARAM); >> - } >> - clk_enable(pxa->clk); >> - pxa->clk_enable = 1; >> - } >> - } >> -} >> - >> -static int set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) >> -{ >> - u16 ctrl_2; >> - >> - /* >> - * Set V18_EN -- UHS modes do not work without this. >> - * does not change signaling voltage >> - */ >> - ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); >> - >> - /* Select Bus Speed Mode for host */ >> - ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; >> - switch (uhs) { >> - case MMC_TIMING_UHS_SDR12: >> - ctrl_2 |= SDHCI_CTRL_UHS_SDR12; >> - break; >> - case MMC_TIMING_UHS_SDR25: >> - ctrl_2 |= SDHCI_CTRL_UHS_SDR25; >> - break; >> - case MMC_TIMING_UHS_SDR50: >> - ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; >> - break; >> - case MMC_TIMING_UHS_SDR104: >> - ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; >> - break; >> - case MMC_TIMING_UHS_DDR50: >> - ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; >> - break; >> - } >> - >> - sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); >> - pr_debug("%s:%s uhs = %d, ctrl_2 = %04X\n", >> - __func__, mmc_hostname(host->mmc), uhs, ctrl_2); >> - >> - return 0; >> -} >> - >> -static struct sdhci_ops sdhci_pxa_ops = { >> - .set_uhs_signaling = set_uhs_signaling, >> - .set_clock = set_clock, >> -}; >> - >> -/*****************************************************************************\ >> - * * >> - * Device probing/removal * >> - * * >> -\*****************************************************************************/ >> - >> -static int __devinit sdhci_pxa_probe(struct platform_device *pdev) >> -{ >> - struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; >> - struct device *dev = &pdev->dev; >> - struct sdhci_host *host = NULL; >> - struct resource *iomem = NULL; >> - struct sdhci_pxa *pxa = NULL; >> - int ret, irq; >> - >> - irq = platform_get_irq(pdev, 0); >> - if (irq < 0) { >> - dev_err(dev, "no irq specified\n"); >> - return irq; >> - } >> - >> - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> - if (!iomem) { >> - dev_err(dev, "no memory specified\n"); >> - return -ENOENT; >> - } >> - >> - host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pxa)); >> - if (IS_ERR(host)) { >> - dev_err(dev, "failed to alloc host\n"); >> - return PTR_ERR(host); >> - } >> - >> - pxa = sdhci_priv(host); >> - pxa->host = host; >> - pxa->pdata = pdata; >> - pxa->clk_enable = 0; >> - >> - pxa->clk = clk_get(dev, "PXA-SDHCLK"); >> - if (IS_ERR(pxa->clk)) { >> - dev_err(dev, "failed to get io clock\n"); >> - ret = PTR_ERR(pxa->clk); >> - goto out; >> - } >> - >> - pxa->res = request_mem_region(iomem->start, resource_size(iomem), >> - mmc_hostname(host->mmc)); >> - if (!pxa->res) { >> - dev_err(&pdev->dev, "cannot request region\n"); >> - ret = -EBUSY; >> - goto out; >> - } >> - >> - host->ioaddr = ioremap(iomem->start, resource_size(iomem)); >> - if (!host->ioaddr) { >> - dev_err(&pdev->dev, "failed to remap registers\n"); >> - ret = -ENOMEM; >> - goto out; >> - } >> - >> - host->hw_name = "MMC"; >> - host->ops = &sdhci_pxa_ops; >> - host->irq = irq; >> - host->quirks = SDHCI_QUIRK_BROKEN_ADMA >> - | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL >> - | SDHCI_QUIRK_32BIT_DMA_ADDR >> - | SDHCI_QUIRK_32BIT_DMA_SIZE >> - | SDHCI_QUIRK_32BIT_ADMA_SIZE >> - | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; >> - >> - if (pdata->quirks) >> - host->quirks |= pdata->quirks; >> - >> - /* enable 1/8V DDR capable */ >> - host->mmc->caps |= MMC_CAP_1_8V_DDR; >> - >> - /* If slot design supports 8 bit data, indicate this to MMC. */ >> - if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) >> - host->mmc->caps |= MMC_CAP_8_BIT_DATA; >> - >> - ret = sdhci_add_host(host); >> - if (ret) { >> - dev_err(&pdev->dev, "failed to add host\n"); >> - goto out; >> - } >> - >> - if (pxa->pdata->max_speed) >> - host->mmc->f_max = pxa->pdata->max_speed; >> - >> - platform_set_drvdata(pdev, host); >> - >> - return 0; >> -out: >> - if (host) { >> - clk_put(pxa->clk); >> - if (host->ioaddr) >> - iounmap(host->ioaddr); >> - if (pxa->res) >> - release_mem_region(pxa->res->start, >> - resource_size(pxa->res)); >> - sdhci_free_host(host); >> - } >> - >> - return ret; >> -} >> - >> -static int __devexit sdhci_pxa_remove(struct platform_device *pdev) >> -{ >> - struct sdhci_host *host = platform_get_drvdata(pdev); >> - struct sdhci_pxa *pxa = sdhci_priv(host); >> - int dead = 0; >> - u32 scratch; >> - >> - if (host) { >> - scratch = readl(host->ioaddr + SDHCI_INT_STATUS); >> - if (scratch == (u32)-1) >> - dead = 1; >> - >> - sdhci_remove_host(host, dead); >> - >> - if (host->ioaddr) >> - iounmap(host->ioaddr); >> - if (pxa->res) >> - release_mem_region(pxa->res->start, >> - resource_size(pxa->res)); >> - if (pxa->clk_enable) { >> - clk_disable(pxa->clk); >> - pxa->clk_enable = 0; >> - } >> - clk_put(pxa->clk); >> - >> - sdhci_free_host(host); >> - platform_set_drvdata(pdev, NULL); >> - } >> - >> - return 0; >> -} >> - >> -#ifdef CONFIG_PM >> -static int sdhci_pxa_suspend(struct platform_device *dev, pm_message_t state) >> -{ >> - struct sdhci_host *host = platform_get_drvdata(dev); >> - >> - return sdhci_suspend_host(host, state); >> -} >> - >> -static int sdhci_pxa_resume(struct platform_device *dev) >> -{ >> - struct sdhci_host *host = platform_get_drvdata(dev); >> - >> - return sdhci_resume_host(host); >> -} >> -#else >> -#define sdhci_pxa_suspend NULL >> -#define sdhci_pxa_resume NULL >> -#endif >> - >> -static struct platform_driver sdhci_pxa_driver = { >> - .probe = sdhci_pxa_probe, >> - .remove = __devexit_p(sdhci_pxa_remove), >> - .suspend = sdhci_pxa_suspend, >> - .resume = sdhci_pxa_resume, >> - .driver = { >> - .name = DRIVER_NAME, >> - .owner = THIS_MODULE, >> - }, >> -}; >> - >> -/*****************************************************************************\ >> - * * >> - * Driver init/exit * >> - * * >> -\*****************************************************************************/ >> - >> -static int __init sdhci_pxa_init(void) >> -{ >> - return platform_driver_register(&sdhci_pxa_driver); >> -} >> - >> -static void __exit sdhci_pxa_exit(void) >> -{ >> - platform_driver_unregister(&sdhci_pxa_driver); >> -} >> - >> -module_init(sdhci_pxa_init); >> -module_exit(sdhci_pxa_exit); >> - >> -MODULE_DESCRIPTION("SDH controller driver for PXA168/PXA910/MMP2"); >> -MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@xxxxxxxxxxx>"); >> -MODULE_LICENSE("GPL v2"); >> -- >> 1.7.0.4 >> > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html