Skip to content
Snippets Groups Projects
Commit bba1594d authored by Russell King's avatar Russell King
Browse files

Merge branch 'mmci' into amba

parents 9e5ed094 7437cfa5
No related merge requests found
...@@ -31,21 +31,13 @@ ...@@ -31,21 +31,13 @@
* SDI 0 (MicroSD slot) * SDI 0 (MicroSD slot)
*/ */
/* MMCIPOWER bits */
#define MCI_DATA2DIREN (1 << 2)
#define MCI_CMDDIREN (1 << 3)
#define MCI_DATA0DIREN (1 << 4)
#define MCI_DATA31DIREN (1 << 5)
#define MCI_FBCLKEN (1 << 7)
/* GPIO pins used by the sdi0 level shifter */ /* GPIO pins used by the sdi0 level shifter */
static int sdi0_en = -1; static int sdi0_en = -1;
static int sdi0_vsel = -1; static int sdi0_vsel = -1;
static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd, static int mop500_sdi0_ios_handler(struct device *dev, struct mmc_ios *ios)
unsigned char power_mode)
{ {
switch (power_mode) { switch (ios->power_mode) {
case MMC_POWER_UP: case MMC_POWER_UP:
case MMC_POWER_ON: case MMC_POWER_ON:
/* /*
...@@ -65,8 +57,7 @@ static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd, ...@@ -65,8 +57,7 @@ static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd,
break; break;
} }
return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN | return 0;
MCI_DATA2DIREN | MCI_DATA31DIREN;
} }
#ifdef CONFIG_STE_DMA40 #ifdef CONFIG_STE_DMA40
...@@ -90,13 +81,17 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = { ...@@ -90,13 +81,17 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = {
#endif #endif
static struct mmci_platform_data mop500_sdi0_data = { static struct mmci_platform_data mop500_sdi0_data = {
.vdd_handler = mop500_sdi0_vdd_handler, .ios_handler = mop500_sdi0_ios_handler,
.ocr_mask = MMC_VDD_29_30, .ocr_mask = MMC_VDD_29_30,
.f_max = 50000000, .f_max = 50000000,
.capabilities = MMC_CAP_4_BIT_DATA | .capabilities = MMC_CAP_4_BIT_DATA |
MMC_CAP_SD_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_MMC_HIGHSPEED, MMC_CAP_MMC_HIGHSPEED,
.gpio_wp = -1, .gpio_wp = -1,
.sigdir = MCI_ST_FBCLKEN |
MCI_ST_CMDDIREN |
MCI_ST_DATA0DIREN |
MCI_ST_DATA2DIREN,
#ifdef CONFIG_STE_DMA40 #ifdef CONFIG_STE_DMA40
.dma_filter = stedma40_filter, .dma_filter = stedma40_filter,
.dma_rx_param = &mop500_sdi0_dma_cfg_rx, .dma_rx_param = &mop500_sdi0_dma_cfg_rx,
......
...@@ -53,6 +53,8 @@ static unsigned int fmax = 515633; ...@@ -53,6 +53,8 @@ static unsigned int fmax = 515633;
* @sdio: variant supports SDIO * @sdio: variant supports SDIO
* @st_clkdiv: true if using a ST-specific clock divider algorithm * @st_clkdiv: true if using a ST-specific clock divider algorithm
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
* @pwrreg_powerup: power up value for MMCIPOWER register
* @signal_direction: input/out direction of bus signals can be indicated
*/ */
struct variant_data { struct variant_data {
unsigned int clkreg; unsigned int clkreg;
...@@ -63,18 +65,22 @@ struct variant_data { ...@@ -63,18 +65,22 @@ struct variant_data {
bool sdio; bool sdio;
bool st_clkdiv; bool st_clkdiv;
bool blksz_datactrl16; bool blksz_datactrl16;
u32 pwrreg_powerup;
bool signal_direction;
}; };
static struct variant_data variant_arm = { static struct variant_data variant_arm = {
.fifosize = 16 * 4, .fifosize = 16 * 4,
.fifohalfsize = 8 * 4, .fifohalfsize = 8 * 4,
.datalength_bits = 16, .datalength_bits = 16,
.pwrreg_powerup = MCI_PWR_UP,
}; };
static struct variant_data variant_arm_extended_fifo = { static struct variant_data variant_arm_extended_fifo = {
.fifosize = 128 * 4, .fifosize = 128 * 4,
.fifohalfsize = 64 * 4, .fifohalfsize = 64 * 4,
.datalength_bits = 16, .datalength_bits = 16,
.pwrreg_powerup = MCI_PWR_UP,
}; };
static struct variant_data variant_u300 = { static struct variant_data variant_u300 = {
...@@ -83,6 +89,8 @@ static struct variant_data variant_u300 = { ...@@ -83,6 +89,8 @@ static struct variant_data variant_u300 = {
.clkreg_enable = MCI_ST_U300_HWFCEN, .clkreg_enable = MCI_ST_U300_HWFCEN,
.datalength_bits = 16, .datalength_bits = 16,
.sdio = true, .sdio = true,
.pwrreg_powerup = MCI_PWR_ON,
.signal_direction = true,
}; };
static struct variant_data variant_ux500 = { static struct variant_data variant_ux500 = {
...@@ -93,6 +101,8 @@ static struct variant_data variant_ux500 = { ...@@ -93,6 +101,8 @@ static struct variant_data variant_ux500 = {
.datalength_bits = 24, .datalength_bits = 24,
.sdio = true, .sdio = true,
.st_clkdiv = true, .st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
.signal_direction = true,
}; };
static struct variant_data variant_ux500v2 = { static struct variant_data variant_ux500v2 = {
...@@ -104,8 +114,32 @@ static struct variant_data variant_ux500v2 = { ...@@ -104,8 +114,32 @@ static struct variant_data variant_ux500v2 = {
.sdio = true, .sdio = true,
.st_clkdiv = true, .st_clkdiv = true,
.blksz_datactrl16 = true, .blksz_datactrl16 = true,
.pwrreg_powerup = MCI_PWR_ON,
.signal_direction = true,
}; };
/*
* This must be called with host->lock held
*/
static void mmci_write_clkreg(struct mmci_host *host, u32 clk)
{
if (host->clk_reg != clk) {
host->clk_reg = clk;
writel(clk, host->base + MMCICLOCK);
}
}
/*
* This must be called with host->lock held
*/
static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
{
if (host->pwr_reg != pwr) {
host->pwr_reg = pwr;
writel(pwr, host->base + MMCIPOWER);
}
}
/* /*
* This must be called with host->lock held * This must be called with host->lock held
*/ */
...@@ -153,7 +187,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) ...@@ -153,7 +187,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
clk |= MCI_ST_8BIT_BUS; clk |= MCI_ST_8BIT_BUS;
writel(clk, host->base + MMCICLOCK); mmci_write_clkreg(host, clk);
} }
static void static void
...@@ -166,14 +200,10 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) ...@@ -166,14 +200,10 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
host->mrq = NULL; host->mrq = NULL;
host->cmd = NULL; host->cmd = NULL;
/*
* Need to drop the host lock here; mmc_request_done may call
* back into the driver...
*/
spin_unlock(&host->lock);
pm_runtime_put(mmc_dev(host->mmc));
mmc_request_done(host->mmc, mrq); mmc_request_done(host->mmc, mrq);
spin_lock(&host->lock);
pm_runtime_mark_last_busy(mmc_dev(host->mmc));
pm_runtime_put_autosuspend(mmc_dev(host->mmc));
} }
static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
...@@ -607,6 +637,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) ...@@ -607,6 +637,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
if (data->flags & MMC_DATA_READ) if (data->flags & MMC_DATA_READ)
datactrl |= MCI_DPSM_DIRECTION; datactrl |= MCI_DPSM_DIRECTION;
/* The ST Micro variants has a special bit to enable SDIO */
if (variant->sdio && host->mmc->card)
if (mmc_card_sdio(host->mmc->card))
datactrl |= MCI_ST_DPSM_SDIOEN;
/* /*
* Attempt to use DMA operation mode, if this * Attempt to use DMA operation mode, if this
* should fail, fall back to PIO mode * should fail, fall back to PIO mode
...@@ -635,11 +670,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) ...@@ -635,11 +670,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
irqmask = MCI_TXFIFOHALFEMPTYMASK; irqmask = MCI_TXFIFOHALFEMPTYMASK;
} }
/* The ST Micro variants has a special bit to enable SDIO */
if (variant->sdio && host->mmc->card)
if (mmc_card_sdio(host->mmc->card))
datactrl |= MCI_ST_DPSM_SDIOEN;
writel(datactrl, base + MMCIDATACTRL); writel(datactrl, base + MMCIDATACTRL);
writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
mmci_set_mask1(host, irqmask); mmci_set_mask1(host, irqmask);
...@@ -786,7 +816,24 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema ...@@ -786,7 +816,24 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
if (count <= 0) if (count <= 0)
break; break;
readsl(base + MMCIFIFO, ptr, count >> 2); /*
* SDIO especially may want to send something that is
* not divisible by 4 (as opposed to card sectors
* etc). Therefore make sure to always read the last bytes
* while only doing full 32-bit reads towards the FIFO.
*/
if (unlikely(count & 0x3)) {
if (count < 4) {
unsigned char buf[4];
readsl(base + MMCIFIFO, buf, 1);
memcpy(ptr, buf, count);
} else {
readsl(base + MMCIFIFO, ptr, count >> 2);
count &= ~0x3;
}
} else {
readsl(base + MMCIFIFO, ptr, count >> 2);
}
ptr += count; ptr += count;
remain -= count; remain -= count;
...@@ -821,14 +868,13 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem ...@@ -821,14 +868,13 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
*/ */
if (variant->sdio && if (variant->sdio &&
mmc_card_sdio(host->mmc->card)) { mmc_card_sdio(host->mmc->card)) {
u32 clk;
if (count < 8) if (count < 8)
writel(readl(host->base + MMCICLOCK) & clk = host->clk_reg & ~variant->clkreg_enable;
~variant->clkreg_enable,
host->base + MMCICLOCK);
else else
writel(readl(host->base + MMCICLOCK) | clk = host->clk_reg | variant->clkreg_enable;
variant->clkreg_enable,
host->base + MMCICLOCK); mmci_write_clkreg(host, clk);
} }
/* /*
...@@ -1015,10 +1061,17 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -1015,10 +1061,17 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{ {
struct mmci_host *host = mmc_priv(mmc); struct mmci_host *host = mmc_priv(mmc);
struct variant_data *variant = host->variant;
u32 pwr = 0; u32 pwr = 0;
unsigned long flags; unsigned long flags;
int ret; int ret;
pm_runtime_get_sync(mmc_dev(mmc));
if (host->plat->ios_handler &&
host->plat->ios_handler(mmc_dev(mmc), ios))
dev_err(mmc_dev(mmc), "platform ios_handler failed\n");
switch (ios->power_mode) { switch (ios->power_mode) {
case MMC_POWER_OFF: case MMC_POWER_OFF:
if (host->vcc) if (host->vcc)
...@@ -1035,22 +1088,38 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1035,22 +1088,38 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
* power should be rare so we print an error * power should be rare so we print an error
* and return here. * and return here.
*/ */
return; goto out;
} }
} }
if (host->plat->vdd_handler) /*
pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd, * The ST Micro variant doesn't have the PL180s MCI_PWR_UP
ios->power_mode); * and instead uses MCI_PWR_ON so apply whatever value is
/* The ST version does not have this, fall through to POWER_ON */ * configured in the variant data.
if (host->hw_designer != AMBA_VENDOR_ST) { */
pwr |= MCI_PWR_UP; pwr |= variant->pwrreg_powerup;
break;
} break;
case MMC_POWER_ON: case MMC_POWER_ON:
pwr |= MCI_PWR_ON; pwr |= MCI_PWR_ON;
break; break;
} }
if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) {
/*
* The ST Micro variant has some additional bits
* indicating signal direction for the signals in
* the SD/MMC bus and feedback-clock usage.
*/
pwr |= host->plat->sigdir;
if (ios->bus_width == MMC_BUS_WIDTH_4)
pwr &= ~MCI_ST_DATA74DIREN;
else if (ios->bus_width == MMC_BUS_WIDTH_1)
pwr &= (~MCI_ST_DATA74DIREN &
~MCI_ST_DATA31DIREN &
~MCI_ST_DATA2DIREN);
}
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
if (host->hw_designer != AMBA_VENDOR_ST) if (host->hw_designer != AMBA_VENDOR_ST)
pwr |= MCI_ROD; pwr |= MCI_ROD;
...@@ -1066,13 +1135,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1066,13 +1135,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
mmci_set_clkreg(host, ios->clock); mmci_set_clkreg(host, ios->clock);
mmci_write_pwrreg(host, pwr);
if (host->pwr != pwr) {
host->pwr = pwr;
writel(pwr, host->base + MMCIPOWER);
}
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
out:
pm_runtime_mark_last_busy(mmc_dev(mmc));
pm_runtime_put_autosuspend(mmc_dev(mmc));
} }
static int mmci_get_ro(struct mmc_host *mmc) static int mmci_get_ro(struct mmc_host *mmc)
...@@ -1345,6 +1414,8 @@ static int __devinit mmci_probe(struct amba_device *dev, ...@@ -1345,6 +1414,8 @@ static int __devinit mmci_probe(struct amba_device *dev,
mmci_dma_setup(host); mmci_dma_setup(host);
pm_runtime_set_autosuspend_delay(&dev->dev, 50);
pm_runtime_use_autosuspend(&dev->dev);
pm_runtime_put(&dev->dev); pm_runtime_put(&dev->dev);
mmc_add_host(mmc); mmc_add_host(mmc);
...@@ -1429,43 +1500,49 @@ static int __devexit mmci_remove(struct amba_device *dev) ...@@ -1429,43 +1500,49 @@ static int __devexit mmci_remove(struct amba_device *dev)
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_SUSPEND
static int mmci_suspend(struct amba_device *dev, pm_message_t state) static int mmci_suspend(struct device *dev)
{ {
struct mmc_host *mmc = amba_get_drvdata(dev); struct amba_device *adev = to_amba_device(dev);
struct mmc_host *mmc = amba_get_drvdata(adev);
int ret = 0; int ret = 0;
if (mmc) { if (mmc) {
struct mmci_host *host = mmc_priv(mmc); struct mmci_host *host = mmc_priv(mmc);
ret = mmc_suspend_host(mmc); ret = mmc_suspend_host(mmc);
if (ret == 0) if (ret == 0) {
pm_runtime_get_sync(dev);
writel(0, host->base + MMCIMASK0); writel(0, host->base + MMCIMASK0);
}
} }
return ret; return ret;
} }
static int mmci_resume(struct amba_device *dev) static int mmci_resume(struct device *dev)
{ {
struct mmc_host *mmc = amba_get_drvdata(dev); struct amba_device *adev = to_amba_device(dev);
struct mmc_host *mmc = amba_get_drvdata(adev);
int ret = 0; int ret = 0;
if (mmc) { if (mmc) {
struct mmci_host *host = mmc_priv(mmc); struct mmci_host *host = mmc_priv(mmc);
writel(MCI_IRQENABLE, host->base + MMCIMASK0); writel(MCI_IRQENABLE, host->base + MMCIMASK0);
pm_runtime_put(dev);
ret = mmc_resume_host(mmc); ret = mmc_resume_host(mmc);
} }
return ret; return ret;
} }
#else
#define mmci_suspend NULL
#define mmci_resume NULL
#endif #endif
static const struct dev_pm_ops mmci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume)
};
static struct amba_id mmci_ids[] = { static struct amba_id mmci_ids[] = {
{ {
.id = 0x00041180, .id = 0x00041180,
...@@ -1511,11 +1588,10 @@ MODULE_DEVICE_TABLE(amba, mmci_ids); ...@@ -1511,11 +1588,10 @@ MODULE_DEVICE_TABLE(amba, mmci_ids);
static struct amba_driver mmci_driver = { static struct amba_driver mmci_driver = {
.drv = { .drv = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.pm = &mmci_dev_pm_ops,
}, },
.probe = mmci_probe, .probe = mmci_probe,
.remove = __devexit_p(mmci_remove), .remove = __devexit_p(mmci_remove),
.suspend = mmci_suspend,
.resume = mmci_resume,
.id_table = mmci_ids, .id_table = mmci_ids,
}; };
......
...@@ -13,16 +13,6 @@ ...@@ -13,16 +13,6 @@
#define MCI_PWR_ON 0x03 #define MCI_PWR_ON 0x03
#define MCI_OD (1 << 6) #define MCI_OD (1 << 6)
#define MCI_ROD (1 << 7) #define MCI_ROD (1 << 7)
/*
* The ST Micro version does not have ROD and reuse the voltage registers
* for direction settings
*/
#define MCI_ST_DATA2DIREN (1 << 2)
#define MCI_ST_CMDDIREN (1 << 3)
#define MCI_ST_DATA0DIREN (1 << 4)
#define MCI_ST_DATA31DIREN (1 << 5)
#define MCI_ST_FBCLKEN (1 << 7)
#define MCI_ST_DATA74DIREN (1 << 8)
#define MMCICLOCK 0x004 #define MMCICLOCK 0x004
#define MCI_CLK_ENABLE (1 << 8) #define MCI_CLK_ENABLE (1 << 8)
...@@ -160,7 +150,7 @@ ...@@ -160,7 +150,7 @@
(MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
MCI_TXFIFOHALFEMPTYMASK) MCI_TXFIFOHALFEMPTYMASK)
#define NR_SG 16 #define NR_SG 128
struct clk; struct clk;
struct variant_data; struct variant_data;
...@@ -189,7 +179,8 @@ struct mmci_host { ...@@ -189,7 +179,8 @@ struct mmci_host {
unsigned int mclk; unsigned int mclk;
unsigned int cclk; unsigned int cclk;
u32 pwr; u32 pwr_reg;
u32 clk_reg;
struct mmci_platform_data *plat; struct mmci_platform_data *plat;
struct variant_data *variant; struct variant_data *variant;
......
...@@ -6,6 +6,19 @@ ...@@ -6,6 +6,19 @@
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
/*
* These defines is places here due to access is needed from machine
* configuration files. The ST Micro version does not have ROD and
* reuse the voltage registers for direction settings.
*/
#define MCI_ST_DATA2DIREN (1 << 2)
#define MCI_ST_CMDDIREN (1 << 3)
#define MCI_ST_DATA0DIREN (1 << 4)
#define MCI_ST_DATA31DIREN (1 << 5)
#define MCI_ST_FBCLKEN (1 << 7)
#define MCI_ST_DATA74DIREN (1 << 8)
/* Just some dummy forwarding */ /* Just some dummy forwarding */
struct dma_chan; struct dma_chan;
...@@ -18,7 +31,8 @@ struct dma_chan; ...@@ -18,7 +31,8 @@ struct dma_chan;
* @ocr_mask: available voltages on the 4 pins from the block, this * @ocr_mask: available voltages on the 4 pins from the block, this
* is ignored if a regulator is used, see the MMC_VDD_* masks in * is ignored if a regulator is used, see the MMC_VDD_* masks in
* mmc/host.h * mmc/host.h
* @vdd_handler: a callback function to translate a MMC_VDD_* * @ios_handler: a callback function to act on specfic ios changes,
* used for example to control a levelshifter
* mask into a value to be binary (or set some other custom bits * mask into a value to be binary (or set some other custom bits
* in MMCIPWR) or:ed and written into the MMCIPWR register of the * in MMCIPWR) or:ed and written into the MMCIPWR register of the
* block. May also control external power based on the power_mode. * block. May also control external power based on the power_mode.
...@@ -31,6 +45,8 @@ struct dma_chan; ...@@ -31,6 +45,8 @@ struct dma_chan;
* @capabilities: the capabilities of the block as implemented in * @capabilities: the capabilities of the block as implemented in
* this platform, signify anything MMC_CAP_* from mmc/host.h * this platform, signify anything MMC_CAP_* from mmc/host.h
* @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h
* @sigdir: a bit field indicating for what bits in the MMC bus the host
* should enable signal direction indication.
* @dma_filter: function used to select an appropriate RX and TX * @dma_filter: function used to select an appropriate RX and TX
* DMA channel to be used for DMA, if and only if you're deploying the * DMA channel to be used for DMA, if and only if you're deploying the
* generic DMA engine * generic DMA engine
...@@ -46,14 +62,14 @@ struct dma_chan; ...@@ -46,14 +62,14 @@ struct dma_chan;
struct mmci_platform_data { struct mmci_platform_data {
unsigned int f_max; unsigned int f_max;
unsigned int ocr_mask; unsigned int ocr_mask;
u32 (*vdd_handler)(struct device *, unsigned int vdd, int (*ios_handler)(struct device *, struct mmc_ios *);
unsigned char power_mode);
unsigned int (*status)(struct device *); unsigned int (*status)(struct device *);
int gpio_wp; int gpio_wp;
int gpio_cd; int gpio_cd;
bool cd_invert; bool cd_invert;
unsigned long capabilities; unsigned long capabilities;
unsigned long capabilities2; unsigned long capabilities2;
u32 sigdir;
bool (*dma_filter)(struct dma_chan *chan, void *filter_param); bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
void *dma_rx_param; void *dma_rx_param;
void *dma_tx_param; void *dma_tx_param;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment