mmc: sdhci-esdhc-imx: add basic imx6q usdhc support
This patch adds the basic support for imx6q usdhc, which is a derivative of esdhc controller. Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
Родитель
cd8a366698
Коммит
95a2482a9b
|
@ -130,13 +130,13 @@ config MMC_SDHCI_CNS3XXX
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
config MMC_SDHCI_ESDHC_IMX
|
config MMC_SDHCI_ESDHC_IMX
|
||||||
tristate "SDHCI platform support for the Freescale eSDHC i.MX controller"
|
tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller"
|
||||||
depends on ARCH_MXC
|
depends on ARCH_MXC
|
||||||
depends on MMC_SDHCI_PLTFM
|
depends on MMC_SDHCI_PLTFM
|
||||||
select MMC_SDHCI_IO_ACCESSORS
|
select MMC_SDHCI_IO_ACCESSORS
|
||||||
help
|
help
|
||||||
This selects the Freescale eSDHC controller support on the platform
|
This selects the Freescale eSDHC/uSDHC controller support
|
||||||
bus, found on i.MX25, i.MX35 and i.MX5x.
|
found on i.MX25, i.MX35 i.MX5x and i.MX6x.
|
||||||
|
|
||||||
If you have a controller with this interface, say Y or M here.
|
If you have a controller with this interface, say Y or M here.
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
/* VENDOR SPEC register */
|
/* VENDOR SPEC register */
|
||||||
#define SDHCI_VENDOR_SPEC 0xC0
|
#define SDHCI_VENDOR_SPEC 0xC0
|
||||||
#define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002
|
#define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002
|
||||||
|
#define SDHCI_MIX_CTRL 0x48
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC:
|
* There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC:
|
||||||
|
@ -59,6 +60,7 @@ enum imx_esdhc_type {
|
||||||
IMX35_ESDHC,
|
IMX35_ESDHC,
|
||||||
IMX51_ESDHC,
|
IMX51_ESDHC,
|
||||||
IMX53_ESDHC,
|
IMX53_ESDHC,
|
||||||
|
IMX6Q_USDHC,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pltfm_imx_data {
|
struct pltfm_imx_data {
|
||||||
|
@ -81,6 +83,9 @@ static struct platform_device_id imx_esdhc_devtype[] = {
|
||||||
}, {
|
}, {
|
||||||
.name = "sdhci-esdhc-imx53",
|
.name = "sdhci-esdhc-imx53",
|
||||||
.driver_data = IMX53_ESDHC,
|
.driver_data = IMX53_ESDHC,
|
||||||
|
}, {
|
||||||
|
.name = "sdhci-usdhc-imx6q",
|
||||||
|
.driver_data = IMX6Q_USDHC,
|
||||||
}, {
|
}, {
|
||||||
/* sentinel */
|
/* sentinel */
|
||||||
}
|
}
|
||||||
|
@ -92,6 +97,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
|
||||||
{ .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], },
|
{ .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], },
|
||||||
{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
|
{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
|
||||||
{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
|
{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
|
||||||
|
{ .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
|
MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
|
||||||
|
@ -116,6 +122,11 @@ static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
|
||||||
return data->devtype == IMX53_ESDHC;
|
return data->devtype == IMX53_ESDHC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
|
||||||
|
{
|
||||||
|
return data->devtype == IMX6Q_USDHC;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
|
static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
|
||||||
{
|
{
|
||||||
void __iomem *base = host->ioaddr + (reg & ~0x3);
|
void __iomem *base = host->ioaddr + (reg & ~0x3);
|
||||||
|
@ -220,8 +231,16 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
|
||||||
|
|
||||||
static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
|
static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
|
||||||
{
|
{
|
||||||
if (unlikely(reg == SDHCI_HOST_VERSION))
|
if (unlikely(reg == SDHCI_HOST_VERSION)) {
|
||||||
reg ^= 2;
|
u16 val = readw(host->ioaddr + (reg ^ 2));
|
||||||
|
/*
|
||||||
|
* uSDHC supports SDHCI v3.0, but it's encoded as value
|
||||||
|
* 0x3 in host controller version register, which violates
|
||||||
|
* SDHCI_SPEC_300 definition. Work it around here.
|
||||||
|
*/
|
||||||
|
if ((val & SDHCI_SPEC_VER_MASK) == 3)
|
||||||
|
return --val;
|
||||||
|
}
|
||||||
|
|
||||||
return readw(host->ioaddr + reg);
|
return readw(host->ioaddr + reg);
|
||||||
}
|
}
|
||||||
|
@ -252,8 +271,17 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
|
||||||
if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
|
if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
|
||||||
&& (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
|
&& (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
|
||||||
val |= SDHCI_CMD_ABORTCMD;
|
val |= SDHCI_CMD_ABORTCMD;
|
||||||
|
|
||||||
|
if (is_imx6q_usdhc(imx_data)) {
|
||||||
|
u32 m = readl(host->ioaddr + SDHCI_MIX_CTRL);
|
||||||
|
m = imx_data->scratchpad | (m & 0xffff0000);
|
||||||
|
writel(m, host->ioaddr + SDHCI_MIX_CTRL);
|
||||||
|
writel(val << 16,
|
||||||
|
host->ioaddr + SDHCI_TRANSFER_MODE);
|
||||||
|
} else {
|
||||||
writel(val << 16 | imx_data->scratchpad,
|
writel(val << 16 | imx_data->scratchpad,
|
||||||
host->ioaddr + SDHCI_TRANSFER_MODE);
|
host->ioaddr + SDHCI_TRANSFER_MODE);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case SDHCI_BLOCK_SIZE:
|
case SDHCI_BLOCK_SIZE:
|
||||||
val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
|
val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче