diff mbox

[1/5] mmc: mxcmmc: add mpc512x SDHC support

Message ID 1363279254-22351-2-git-send-email-agust@denx.de (mailing list archive)
State New, archived
Headers show

Commit Message

Anatolij Gustschin March 14, 2013, 4:40 p.m. UTC
The SDHC controller on mpc512x is compatible with i.MX31 SDHC,
so the mxcmmc driver can be used on mpc512x, too. Extend the
driver to support mpc512x as well.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
 drivers/mmc/host/Kconfig  |   10 +-
 drivers/mmc/host/mxcmmc.c |  222 +++++++++++++++++++++++++++++++++------------
 2 files changed, 167 insertions(+), 65 deletions(-)

Comments

Arnd Bergmann March 14, 2013, 4:50 p.m. UTC | #1
On Thursday 14 March 2013 17:40:49 Anatolij Gustschin wrote:

> +
> +struct mxcmci_reg_ops mxcmci_reg_ops = {
> +	.read_l = mpcmci_readl,
> +	.write_l = mpcmci_writel,
> +	.read_w = mpcmci_readw,
> +	.write_w = mpcmci_writew,
> +};
> +#else
> +struct mxcmci_reg_ops mxcmci_reg_ops;
> +#endif

Should the struct be static?

> +static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg)
> +{
> +	if (host->reg_ops->read_l)
> +		return host->reg_ops->read_l(host, reg);
> +	else
> +		return readl(host->base + reg);
> +}

This seems a bit strange. I would suggest you either use the ops structure
all the time and provide an imx variant, or you make it completely
compile-time selected.

> @@ -1026,24 +1115,33 @@ static int mxcmci_probe(struct platform_device *pdev)
>  	host->res = r;
>  	host->irq = irq;
>  
> -	host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
> -	if (IS_ERR(host->clk_ipg)) {
> -		ret = PTR_ERR(host->clk_ipg);
> -		goto out_iounmap;
> -	}
> +	if (!is_mpc512x_mmc(host)) {
> +		host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
> +		if (IS_ERR(host->clk_ipg)) {
> +			ret = PTR_ERR(host->clk_ipg);
> +			goto out_iounmap;
> +		}

Does mpc512x have no clock management? I think it should still
work without modifications if CONFIG_HAVE_CLK is disabled.
In that case, devm_clk_get() will return NULL and we don't
error out here.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Anatolij Gustschin March 14, 2013, 6:13 p.m. UTC | #2
On Thu, 14 Mar 2013 17:50:08 +0100
Arnd Bergmann <arnd@arndb.de> wrote:

> On Thursday 14 March 2013 17:40:49 Anatolij Gustschin wrote:
> 
> > +
> > +struct mxcmci_reg_ops mxcmci_reg_ops = {
> > +	.read_l = mpcmci_readl,
> > +	.write_l = mpcmci_writel,
> > +	.read_w = mpcmci_readw,
> > +	.write_w = mpcmci_writew,
> > +};
> > +#else
> > +struct mxcmci_reg_ops mxcmci_reg_ops;
> > +#endif
> 
> Should the struct be static?

yes, it should.

> > +static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg)
> > +{
> > +	if (host->reg_ops->read_l)
> > +		return host->reg_ops->read_l(host, reg);
> > +	else
> > +		return readl(host->base + reg);
> > +}
> 
> This seems a bit strange. I would suggest you either use the ops structure
> all the time and provide an imx variant, or you make it completely
> compile-time selected.

I wanted to avoid additional levels of indirection and function calls
on i.MX. If something like

static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg)
{
#if IS_ENABLED(CONFIG_PPC_MPC512x)
	return in_be32(host->base + reg);
#else
	return readl(host->base + reg); 
#endif
}

is acceptable, I'll use it.

> > @@ -1026,24 +1115,33 @@ static int mxcmci_probe(struct platform_device *pdev)
> >  	host->res = r;
> >  	host->irq = irq;
> >  
> > -	host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
> > -	if (IS_ERR(host->clk_ipg)) {
> > -		ret = PTR_ERR(host->clk_ipg);
> > -		goto out_iounmap;
> > -	}
> > +	if (!is_mpc512x_mmc(host)) {
> > +		host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
> > +		if (IS_ERR(host->clk_ipg)) {
> > +			ret = PTR_ERR(host->clk_ipg);
> > +			goto out_iounmap;
> > +		}
> 
> Does mpc512x have no clock management? I think it should still
> work without modifications if CONFIG_HAVE_CLK is disabled.
> In that case, devm_clk_get() will return NULL and we don't
> error out here.

It does have some clock management (a platform clock driver) and
the platform selects CONFIG_HAVE_CLK. But we do not have "ipg"
and "per" clocks on that platform, but "sdhc_clk" instead.

Thanks,

Anatolij
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sascha Hauer March 14, 2013, 8:05 p.m. UTC | #3
On Thu, Mar 14, 2013 at 07:13:32PM +0100, Anatolij Gustschin wrote:
> On Thu, 14 Mar 2013 17:50:08 +0100
> Arnd Bergmann <arnd@arndb.de> wrote:
> 
> > On Thursday 14 March 2013 17:40:49 Anatolij Gustschin wrote:
> > 
> > > +
> > > +struct mxcmci_reg_ops mxcmci_reg_ops = {
> > > +	.read_l = mpcmci_readl,
> > > +	.write_l = mpcmci_writel,
> > > +	.read_w = mpcmci_readw,
> > > +	.write_w = mpcmci_writew,
> > > +};
> > > +#else
> > > +struct mxcmci_reg_ops mxcmci_reg_ops;
> > > +#endif
> > 
> > Should the struct be static?
> 
> yes, it should.
> 
> > > +static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg)
> > > +{
> > > +	if (host->reg_ops->read_l)
> > > +		return host->reg_ops->read_l(host, reg);
> > > +	else
> > > +		return readl(host->base + reg);
> > > +}
> > 
> > This seems a bit strange. I would suggest you either use the ops structure
> > all the time and provide an imx variant, or you make it completely
> > compile-time selected.
> 
> I wanted to avoid additional levels of indirection and function calls
> on i.MX. If something like
> 
> static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg)
> {
> #if IS_ENABLED(CONFIG_PPC_MPC512x)
> 	return in_be32(host->base + reg);
> #else
> 	return readl(host->base + reg); 
> #endif

I really wish we would have native endianess accessors...

> 
> is acceptable, I'll use it.

Looks better to me.

> > > @@ -1026,24 +1115,33 @@ static int mxcmci_probe(struct platform_device *pdev)
> > >  	host->res = r;
> > >  	host->irq = irq;
> > >  
> > > -	host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
> > > -	if (IS_ERR(host->clk_ipg)) {
> > > -		ret = PTR_ERR(host->clk_ipg);
> > > -		goto out_iounmap;
> > > -	}
> > > +	if (!is_mpc512x_mmc(host)) {
> > > +		host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
> > > +		if (IS_ERR(host->clk_ipg)) {
> > > +			ret = PTR_ERR(host->clk_ipg);
> > > +			goto out_iounmap;
> > > +		}
> > 
> > Does mpc512x have no clock management? I think it should still
> > work without modifications if CONFIG_HAVE_CLK is disabled.
> > In that case, devm_clk_get() will return NULL and we don't
> > error out here.
> 
> It does have some clock management (a platform clock driver) and
> the platform selects CONFIG_HAVE_CLK. But we do not have "ipg"
> and "per" clocks on that platform, but "sdhc_clk" instead.

The clocks should be modelled after the input clocks the MMC controller
has, not after the clocks the SoC provides control for. So if you cannot
software control a clock then you should provide a dummy clock for it.

That said, 'ipg' is not a very good name for a mpc SoC,
something like 'bus' would probably be better.

Sascha
Arnd Bergmann March 14, 2013, 10:52 p.m. UTC | #4
On Thursday 14 March 2013, Anatolij Gustschin wrote:
> I wanted to avoid additional levels of indirection and function calls
> on i.MX. If something like
> 
> static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg)
> {
> #if IS_ENABLED(CONFIG_PPC_MPC512x)
>         return in_be32(host->base + reg);
> #else
>         return readl(host->base + reg); 
> #endif
> }
> 
> is acceptable, I'll use it.

I think that's ok. A single #ifdef around the four functions might be
nicer though. You could also use ioread32_be on powerpc and write it
like

static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg)
{
	if (IS_ENABLED(CONFIG_PPC_MPC512x))
		return ioread32_be(host->base + reg);
	else
		return readl(host->base + reg); 
}

> > Does mpc512x have no clock management? I think it should still
> > work without modifications if CONFIG_HAVE_CLK is disabled.
> > In that case, devm_clk_get() will return NULL and we don't
> > error out here.
> 
> It does have some clock management (a platform clock driver) and
> the platform selects CONFIG_HAVE_CLK. But we do not have "ipg"
> and "per" clocks on that platform, but "sdhc_clk" instead.

As Sascha said, they should really use the same name, although it's
possible that neither sdhc_clk nor ipg is a good name here.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index d88219e..eda4376 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -319,12 +319,12 @@  config MMC_MSM
 	  support for SDIO devices.
 
 config MMC_MXC
-	tristate "Freescale i.MX21/27/31 Multimedia Card Interface support"
-	depends on ARCH_MXC
+	tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support"
+	depends on ARCH_MXC || PPC_MPC512x
 	help
-	  This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card
-	  Interface. If you have a i.MX platform with a Multimedia Card slot,
-	  say Y or M here.
+	  This selects the Freescale i.MX21, i.MX27, i.MX31 or MPC512x
+	  Multimedia Card Interface. If you have an i.MX or MPC512x platform
+	  with a Multimedia Card slot, say Y or M here.
 
 	  If unsure, say N.
 
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 626698b..562f4e6 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -41,7 +41,6 @@ 
 
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
 #include <linux/platform_data/mmc-mxcmmc.h>
 
 #include <linux/platform_data/dma-imx.h>
@@ -119,8 +118,11 @@ 
 enum mxcmci_type {
 	IMX21_MMC,
 	IMX31_MMC,
+	MPC512X_MMC,
 };
 
+struct mxcmci_reg_ops;
+
 struct mxcmci_host {
 	struct mmc_host		*mmc;
 	struct resource		*res;
@@ -162,6 +164,8 @@  struct mxcmci_host {
 
 	struct timer_list	watchdog;
 	enum mxcmci_type	devtype;
+
+	struct mxcmci_reg_ops   *reg_ops;
 };
 
 static struct platform_device_id mxcmci_devtype[] = {
@@ -172,6 +176,9 @@  static struct platform_device_id mxcmci_devtype[] = {
 		.name = "imx31-mmc",
 		.driver_data = IMX31_MMC,
 	}, {
+		.name = "mpc512x-sdhc",
+		.driver_data = MPC512X_MMC,
+	}, {
 		/* sentinel */
 	}
 };
@@ -185,6 +192,9 @@  static const struct of_device_id mxcmci_of_match[] = {
 		.compatible = "fsl,imx31-mmc",
 		.data = &mxcmci_devtype[IMX31_MMC],
 	}, {
+		.compatible = "fsl,mpc5121-sdhc",
+		.data = &mxcmci_devtype[MPC512X_MMC],
+	}, {
 		/* sentinel */
 	}
 };
@@ -195,6 +205,81 @@  static inline int is_imx31_mmc(struct mxcmci_host *host)
 	return host->devtype == IMX31_MMC;
 }
 
+static inline int is_mpc512x_mmc(struct mxcmci_host *host)
+{
+	return host->devtype == MPC512X_MMC;
+}
+
+struct mxcmci_reg_ops {
+	void	(*write_l)(struct mxcmci_host *host, u32 val, int reg);
+	u32	(*read_l)(struct mxcmci_host *host, int reg);
+	void	(*write_w)(struct mxcmci_host *host, u16 val, int reg);
+	u16	(*read_w)(struct mxcmci_host *host, int reg);
+};
+
+#if IS_ENABLED(CONFIG_PPC_MPC512x)
+static void mpcmci_writel(struct mxcmci_host *host, u32 val, int reg)
+{
+	out_be32(host->base + reg, val);
+}
+
+static u32 mpcmci_readl(struct mxcmci_host *host, int reg)
+{
+	return in_be32(host->base + reg);
+}
+
+static void mpcmci_writew(struct mxcmci_host *host, u16 val, int reg)
+{
+	out_be32(host->base + reg, val);
+}
+
+static u16 mpcmci_readw(struct mxcmci_host *host, int reg)
+{
+	return in_be32(host->base + reg);
+}
+
+struct mxcmci_reg_ops mxcmci_reg_ops = {
+	.read_l = mpcmci_readl,
+	.write_l = mpcmci_writel,
+	.read_w = mpcmci_readw,
+	.write_w = mpcmci_writew,
+};
+#else
+struct mxcmci_reg_ops mxcmci_reg_ops;
+#endif
+
+static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg)
+{
+	if (host->reg_ops->read_l)
+		return host->reg_ops->read_l(host, reg);
+	else
+		return readl(host->base + reg);
+}
+
+static inline void mxcmci_writel(struct mxcmci_host *host, u32 val, int reg)
+{
+	if (host->reg_ops->write_l)
+		host->reg_ops->write_l(host, val, reg);
+	else
+		writel(val, host->base + reg);
+}
+
+static inline u16 mxcmci_readw(struct mxcmci_host *host, int reg)
+{
+	if (host->reg_ops->read_w)
+		return host->reg_ops->read_w(host, reg);
+	else
+		return readw(host->base + reg);
+}
+
+static inline void mxcmci_writew(struct mxcmci_host *host, u16 val, int reg)
+{
+	if (host->reg_ops->write_w)
+		host->reg_ops->write_w(host, val, reg);
+	else
+		writew(val, host->base + reg);
+}
+
 static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
 
 static inline void mxcmci_init_ocr(struct mxcmci_host *host)
@@ -246,14 +331,14 @@  static void mxcmci_softreset(struct mxcmci_host *host)
 	dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n");
 
 	/* reset sequence */
-	writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK);
-	writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
-			host->base + MMC_REG_STR_STP_CLK);
+	mxcmci_writew(host, STR_STP_CLK_RESET, MMC_REG_STR_STP_CLK);
+	mxcmci_writew(host, STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
+			MMC_REG_STR_STP_CLK);
 
 	for (i = 0; i < 8; i++)
-		writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
+		mxcmci_writew(host, STR_STP_CLK_START_CLK, MMC_REG_STR_STP_CLK);
 
-	writew(0xff, host->base + MMC_REG_RES_TO);
+	mxcmci_writew(host, 0xff, MMC_REG_RES_TO);
 }
 static int mxcmci_setup_dma(struct mmc_host *mmc);
 
@@ -272,8 +357,8 @@  static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
 	host->data = data;
 	data->bytes_xfered = 0;
 
-	writew(nob, host->base + MMC_REG_NOB);
-	writew(blksz, host->base + MMC_REG_BLK_LEN);
+	mxcmci_writew(host, nob, MMC_REG_NOB);
+	mxcmci_writew(host, blksz, MMC_REG_BLK_LEN);
 	host->datasize = datasize;
 
 	if (!mxcmci_use_dma(host))
@@ -329,13 +414,13 @@  static void mxcmci_dma_callback(void *data)
 
 	del_timer(&host->watchdog);
 
-	stat = readl(host->base + MMC_REG_STATUS);
-	writel(stat & ~STATUS_DATA_TRANS_DONE, host->base + MMC_REG_STATUS);
+	stat = mxcmci_readl(host, MMC_REG_STATUS);
+	mxcmci_writel(host, stat & ~STATUS_DATA_TRANS_DONE, MMC_REG_STATUS);
 
 	dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
 
 	if (stat & STATUS_READ_OP_DONE)
-		writel(STATUS_READ_OP_DONE, host->base + MMC_REG_STATUS);
+		mxcmci_writel(host, STATUS_READ_OP_DONE, MMC_REG_STATUS);
 
 	mxcmci_data_done(host, stat);
 }
@@ -383,12 +468,12 @@  static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
 	spin_lock_irqsave(&host->lock, flags);
 	if (host->use_sdio)
 		int_cntr |= INT_SDIO_IRQ_EN;
-	writel(int_cntr, host->base + MMC_REG_INT_CNTR);
+	mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR);
 	spin_unlock_irqrestore(&host->lock, flags);
 
-	writew(cmd->opcode, host->base + MMC_REG_CMD);
-	writel(cmd->arg, host->base + MMC_REG_ARG);
-	writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT);
+	mxcmci_writew(host, cmd->opcode, MMC_REG_CMD);
+	mxcmci_writel(host, cmd->arg, MMC_REG_ARG);
+	mxcmci_writew(host, cmdat, MMC_REG_CMD_DAT_CONT);
 
 	return 0;
 }
@@ -402,7 +487,7 @@  static void mxcmci_finish_request(struct mxcmci_host *host,
 	spin_lock_irqsave(&host->lock, flags);
 	if (host->use_sdio)
 		int_cntr |= INT_SDIO_IRQ_EN;
-	writel(int_cntr, host->base + MMC_REG_INT_CNTR);
+	mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR);
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	host->req = NULL;
@@ -477,14 +562,14 @@  static void mxcmci_read_response(struct mxcmci_host *host, unsigned int stat)
 	if (cmd->flags & MMC_RSP_PRESENT) {
 		if (cmd->flags & MMC_RSP_136) {
 			for (i = 0; i < 4; i++) {
-				a = readw(host->base + MMC_REG_RES_FIFO);
-				b = readw(host->base + MMC_REG_RES_FIFO);
+				a = mxcmci_readw(host, MMC_REG_RES_FIFO);
+				b = mxcmci_readw(host, MMC_REG_RES_FIFO);
 				cmd->resp[i] = a << 16 | b;
 			}
 		} else {
-			a = readw(host->base + MMC_REG_RES_FIFO);
-			b = readw(host->base + MMC_REG_RES_FIFO);
-			c = readw(host->base + MMC_REG_RES_FIFO);
+			a = mxcmci_readw(host, MMC_REG_RES_FIFO);
+			b = mxcmci_readw(host, MMC_REG_RES_FIFO);
+			c = mxcmci_readw(host, MMC_REG_RES_FIFO);
 			cmd->resp[0] = a << 24 | b << 8 | c >> 8;
 		}
 	}
@@ -496,7 +581,7 @@  static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
 	unsigned long timeout = jiffies + HZ;
 
 	do {
-		stat = readl(host->base + MMC_REG_STATUS);
+		stat = mxcmci_readl(host, MMC_REG_STATUS);
 		if (stat & STATUS_ERR_MASK)
 			return stat;
 		if (time_after(jiffies, timeout)) {
@@ -520,7 +605,7 @@  static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
 				STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
 		if (stat)
 			return stat;
-		*buf++ = readl(host->base + MMC_REG_BUFFER_ACCESS);
+		*buf++ = cpu_to_le32(mxcmci_readl(host, MMC_REG_BUFFER_ACCESS));
 		bytes -= 4;
 	}
 
@@ -532,7 +617,7 @@  static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
 				STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
 		if (stat)
 			return stat;
-		tmp = readl(host->base + MMC_REG_BUFFER_ACCESS);
+		tmp = cpu_to_le32(mxcmci_readl(host, MMC_REG_BUFFER_ACCESS));
 		memcpy(b, &tmp, bytes);
 	}
 
@@ -548,7 +633,7 @@  static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
 		stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
 		if (stat)
 			return stat;
-		writel(*buf++, host->base + MMC_REG_BUFFER_ACCESS);
+		mxcmci_writel(host, cpu_to_le32(*buf++), MMC_REG_BUFFER_ACCESS);
 		bytes -= 4;
 	}
 
@@ -561,7 +646,7 @@  static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
 			return stat;
 
 		memcpy(&tmp, b, bytes);
-		writel(tmp, host->base + MMC_REG_BUFFER_ACCESS);
+		mxcmci_writel(host, cpu_to_le32(tmp), MMC_REG_BUFFER_ACCESS);
 	}
 
 	stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
@@ -607,8 +692,8 @@  static void mxcmci_datawork(struct work_struct *work)
 						  datawork);
 	int datastat = mxcmci_transfer_data(host);
 
-	writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
-		host->base + MMC_REG_STATUS);
+	mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
+		MMC_REG_STATUS);
 	mxcmci_finish_data(host, datastat);
 
 	if (host->req->stop) {
@@ -670,9 +755,11 @@  static irqreturn_t mxcmci_irq(int irq, void *devid)
 	bool sdio_irq;
 	u32 stat;
 
-	stat = readl(host->base + MMC_REG_STATUS);
-	writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE |
-			STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS);
+	stat = mxcmci_readl(host, MMC_REG_STATUS);
+	mxcmci_writel(host,
+		stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE |
+			 STATUS_WRITE_OP_DONE),
+		MMC_REG_STATUS);
 
 	dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
 
@@ -682,11 +769,11 @@  static irqreturn_t mxcmci_irq(int irq, void *devid)
 
 	if (mxcmci_use_dma(host) &&
 	    (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE)))
-		writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
-			host->base + MMC_REG_STATUS);
+		mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
+			MMC_REG_STATUS);
 
 	if (sdio_irq) {
-		writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS);
+		mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS);
 		mmc_signal_sdio_irq(host->mmc);
 	}
 
@@ -768,7 +855,7 @@  static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios)
 			prescaler <<= 1;
 	}
 
-	writew((prescaler << 4) | divider, host->base + MMC_REG_CLK_RATE);
+	mxcmci_writew(host, (prescaler << 4) | divider, MMC_REG_CLK_RATE);
 
 	dev_dbg(mmc_dev(host->mmc), "scaler: %d divider: %d in: %d out: %d\n",
 			prescaler, divider, clk_in, clk_ios);
@@ -831,9 +918,9 @@  static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
 	if (ios->clock) {
 		mxcmci_set_clk_rate(host, ios->clock);
-		writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
+		mxcmci_writew(host, STR_STP_CLK_START_CLK, MMC_REG_STR_STP_CLK);
 	} else {
-		writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK);
+		mxcmci_writew(host, STR_STP_CLK_STOP_CLK, MMC_REG_STR_STP_CLK);
 	}
 
 	host->clock = ios->clock;
@@ -870,14 +957,14 @@  static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 
 	spin_lock_irqsave(&host->lock, flags);
 	host->use_sdio = enable;
-	int_cntr = readl(host->base + MMC_REG_INT_CNTR);
+	int_cntr = mxcmci_readl(host, MMC_REG_INT_CNTR);
 
 	if (enable)
 		int_cntr |= INT_SDIO_IRQ_EN;
 	else
 		int_cntr &= ~INT_SDIO_IRQ_EN;
 
-	writel(int_cntr, host->base + MMC_REG_INT_CNTR);
+	mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR);
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -915,7 +1002,7 @@  static void mxcmci_watchdog(unsigned long data)
 	struct mmc_host *mmc = (struct mmc_host *)data;
 	struct mxcmci_host *host = mmc_priv(mmc);
 	struct mmc_request *req = host->req;
-	unsigned int stat = readl(host->base + MMC_REG_STATUS);
+	unsigned int stat = mxcmci_readl(host, MMC_REG_STATUS);
 
 	if (host->dma_dir == DMA_FROM_DEVICE) {
 		dmaengine_terminate_all(host->dma);
@@ -957,7 +1044,7 @@  static int mxcmci_probe(struct platform_device *pdev)
 	const struct of_device_id *of_id;
 	struct imxmmc_platform_data *pdata = pdev->dev.platform_data;
 
-	pr_info("i.MX SDHC driver\n");
+	pr_info("i.MX/MPC512x SDHC driver\n");
 
 	of_id = of_match_device(mxcmci_of_match, &pdev->dev);
 
@@ -999,6 +1086,8 @@  static int mxcmci_probe(struct platform_device *pdev)
 		goto out_free;
 	}
 
