diff mbox

[U-Boot,RFC] mmc: Remove ops from struct mmc and put in mmc_ops

Message ID 1393437144-27563-1-git-send-email-panto@antoniou-consulting.com
State RFC
Delegated to: Tom Rini
Headers show

Commit Message

Pantelis Antoniou Feb. 26, 2014, 5:52 p.m. UTC
Remove the in-structure ops and put them in mmc_ops with
a constant pointer to it.

This makes the mmc structure smaller as well as conserving
code space (in theory).

All in-tree drivers are converted as well; this is done in a
single patch in order to not break git bisect.

Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>
---
 drivers/mmc/arm_pl180_mmci.c | 12 +++++----
 drivers/mmc/bfin_sdh.c       | 11 ++++----
 drivers/mmc/davinci_mmc.c    | 13 ++++-----
 drivers/mmc/dw_mmc.c         | 10 ++++---
 drivers/mmc/fsl_esdhc.c      | 14 +++++-----
 drivers/mmc/ftsdc010_mci.c   | 11 +++++---
 drivers/mmc/gen_atmel_mci.c  | 12 +++++----
 drivers/mmc/mmc.c            | 21 ++++++++-------
 drivers/mmc/mmc_spi.c        | 12 +++++----
 drivers/mmc/mxcmmc.c         | 12 +++++----
 drivers/mmc/mxsmmc.c         | 12 +++++----
 drivers/mmc/omap_hsmmc.c     | 63 +++++++++++++++++++++++++++-----------------
 drivers/mmc/pxa_mmc_gen.c    | 11 +++++---
 drivers/mmc/sdhci.c          | 13 +++++----
 drivers/mmc/sh_mmcif.c       | 12 +++++----
 drivers/mmc/tegra_mmc.c      | 19 +++++++------
 include/mmc.h                | 19 ++++++++-----
 17 files changed, 167 insertions(+), 110 deletions(-)

Comments

Rommel G Custodio Feb. 27, 2014, 4:04 a.m. UTC | #1
Dear Pantelis Antoniou

Pantelis Antoniou <panto <at> antoniou-consulting.com> writes:

> 
> Remove the in-structure ops and put them in mmc_ops with
> a constant pointer to it.
> 
> This makes the mmc structure smaller as well as conserving
> code space (in theory).

First build is latest master. Second build was with your patch. Compare size 
output.


[local (powerpc-linux-gnuspe)]$ powerpc-linux-gnuspe-size obj-
P5040DS_SPIFLASH_master/u-boot
   text    data     bss     dec     hex filename
 463352   39236  314064  816652   c760c obj-P5040DS_SPIFLASH_master/u-boot


[local (powerpc-linux-gnuspe)]$ powerpc-linux-gnuspe-size obj-
P5040DS_SPIFLASH/u-boot
   text    data     bss     dec     hex filename
 463364   39256  314064  816684   c762c obj-P5040DS_SPIFLASH/u-boot

> 
> All in-tree drivers are converted as well; this is done in a
> single patch in order to not break git bisect.
> 

<snipped>
Tom Rini Feb. 27, 2014, 1:46 p.m. UTC | #2
On Wed, Feb 26, 2014 at 07:52:24PM +0200, Pantelis Antoniou wrote:

> Remove the in-structure ops and put them in mmc_ops with
> a constant pointer to it.
> 
> This makes the mmc structure smaller as well as conserving
> code space (in theory).
> 
> All in-tree drivers are converted as well; this is done in a
> single patch in order to not break git bisect.
> 
> Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>
[snip]
> diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
> index d3a8b53..4b27097 100644
> --- a/drivers/mmc/omap_hsmmc.c
> +++ b/drivers/mmc/omap_hsmmc.c
> @@ -70,25 +70,12 @@ static int omap_mmc_setup_gpio_in(int gpio, const char *label)
>  	return gpio;
>  }
>  
> -static int omap_mmc_getcd(struct mmc *mmc)
> -{
> -	int cd_gpio = ((struct omap_hsmmc_data *)mmc->priv)->cd_gpio;
> -	return gpio_get_value(cd_gpio);
> -}
> -
> -static int omap_mmc_getwp(struct mmc *mmc)
> -{
> -	int wp_gpio = ((struct omap_hsmmc_data *)mmc->priv)->wp_gpio;
> -	return gpio_get_value(wp_gpio);
> -}
>  #else
>  static inline int omap_mmc_setup_gpio_in(int gpio, const char *label)
>  {
>  	return -1;
>  }
>  
> -#define omap_mmc_getcd NULL
> -#define omap_mmc_getwp NULL
>  #endif

Note that we're not just testing for SPL in the above we're also testing
for OMAP_GPIO being set.  So this breaks am3517_evm tseries_spi mcx
am3517_crane omap3_evm_quick_mmc omap3_evm omap3_zoom1 omap3_sdp3430 and
tseries_mmc.
Tom Rini Feb. 27, 2014, 1:50 p.m. UTC | #3
On Thu, Feb 27, 2014 at 04:04:55AM +0000, Rommel G Custodio wrote:
> Dear Pantelis Antoniou
> 
> Pantelis Antoniou <panto <at> antoniou-consulting.com> writes:
> 
> > 
> > Remove the in-structure ops and put them in mmc_ops with
> > a constant pointer to it.
> > 
> > This makes the mmc structure smaller as well as conserving
> > code space (in theory).
> 
> First build is latest master. Second build was with your patch. Compare size 
> output.
> 
> 
> [local (powerpc-linux-gnuspe)]$ powerpc-linux-gnuspe-size obj-
> P5040DS_SPIFLASH_master/u-boot
>    text    data     bss     dec     hex filename
>  463352   39236  314064  816652   c760c obj-P5040DS_SPIFLASH_master/u-boot
> 
> 
> [local (powerpc-linux-gnuspe)]$ powerpc-linux-gnuspe-size obj-
> P5040DS_SPIFLASH/u-boot
>    text    data     bss     dec     hex filename
>  463364   39256  314064  816684   c762c obj-P5040DS_SPIFLASH/u-boot

The size increase on ARM is smaller, but still there too.

So we aren't making the code smaller nor the binaries.  Marek, was this
your request to clean up or ?  Will this help make device model stuff
easier down the line?
Marek Vasut March 3, 2014, 10:04 a.m. UTC | #4
On Wednesday, February 26, 2014 at 06:52:24 PM, Pantelis Antoniou wrote:
> Remove the in-structure ops and put them in mmc_ops with
> a constant pointer to it.
> 
> This makes the mmc structure smaller as well as conserving
> code space (in theory).
> 
> All in-tree drivers are converted as well; this is done in a
> single patch in order to not break git bisect.
> 
> Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>

f_min, voltages ... are also slot-specific , so you want to pull them out as 
well I think.

Best regards,
Marek Vasut
diff mbox

Patch

diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c
index 5a55fe7..4490e97 100644
--- a/drivers/mmc/arm_pl180_mmci.c
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -335,6 +335,12 @@  static void host_set_ios(struct mmc *dev)
 	udelay(CLK_CHANGE_DELAY);
 }
 
+static const struct mmc_ops arm_pl180_mmci_ops = {
+	.send_cmd = host_request,
+	.set_ios = host_set_ios,
+	.init = mmc_host_reset,
+};
+
 /*
  * mmc_host_init - initialize the mmc controller.
  * Set initial clock and power for mmc slot.
@@ -360,11 +366,7 @@  int arm_pl180_mmci_init(struct pl180_mmc_host *host)
 	sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
 	writel(sdi_u32, &host->base->mask0);
 	strncpy(dev->name, host->name, sizeof(dev->name));
-	dev->send_cmd = host_request;
-	dev->set_ios = host_set_ios;
-	dev->init = mmc_host_reset;
-	dev->getcd = NULL;
-	dev->getwp = NULL;
+	dev->ops = &arm_pl180_mmci_ops;
 	dev->host_caps = host->caps;
 	dev->voltages = host->voltages;
 	dev->f_min = host->clock_min;
diff --git a/drivers/mmc/bfin_sdh.c b/drivers/mmc/bfin_sdh.c
index bd9b641..f0871ec 100644
--- a/drivers/mmc/bfin_sdh.c
+++ b/drivers/mmc/bfin_sdh.c
@@ -274,6 +274,11 @@  static int bfin_sdh_init(struct mmc *mmc)
 	return 0;
 }
 
+static const struct mmc_ops bfin_mmc_ops = {
+	.send_cmd	= bfin_sdh_request,
+	.set_ios	= bfin_sdh_set_ios,
+	.init		= bfin_sdh_init,
+};
 
 int bfin_mmc_init(bd_t *bis)
 {
@@ -284,11 +289,7 @@  int bfin_mmc_init(bd_t *bis)
 	if (!mmc)
 		return -ENOMEM;
 	sprintf(mmc->name, "Blackfin SDH");
-	mmc->send_cmd = bfin_sdh_request;
-	mmc->set_ios = bfin_sdh_set_ios;
-	mmc->init = bfin_sdh_init;
-	mmc->getcd = NULL;
-	mmc->getwp = NULL;
+	mmc->ops = &bfin_mmc_ops;
 	mmc->host_caps = MMC_MODE_4BIT;
 
 	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c
index b380961..29ca4a6 100644
--- a/drivers/mmc/davinci_mmc.c
+++ b/drivers/mmc/davinci_mmc.c
@@ -363,6 +363,12 @@  static void dmmc_set_ios(struct mmc *mmc)
 		dmmc_set_clock(mmc, mmc->clock);
 }
 
+static const struct mmc_ops dmmc_ops = {
+	.send_cmd	= dmmc_send_cmd,
+	.set_ios	= dmmc_set_ios,
+	.init		= dmmc_init,
+};
+
 /* Called from board_mmc_init during startup. Can be called multiple times
  * depending on the number of slots available on board and controller
  */
@@ -375,12 +381,7 @@  int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host)
 
 	sprintf(mmc->name, "davinci");
 	mmc->priv = host;
-	mmc->send_cmd = dmmc_send_cmd;
-	mmc->set_ios = dmmc_set_ios;
-	mmc->init = dmmc_init;
-	mmc->getcd = NULL;
-	mmc->getwp = NULL;
-
+	mmc->ops = &dmmc_ops;
 	mmc->f_min = 200000;
 	mmc->f_max = 25000000;
 	mmc->voltages = host->voltages;
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index d45c15c..2e6576e 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -343,6 +343,12 @@  static int dwmci_init(struct mmc *mmc)
 	return 0;
 }
 
+static const struct mmc_ops dwmci_ops = {
+	.send_cmd	= dwmci_send_cmd,
+	.set_ios	= dwmci_set_ios,
+	.init		= dwmci_init,
+};
+
 int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk)
 {
 	struct mmc *mmc;
@@ -358,9 +364,7 @@  int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk)
 	host->mmc = mmc;
 
 	sprintf(mmc->name, "%s", host->name);
-	mmc->send_cmd = dwmci_send_cmd;
-	mmc->set_ios = dwmci_set_ios;
-	mmc->init = dwmci_init;
+	mmc->ops = &dwmci_ops;
 	mmc->f_min = min_clk;
 	mmc->f_max = max_clk;
 
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 7b146a3..861f536 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -524,6 +524,13 @@  static void esdhc_reset(struct fsl_esdhc *regs)
 		printf("MMC/SD: Reset never completed.\n");
 }
 
+static const struct mmc_ops esdhc_ops = {
+	.send_cmd	= esdhc_send_cmd,
+	.set_ios	= esdhc_set_ios,
+	.init		= esdhc_init,
+	.getcd		= esdhc_getcd,
+};
+
 int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
 {
 	struct fsl_esdhc *regs;
@@ -548,12 +555,7 @@  int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
 				| SYSCTL_IPGEN | SYSCTL_CKEN);
 
 	mmc->priv = cfg;
