[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