+	host->reg_ops = &mxcmci_reg_ops;
+
 	if (of_id) {
 		struct platform_device_id *id_entry = of_id->data;
 		host->devtype = id_entry->driver_data;
@@ -1026,24 +1115,33 @@  static int mxcmci_probe(struct platform_device *pdev)
 	host->res = r;
 	host->irq = irq;
 
-	host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
-	if (IS_ERR(host->clk_ipg)) {
-		ret = PTR_ERR(host->clk_ipg);
-		goto out_iounmap;
-	}
+	if (!is_mpc512x_mmc(host)) {
+		host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
+		if (IS_ERR(host->clk_ipg)) {
+			ret = PTR_ERR(host->clk_ipg);
+			goto out_iounmap;
+		}
 
-	host->clk_per = devm_clk_get(&pdev->dev, "per");
-	if (IS_ERR(host->clk_per)) {
-		ret = PTR_ERR(host->clk_per);
-		goto out_iounmap;
-	}
+		host->clk_per = devm_clk_get(&pdev->dev, "per");
+		if (IS_ERR(host->clk_per)) {
+			ret = PTR_ERR(host->clk_per);
+			goto out_iounmap;
+		}
 
-	clk_prepare_enable(host->clk_per);
-	clk_prepare_enable(host->clk_ipg);
+		clk_prepare_enable(host->clk_per);
+		clk_prepare_enable(host->clk_ipg);
+	} else {
+		host->clk_per = clk_get(&pdev->dev, "sdhc_clk");
+		if (IS_ERR(host->clk_per)) {
+			ret = PTR_ERR(host->clk_per);
+			goto out_iounmap;
+		}
+		clk_prepare_enable(host->clk_per);
+	}
 
 	mxcmci_softreset(host);
 
-	host->rev_no = readw(host->base + MMC_REG_REV_NO);
+	host->rev_no = mxcmci_readw(host, MMC_REG_REV_NO);
 	if (host->rev_no != 0x400) {
 		ret = -ENODEV;
 		dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
@@ -1055,9 +1153,9 @@  static int mxcmci_probe(struct platform_device *pdev)
 	mmc->f_max = clk_get_rate(host->clk_per) >> 1;
 
 	/* recommended in data sheet */
-	writew(0x2db4, host->base + MMC_REG_READ_TO);
+	mxcmci_writew(host, 0x2db4, MMC_REG_READ_TO);
 
-	writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR);
+	mxcmci_writel(host, host->default_irq_mask, MMC_REG_INT_CNTR);
 
 	if (!host->pdata) {
 		host->dma = of_dma_request_slave_channel(pdev->dev.of_node,
@@ -1110,7 +1208,8 @@  out_free_dma:
 		dma_release_channel(host->dma);
 out_clk_put:
 	clk_disable_unprepare(host->clk_per);
-	clk_disable_unprepare(host->clk_ipg);
+	if (!is_mpc512x_mmc(host))
+		clk_disable_unprepare(host->clk_ipg);
 out_iounmap:
 	iounmap(host->base);
 out_free:
@@ -1142,7 +1241,8 @@  static int mxcmci_remove(struct platform_device *pdev)
 		dma_release_channel(host->dma);
 
 	clk_disable_unprepare(host->clk_per);
-	clk_disable_unprepare(host->clk_ipg);
+	if (!is_mpc512x_mmc(host))
+		clk_disable_unprepare(host->clk_ipg);
 
 	release_mem_region(host->res->start, resource_size(host->res));
 
@@ -1161,7 +1261,8 @@  static int mxcmci_suspend(struct device *dev)
 	if (mmc)
 		ret = mmc_suspend_host(mmc);
 	clk_disable_unprepare(host->clk_per);
-	clk_disable_unprepare(host->clk_ipg);
+	if (!is_mpc512x_mmc(host))
+		clk_disable_unprepare(host->clk_ipg);
 
 	return ret;
 }
@@ -1173,7 +1274,8 @@  static int mxcmci_resume(struct device *dev)
 	int ret = 0;
 
 	clk_prepare_enable(host->clk_per);
-	clk_prepare_enable(host->clk_ipg);
+	if (!is_mpc512x_mmc(host))
+		clk_prepare_enable(host->clk_ipg);
 	if (mmc)
 		ret = mmc_resume_host(mmc);