-	mmc->send_cmd = esdhc_send_cmd;
-	mmc->set_ios = esdhc_set_ios;
-	mmc->init = esdhc_init;
-	mmc->getcd = esdhc_getcd;
-	mmc->getwp = NULL;
-
+	mmc->ops = &esdhc_ops;
 	voltage_caps = 0;
 	caps = regs->hostcapblt;
 
diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
index 7600d5c..ce43ae1 100644
--- a/drivers/mmc/ftsdc010_mci.c
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -316,6 +316,12 @@  static int ftsdc010_init(struct mmc *mmc)
 	return 0;
 }
 
+static const struct mmc_ops ftsdc010_ops = {
+	.send_cmd	= ftsdc010_request,
+	.set_ios	= ftsdc010_set_ios,
+	.init		= ftsdc010_init,
+};
+
 int ftsdc010_mmc_init(int devid)
 {
 	struct mmc *mmc;
@@ -347,10 +353,7 @@  int ftsdc010_mmc_init(int devid)
 	mmc->priv  = chip;
 
 	sprintf(mmc->name, "ftsdc010");
-	mmc->send_cmd  = ftsdc010_request;
-	mmc->set_ios   = ftsdc010_set_ios;
-	mmc->init      = ftsdc010_init;
-
+	mmc->ops = &ftsdc010_ops;
 	mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
 	switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
 	case FTSDC010_BWR_CAPS_4BIT:
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c
index c11dcd0..456f8bf 100644
--- a/drivers/mmc/gen_atmel_mci.c
+++ b/drivers/mmc/gen_atmel_mci.c
@@ -344,6 +344,12 @@  static int mci_init(struct mmc *mmc)
 	return 0;
 }
 
+static const struct mmc_ops atmel_mci_ops = {
+	.send_cmd	= mci_send_cmd,
+	.set_ios	= mci_set_ios,
+	.init		= mci_init,
+};
+
 /*
  * This is the only exported function
  *
@@ -360,11 +366,7 @@  int atmel_mci_init(void *regs)
 
 	strcpy(mmc->name, "mci");
 	mmc->priv = regs;
-	mmc->send_cmd = mci_send_cmd;
-	mmc->set_ios = mci_set_ios;
-	mmc->init = mci_init;
-	mmc->getcd = NULL;
-	mmc->getwp = NULL;
+	mmc->ops = &atmel_mci_ops;
 
 	/* need to be able to pass these in on a board by board basis */
 	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 8ab0bc9..ac07bb9 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -37,8 +37,8 @@  int mmc_getwp(struct mmc *mmc)
 	wp = board_mmc_getwp(mmc);
 
 	if (wp < 0) {
-		if (mmc->getwp)
-			wp = mmc->getwp(mmc);
+		if (mmc->ops->getwp)
+			wp = mmc->ops->getwp(mmc);
 		else
 			wp = 0;
 	}
@@ -63,7 +63,7 @@  int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 
 	printf("CMD_SEND:%d\n", cmd->cmdidx);
 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
-	ret = mmc->send_cmd(mmc, cmd, data);
+	ret = mmc->ops->send_cmd(mmc, cmd, data);
 	switch (cmd->resp_type) {
 		case MMC_RSP_NONE:
 			printf("\t\tMMC_RSP_NONE\n");
@@ -106,7 +106,7 @@  int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 			break;
 	}
 #else
-	ret = mmc->send_cmd(mmc, cmd, data);
+	ret = mmc->ops->send_cmd(mmc, cmd, data);
 #endif
 	return ret;
 }
@@ -578,8 +578,8 @@  int mmc_getcd(struct mmc *mmc)
 	cd = board_mmc_getcd(mmc);
 
 	if (cd < 0) {
-		if (mmc->getcd)
-			cd = mmc->getcd(mmc);
+		if (mmc->ops->getcd)
+			cd = mmc->ops->getcd(mmc);
 		else
 			cd = 1;
 	}
