Commit bba1594d authored by Russell King's avatar Russell King

Merge branch 'mmci' into amba

parents 9e5ed094 7437cfa5
...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment