[PATCH v3 2/4] mmc: support sdhci-pxav2.c
zhangfei gao
zhangfei.gao at gmail.com
Tue Jun 7 02:08:27 EDT 2011
On Tue, Jun 7, 2011 at 3:39 AM, Philip Rakity <prakity at marvell.com> wrote:
>
> On Jun 3, 2011, at 2:50 AM, Zhangfei Gao wrote:
>
>> SDHCI driver for pxav2 SoCs, such as pxa910, the driver based on sdhci-pltfm to handle resource etc.
>>
>> Signed-off-by: Zhangfei Gao <zhangfei.gao at marvell.com>
>> Signed-off-by: Jun Nie <njun at marvell.com>
>> Signed-off-by: Qiming Wu <wuqm at marvell.com>
>> ---
>> drivers/mmc/host/Kconfig | 11 ++
>> drivers/mmc/host/Makefile | 1 +
>> drivers/mmc/host/sdhci-pxav2.c | 261 ++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 273 insertions(+), 0 deletions(-)
>> create mode 100644 drivers/mmc/host/sdhci-pxav2.c
>>
>> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
>> index 4ee869a..1a53d59 100644
>> --- a/drivers/mmc/host/Kconfig
>> +++ b/drivers/mmc/host/Kconfig
>> @@ -192,6 +192,17 @@ config MMC_SDHCI_PXAV3
>>
>> If unsure, say N.
>>
>> +config MMC_SDHCI_PXAV2
>> + tristate "Marvell PXAV2 SD Host Controller support"
>> + select MMC_SDHCI
>> + select MMC_SDHCI_PLTFM
>> + help
>> + This selects the Marvell(R) PXAV2 SD Host Controller.
>> + If you have a PXAV2 platform (such as pxa910) with SD Host Controller
>> + and a card slot, say Y or M here.
>> +
>> + If unsure, say N.
>> +
>
> The following might be a better approach. This way we preserve the existing SDHCI_PXA definition
> and allow users to see what CPU's are supported.
>
> config MMC_SDHCI_PXA
>> tristate "Marvell MMP SD Host Controller support"
>> depends on ARCH_MMP2
>> select MMC_SDHCI_PXAV3
>
>
>> config MMC_SDHCI_PXA168
>> tristate "Marvell PXA168 SD Host Controller support"
>> depends on ARCH_PXA
>> select MMC_SDHCI_PXAV2
>>
>> config MMC_SDHCI_PXA9XX
>> tristate "Marvell PXA910 SD Host Controller support"
>> depends on ARCH_PXA
>> select MMC_SDHCI_PXAV3
>>
>> config MMC_SDHCI_MMP2
>> tristate "Marvell MMP SD Host Controller support"
>> depends on ARCH_MMP2
>> select MMC_SDHCI_PXAV3
>
Still prefer the original method, it is simple and no dependence.
>
> ====
>
>> 3config MMC_SDHCI_SPEAR
>> tristate "SDHCI support on ST SPEAr platform"
>> depends on MMC_SDHCI && PLAT_SPEAR
>> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
>> index 9131a27..cf95330 100644
>> --- a/drivers/mmc/host/Makefile
>> +++ b/drivers/mmc/host/Makefile
>> @@ -10,6 +10,7 @@ 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_PXAV3) += sdhci-pxav3.o
>> +obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.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-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
>> new file mode 100644
>> index 0000000..759f526
>> --- /dev/null
>> +++ b/drivers/mmc/host/sdhci-pxav2.c
>> @@ -0,0 +1,261 @@
>> +/*
>> + * Copyright (C) 2010 Marvell International Ltd.
>> + * Zhangfei Gao <zhangfei.gao at marvell.com>
>> + * Kevin Wang <dwang4 at marvell.com>
>> + * Jun Nie <njun at marvell.com>
>> + * Qiming Wu <wuqm at marvell.com>
>> + * Philip Rakity <prakity at marvell.com>
>> + *
>> + * 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 SD_FIFO_PARAM 0xe0
>> +#define DIS_PAD_SD_CLK_GATE 0x0400 /* Turn on/off Dynamic SD Clock Gating */
>> +#define CLK_GATE_ON 0x0200 /* Disable/enable Clock Gate */
>> +#define CLK_GATE_CTL 0x0100 /* Clock Gate Control */
>> +#define CLK_GATE_SETTING_BITS (DIS_PAD_SD_CLK_GATE | \
>> + CLK_GATE_ON | CLK_GATE_CTL)
>> +
>> +#define SD_CLOCK_BURST_SIZE_SETUP 0xe6
>> +#define SDCLK_SEL_SHIFT 8
>> +#define SDCLK_SEL_MASK 0x3
>> +#define SDCLK_DELAY_SHIFT 10
>> +#define SDCLK_DELAY_MASK 0x3c
>> +
>> +#define SDHCI_HOST_CONTROL 0x28
>> +#define SDHCI_CTRL_4BITBUS 0x02
>> +
>> +#define SD_CE_ATA_2 0xea
>> +#define MMC_CARD 0x1000
>> +#define MMC_WIDTH 0x0100
>> +
>> +static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask)
>> +{
>> + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
>> + struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
>> +
>> + if (mask == SDHCI_RESET_ALL) {
>> + u16 tmp = 0;
>> +
>> + /*
>> + * tune timing of read data/command when crc error happen
>> + * no performance impact
>> + */
>> + if (pdata->clk_delay_sel == 1) {
>> + tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
>> +
>> + tmp &= ~(SDCLK_DELAY_MASK << SDCLK_DELAY_SHIFT);
>> + tmp |= (pdata->clk_delay_cycles & SDCLK_DELAY_MASK)
>> + << SDCLK_DELAY_SHIFT;
>> + tmp &= ~(SDCLK_SEL_MASK << SDCLK_SEL_SHIFT);
>> + tmp |= (1 & SDCLK_SEL_MASK) << SDCLK_SEL_SHIFT;
>> +
>> + writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
>> + }
>> +
>> + if (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING) {
>> + tmp = readw(host->ioaddr + SD_FIFO_PARAM);
>> + tmp &= ~CLK_GATE_SETTING_BITS;
>> + writew(tmp, host->ioaddr + SD_FIFO_PARAM);
>> + } else {
>> + tmp = readw(host->ioaddr + SD_FIFO_PARAM);
>> + tmp &= ~CLK_GATE_SETTING_BITS;
>> + tmp |= CLK_GATE_SETTING_BITS;
>> + writew(tmp, host->ioaddr + SD_FIFO_PARAM);
>> + }
>> + }
>> +}
>> +
>> +static int pxav2_mmc_set_width(struct sdhci_host *host, int width)
>> +{
>> + u8 ctrl;
>> + u16 tmp;
>> +
>> + ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
>> + tmp = readw(host->ioaddr + SD_CE_ATA_2);
>> + if (width == MMC_BUS_WIDTH_8) {
>> + ctrl &= ~SDHCI_CTRL_4BITBUS;
>> + tmp |= MMC_CARD | MMC_WIDTH;
>> + } else {
>> + tmp &= ~(MMC_CARD | MMC_WIDTH);
>> + if (width == MMC_BUS_WIDTH_4)
>> + ctrl |= SDHCI_CTRL_4BITBUS;
>> + else
>> + ctrl &= ~SDHCI_CTRL_4BITBUS;
>> + }
>> + writew(tmp, host->ioaddr + SD_CE_ATA_2);
>> + writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
>> +
>> + return 0;
>> +}
>> +
>> +static unsigned int pxav2_get_ro(struct sdhci_host *host)
>> +{
>> + /* Micro SD does not support write-protect feature */
>> + return 0;
>> +}
>> +
>> +static u32 pxav2_get_max_clock(struct sdhci_host *host)
>> +{
>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>> +
>> + return clk_get_rate(pltfm_host->clk);
>> +}
>> +
>> +static struct sdhci_ops pxav2_sdhci_ops = {
>> + .get_ro = pxav2_get_ro,
>> + .get_max_clock = pxav2_get_max_clock,
>> + .platform_reset_exit = pxav2_set_private_registers,
>> + .platform_8bit_width = pxav2_mmc_set_width,
>> +};
>> +
>> +static int __devinit sdhci_pxav2_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)
>> + return -ENOMEM;
>> +
>> + host = sdhci_pltfm_init(pdev, NULL);
>> + if (IS_ERR(host)) {
>> + kfree(pxa);
>> + return PTR_ERR(host);
>> + }
>> + pltfm_host = sdhci_priv(host);
>> + pltfm_host->priv = pxa;
>> +
>> + clk = clk_get(dev, "PXA-SDHCLK");
>> + if (IS_ERR(clk)) {
>> + dev_err(dev, "failed to get io clock\n");
>> + ret = PTR_ERR(clk);
>> + goto err_clk_get;
>> + }
>> + pltfm_host->clk = clk;
>> + clk_enable(clk);
>> +
>> + host->quirks = SDHCI_QUIRK_BROKEN_ADMA
>> + | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
>> + | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
>> +
>> + if (pdata) {
>> + if (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->quirks)
>> + host->quirks |= pdata->quirks;
>> + if (pdata->host_caps)
>> + host->mmc->caps |= pdata->host_caps;
>> + if (pdata->pm_caps)
>> + host->mmc->pm_caps |= pdata->pm_caps;
>> + }
>> +
>> + host->ops = &pxav2_sdhci_ops;
>> +
>> + ret = sdhci_add_host(host);
>> + if (ret) {
>> + dev_err(&pdev->dev, "failed to add host\n");
>> + goto err_add_host;
>> + }
>> +
>> + if (pdata && pdata->max_speed) {
>> + host->mmc->f_max = pdata->max_speed;
>> + if (!(host->mmc->f_max > 25000000))
>> + host->mmc->caps &= ~(MMC_CAP_SD_HIGHSPEED |
>> + MMC_CAP_MMC_HIGHSPEED);
>> + }
>> +
>> + platform_set_drvdata(pdev, host);
>> +
>> + return 0;
>> +
>> +err_add_host:
>> + clk_disable(clk);
>> + clk_put(clk);
>> +err_clk_get:
>> + sdhci_pltfm_free(pdev);
>> + kfree(pxa);
>> + return ret;
>> +}
>> +
>> +static int __devexit sdhci_pxav2_remove(struct platform_device *pdev)
>> +{
>> + struct sdhci_host *host = platform_get_drvdata(pdev);
>> + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>> + struct sdhci_pxa *pxa = pltfm_host->priv;
>> +
>> + sdhci_remove_host(host, 1);
>> +
>> + clk_disable(pltfm_host->clk);
>> + clk_put(pltfm_host->clk);
>> + sdhci_pltfm_free(pdev);
>> + kfree(pxa);
>> +
>> + platform_set_drvdata(pdev, NULL);
>> +
>> + return 0;
>> +}
>> +
>> +static struct platform_driver sdhci_pxav2_driver = {
>> + .driver = {
>> + .name = "sdhci-pxav2",
>> + .owner = THIS_MODULE,
>> + },
>> + .probe = sdhci_pxav2_probe,
>> + .remove = __devexit_p(sdhci_pxav2_remove),
>> +#ifdef CONFIG_PM
>> + .suspend = sdhci_pltfm_suspend,
>> + .resume = sdhci_pltfm_resume,
>> +#endif
>> +};
>> +static int __init sdhci_pxav2_init(void)
>> +{
>> + return platform_driver_register(&sdhci_pxav2_driver);
>> +}
>> +
>> +static void __exit sdhci_pxav2_exit(void)
>> +{
>> + platform_driver_unregister(&sdhci_pxav2_driver);
>> +}
>> +
>> +module_init(sdhci_pxav2_init);
>> +module_exit(sdhci_pxav2_exit);
>> +
>> +MODULE_DESCRIPTION("SDHCI driver for pxav2");
>> +MODULE_AUTHOR("Marvell International Ltd.");
>> +MODULE_LICENSE("GPL v2");
>> +
>> --
>> 1.7.0.4
>>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
More information about the linux-arm-kernel
mailing list