@@ -751,7 +751,8 @@  static const int multipliers[] = {
 
 static void mmc_set_ios(struct mmc *mmc)
 {
-	mmc->set_ios(mmc);
+	if (mmc->ops->set_ios)
+		mmc->ops->set_ios(mmc);
 }
 
 void mmc_set_clock(struct mmc *mmc, uint clock)
@@ -1207,7 +1208,8 @@  int mmc_start_init(struct mmc *mmc)
 {
 	int err;
 
-	if (mmc_getcd(mmc) == 0) {
+	/* we pretend there's no card when init is NULL */
+	if (mmc_getcd(mmc) == 0 || mmc->ops->init == NULL) {
 		mmc->has_init = 0;
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
 		printf("MMC: no card present\n");
@@ -1218,7 +1220,8 @@  int mmc_start_init(struct mmc *mmc)
 	if (mmc->has_init)
 		return 0;
 
-	err = mmc->init(mmc);
+	/* made sure it's not NULL earlier */
+	err = mmc->ops->init(mmc);
 
 	if (err)
 		return err;
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c
index fe6a5a1..0a0f894 100644
--- a/drivers/mmc/mmc_spi.c
+++ b/drivers/mmc/mmc_spi.c
@@ -255,6 +255,12 @@  static int mmc_spi_init_p(struct mmc *mmc)
 	return 0;
 }
 
+static const struct mmc_ops mmc_spi_ops = {
+	.send_cmd	= mmc_spi_request,
+	.set_ios	= mmc_spi_set_ios,
+	.init		= mmc_spi_init_p,
+};
+
 struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode)
 {
 	struct mmc *mmc;
@@ -269,11 +275,7 @@  struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode)
 		return NULL;
 	}
 	sprintf(mmc->name, "MMC_SPI");
-	mmc->send_cmd = mmc_spi_request;
-	mmc->set_ios = mmc_spi_set_ios;
-	mmc->init = mmc_spi_init_p;
-	mmc->getcd = NULL;
-	mmc->getwp = NULL;
+	mmc->ops = &mmc_spi_ops;
 	mmc->host_caps = MMC_MODE_SPI;
 
 	mmc->voltages = MMC_SPI_VOLTAGE;
diff --git a/drivers/mmc/mxcmmc.c b/drivers/mmc/mxcmmc.c
index 4f99617..f3e1eed 100644
--- a/drivers/mmc/mxcmmc.c
+++ b/drivers/mmc/mxcmmc.c
@@ -485,6 +485,12 @@  static int mxcmci_init(struct mmc *mmc)
 	return 0;
 }
 
+static const struct mmc_ops mxcmci_ops = {
+	.send_cmd	= mxcmci_request,
+	.set_ios	= mxcmci_set_ios,
+	.init		= mxcmci_init,
+};
+
 static int mxcmci_initialize(bd_t *bis)
 {
 	struct mmc *mmc = NULL;
@@ -495,11 +501,7 @@  static int mxcmci_initialize(bd_t *bis)
 		return -ENOMEM;
 
 	sprintf(mmc->name, "MXC MCI");
-	mmc->send_cmd = mxcmci_request;
-	mmc->set_ios = mxcmci_set_ios;
-	mmc->init = mxcmci_init;
-	mmc->getcd = NULL;
-	mmc->getwp = NULL;
+	mmc->ops = &mxcmci_ops;
 	mmc->host_caps = MMC_MODE_4BIT;
 
 	host->base = (struct mxcmci_regs *)CONFIG_MXC_MCI_REGS_BASE;
diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c
index 245f9d0..97c9ee8 100644
--- a/drivers/mmc/mxsmmc.c
+++ b/drivers/mmc/mxsmmc.c
@@ -363,6 +363,12 @@  static int mxsmmc_init(struct mmc *mmc)
 	return 0;
 }
 
+static const struct mmc_ops mxsmmc_ops = {
+	.send_cmd	= mxsmmc_send_cmd,
+	.set_ios	= mxsmmc_set_ios,
+	.init		= mxsmmc_init,
+};
+
 int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int))
 {
 	struct mmc *mmc = NULL;
@@ -400,11 +406,7 @@  int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int))
 	priv->regs = mxs_ssp_regs_by_bus(id);
 
 	sprintf(mmc->name, "MXS MMC");
-	mmc->send_cmd = mxsmmc_send_cmd;
-	mmc->set_ios = mxsmmc_set_ios;
-	mmc->init = mxsmmc_init;
-	mmc->getcd = NULL;
-	mmc->getwp = NULL;
+	mmc->ops = &mxsmmc_ops;
 	mmc->priv = priv;
 
 	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index d3a8b53..4b27097 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -70,25 +70,12 @@  static int omap_mmc_setup_gpio_in(int gpio, const char *label)
 	return gpio;
 }
 
-static int omap_mmc_getcd(struct mmc *mmc)
-{
-	int cd_gpio = ((struct omap_hsmmc_data *)mmc->priv)->cd_gpio;
-	return gpio_get_value(cd_gpio);
-}
-
-static int omap_mmc_getwp(struct mmc *mmc)
-{
-	int wp_gpio = ((struct omap_hsmmc_data *)mmc->priv)->wp_gpio;
-	return gpio_get_value(wp_gpio);
-}
 #else
 static inline int omap_mmc_setup_gpio_in(int gpio, const char *label)
 {
 	return -1;
 }
 
-#define omap_mmc_getcd NULL
-#define omap_mmc_getwp NULL
 #endif
 
 #if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
@@ -213,7 +200,7 @@  void mmc_init_stream(struct hsmmc *mmc_base)
 }
 
 
-static int mmc_init_setup(struct mmc *mmc)
+static int omap_hsmmc_init_setup(struct mmc *mmc)
 {
 	struct hsmmc *mmc_base;
 	unsigned int reg_val;
@@ -322,7 +309,7 @@  static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
 	}
 }
 
-static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 			struct mmc_data *data)
 {
 	struct hsmmc *mmc_base;
@@ -552,7 +539,7 @@  static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
 	return 0;
 }
 
-static void mmc_set_ios(struct mmc *mmc)
+static void omap_hsmmc_set_ios(struct mmc *mmc)
 {
 	struct hsmmc *mmc_base;
 	unsigned int dsor = 0;
@@ -606,6 +593,40 @@  static void mmc_set_ios(struct mmc *mmc)
 	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
 }
 
+static int omap_hsmmc_getcd(struct mmc *mmc)
+{
+	struct omap_hsmmc_data *priv_data = mmc->priv;
+	int cd_gpio;
+
+	/* if no CD return as 1 */
+	cd_gpio = priv_data->cd_gpio;
+	if (cd_gpio < 0)
+		return 1;
+
+	return gpio_get_value(cd_gpio);
+}
+
+static int omap_hsmmc_getwp(struct mmc *mmc)
+{
+	struct omap_hsmmc_data *priv_data = mmc->priv;
+	int wp_gpio;
+
+	/* if no WP return as 0 */
+	wp_gpio = priv_data->wp_gpio;
+	if (wp_gpio < 0)
+		return 0;
+
+	return gpio_get_value(wp_gpio);
+}
+
+static const struct mmc_ops omap_hsmmc_ops = {
+	.send_cmd	= omap_hsmmc_send_cmd,
+	.set_ios	= omap_hsmmc_set_ios,
+	.init		= omap_hsmmc_init_setup,
+	.getcd		= omap_hsmmc_getcd,
+	.getwp		= omap_hsmmc_getwp,
+};
+
 int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
 		int wp_gpio)
 {
@@ -615,9 +636,7 @@  int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
 			     MMC_MODE_HC;
 
 	sprintf(mmc->name, "OMAP SD/MMC");
-	mmc->send_cmd = mmc_send_cmd;
-	mmc->set_ios = mmc_set_ios;
-	mmc->init = mmc_init_setup;
+	mmc->ops = &omap_hsmmc_ops;
 	mmc->priv = priv_data;
 
 	switch (dev_index) {
@@ -647,13 +666,9 @@  int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
 		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
 		return 1;
 	}
+	/* on error gpio values are set to -1, which is what we want */
 	priv_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd");
-	if (priv_data->cd_gpio != -1)
-		mmc->getcd = omap_mmc_getcd;
-
 	priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");
-	if (priv_data->wp_gpio != -1)
-		mmc->getwp = omap_mmc_getwp;
 
 	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
 	mmc->host_caps = host_caps_val & ~host_caps_mask;
diff --git a/drivers/mmc/pxa_mmc_gen.c b/drivers/mmc/pxa_mmc_gen.c
index 29f3eaf..4694c8f 100644
--- a/drivers/mmc/pxa_mmc_gen.c
+++ b/drivers/mmc/pxa_mmc_gen.c
@@ -366,6 +366,12 @@  static int pxa_mmc_init(struct mmc *mmc)
 	return 0;
 }
 
+static const struct mmc_ops pxa_mmc_ops = {
+	.send_cmd	= pxa_mmc_request,
+	.set_ios	= pxa_mmc_set_ios,
+	.init		= pxa_mmc_init,
+};
+
 int pxa_mmc_register(int card_index)
 {
 	struct mmc *mmc;
@@ -397,10 +403,7 @@  int pxa_mmc_register(int card_index)
 	mmc->priv = priv;
 
 	sprintf(mmc->name, "PXA MMC");
-	mmc->send_cmd	= pxa_mmc_request;
-	mmc->set_ios	= pxa_mmc_set_ios;
-	mmc->init	= pxa_mmc_init;
-	mmc->getcd	= NULL;
+	mmc->ops = &pxa_mmc_ops;
 
 	mmc->voltages	= MMC_VDD_32_33 | MMC_VDD_33_34;
 	mmc->f_max	= PXAMMC_MAX_SPEED;
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 1e86b92..c3425a6 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -430,6 +430,13 @@  int sdhci_init(struct mmc *mmc)
 	return 0;
 }
 
+
+static const struct mmc_ops sdhci_ops = {
+	.send_cmd	= sdhci_send_command,
+	.set_ios	= sdhci_set_ios,
+	.init		= sdhci_init,
+};
+
 int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
 {
 	struct mmc *mmc;
@@ -445,11 +452,7 @@  int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
 	host->mmc = mmc;
 
 	sprintf(mmc->name, "%s", host->name);
-	mmc->send_cmd = sdhci_send_command;
-	mmc->set_ios = sdhci_set_ios;
-	mmc->init = sdhci_init;
-	mmc->getcd = NULL;
-	mmc->getwp = NULL;
+	mmc->ops = &sdhci_ops;
 
 	caps = sdhci_readl(host, SDHCI_CAPABILITIES);
 #ifdef CONFIG_MMC_SDMA
diff --git a/drivers/mmc/sh_mmcif.c b/drivers/mmc/sh_mmcif.c
index 011d4f3..6a4860b 100644
--- a/drivers/mmc/sh_mmcif.c
+++ b/drivers/mmc/sh_mmcif.c
@@ -574,6 +574,12 @@  static int sh_mmcif_init(struct mmc *mmc)
 	return 0;
 }
 
+static const struct mmc_ops sh_mmcif_ops = {
+	.send_cmd	= sh_mmcif_request,
+	.set_ios	= sh_mmcif_set_ios,
+	.init		= sh_mmcif_init,
+};
+
 int mmcif_mmc_init(void)
 {
 	int ret = 0;
@@ -595,11 +601,7 @@  int mmcif_mmc_init(void)
 	mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT |
 			 MMC_MODE_8BIT | MMC_MODE_HC;
 	memcpy(mmc->name, DRIVER_NAME, sizeof(DRIVER_NAME));
-	mmc->send_cmd = sh_mmcif_request;
-	mmc->set_ios = sh_mmcif_set_ios;
-	mmc->init = sh_mmcif_init;
-	mmc->getcd = NULL;
-	mmc->getwp = NULL;
+	mmc->ops = &sh_mmcif_ops;
 	host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR;
 	host->clk = CONFIG_SH_MMCIF_CLK;
 	mmc->priv = host;
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index 3d1ce12..5f7b590 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -314,7 +314,7 @@  static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
 	return 0;
 }
 
-static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+static int tegra_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 			struct mmc_data *data)
 {
 	void *buf;
@@ -396,7 +396,7 @@  out:
 	host->clock = clock;
 }
 
-static void mmc_set_ios(struct mmc *mmc)
+static void tegra_mmc_set_ios(struct mmc *mmc)
 {
 	struct mmc_host *host = mmc->priv;
 	unsigned char ctrl;
@@ -464,7 +464,7 @@  static void mmc_reset(struct mmc_host *host, struct mmc *mmc)
 	pad_init_mmc(host);
 }
 
-static int mmc_core_init(struct mmc *mmc)
+static int tegra_mmc_core_init(struct mmc *mmc)
 {
 	struct mmc_host *host = (struct mmc_host *)mmc->priv;
 	unsigned int mask;
@@ -521,6 +521,13 @@  int tegra_mmc_getcd(struct mmc *mmc)
 	return 1;
 }
 
+static const struct mmc_ops tegra_mmc_ops = {
+	.send_cmd	= tegra_mmc_send_cmd,
+	.set_ios	= tegra_mmc_set_ios,
+	.init		= tegra_mmc_core_init,
+	.getcd		= tegra_mmc_getcd,
+};
+
 static int do_mmc_init(int dev_index)
 {
 	struct mmc_host *host;
@@ -558,11 +565,7 @@  static int do_mmc_init(int dev_index)
 
 	sprintf(mmc->name, "Tegra SD/MMC");
 	mmc->priv = host;
-	mmc->send_cmd = mmc_send_cmd;
-	mmc->set_ios = mmc_set_ios;
-	mmc->init = mmc_core_init;
-	mmc->getcd = tegra_mmc_getcd;
-	mmc->getwp = NULL;
+	mmc->ops = &tegra_mmc_ops;
 
 	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
 	mmc->host_caps = 0;
diff --git a/include/mmc.h b/include/mmc.h
index e95a237..3d53ce1 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -250,6 +250,18 @@  struct mmc_data {
 	uint blocksize;
 };
 
+/* forward decl. */
+struct mmc;
+
+struct mmc_ops {
+	int (*send_cmd)(struct mmc *mmc,
+			struct mmc_cmd *cmd, struct mmc_data *data);
+	void (*set_ios)(struct mmc *mmc);
+	int (*init)(struct mmc *mmc);
+	int (*getcd)(struct mmc *mmc);
+	int (*getwp)(struct mmc *mmc);
+};
+
 struct mmc {
 	struct list_head link;
 	char name[32];
@@ -283,12 +295,7 @@  struct mmc {
 	u64 capacity_rpmb;
 	u64 capacity_gp[4];
 	block_dev_desc_t block_dev;
-	int (*send_cmd)(struct mmc *mmc,
-			struct mmc_cmd *cmd, struct mmc_data *data);
-	void (*set_ios)(struct mmc *mmc);
-	int (*init)(struct mmc *mmc);
-	int (*getcd)(struct mmc *mmc);
-	int (*getwp)(struct mmc *mmc);
+	const struct mmc_ops *ops;
 	uint b_max;
 	char op_cond_pending;	/* 1 if we are waiting on an op_cond command */
 	char init_in_progress;	/* 1 if we have done mmc_start_init() */