diff options
Diffstat (limited to 'drivers/mmc/host')
41 files changed, 1898 insertions, 755 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 8c87096531e9..cf444b0ca2cc 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -130,13 +130,13 @@ config MMC_SDHCI_CNS3XXX If unsure, say N. config MMC_SDHCI_ESDHC_IMX - tristate "SDHCI platform support for the Freescale eSDHC i.MX controller" - depends on ARCH_MX25 || ARCH_MX35 || ARCH_MX5 + tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" + depends on ARCH_MXC depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS help - This selects the Freescale eSDHC controller support on the platform - bus, found on platforms like mx35/51. + This selects the Freescale eSDHC/uSDHC controller support + found on i.MX25, i.MX35 i.MX5x and i.MX6x. If you have a controller with this interface, say Y or M here. @@ -263,7 +263,7 @@ config MMC_WBSD config MMC_AU1X tristate "Alchemy AU1XX0 MMC Card Interface support" - depends on SOC_AU1200 + depends on MIPS_ALCHEMY help This selects the AMD Alchemy(R) Multimedia card interface. If you have a Alchemy platform with a MMC slot, say Y or M here. @@ -326,11 +326,11 @@ config MMC_MSM support for SDIO devices. config MMC_MXC - tristate "Freescale i.MX2/3 Multimedia Card Interface support" - depends on MACH_MX21 || MACH_MX27 || ARCH_MX31 + tristate "Freescale i.MX21/27/31 Multimedia Card Interface support" + depends on ARCH_MXC help - This selects the Freescale i.MX2/3 Multimedia card Interface. - If you have a i.MX platform with a Multimedia Card slot, + 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. If unsure, say N. diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index a4aa3af86fed..a8b4d2aa18e5 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -869,7 +869,11 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) static irqreturn_t at91_mmc_det_irq(int irq, void *_host) { struct at91mci_host *host = _host; - int present = !gpio_get_value(irq_to_gpio(irq)); + int present; + + /* entering this ISR means that we have configured det_pin: + * we can use its value in board structure */ + present = !gpio_get_value(host->board->det_pin); /* * we expect this irq on both insert and remove, diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index fc8a0fe7c5c5..000b3ad0f5ca 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -17,112 +17,126 @@ #define __DRIVERS_MMC_ATMEL_MCI_H__ /* MCI Register Definitions */ -#define MCI_CR 0x0000 /* Control */ -# define MCI_CR_MCIEN ( 1 << 0) /* MCI Enable */ -# define MCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */ -# define MCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */ -# define MCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */ -# define MCI_CR_SWRST ( 1 << 7) /* Software Reset */ -#define MCI_MR 0x0004 /* Mode */ -# define MCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ -# define MCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ -# define MCI_MR_RDPROOF ( 1 << 11) /* Read Proof */ -# define MCI_MR_WRPROOF ( 1 << 12) /* Write Proof */ -# define MCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ -# define MCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ -# define MCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ -#define MCI_DTOR 0x0008 /* Data Timeout */ -# define MCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ -# define MCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ -#define MCI_SDCR 0x000c /* SD Card / SDIO */ -# define MCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */ -# define MCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */ -# define MCI_SDCSEL_MASK ( 3 << 0) -# define MCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */ -# define MCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */ -# define MCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */ -# define MCI_SDCBUS_MASK ( 3 << 6) -#define MCI_ARGR 0x0010 /* Command Argument */ -#define MCI_CMDR 0x0014 /* Command */ -# define MCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ -# define MCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */ -# define MCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */ -# define MCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */ -# define MCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */ -# define MCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */ -# define MCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */ -# define MCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */ -# define MCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */ -# define MCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */ -# define MCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */ -# define MCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */ -# define MCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */ -# define MCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */ -# define MCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */ -# define MCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */ -# define MCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */ -# define MCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */ -# define MCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */ -# define MCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */ -# define MCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */ -# define MCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */ -#define MCI_BLKR 0x0018 /* Block */ -# define MCI_BCNT(x) ((x) << 0) /* Data Block Count */ -# define MCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ -#define MCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ -# define MCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ -# define MCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ -#define MCI_RSPR 0x0020 /* Response 0 */ -#define MCI_RSPR1 0x0024 /* Response 1 */ -#define MCI_RSPR2 0x0028 /* Response 2 */ -#define MCI_RSPR3 0x002c /* Response 3 */ -#define MCI_RDR 0x0030 /* Receive Data */ -#define MCI_TDR 0x0034 /* Transmit Data */ -#define MCI_SR 0x0040 /* Status */ -#define MCI_IER 0x0044 /* Interrupt Enable */ -#define MCI_IDR 0x0048 /* Interrupt Disable */ -#define MCI_IMR 0x004c /* Interrupt Mask */ -# define MCI_CMDRDY ( 1 << 0) /* Command Ready */ -# define MCI_RXRDY ( 1 << 1) /* Receiver Ready */ -# define MCI_TXRDY ( 1 << 2) /* Transmitter Ready */ -# define MCI_BLKE ( 1 << 3) /* Data Block Ended */ -# define MCI_DTIP ( 1 << 4) /* Data Transfer In Progress */ -# define MCI_NOTBUSY ( 1 << 5) /* Data Not Busy */ -# define MCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ -# define MCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ -# define MCI_RINDE ( 1 << 16) /* Response Index Error */ -# define MCI_RDIRE ( 1 << 17) /* Response Direction Error */ -# define MCI_RCRCE ( 1 << 18) /* Response CRC Error */ -# define MCI_RENDE ( 1 << 19) /* Response End Bit Error */ -# define MCI_RTOE ( 1 << 20) /* Response Time-Out Error */ -# define MCI_DCRCE ( 1 << 21) /* Data CRC Error */ -# define MCI_DTOE ( 1 << 22) /* Data Time-Out Error */ -# define MCI_OVRE ( 1 << 30) /* RX Overrun Error */ -# define MCI_UNRE ( 1 << 31) /* TX Underrun Error */ -#define MCI_DMA 0x0050 /* DMA Configuration[2] */ -# define MCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ -# define MCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ -# define MCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */ -#define MCI_CFG 0x0054 /* Configuration[2] */ -# define MCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */ -# define MCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */ -# define MCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */ -# define MCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */ -#define MCI_WPMR 0x00e4 /* Write Protection Mode[2] */ -# define MCI_WP_EN ( 1 << 0) /* WP Enable */ -# define MCI_WP_KEY (0x4d4349 << 8) /* WP Key */ -#define MCI_WPSR 0x00e8 /* Write Protection Status[2] */ -# define MCI_GET_WP_VS(x) ((x) & 0x0f) -# define MCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) -#define MCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ +#define ATMCI_CR 0x0000 /* Control */ +# define ATMCI_CR_MCIEN ( 1 << 0) /* MCI Enable */ +# define ATMCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */ +# define ATMCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */ +# define ATMCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */ +# define ATMCI_CR_SWRST ( 1 << 7) /* Software Reset */ +#define ATMCI_MR 0x0004 /* Mode */ +# define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ +# define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ +# define ATMCI_MR_RDPROOF ( 1 << 11) /* Read Proof */ +# define ATMCI_MR_WRPROOF ( 1 << 12) /* Write Proof */ +# define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ +# define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ +# define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ +#define ATMCI_DTOR 0x0008 /* Data Timeout */ +# define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ +# define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ +#define ATMCI_SDCR 0x000c /* SD Card / SDIO */ +# define ATMCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */ +# define ATMCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */ +# define ATMCI_SDCSEL_MASK ( 3 << 0) +# define ATMCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */ +# define ATMCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */ +# define ATMCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */ +# define ATMCI_SDCBUS_MASK ( 3 << 6) +#define ATMCI_ARGR 0x0010 /* Command Argument */ +#define ATMCI_CMDR 0x0014 /* Command */ +# define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ +# define ATMCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */ +# define ATMCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */ +# define ATMCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */ +# define ATMCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */ +# define ATMCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */ +# define ATMCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */ +# define ATMCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */ +# define ATMCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */ +# define ATMCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */ +# define ATMCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */ +# define ATMCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */ +# define ATMCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */ +# define ATMCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */ +# define ATMCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */ +# define ATMCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */ +# define ATMCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */ +# define ATMCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */ +# define ATMCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */ +# define ATMCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */ +# define ATMCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */ +# define ATMCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */ +#define ATMCI_BLKR 0x0018 /* Block */ +# define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */ +# define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ +#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ +# define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ +# define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ +#define ATMCI_RSPR 0x0020 /* Response 0 */ +#define ATMCI_RSPR1 0x0024 /* Response 1 */ +#define ATMCI_RSPR2 0x0028 /* Response 2 */ +#define ATMCI_RSPR3 0x002c /* Response 3 */ +#define ATMCI_RDR 0x0030 /* Receive Data */ +#define ATMCI_TDR 0x0034 /* Transmit Data */ +#define ATMCI_SR 0x0040 /* Status */ +#define ATMCI_IER 0x0044 /* Interrupt Enable */ +#define ATMCI_IDR 0x0048 /* Interrupt Disable */ +#define ATMCI_IMR 0x004c /* Interrupt Mask */ +# define ATMCI_CMDRDY ( 1 << 0) /* Command Ready */ +# define ATMCI_RXRDY ( 1 << 1) /* Receiver Ready */ +# define ATMCI_TXRDY ( 1 << 2) /* Transmitter Ready */ +# define ATMCI_BLKE ( 1 << 3) /* Data Block Ended */ +# define ATMCI_DTIP ( 1 << 4) /* Data Transfer In Progress */ +# define ATMCI_NOTBUSY ( 1 << 5) /* Data Not Busy */ +# define ATMCI_ENDRX ( 1 << 6) /* End of RX Buffer */ +# define ATMCI_ENDTX ( 1 << 7) /* End of TX Buffer */ +# define ATMCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ +# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ +# define ATMCI_SDIOWAIT ( 1 << 12) /* SDIO Read Wait Operation Status */ +# define ATMCI_CSRCV ( 1 << 13) /* CE-ATA Completion Signal Received */ +# define ATMCI_RXBUFF ( 1 << 14) /* RX Buffer Full */ +# define ATMCI_TXBUFE ( 1 << 15) /* TX Buffer Empty */ +# define ATMCI_RINDE ( 1 << 16) /* Response Index Error */ +# define ATMCI_RDIRE ( 1 << 17) /* Response Direction Error */ +# define ATMCI_RCRCE ( 1 << 18) /* Response CRC Error */ +# define ATMCI_RENDE ( 1 << 19) /* Response End Bit Error */ +# define ATMCI_RTOE ( 1 << 20) /* Response Time-Out Error */ +# define ATMCI_DCRCE ( 1 << 21) /* Data CRC Error */ +# define ATMCI_DTOE ( 1 << 22) /* Data Time-Out Error */ +# define ATMCI_CSTOE ( 1 << 23) /* Completion Signal Time-out Error */ +# define ATMCI_BLKOVRE ( 1 << 24) /* DMA Block Overrun Error */ +# define ATMCI_DMADONE ( 1 << 25) /* DMA Transfer Done */ +# define ATMCI_FIFOEMPTY ( 1 << 26) /* FIFO Empty Flag */ +# define ATMCI_XFRDONE ( 1 << 27) /* Transfer Done Flag */ +# define ATMCI_ACKRCV ( 1 << 28) /* Boot Operation Acknowledge Received */ +# define ATMCI_ACKRCVE ( 1 << 29) /* Boot Operation Acknowledge Error */ +# define ATMCI_OVRE ( 1 << 30) /* RX Overrun Error */ +# define ATMCI_UNRE ( 1 << 31) /* TX Underrun Error */ +#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */ +# define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ +# define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ +# define ATMCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */ +#define ATMCI_CFG 0x0054 /* Configuration[2] */ +# define ATMCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */ +# define ATMCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */ +# define ATMCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */ +# define ATMCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */ +#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */ +# define ATMCI_WP_EN ( 1 << 0) /* WP Enable */ +# define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */ +#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */ +# define ATMCI_GET_WP_VS(x) ((x) & 0x0f) +# define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) +#define ATMCI_VERSION 0x00FC /* Version */ +#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ /* This is not including the FIFO Aperture on MCI2 */ -#define MCI_REGS_SIZE 0x100 +#define ATMCI_REGS_SIZE 0x100 /* Register access macros */ -#define mci_readl(port,reg) \ - __raw_readl((port)->regs + MCI_##reg) -#define mci_writel(port,reg,value) \ - __raw_writel((value), (port)->regs + MCI_##reg) +#define atmci_readl(port,reg) \ + __raw_readl((port)->regs + reg) +#define atmci_writel(port,reg,value) \ + __raw_writel((value), (port)->regs + reg) #endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */ diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index fa8cae1d7005..a7ee50271465 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -30,6 +30,7 @@ #include <mach/atmel-mci.h> #include <linux/atmel-mci.h> +#include <linux/atmel_pdc.h> #include <asm/io.h> #include <asm/unaligned.h> @@ -39,7 +40,7 @@ #include "atmel-mci-regs.h" -#define ATMCI_DATA_ERROR_FLAGS (MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE) +#define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) #define ATMCI_DMA_THRESHOLD 16 enum { @@ -58,18 +59,35 @@ enum atmel_mci_state { STATE_DATA_ERROR, }; +enum atmci_xfer_dir { + XFER_RECEIVE = 0, + XFER_TRANSMIT, +}; + +enum atmci_pdc_buf { + PDC_FIRST_BUF = 0, + PDC_SECOND_BUF, +}; + +struct atmel_mci_caps { + bool has_dma; + bool has_pdc; + bool has_cfg_reg; + bool has_cstor_reg; + bool has_highspeed; + bool has_rwproof; +}; + struct atmel_mci_dma { -#ifdef CONFIG_MMC_ATMELMCI_DMA struct dma_chan *chan; struct dma_async_tx_descriptor *data_desc; -#endif }; /** * struct atmel_mci - MMC controller state shared between all slots * @lock: Spinlock protecting the queue and associated data. * @regs: Pointer to MMIO registers. - * @sg: Scatterlist entry currently being processed by PIO code, if any. + * @sg: Scatterlist entry currently being processed by PIO or PDC code. * @pio_offset: Offset into the current scatterlist entry. * @cur_slot: The slot which is currently using the controller. * @mrq: The request currently being processed on @cur_slot, @@ -77,6 +95,7 @@ struct atmel_mci_dma { * @cmd: The command currently being sent to the card, or NULL. * @data: The data currently being transferred, or NULL if no data * transfer is in progress. + * @data_size: just data->blocks * data->blksz. * @dma: DMA client state. * @data_chan: DMA channel being used for the current data transfer. * @cmd_status: Snapshot of SR taken upon completion of the current @@ -103,6 +122,13 @@ struct atmel_mci_dma { * @mck: The peripheral bus clock hooked up to the MMC controller. * @pdev: Platform device associated with the MMC controller. * @slot: Slots sharing this MMC controller. + * @caps: MCI capabilities depending on MCI version. + * @prepare_data: function to setup MCI before data transfer which + * depends on MCI capabilities. + * @submit_data: function to start data transfer which depends on MCI + * capabilities. + * @stop_transfer: function to stop data transfer which depends on MCI + * capabilities. * * Locking * ======= @@ -143,6 +169,7 @@ struct atmel_mci { struct mmc_request *mrq; struct mmc_command *cmd; struct mmc_data *data; + unsigned int data_size; struct atmel_mci_dma dma; struct dma_chan *data_chan; @@ -166,7 +193,13 @@ struct atmel_mci { struct clk *mck; struct platform_device *pdev; - struct atmel_mci_slot *slot[ATMEL_MCI_MAX_NR_SLOTS]; + struct atmel_mci_slot *slot[ATMCI_MAX_NR_SLOTS]; + + struct atmel_mci_caps caps; + + u32 (*prepare_data)(struct atmel_mci *host, struct mmc_data *data); + void (*submit_data)(struct atmel_mci *host, struct mmc_data *data); + void (*stop_transfer)(struct atmel_mci *host); }; /** @@ -220,31 +253,6 @@ struct atmel_mci_slot { set_bit(event, &host->pending_events) /* - * Enable or disable features/registers based on - * whether the processor supports them - */ -static bool mci_has_rwproof(void) -{ - if (cpu_is_at91sam9261() || cpu_is_at91rm9200()) - return false; - else - return true; -} - -/* - * The new MCI2 module isn't 100% compatible with the old MCI module, - * and it has a few nice features which we want to use... - */ -static inline bool atmci_is_mci2(void) -{ - if (cpu_is_at91sam9g45()) - return true; - - return false; -} - - -/* * The debugfs stuff below is mostly optimized away when * CONFIG_DEBUG_FS is not set. */ @@ -352,7 +360,7 @@ static int atmci_regs_show(struct seq_file *s, void *v) struct atmel_mci *host = s->private; u32 *buf; - buf = kmalloc(MCI_REGS_SIZE, GFP_KERNEL); + buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -363,47 +371,50 @@ static int atmci_regs_show(struct seq_file *s, void *v) */ spin_lock_bh(&host->lock); clk_enable(host->mck); - memcpy_fromio(buf, host->regs, MCI_REGS_SIZE); + memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); clk_disable(host->mck); spin_unlock_bh(&host->lock); seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n", - buf[MCI_MR / 4], - buf[MCI_MR / 4] & MCI_MR_RDPROOF ? " RDPROOF" : "", - buf[MCI_MR / 4] & MCI_MR_WRPROOF ? " WRPROOF" : "", - buf[MCI_MR / 4] & 0xff); - seq_printf(s, "DTOR:\t0x%08x\n", buf[MCI_DTOR / 4]); - seq_printf(s, "SDCR:\t0x%08x\n", buf[MCI_SDCR / 4]); - seq_printf(s, "ARGR:\t0x%08x\n", buf[MCI_ARGR / 4]); + buf[ATMCI_MR / 4], + buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "", + buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "", + buf[ATMCI_MR / 4] & 0xff); + seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]); + seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]); + seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]); seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n", - buf[MCI_BLKR / 4], - buf[MCI_BLKR / 4] & 0xffff, - (buf[MCI_BLKR / 4] >> 16) & 0xffff); - if (atmci_is_mci2()) - seq_printf(s, "CSTOR:\t0x%08x\n", buf[MCI_CSTOR / 4]); + buf[ATMCI_BLKR / 4], + buf[ATMCI_BLKR / 4] & 0xffff, + (buf[ATMCI_BLKR / 4] >> 16) & 0xffff); + if (host->caps.has_cstor_reg) + seq_printf(s, "CSTOR:\t0x%08x\n", buf[ATMCI_CSTOR / 4]); /* Don't read RSPR and RDR; it will consume the data there */ - atmci_show_status_reg(s, "SR", buf[MCI_SR / 4]); - atmci_show_status_reg(s, "IMR", buf[MCI_IMR / 4]); + atmci_show_status_reg(s, "SR", buf[ATMCI_SR / 4]); + atmci_show_status_reg(s, "IMR", buf[ATMCI_IMR / 4]); - if (atmci_is_mci2()) { + if (host->caps.has_dma) { u32 val; - val = buf[MCI_DMA / 4]; + val = buf[ATMCI_DMA / 4]; seq_printf(s, "DMA:\t0x%08x OFFSET=%u CHKSIZE=%u%s\n", val, val & 3, ((val >> 4) & 3) ? 1 << (((val >> 4) & 3) + 1) : 1, - val & MCI_DMAEN ? " DMAEN" : ""); + val & ATMCI_DMAEN ? " DMAEN" : ""); + } + if (host->caps.has_cfg_reg) { + u32 val; - val = buf[MCI_CFG / 4]; + val = buf[ATMCI_CFG / 4]; seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n", val, - val & MCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "", - val & MCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "", - val & MCI_CFG_HSMODE ? " HSMODE" : "", - val & MCI_CFG_LSYNC ? " LSYNC" : ""); + val & ATMCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "", + val & ATMCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "", + val & ATMCI_CFG_HSMODE ? " HSMODE" : "", + val & ATMCI_CFG_LSYNC ? " LSYNC" : ""); } kfree(buf); @@ -466,7 +477,7 @@ err: dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); } -static inline unsigned int ns_to_clocks(struct atmel_mci *host, +static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host, unsigned int ns) { return (ns * (host->bus_hz / 1000000) + 999) / 1000; @@ -482,7 +493,8 @@ static void atmci_set_timeout(struct atmel_mci *host, unsigned dtocyc; unsigned dtomul; - timeout = ns_to_clocks(host, data->timeout_ns) + data->timeout_clks; + timeout = atmci_ns_to_clocks(host, data->timeout_ns) + + data->timeout_clks; for (dtomul = 0; dtomul < 8; dtomul++) { unsigned shift = dtomul_to_shift[dtomul]; @@ -498,7 +510,7 @@ static void atmci_set_timeout(struct atmel_mci *host, dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n", dtocyc << dtomul_to_shift[dtomul]); - mci_writel(host, DTOR, (MCI_DTOMUL(dtomul) | MCI_DTOCYC(dtocyc))); + atmci_writel(host, ATMCI_DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc))); } /* @@ -512,13 +524,13 @@ static u32 atmci_prepare_command(struct mmc_host *mmc, cmd->error = -EINPROGRESS; - cmdr = MCI_CMDR_CMDNB(cmd->opcode); + cmdr = ATMCI_CMDR_CMDNB(cmd->opcode); if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) - cmdr |= MCI_CMDR_RSPTYP_136BIT; + cmdr |= ATMCI_CMDR_RSPTYP_136BIT; else - cmdr |= MCI_CMDR_RSPTYP_48BIT; + cmdr |= ATMCI_CMDR_RSPTYP_48BIT; } /* @@ -526,34 +538,34 @@ static u32 atmci_prepare_command(struct mmc_host *mmc, * it's too difficult to determine whether this is an ACMD or * not. Better make it 64. */ - cmdr |= MCI_CMDR_MAXLAT_64CYC; + cmdr |= ATMCI_CMDR_MAXLAT_64CYC; if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN) - cmdr |= MCI_CMDR_OPDCMD; + cmdr |= ATMCI_CMDR_OPDCMD; data = cmd->data; if (data) { - cmdr |= MCI_CMDR_START_XFER; + cmdr |= ATMCI_CMDR_START_XFER; if (cmd->opcode == SD_IO_RW_EXTENDED) { - cmdr |= MCI_CMDR_SDIO_BLOCK; + cmdr |= ATMCI_CMDR_SDIO_BLOCK; } else { if (data->flags & MMC_DATA_STREAM) - cmdr |= MCI_CMDR_STREAM; + cmdr |= ATMCI_CMDR_STREAM; else if (data->blocks > 1) - cmdr |= MCI_CMDR_MULTI_BLOCK; + cmdr |= ATMCI_CMDR_MULTI_BLOCK; else - cmdr |= MCI_CMDR_BLOCK; + cmdr |= ATMCI_CMDR_BLOCK; } if (data->flags & MMC_DATA_READ) - cmdr |= MCI_CMDR_TRDIR_READ; + cmdr |= ATMCI_CMDR_TRDIR_READ; } return cmdr; } -static void atmci_start_command(struct atmel_mci *host, +static void atmci_send_command(struct atmel_mci *host, struct mmc_command *cmd, u32 cmd_flags) { WARN_ON(host->cmd); @@ -563,43 +575,119 @@ static void atmci_start_command(struct atmel_mci *host, "start command: ARGR=0x%08x CMDR=0x%08x\n", cmd->arg, cmd_flags); - mci_writel(host, ARGR, cmd->arg); - mci_writel(host, CMDR, cmd_flags); + atmci_writel(host, ATMCI_ARGR, cmd->arg); + atmci_writel(host, ATMCI_CMDR, cmd_flags); } -static void send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) +static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) { - atmci_start_command(host, data->stop, host->stop_cmdr); - mci_writel(host, IER, MCI_CMDRDY); + atmci_send_command(host, data->stop, host->stop_cmdr); + atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); } -#ifdef CONFIG_MMC_ATMELMCI_DMA -static void atmci_dma_cleanup(struct atmel_mci *host) +/* + * Configure given PDC buffer taking care of alignement issues. + * Update host->data_size and host->sg. + */ +static void atmci_pdc_set_single_buf(struct atmel_mci *host, + enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb) +{ + u32 pointer_reg, counter_reg; + + if (dir == XFER_RECEIVE) { + pointer_reg = ATMEL_PDC_RPR; + counter_reg = ATMEL_PDC_RCR; + } else { + pointer_reg = ATMEL_PDC_TPR; + counter_reg = ATMEL_PDC_TCR; + } + + if (buf_nb == PDC_SECOND_BUF) { + pointer_reg += ATMEL_PDC_SCND_BUF_OFF; + counter_reg += ATMEL_PDC_SCND_BUF_OFF; + } + + atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); + if (host->data_size <= sg_dma_len(host->sg)) { + if (host->data_size & 0x3) { + /* If size is different from modulo 4, transfer bytes */ + atmci_writel(host, counter_reg, host->data_size); + atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCFBYTE); + } else { + /* Else transfer 32-bits words */ + atmci_writel(host, counter_reg, host->data_size / 4); + } + host->data_size = 0; + } else { + /* We assume the size of a page is 32-bits aligned */ + atmci_writel(host, counter_reg, sg_dma_len(host->sg) / 4); + host->data_size -= sg_dma_len(host->sg); + if (host->data_size) + host->sg = sg_next(host->sg); + } +} + +/* + * Configure PDC buffer according to the data size ie configuring one or two + * buffers. Don't use this function if you want to configure only the second + * buffer. In this case, use atmci_pdc_set_single_buf. + */ +static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir) { - struct mmc_data *data = host->data; + atmci_pdc_set_single_buf(host, dir, PDC_FIRST_BUF); + if (host->data_size) + atmci_pdc_set_single_buf(host, dir, PDC_SECOND_BUF); +} + +/* + * Unmap sg lists, called when transfer is finished. + */ +static void atmci_pdc_cleanup(struct atmel_mci *host) +{ + struct mmc_data *data = host->data; if (data) - dma_unmap_sg(host->dma.chan->device->dev, - data->sg, data->sg_len, - ((data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); + dma_unmap_sg(&host->pdev->dev, + data->sg, data->sg_len, + ((data->flags & MMC_DATA_WRITE) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); } -static void atmci_stop_dma(struct atmel_mci *host) +/* + * Disable PDC transfers. Update pending flags to EVENT_XFER_COMPLETE after + * having received ATMCI_TXBUFE or ATMCI_RXBUFF interrupt. Enable ATMCI_NOTBUSY + * interrupt needed for both transfer directions. + */ +static void atmci_pdc_complete(struct atmel_mci *host) { - struct dma_chan *chan = host->data_chan; + atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); + atmci_pdc_cleanup(host); - if (chan) { - dmaengine_terminate_all(chan); - atmci_dma_cleanup(host); - } else { - /* Data transfer was stopped by the interrupt handler */ + /* + * If the card was removed, data will be NULL. No point trying + * to send the stop command or waiting for NBUSY in this case. + */ + if (host->data) { atmci_set_pending(host, EVENT_XFER_COMPLETE); - mci_writel(host, IER, MCI_NOTBUSY); + tasklet_schedule(&host->tasklet); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } } -/* This function is called by the DMA driver from tasklet context. */ +static void atmci_dma_cleanup(struct atmel_mci *host) +{ + struct mmc_data *data = host->data; + + if (data) + dma_unmap_sg(host->dma.chan->device->dev, + data->sg, data->sg_len, + ((data->flags & MMC_DATA_WRITE) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); +} + +/* + * This function is called by the DMA driver from tasklet context. + */ static void atmci_dma_complete(void *arg) { struct atmel_mci *host = arg; @@ -607,9 +695,9 @@ static void atmci_dma_complete(void *arg) dev_vdbg(&host->pdev->dev, "DMA complete\n"); - if (atmci_is_mci2()) + if (host->caps.has_dma) /* Disable DMA hardware handshaking on MCI */ - mci_writel(host, DMA, mci_readl(host, DMA) & ~MCI_DMAEN); + atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN); atmci_dma_cleanup(host); @@ -641,11 +729,93 @@ static void atmci_dma_complete(void *arg) * completion callback" rule of the dma engine * framework. */ - mci_writel(host, IER, MCI_NOTBUSY); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } } -static int +/* + * Returns a mask of interrupt flags to be enabled after the whole + * request has been prepared. + */ +static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) +{ + u32 iflags; + + data->error = -EINPROGRESS; + + host->sg = data->sg; + host->data = data; + host->data_chan = NULL; + + iflags = ATMCI_DATA_ERROR_FLAGS; + + /* + * Errata: MMC data write operation with less than 12 + * bytes is impossible. + * + * Errata: MCI Transmit Data Register (TDR) FIFO + * corruption when length is not multiple of 4. + */ + if (data->blocks * data->blksz < 12 + || (data->blocks * data->blksz) & 3) + host->need_reset = true; + + host->pio_offset = 0; + if (data->flags & MMC_DATA_READ) + iflags |= ATMCI_RXRDY; + else + iflags |= ATMCI_TXRDY; + + return iflags; +} + +/* + * Set interrupt flags and set block length into the MCI mode register even + * if this value is also accessible in the MCI block register. It seems to be + * necessary before the High Speed MCI version. It also map sg and configure + * PDC registers. + */ +static u32 +atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) +{ + u32 iflags, tmp; + unsigned int sg_len; + enum dma_data_direction dir; + + data->error = -EINPROGRESS; + + host->data = data; + host->sg = data->sg; + iflags = ATMCI_DATA_ERROR_FLAGS; + + /* Enable pdc mode */ + atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE); + + if (data->flags & MMC_DATA_READ) { + dir = DMA_FROM_DEVICE; + iflags |= ATMCI_ENDRX | ATMCI_RXBUFF; + } else { + dir = DMA_TO_DEVICE; + iflags |= ATMCI_ENDTX | ATMCI_TXBUFE; + } + + /* Set BLKLEN */ + tmp = atmci_readl(host, ATMCI_MR); + tmp &= 0x0000ffff; + tmp |= ATMCI_BLKLEN(data->blksz); + atmci_writel(host, ATMCI_MR, tmp); + + /* Configure PDC */ + host->data_size = data->blocks * data->blksz; + sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir); + if (host->data_size) + atmci_pdc_set_both_buf(host, + ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT)); + + return iflags; +} + +static u32 atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) { struct dma_chan *chan; @@ -654,6 +824,15 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) unsigned int i; enum dma_data_direction direction; unsigned int sglen; + u32 iflags; + + data->error = -EINPROGRESS; + + WARN_ON(host->data); + host->sg = NULL; + host->data = data; + + iflags = ATMCI_DATA_ERROR_FLAGS; /* * We don't do DMA on "complex" transfers, i.e. with @@ -661,13 +840,13 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) * with all the DMA setup overhead for short transfers. */ if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD) - return -EINVAL; + return atmci_prepare_data(host, data); if (data->blksz & 3) - return -EINVAL; + return atmci_prepare_data(host, data); for_each_sg(data->sg, sg, data->sg_len, i) { if (sg->offset & 3 || sg->length & 3) - return -EINVAL; + return atmci_prepare_data(host, data); } /* If we don't have a channel, we can't do DMA */ @@ -678,8 +857,8 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) if (!chan) return -ENODEV; - if (atmci_is_mci2()) - mci_writel(host, DMA, MCI_DMA_CHKSIZE(3) | MCI_DMAEN); + if (host->caps.has_dma) + atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN); if (data->flags & MMC_DATA_READ) direction = DMA_FROM_DEVICE; @@ -687,7 +866,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) direction = DMA_TO_DEVICE; sglen = dma_map_sg(chan->device->dev, data->sg, - data->sg_len, direction); + data->sg_len, direction); desc = chan->device->device_prep_slave_sg(chan, data->sg, sglen, direction, @@ -699,13 +878,32 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) desc->callback = atmci_dma_complete; desc->callback_param = host; - return 0; + return iflags; unmap_exit: dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction); return -ENOMEM; } -static void atmci_submit_data(struct atmel_mci *host) +static void +atmci_submit_data(struct atmel_mci *host, struct mmc_data *data) +{ + return; +} + +/* + * Start PDC according to transfer direction. + */ +static void +atmci_submit_data_pdc(struct atmel_mci *host, struct mmc_data *data) +{ + if (data->flags & MMC_DATA_READ) + atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); + else + atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); +} + +static void +atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) { struct dma_chan *chan = host->data_chan; struct dma_async_tx_descriptor *desc = host->dma.data_desc; @@ -716,64 +914,39 @@ static void atmci_submit_data(struct atmel_mci *host) } } -#else /* CONFIG_MMC_ATMELMCI_DMA */ - -static int atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) -{ - return -ENOSYS; -} - -static void atmci_submit_data(struct atmel_mci *host) {} - -static void atmci_stop_dma(struct atmel_mci *host) +static void atmci_stop_transfer(struct atmel_mci *host) { - /* Data transfer was stopped by the interrupt handler */ atmci_set_pending(host, EVENT_XFER_COMPLETE); - mci_writel(host, IER, MCI_NOTBUSY); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } -#endif /* CONFIG_MMC_ATMELMCI_DMA */ - /* - * Returns a mask of interrupt flags to be enabled after the whole - * request has been prepared. + * Stop data transfer because error(s) occured. */ -static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) +static void atmci_stop_transfer_pdc(struct atmel_mci *host) { - u32 iflags; - - data->error = -EINPROGRESS; - - WARN_ON(host->data); - host->sg = NULL; - host->data = data; - - iflags = ATMCI_DATA_ERROR_FLAGS; - if (atmci_prepare_data_dma(host, data)) { - host->data_chan = NULL; + atmci_set_pending(host, EVENT_XFER_COMPLETE); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); +} - /* - * Errata: MMC data write operation with less than 12 - * bytes is impossible. - * - * Errata: MCI Transmit Data Register (TDR) FIFO - * corruption when length is not multiple of 4. - */ - if (data->blocks * data->blksz < 12 - || (data->blocks * data->blksz) & 3) - host->need_reset = true; +static void atmci_stop_transfer_dma(struct atmel_mci *host) +{ + struct dma_chan *chan = host->data_chan; - host->sg = data->sg; - host->pio_offset = 0; - if (data->flags & MMC_DATA_READ) - iflags |= MCI_RXRDY; - else - iflags |= MCI_TXRDY; + if (chan) { + dmaengine_terminate_all(chan); + atmci_dma_cleanup(host); + } else { + /* Data transfer was stopped by the interrupt handler */ + atmci_set_pending(host, EVENT_XFER_COMPLETE); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } - - return iflags; } +/* + * Start a request: prepare data if needed, prepare the command and activate + * interrupts. + */ static void atmci_start_request(struct atmel_mci *host, struct atmel_mci_slot *slot) { @@ -792,24 +965,24 @@ static void atmci_start_request(struct atmel_mci *host, host->data_status = 0; if (host->need_reset) { - mci_writel(host, CR, MCI_CR_SWRST); - mci_writel(host, CR, MCI_CR_MCIEN); - mci_writel(host, MR, host->mode_reg); - if (atmci_is_mci2()) - mci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); + atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); + atmci_writel(host, ATMCI_MR, host->mode_reg); + if (host->caps.has_cfg_reg) + atmci_writel(host, ATMCI_CFG, host->cfg_reg); host->need_reset = false; } - mci_writel(host, SDCR, slot->sdc_reg); + atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); - iflags = mci_readl(host, IMR); - if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB)) + iflags = atmci_readl(host, ATMCI_IMR); + if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n", iflags); if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) { /* Send init sequence (74 clock cycles) */ - mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT); - while (!(mci_readl(host, SR) & MCI_CMDRDY)) + atmci_writel(host, ATMCI_CMDR, ATMCI_CMDR_SPCMD_INIT); + while (!(atmci_readl(host, ATMCI_SR) & ATMCI_CMDRDY)) cpu_relax(); } iflags = 0; @@ -818,31 +991,31 @@ static void atmci_start_request(struct atmel_mci *host, atmci_set_timeout(host, slot, data); /* Must set block count/size before sending command */ - mci_writel(host, BLKR, MCI_BCNT(data->blocks) - | MCI_BLKLEN(data->blksz)); + atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(data->blocks) + | ATMCI_BLKLEN(data->blksz)); dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n", - MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz)); + ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz)); - iflags |= atmci_prepare_data(host, data); + iflags |= host->prepare_data(host, data); } - iflags |= MCI_CMDRDY; + iflags |= ATMCI_CMDRDY; cmd = mrq->cmd; cmdflags = atmci_prepare_command(slot->mmc, cmd); - atmci_start_command(host, cmd, cmdflags); + atmci_send_command(host, cmd, cmdflags); if (data) - atmci_submit_data(host); + host->submit_data(host, data); if (mrq->stop) { host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop); - host->stop_cmdr |= MCI_CMDR_STOP_XFER; + host->stop_cmdr |= ATMCI_CMDR_STOP_XFER; if (!(data->flags & MMC_DATA_WRITE)) - host->stop_cmdr |= MCI_CMDR_TRDIR_READ; + host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ; if (data->flags & MMC_DATA_STREAM) - host->stop_cmdr |= MCI_CMDR_STREAM; + host->stop_cmdr |= ATMCI_CMDR_STREAM; else - host->stop_cmdr |= MCI_CMDR_MULTI_BLOCK; + host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK; } /* @@ -851,7 +1024,7 @@ static void atmci_start_request(struct atmel_mci *host, * conditions (e.g. command and data complete, but stop not * prepared yet.) */ - mci_writel(host, IER, iflags); + atmci_writel(host, ATMCI_IER, iflags); } static void atmci_queue_request(struct atmel_mci *host, @@ -909,13 +1082,13 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct atmel_mci *host = slot->host; unsigned int i; - slot->sdc_reg &= ~MCI_SDCBUS_MASK; + slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; switch (ios->bus_width) { case MMC_BUS_WIDTH_1: - slot->sdc_reg |= MCI_SDCBUS_1BIT; + slot->sdc_reg |= ATMCI_SDCBUS_1BIT; break; case MMC_BUS_WIDTH_4: - slot->sdc_reg |= MCI_SDCBUS_4BIT; + slot->sdc_reg |= ATMCI_SDCBUS_4BIT; break; } @@ -926,10 +1099,10 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_bh(&host->lock); if (!host->mode_reg) { clk_enable(host->mck); - mci_writel(host, CR, MCI_CR_SWRST); - mci_writel(host, CR, MCI_CR_MCIEN); - if (atmci_is_mci2()) - mci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); + atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); + if (host->caps.has_cfg_reg) + atmci_writel(host, ATMCI_CFG, host->cfg_reg); } /* @@ -937,7 +1110,7 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) * core ios update when finding the minimum. */ slot->clock = ios->clock; - for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { if (host->slot[i] && host->slot[i]->clock && host->slot[i]->clock < clock_min) clock_min = host->slot[i]->clock; @@ -952,28 +1125,28 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) clkdiv = 255; } - host->mode_reg = MCI_MR_CLKDIV(clkdiv); + host->mode_reg = ATMCI_MR_CLKDIV(clkdiv); /* * WRPROOF and RDPROOF prevent overruns/underruns by * stopping the clock when the FIFO is full/empty. * This state is not expected to last for long. */ - if (mci_has_rwproof()) - host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF); + if (host->caps.has_rwproof) + host->mode_reg |= (ATMCI_MR_WRPROOF | ATMCI_MR_RDPROOF); - if (atmci_is_mci2()) { + if (host->caps.has_cfg_reg) { /* setup High Speed mode in relation with card capacity */ if (ios->timing == MMC_TIMING_SD_HS) - host->cfg_reg |= MCI_CFG_HSMODE; + host->cfg_reg |= ATMCI_CFG_HSMODE; else - host->cfg_reg &= ~MCI_CFG_HSMODE; + host->cfg_reg &= ~ATMCI_CFG_HSMODE; } if (list_empty(&host->queue)) { - mci_writel(host, MR, host->mode_reg); - if (atmci_is_mci2()) - mci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, ATMCI_MR, host->mode_reg); + if (host->caps.has_cfg_reg) + atmci_writel(host, ATMCI_CFG, host->cfg_reg); } else { host->need_clock_update = true; } @@ -984,16 +1157,16 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_bh(&host->lock); slot->clock = 0; - for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { if (host->slot[i] && host->slot[i]->clock) { any_slot_active = true; break; } } if (!any_slot_active) { - mci_writel(host, CR, MCI_CR_MCIDIS); + atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); if (host->mode_reg) { - mci_readl(host, MR); + atmci_readl(host, ATMCI_MR); clk_disable(host->mck); } host->mode_reg = 0; @@ -1057,9 +1230,9 @@ static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable) struct atmel_mci *host = slot->host; if (enable) - mci_writel(host, IER, slot->sdio_irq); + atmci_writel(host, ATMCI_IER, slot->sdio_irq); else - mci_writel(host, IDR, slot->sdio_irq); + atmci_writel(host, ATMCI_IDR, slot->sdio_irq); } static const struct mmc_host_ops atmci_ops = { @@ -1086,9 +1259,9 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) * busy transferring data. */ if (host->need_clock_update) { - mci_writel(host, MR, host->mode_reg); - if (atmci_is_mci2()) - mci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, ATMCI_MR, host->mode_reg); + if (host->caps.has_cfg_reg) + atmci_writel(host, ATMCI_CFG, host->cfg_reg); } host->cur_slot->mrq = NULL; @@ -1117,16 +1290,16 @@ static void atmci_command_complete(struct atmel_mci *host, u32 status = host->cmd_status; /* Read the response from the card (up to 16 bytes) */ - cmd->resp[0] = mci_readl(host, RSPR); - cmd->resp[1] = mci_readl(host, RSPR); - cmd->resp[2] = mci_readl(host, RSPR); - cmd->resp[3] = mci_readl(host, RSPR); + cmd->resp[0] = atmci_readl(host, ATMCI_RSPR); + cmd->resp[1] = atmci_readl(host, ATMCI_RSPR); + cmd->resp[2] = atmci_readl(host, ATMCI_RSPR); + cmd->resp[3] = atmci_readl(host, ATMCI_RSPR); - if (status & MCI_RTOE) + if (status & ATMCI_RTOE) cmd->error = -ETIMEDOUT; - else if ((cmd->flags & MMC_RSP_CRC) && (status & MCI_RCRCE)) + else if ((cmd->flags & MMC_RSP_CRC) && (status & ATMCI_RCRCE)) cmd->error = -EILSEQ; - else if (status & (MCI_RINDE | MCI_RDIRE | MCI_RENDE)) + else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE)) cmd->error = -EIO; else cmd->error = 0; @@ -1136,10 +1309,10 @@ static void atmci_command_complete(struct atmel_mci *host, "command error: status=0x%08x\n", status); if (cmd->data) { - atmci_stop_dma(host); + host->stop_transfer(host); host->data = NULL; - mci_writel(host, IDR, MCI_NOTBUSY - | MCI_TXRDY | MCI_RXRDY + atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY + | ATMCI_TXRDY | ATMCI_RXRDY | ATMCI_DATA_ERROR_FLAGS); } } @@ -1191,11 +1364,11 @@ static void atmci_detect_change(unsigned long data) * Reset controller to terminate any ongoing * commands or data transfers. */ - mci_writel(host, CR, MCI_CR_SWRST); - mci_writel(host, CR, MCI_CR_MCIEN); - mci_writel(host, MR, host->mode_reg); - if (atmci_is_mci2()) - mci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); + atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); + atmci_writel(host, ATMCI_MR, host->mode_reg); + if (host->caps.has_cfg_reg) + atmci_writel(host, ATMCI_CFG, host->cfg_reg); host->data = NULL; host->cmd = NULL; @@ -1210,7 +1383,7 @@ static void atmci_detect_change(unsigned long data) /* fall through */ case STATE_SENDING_DATA: mrq->data->error = -ENOMEDIUM; - atmci_stop_dma(host); + host->stop_transfer(host); break; case STATE_DATA_BUSY: case STATE_DATA_ERROR: @@ -1261,7 +1434,7 @@ static void atmci_tasklet_func(unsigned long priv) dev_vdbg(&host->pdev->dev, "tasklet: state %u pending/completed/mask %lx/%lx/%x\n", state, host->pending_events, host->completed_events, - mci_readl(host, IMR)); + atmci_readl(host, ATMCI_IMR)); do { prev_state = state; @@ -1289,9 +1462,9 @@ static void atmci_tasklet_func(unsigned long priv) case STATE_SENDING_DATA: if (atmci_test_and_clear_pending(host, EVENT_DATA_ERROR)) { - atmci_stop_dma(host); + host->stop_transfer(host); if (data->stop) - send_stop_cmd(host, data); + atmci_send_stop_cmd(host, data); state = STATE_DATA_ERROR; break; } @@ -1313,11 +1486,11 @@ static void atmci_tasklet_func(unsigned long priv) atmci_set_completed(host, EVENT_DATA_COMPLETE); status = host->data_status; if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) { - if (status & MCI_DTOE) { + if (status & ATMCI_DTOE) { dev_dbg(&host->pdev->dev, "data timeout error\n"); data->error = -ETIMEDOUT; - } else if (status & MCI_DCRCE) { + } else if (status & ATMCI_DCRCE) { dev_dbg(&host->pdev->dev, "data CRC error\n"); data->error = -EILSEQ; @@ -1330,7 +1503,7 @@ static void atmci_tasklet_func(unsigned long priv) } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; - mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS); + atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS); } if (!data->stop) { @@ -1340,7 +1513,7 @@ static void atmci_tasklet_func(unsigned long priv) prev_state = state = STATE_SENDING_STOP; if (!data->error) - send_stop_cmd(host, data); + atmci_send_stop_cmd(host, data); /* fall through */ case STATE_SENDING_STOP: @@ -1380,7 +1553,7 @@ static void atmci_read_data_pio(struct atmel_mci *host) unsigned int nbytes = 0; do { - value = mci_readl(host, RDR); + value = atmci_readl(host, ATMCI_RDR); if (likely(offset + 4 <= sg->length)) { put_unaligned(value, (u32 *)(buf + offset)); @@ -1412,9 +1585,9 @@ static void atmci_read_data_pio(struct atmel_mci *host) nbytes += offset; } - status = mci_readl(host, SR); + status = atmci_readl(host, ATMCI_SR); if (status & ATMCI_DATA_ERROR_FLAGS) { - mci_writel(host, IDR, (MCI_NOTBUSY | MCI_RXRDY + atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY | ATMCI_DATA_ERROR_FLAGS)); host->data_status = status; data->bytes_xfered += nbytes; @@ -1423,7 +1596,7 @@ static void atmci_read_data_pio(struct atmel_mci *host) tasklet_schedule(&host->tasklet); return; } - } while (status & MCI_RXRDY); + } while (status & ATMCI_RXRDY); host->pio_offset = offset; data->bytes_xfered += nbytes; @@ -1431,8 +1604,8 @@ static void atmci_read_data_pio(struct atmel_mci *host) return; done: - mci_writel(host, IDR, MCI_RXRDY); - mci_writel(host, IER, MCI_NOTBUSY); + atmci_writel(host, ATMCI_IDR, ATMCI_RXRDY); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); data->bytes_xfered += nbytes; smp_wmb(); atmci_set_pending(host, EVENT_XFER_COMPLETE); @@ -1451,7 +1624,7 @@ static void atmci_write_data_pio(struct atmel_mci *host) do { if (likely(offset + 4 <= sg->length)) { value = get_unaligned((u32 *)(buf + offset)); - mci_writel(host, TDR, value); + atmci_writel(host, ATMCI_TDR, value); offset += 4; nbytes += 4; @@ -1472,20 +1645,20 @@ static void atmci_write_data_pio(struct atmel_mci *host) host->sg = sg = sg_next(sg); if (!sg) { - mci_writel(host, TDR, value); + atmci_writel(host, ATMCI_TDR, value); goto done; } offset = 4 - remaining; buf = sg_virt(sg); memcpy((u8 *)&value + remaining, buf, offset); - mci_writel(host, TDR, value); + atmci_writel(host, ATMCI_TDR, value); nbytes += offset; } - status = mci_readl(host, SR); + status = atmci_readl(host, ATMCI_SR); if (status & ATMCI_DATA_ERROR_FLAGS) { - mci_writel(host, IDR, (MCI_NOTBUSY | MCI_TXRDY + atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY | ATMCI_DATA_ERROR_FLAGS)); host->data_status = status; data->bytes_xfered += nbytes; @@ -1494,7 +1667,7 @@ static void atmci_write_data_pio(struct atmel_mci *host) tasklet_schedule(&host->tasklet); return; } - } while (status & MCI_TXRDY); + } while (status & ATMCI_TXRDY); host->pio_offset = offset; data->bytes_xfered += nbytes; @@ -1502,8 +1675,8 @@ static void atmci_write_data_pio(struct atmel_mci *host) return; done: - mci_writel(host, IDR, MCI_TXRDY); - mci_writel(host, IER, MCI_NOTBUSY); + atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); data->bytes_xfered += nbytes; smp_wmb(); atmci_set_pending(host, EVENT_XFER_COMPLETE); @@ -1511,7 +1684,7 @@ done: static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) { - mci_writel(host, IDR, MCI_CMDRDY); + atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); host->cmd_status = status; smp_wmb(); @@ -1523,7 +1696,7 @@ static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status) { int i; - for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { struct atmel_mci_slot *slot = host->slot[i]; if (slot && (status & slot->sdio_irq)) { mmc_signal_sdio_irq(slot->mmc); @@ -1539,40 +1712,92 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) unsigned int pass_count = 0; do { - status = mci_readl(host, SR); - mask = mci_readl(host, IMR); + status = atmci_readl(host, ATMCI_SR); + mask = atmci_readl(host, ATMCI_IMR); pending = status & mask; if (!pending) break; if (pending & ATMCI_DATA_ERROR_FLAGS) { - mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS - | MCI_RXRDY | MCI_TXRDY); - pending &= mci_readl(host, IMR); + atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS + | ATMCI_RXRDY | ATMCI_TXRDY); + pending &= atmci_readl(host, ATMCI_IMR); host->data_status = status; smp_wmb(); atmci_set_pending(host, EVENT_DATA_ERROR); tasklet_schedule(&host->tasklet); } - if (pending & MCI_NOTBUSY) { - mci_writel(host, IDR, - ATMCI_DATA_ERROR_FLAGS | MCI_NOTBUSY); + + if (pending & ATMCI_TXBUFE) { + atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); + atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); + /* + * We can receive this interruption before having configured + * the second pdc buffer, so we need to reconfigure first and + * second buffers again + */ + if (host->data_size) { + atmci_pdc_set_both_buf(host, XFER_TRANSMIT); + atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); + atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE); + } else { + atmci_pdc_complete(host); + } + } else if (pending & ATMCI_ENDTX) { + atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); + + if (host->data_size) { + atmci_pdc_set_single_buf(host, + XFER_TRANSMIT, PDC_SECOND_BUF); + atmci_writel(host, ATMCI_IER, ATMCI_ENDTX); + } + } + + if (pending & ATMCI_RXBUFF) { + atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); + atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); + /* + * We can receive this interruption before having configured + * the second pdc buffer, so we need to reconfigure first and + * second buffers again + */ + if (host->data_size) { + atmci_pdc_set_both_buf(host, XFER_RECEIVE); + atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); + atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF); + } else { + atmci_pdc_complete(host); + } + } else if (pending & ATMCI_ENDRX) { + atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); + + if (host->data_size) { + atmci_pdc_set_single_buf(host, + XFER_RECEIVE, PDC_SECOND_BUF); + atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); + } + } + + + if (pending & ATMCI_NOTBUSY) { + atmci_writel(host, ATMCI_IDR, + ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY); if (!host->data_status) host->data_status = status; smp_wmb(); atmci_set_pending(host, EVENT_DATA_COMPLETE); tasklet_schedule(&host->tasklet); } - if (pending & MCI_RXRDY) + if (pending & ATMCI_RXRDY) atmci_read_data_pio(host); - if (pending & MCI_TXRDY) + if (pending & ATMCI_TXRDY) atmci_write_data_pio(host); - if (pending & MCI_CMDRDY) + if (pending & ATMCI_CMDRDY) atmci_cmd_interrupt(host, status); - if (pending & (MCI_SDIOIRQA | MCI_SDIOIRQB)) + if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB)) atmci_sdio_interrupt(host, status); } while (pass_count++ < 5); @@ -1621,7 +1846,7 @@ static int __init atmci_init_slot(struct atmel_mci *host, mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; if (sdio_irq) mmc->caps |= MMC_CAP_SDIO_IRQ; - if (atmci_is_mci2()) + if (host->caps.has_highspeed) mmc->caps |= MMC_CAP_SD_HIGHSPEED; if (slot_data->bus_width >= 4) mmc->caps |= MMC_CAP_4_BIT_DATA; @@ -1704,8 +1929,7 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot, mmc_free_host(slot->mmc); } -#ifdef CONFIG_MMC_ATMELMCI_DMA -static bool filter(struct dma_chan *chan, void *slave) +static bool atmci_filter(struct dma_chan *chan, void *slave) { struct mci_dma_data *sl = slave; @@ -1730,14 +1954,14 @@ static void atmci_configure_dma(struct atmel_mci *host) dma_cap_mask_t mask; setup_dma_addr(pdata->dma_slave, - host->mapbase + MCI_TDR, - host->mapbase + MCI_RDR); + host->mapbase + ATMCI_TDR, + host->mapbase + ATMCI_RDR); /* Try to grab a DMA channel */ dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); host->dma.chan = - dma_request_channel(mask, filter, pdata->dma_slave); + dma_request_channel(mask, atmci_filter, pdata->dma_slave); } if (!host->dma.chan) dev_notice(&host->pdev->dev, "DMA not available, using PIO\n"); @@ -1746,9 +1970,60 @@ static void atmci_configure_dma(struct atmel_mci *host) "Using %s for DMA transfers\n", dma_chan_name(host->dma.chan)); } + +static inline unsigned int atmci_get_version(struct atmel_mci *host) +{ + return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; +} + +/* + * HSMCI (High Speed MCI) module is not fully compatible with MCI module. + * HSMCI provides DMA support and a new config register but no more supports + * PDC. + */ +static void __init atmci_get_cap(struct atmel_mci *host) +{ + unsigned int version; + + version = atmci_get_version(host); + dev_info(&host->pdev->dev, + "version: 0x%x\n", version); + + host->caps.has_dma = 0; + host->caps.has_pdc = 0; + host->caps.has_cfg_reg = 0; + host->caps.has_cstor_reg = 0; + host->caps.has_highspeed = 0; + host->caps.has_rwproof = 0; + + /* keep only major version number */ + switch (version & 0xf00) { + case 0x100: + case 0x200: + host->caps.has_pdc = 1; + host->caps.has_rwproof = 1; + break; + case 0x300: + case 0x400: + case 0x500: +#ifdef CONFIG_AT_HDMAC + host->caps.has_dma = 1; #else -static void atmci_configure_dma(struct atmel_mci *host) {} + host->caps.has_dma = 0; + dev_info(&host->pdev->dev, + "has dma capability but dma engine is not selected, then use pio\n"); #endif + host->caps.has_cfg_reg = 1; + host->caps.has_cstor_reg = 1; + host->caps.has_highspeed = 1; + host->caps.has_rwproof = 1; + break; + default: + dev_warn(&host->pdev->dev, + "Unmanaged mci version, set minimum capabilities\n"); + break; + } +} static int __init atmci_probe(struct platform_device *pdev) { @@ -1789,7 +2064,7 @@ static int __init atmci_probe(struct platform_device *pdev) goto err_ioremap; clk_enable(host->mck); - mci_writel(host, CR, MCI_CR_SWRST); + atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); host->bus_hz = clk_get_rate(host->mck); clk_disable(host->mck); @@ -1801,7 +2076,27 @@ static int __init atmci_probe(struct platform_device *pdev) if (ret) goto err_request_irq; - atmci_configure_dma(host); + /* Get MCI capabilities and set operations according to it */ + atmci_get_cap(host); + if (host->caps.has_dma) { + dev_info(&pdev->dev, "using DMA\n"); + host->prepare_data = &atmci_prepare_data_dma; + host->submit_data = &atmci_submit_data_dma; + host->stop_transfer = &atmci_stop_transfer_dma; + } else if (host->caps.has_pdc) { + dev_info(&pdev->dev, "using PDC\n"); + host->prepare_data = &atmci_prepare_data_pdc; + host->submit_data = &atmci_submit_data_pdc; + host->stop_transfer = &atmci_stop_transfer_pdc; + } else { + dev_info(&pdev->dev, "no DMA, no PDC\n"); + host->prepare_data = &atmci_prepare_data; + host->submit_data = &atmci_submit_data; + host->stop_transfer = &atmci_stop_transfer; + } + + if (host->caps.has_dma) + atmci_configure_dma(host); platform_set_drvdata(pdev, host); @@ -1810,13 +2105,13 @@ static int __init atmci_probe(struct platform_device *pdev) ret = -ENODEV; if (pdata->slot[0].bus_width) { ret = atmci_init_slot(host, &pdata->slot[0], - 0, MCI_SDCSEL_SLOT_A, MCI_SDIOIRQA); + 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA); if (!ret) nr_slots++; } if (pdata->slot[1].bus_width) { ret = atmci_init_slot(host, &pdata->slot[1], - 1, MCI_SDCSEL_SLOT_B, MCI_SDIOIRQB); + 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB); if (!ret) nr_slots++; } @@ -1833,10 +2128,8 @@ static int __init atmci_probe(struct platform_device *pdev) return 0; err_init_slot: -#ifdef CONFIG_MMC_ATMELMCI_DMA if (host->dma.chan) dma_release_channel(host->dma.chan); -#endif free_irq(irq, host); err_request_irq: iounmap(host->regs); @@ -1854,15 +2147,15 @@ static int __exit atmci_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { if (host->slot[i]) atmci_cleanup_slot(host->slot[i], i); } clk_enable(host->mck); - mci_writel(host, IDR, ~0UL); - mci_writel(host, CR, MCI_CR_MCIDIS); - mci_readl(host, SR); + atmci_writel(host, ATMCI_IDR, ~0UL); + atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); + atmci_readl(host, ATMCI_SR); clk_disable(host->mck); #ifdef CONFIG_MMC_ATMELMCI_DMA @@ -1885,7 +2178,7 @@ static int atmci_suspend(struct device *dev) struct atmel_mci *host = dev_get_drvdata(dev); int i; - for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { struct atmel_mci_slot *slot = host->slot[i]; int ret; @@ -1916,7 +2209,7 @@ static int atmci_resume(struct device *dev) int i; int ret = 0; - for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { + for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { struct atmel_mci_slot *slot = host->slot[i]; int err; diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index ef72e874ca36..5d3b9ae64523 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -55,7 +55,7 @@ #ifdef DEBUG #define DBG(fmt, idx, args...) \ - printk(KERN_DEBUG "au1xmmc(%d): DEBUG: " fmt, idx, ##args) + pr_debug("au1xmmc(%d): DEBUG: " fmt, idx, ##args) #else #define DBG(fmt, idx, args...) do {} while (0) #endif @@ -64,11 +64,8 @@ #define AU1XMMC_DESCRIPTOR_COUNT 1 /* max DMA seg size: 64KB on Au1100, 4MB on Au1200 */ -#ifdef CONFIG_SOC_AU1100 -#define AU1XMMC_DESCRIPTOR_SIZE 0x0000ffff -#else /* Au1200 */ -#define AU1XMMC_DESCRIPTOR_SIZE 0x003fffff -#endif +#define AU1100_MMC_DESCRIPTOR_SIZE 0x0000ffff +#define AU1200_MMC_DESCRIPTOR_SIZE 0x003fffff #define AU1XMMC_OCR (MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \ MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \ @@ -127,6 +124,7 @@ struct au1xmmc_host { #define HOST_F_XMIT 0x0001 #define HOST_F_RECV 0x0002 #define HOST_F_DMA 0x0010 +#define HOST_F_DBDMA 0x0020 #define HOST_F_ACTIVE 0x0100 #define HOST_F_STOP 0x1000 @@ -151,6 +149,16 @@ struct au1xmmc_host { #define DMA_CHANNEL(h) \ (((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan) +static inline int has_dbdma(void) +{ + switch (alchemy_get_cputype()) { + case ALCHEMY_CPU_AU1200: + return 1; + default: + return 0; + } +} + static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask) { u32 val = au_readl(HOST_CONFIG(host)); @@ -268,7 +276,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, mmccmd |= SD_CMD_RT_3; break; default: - printk(KERN_INFO "au1xmmc: unhandled response type %02x\n", + pr_info("au1xmmc: unhandled response type %02x\n", mmc_resp_type(cmd)); return -EINVAL; } @@ -353,14 +361,12 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) data->bytes_xfered = 0; if (!data->error) { - if (host->flags & HOST_F_DMA) { -#ifdef CONFIG_SOC_AU1200 /* DBDMA */ + if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) { u32 chan = DMA_CHANNEL(host); chan_tab_t *c = *((chan_tab_t **)chan); au1x_dma_chan_t *cp = c->chan_ptr; data->bytes_xfered = cp->ddma_bytecnt; -#endif } else data->bytes_xfered = (data->blocks * data->blksz) - host->pio.len; @@ -570,11 +576,10 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) host->status = HOST_S_DATA; - if (host->flags & HOST_F_DMA) { -#ifdef CONFIG_SOC_AU1200 /* DBDMA */ + if ((host->flags & (HOST_F_DMA | HOST_F_DBDMA))) { u32 channel = DMA_CHANNEL(host); - /* Start the DMA as soon as the buffer gets something in it */ + /* Start the DBDMA as soon as the buffer gets something in it */ if (host->flags & HOST_F_RECV) { u32 mask = SD_STATUS_DB | SD_STATUS_NE; @@ -584,7 +589,6 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) } au1xxx_dbdma_start(channel); -#endif } } @@ -633,8 +637,7 @@ static int au1xmmc_prepare_data(struct au1xmmc_host *host, au_writel(data->blksz - 1, HOST_BLKSIZE(host)); - if (host->flags & HOST_F_DMA) { -#ifdef CONFIG_SOC_AU1200 /* DBDMA */ + if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) { int i; u32 channel = DMA_CHANNEL(host); @@ -663,7 +666,6 @@ static int au1xmmc_prepare_data(struct au1xmmc_host *host, datalen -= len; } -#endif } else { host->pio.index = 0; host->pio.offset = 0; @@ -838,7 +840,6 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id) return IRQ_HANDLED; } -#ifdef CONFIG_SOC_AU1200 /* 8bit memory DMA device */ static dbdev_tab_t au1xmmc_mem_dbdev = { .dev_id = DSCR_CMD0_ALWAYS, @@ -905,7 +906,7 @@ static int au1xmmc_dbdma_init(struct au1xmmc_host *host) au1xxx_dbdma_ring_alloc(host->rx_chan, AU1XMMC_DESCRIPTOR_COUNT); /* DBDMA is good to go */ - host->flags |= HOST_F_DMA; + host->flags |= HOST_F_DMA | HOST_F_DBDMA; return 0; } @@ -918,7 +919,6 @@ static void au1xmmc_dbdma_shutdown(struct au1xmmc_host *host) au1xxx_dbdma_chan_free(host->rx_chan); } } -#endif static void au1xmmc_enable_sdio_irq(struct mmc_host *mmc, int en) { @@ -997,8 +997,16 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) mmc->f_min = 450000; mmc->f_max = 24000000; - mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE; - mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; + switch (alchemy_get_cputype()) { + case ALCHEMY_CPU_AU1100: + mmc->max_seg_size = AU1100_MMC_DESCRIPTOR_SIZE; + mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; + break; + case ALCHEMY_CPU_AU1200: + mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE; + mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; + break; + } mmc->max_blk_size = 2048; mmc->max_blk_count = 512; @@ -1028,11 +1036,11 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) tasklet_init(&host->finish_task, au1xmmc_tasklet_finish, (unsigned long)host); -#ifdef CONFIG_SOC_AU1200 - ret = au1xmmc_dbdma_init(host); - if (ret) - printk(KERN_INFO DRIVER_NAME ": DBDMA init failed; using PIO\n"); -#endif + if (has_dbdma()) { + ret = au1xmmc_dbdma_init(host); + if (ret) + pr_info(DRIVER_NAME ": DBDMA init failed; using PIO\n"); + } #ifdef CONFIG_LEDS_CLASS if (host->platdata && host->platdata->led) { @@ -1056,7 +1064,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); - printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X" + pr_info(DRIVER_NAME ": MMC Controller %d set up at %8.8X" " (mode=%s)\n", pdev->id, host->iobase, host->flags & HOST_F_DMA ? "dma" : "pio"); @@ -1073,9 +1081,8 @@ out5: au_writel(0, HOST_CONFIG2(host)); au_sync(); -#ifdef CONFIG_SOC_AU1200 - au1xmmc_dbdma_shutdown(host); -#endif + if (host->flags & HOST_F_DBDMA) + au1xmmc_dbdma_shutdown(host); tasklet_kill(&host->data_task); tasklet_kill(&host->finish_task); @@ -1120,9 +1127,9 @@ static int __devexit au1xmmc_remove(struct platform_device *pdev) tasklet_kill(&host->data_task); tasklet_kill(&host->finish_task); -#ifdef CONFIG_SOC_AU1200 - au1xmmc_dbdma_shutdown(host); -#endif + if (host->flags & HOST_F_DBDMA) + au1xmmc_dbdma_shutdown(host); + au1xmmc_set_power(host, 0); free_irq(host->irq, host); @@ -1181,24 +1188,23 @@ static struct platform_driver au1xmmc_driver = { static int __init au1xmmc_init(void) { -#ifdef CONFIG_SOC_AU1200 - /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride - * of 8 bits. And since devices are shared, we need to create - * our own to avoid freaking out other devices. - */ - memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev); - if (!memid) - printk(KERN_ERR "au1xmmc: cannot add memory dbdma dev\n"); -#endif + if (has_dbdma()) { + /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride + * of 8 bits. And since devices are shared, we need to create + * our own to avoid freaking out other devices. + */ + memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev); + if (!memid) + pr_err("au1xmmc: cannot add memory dbdma\n"); + } return platform_driver_register(&au1xmmc_driver); } static void __exit au1xmmc_exit(void) { -#ifdef CONFIG_SOC_AU1200 - if (memid) + if (has_dbdma() && memid) au1xxx_ddma_del_device(memid); -#endif + platform_driver_unregister(&au1xmmc_driver); } diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 0076c7448fe6..64a8325a4a8a 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -807,12 +807,25 @@ static void calculate_clk_divider(struct mmc_host *mmc, struct mmc_ios *ios) static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmc_davinci_host *host = mmc_priv(mmc); + struct platform_device *pdev = to_platform_device(mmc->parent); + struct davinci_mmc_config *config = pdev->dev.platform_data; dev_dbg(mmc_dev(host->mmc), "clock %dHz busmode %d powermode %d Vdd %04x\n", ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); + switch (ios->power_mode) { + case MMC_POWER_OFF: + if (config && config->set_power) + config->set_power(pdev->id, false); + break; + case MMC_POWER_UP: + if (config && config->set_power) + config->set_power(pdev->id, true); + break; + } + switch (ios->bus_width) { case MMC_BUS_WIDTH_8: dev_dbg(mmc_dev(host->mmc), "Enabling 8 bit mode\n"); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index ff0f714b012c..3aaeb0841914 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -764,11 +764,29 @@ static int dw_mci_get_cd(struct mmc_host *mmc) return present; } +static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci *host = slot->host; + u32 int_mask; + + /* Enable/disable Slot Specific SDIO interrupt */ + int_mask = mci_readl(host, INTMASK); + if (enb) { + mci_writel(host, INTMASK, + (int_mask | (1 << SDMMC_INT_SDIO(slot->id)))); + } else { + mci_writel(host, INTMASK, + (int_mask & ~(1 << SDMMC_INT_SDIO(slot->id)))); + } +} + static const struct mmc_host_ops dw_mci_ops = { - .request = dw_mci_request, - .set_ios = dw_mci_set_ios, - .get_ro = dw_mci_get_ro, - .get_cd = dw_mci_get_cd, + .request = dw_mci_request, + .set_ios = dw_mci_set_ios, + .get_ro = dw_mci_get_ro, + .get_cd = dw_mci_get_cd, + .enable_sdio_irq = dw_mci_enable_sdio_irq, }; static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) @@ -1025,7 +1043,8 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (!sg_next(host->sg) || host->part_buf_count == 2) { - mci_writew(host, DATA, host->part_buf16); + mci_writew(host, DATA(host->data_offset), + host->part_buf16); host->part_buf_count = 0; } } @@ -1042,21 +1061,23 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) cnt -= len; /* push data from aligned buffer into fifo */ for (i = 0; i < items; ++i) - mci_writew(host, DATA, aligned_buf[i]); + mci_writew(host, DATA(host->data_offset), + aligned_buf[i]); } } else #endif { u16 *pdata = buf; for (; cnt >= 2; cnt -= 2) - mci_writew(host, DATA, *pdata++); + mci_writew(host, DATA(host->data_offset), *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); if (!sg_next(host->sg)) - mci_writew(host, DATA, host->part_buf16); + mci_writew(host, DATA(host->data_offset), + host->part_buf16); } } @@ -1071,7 +1092,8 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) int items = len >> 1; int i; for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readw(host, DATA); + aligned_buf[i] = mci_readw(host, + DATA(host->data_offset)); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1082,11 +1104,11 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) { u16 *pdata = buf; for (; cnt >= 2; cnt -= 2) - *pdata++ = mci_readw(host, DATA); + *pdata++ = mci_readw(host, DATA(host->data_offset)); buf = pdata; } if (cnt) { - host->part_buf16 = mci_readw(host, DATA); + host->part_buf16 = mci_readw(host, DATA(host->data_offset)); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1099,7 +1121,8 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (!sg_next(host->sg) || host->part_buf_count == 4) { - mci_writel(host, DATA, host->part_buf32); + mci_writel(host, DATA(host->data_offset), + host->part_buf32); host->part_buf_count = 0; } } @@ -1116,21 +1139,23 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) cnt -= len; /* push data from aligned buffer into fifo */ for (i = 0; i < items; ++i) - mci_writel(host, DATA, aligned_buf[i]); + mci_writel(host, DATA(host->data_offset), + aligned_buf[i]); } } else #endif { u32 *pdata = buf; for (; cnt >= 4; cnt -= 4) - mci_writel(host, DATA, *pdata++); + mci_writel(host, DATA(host->data_offset), *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); if (!sg_next(host->sg)) - mci_writel(host, DATA, host->part_buf32); + mci_writel(host, DATA(host->data_offset), + host->part_buf32); } } @@ -1145,7 +1170,8 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) int items = len >> 2; int i; for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readl(host, DATA); + aligned_buf[i] = mci_readl(host, + DATA(host->data_offset)); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1156,11 +1182,11 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) { u32 *pdata = buf; for (; cnt >= 4; cnt -= 4) - *pdata++ = mci_readl(host, DATA); + *pdata++ = mci_readl(host, DATA(host->data_offset)); buf = pdata; } if (cnt) { - host->part_buf32 = mci_readl(host, DATA); + host->part_buf32 = mci_readl(host, DATA(host->data_offset)); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1173,7 +1199,8 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) buf += len; cnt -= len; if (!sg_next(host->sg) || host->part_buf_count == 8) { - mci_writew(host, DATA, host->part_buf); + mci_writew(host, DATA(host->data_offset), + host->part_buf); host->part_buf_count = 0; } } @@ -1190,21 +1217,23 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) cnt -= len; /* push data from aligned buffer into fifo */ for (i = 0; i < items; ++i) - mci_writeq(host, DATA, aligned_buf[i]); + mci_writeq(host, DATA(host->data_offset), + aligned_buf[i]); } } else #endif { u64 *pdata = buf; for (; cnt >= 8; cnt -= 8) - mci_writeq(host, DATA, *pdata++); + mci_writeq(host, DATA(host->data_offset), *pdata++); buf = pdata; } /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); if (!sg_next(host->sg)) - mci_writeq(host, DATA, host->part_buf); + mci_writeq(host, DATA(host->data_offset), + host->part_buf); } } @@ -1219,7 +1248,8 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) int items = len >> 3; int i; for (i = 0; i < items; ++i) - aligned_buf[i] = mci_readq(host, DATA); + aligned_buf[i] = mci_readq(host, + DATA(host->data_offset)); /* memcpy from aligned buffer into output buffer */ memcpy(buf, aligned_buf, len); buf += len; @@ -1230,11 +1260,11 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) { u64 *pdata = buf; for (; cnt >= 8; cnt -= 8) - *pdata++ = mci_readq(host, DATA); + *pdata++ = mci_readq(host, DATA(host->data_offset)); buf = pdata; } if (cnt) { - host->part_buf = mci_readq(host, DATA); + host->part_buf = mci_readq(host, DATA(host->data_offset)); dw_mci_pull_final_bytes(host, buf, cnt); } } @@ -1406,6 +1436,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) struct dw_mci *host = dev_id; u32 status, pending; unsigned int pass_count = 0; + int i; do { status = mci_readl(host, RINTSTS); @@ -1477,6 +1508,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) queue_work(dw_mci_card_workqueue, &host->card_work); } + /* Handle SDIO Interrupts */ + for (i = 0; i < host->num_slots; i++) { + struct dw_mci_slot *slot = host->slot[i]; + if (pending & SDMMC_INT_SDIO(i)) { + mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i)); + mmc_signal_sdio_irq(slot->mmc); + } + } + } while (pass_count++ < 5); #ifdef CONFIG_MMC_DW_IDMAC @@ -1673,7 +1713,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); if (IS_ERR(host->vmmc)) { - printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); + pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); host->vmmc = NULL; } else regulator_enable(host->vmmc); @@ -1924,6 +1964,18 @@ static int dw_mci_probe(struct platform_device *pdev) } /* + * In 2.40a spec, Data offset is changed. + * Need to check the version-id and set data-offset for DATA register. + */ + host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); + dev_info(&pdev->dev, "Version ID is %04x\n", host->verid); + + if (host->verid < DW_MMC_240A) + host->data_offset = DATA_OFFSET; + else + host->data_offset = DATA_240A_OFFSET; + + /* * Enable interrupts for command done, data over, data empty, card det, * receive ready and error such as transmit, receive timeout, crc error */ diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 027d37735394..72c071f6e001 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -14,6 +14,8 @@ #ifndef _DW_MMC_H_ #define _DW_MMC_H_ +#define DW_MMC_240A 0x240a + #define SDMMC_CTRL 0x000 #define SDMMC_PWREN 0x004 #define SDMMC_CLKDIV 0x008 @@ -51,7 +53,14 @@ #define SDMMC_IDINTEN 0x090 #define SDMMC_DSCADDR 0x094 #define SDMMC_BUFADDR 0x098 -#define SDMMC_DATA 0x100 +#define SDMMC_DATA(x) (x) + +/* + * Data offset is difference according to Version + * Lower than 2.40a : data register offest is 0x100 + */ +#define DATA_OFFSET 0x100 +#define DATA_240A_OFFSET 0x200 /* shift bit field */ #define _SBF(f, v) ((v) << (f)) @@ -82,7 +91,7 @@ #define SDMMC_CTYPE_4BIT BIT(0) #define SDMMC_CTYPE_1BIT 0 /* Interrupt status & mask register defines */ -#define SDMMC_INT_SDIO BIT(16) +#define SDMMC_INT_SDIO(n) BIT(16 + (n)) #define SDMMC_INT_EBE BIT(15) #define SDMMC_INT_ACD BIT(14) #define SDMMC_INT_SBE BIT(13) @@ -130,6 +139,8 @@ #define SDMMC_IDMAC_ENABLE BIT(7) #define SDMMC_IDMAC_FB BIT(1) #define SDMMC_IDMAC_SWRESET BIT(0) +/* Version ID register define */ +#define SDMMC_GET_VERID(x) ((x) & 0xFFFF) /* Register access macros */ #define mci_readl(dev, reg) \ diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 881f7ba545ae..ea0f3cedef21 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -942,7 +942,7 @@ static int __init imxmci_probe(struct platform_device *pdev) int ret = 0, irq; u16 rev_no; - printk(KERN_INFO "i.MX mmc driver\n"); + pr_info("i.MX mmc driver\n"); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 7c1e16aaf17f..92946b84e9fa 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -27,6 +27,7 @@ #include <linux/sched.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/bio.h> #include <linux/dma-mapping.h> #include <linux/crc7.h> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 56e9a4168264..50b5f9926f64 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -29,6 +29,7 @@ #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/amba/mmci.h> +#include <linux/pm_runtime.h> #include <asm/div64.h> #include <asm/io.h> @@ -170,6 +171,7 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) * back into the driver... */ spin_unlock(&host->lock); + pm_runtime_put(mmc_dev(host->mmc)); mmc_request_done(host->mmc, mrq); spin_lock(&host->lock); } @@ -464,7 +466,7 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) struct mmci_host_next *next = &host->next_data; if (data->host_cookie && data->host_cookie != next->cookie) { - printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d" + pr_warning("[%s] invalid cookie: data->host_cookie %d" " host->next_data.cookie %d\n", __func__, data->host_cookie, host->next_data.cookie); data->host_cookie = 0; @@ -529,7 +531,7 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, if (chan) { if (err) dmaengine_terminate_all(chan); - if (err || data->host_cookie) + if (data->host_cookie) dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, dir); mrq->data->host_cookie = 0; @@ -984,6 +986,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) return; } + pm_runtime_get_sync(mmc_dev(mmc)); + spin_lock_irqsave(&host->lock, flags); host->mrq = mrq; @@ -1156,10 +1160,14 @@ static int __devinit mmci_probe(struct amba_device *dev, goto host_free; } - ret = clk_enable(host->clk); + ret = clk_prepare(host->clk); if (ret) goto clk_free; + ret = clk_enable(host->clk); + if (ret) + goto clk_unprep; + host->plat = plat; host->variant = variant; host->mclk = clk_get_rate(host->clk); @@ -1327,6 +1335,8 @@ static int __devinit mmci_probe(struct amba_device *dev, mmci_dma_setup(host); + pm_runtime_put(&dev->dev); + mmc_add_host(mmc); return 0; @@ -1345,6 +1355,8 @@ static int __devinit mmci_probe(struct amba_device *dev, iounmap(host->base); clk_disable: clk_disable(host->clk); + clk_unprep: + clk_unprepare(host->clk); clk_free: clk_put(host->clk); host_free: @@ -1364,6 +1376,12 @@ static int __devexit mmci_remove(struct amba_device *dev) if (mmc) { struct mmci_host *host = mmc_priv(mmc); + /* + * Undo pm_runtime_put() in probe. We use the _sync + * version here so that we can access the primecell. + */ + pm_runtime_get_sync(&dev->dev); + mmc_remove_host(mmc); writel(0, host->base + MMCIMASK0); @@ -1386,6 +1404,7 @@ static int __devexit mmci_remove(struct amba_device *dev) iounmap(host->base); clk_disable(host->clk); + clk_unprepare(host->clk); clk_put(host->clk); if (host->vcc) diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index a4c865a5286b..80d8eb143b48 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -213,7 +213,8 @@ msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, MMCIDATALENGTH); - msmsdcc_writel(host, host->cmd_pio_irqmask, MMCIMASK1); + msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & + (~MCI_IRQ_PIO)) | host->cmd_pio_irqmask, MMCIMASK0); msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); if (host->cmd_cmd) { @@ -388,7 +389,7 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, host->dma.dir); if (n == 0) { - printk(KERN_ERR "%s: Unable to map in all sg elements\n", + pr_err("%s: Unable to map in all sg elements\n", mmc_hostname(host->mmc)); host->dma.sg = NULL; host->dma.num_ents = 0; @@ -474,7 +475,7 @@ msmsdcc_start_command_deferred(struct msmsdcc_host *host, *c |= MCI_CSPM_MCIABORT; if (host->curr.cmd != NULL) { - printk(KERN_ERR "%s: Overlapping command requests\n", + pr_err("%s: Overlapping command requests\n", mmc_hostname(host->mmc)); } host->curr.cmd = cmd; @@ -543,7 +544,9 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); - msmsdcc_writel(host, pio_irqmask, MMCIMASK1); + msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & + (~MCI_IRQ_PIO)) | pio_irqmask, MMCIMASK0); + msmsdcc_writel(host, datactrl, MMCIDATACTRL); if (cmd) { @@ -659,8 +662,13 @@ msmsdcc_pio_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; uint32_t status; + u32 mci_mask0; status = msmsdcc_readl(host, MMCISTATUS); + mci_mask0 = msmsdcc_readl(host, MMCIMASK0); + + if (((mci_mask0 & status) & MCI_IRQ_PIO) == 0) + return IRQ_NONE; do { unsigned long flags; @@ -719,10 +727,12 @@ msmsdcc_pio_irq(int irq, void *dev_id) } while (1); if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) - msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1); + msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | + MCI_RXDATAAVLBLMASK, MMCIMASK0); if (!host->curr.xfer_remain) - msmsdcc_writel(host, 0, MMCIMASK1); + msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | 0, + MMCIMASK0); return IRQ_HANDLED; } @@ -854,6 +864,8 @@ msmsdcc_irq(int irq, void *dev_id) do { status = msmsdcc_readl(host, MMCISTATUS); status &= msmsdcc_readl(host, MMCIMASK0); + if ((status & (~MCI_IRQ_PIO)) == 0) + break; msmsdcc_writel(host, status, MMCICLEAR); if (status & MCI_SDIOINTR) @@ -939,7 +951,7 @@ static void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable) struct msm_mmc_gpio_data *curr; int i, rc = 0; - if (!host->plat->gpio_data && host->gpio_config_status == enable) + if (!host->plat->gpio_data || host->gpio_config_status == enable) return; curr = host->plat->gpio_data; @@ -1052,10 +1064,19 @@ static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_unlock_irqrestore(&host->lock, flags); } +static void msmsdcc_init_card(struct mmc_host *mmc, struct mmc_card *card) +{ + struct msmsdcc_host *host = mmc_priv(mmc); + + if (host->plat->init_card) + host->plat->init_card(card); +} + static const struct mmc_host_ops msmsdcc_ops = { .request = msmsdcc_request, .set_ios = msmsdcc_set_ios, .enable_sdio_irq = msmsdcc_enable_sdio_irq, + .init_card = msmsdcc_init_card, }; static void @@ -1092,7 +1113,7 @@ msmsdcc_platform_status_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; - printk(KERN_DEBUG "%s: %d\n", __func__, irq); + pr_debug("%s: %d\n", __func__, irq); msmsdcc_check_status((unsigned long) host); return IRQ_HANDLED; } @@ -1102,7 +1123,7 @@ msmsdcc_status_notify_cb(int card_present, void *dev_id) { struct msmsdcc_host *host = dev_id; - printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc), + pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc), card_present); msmsdcc_check_status((unsigned long) host); } @@ -1150,7 +1171,6 @@ msmsdcc_probe(struct platform_device *pdev) struct msmsdcc_host *host; struct mmc_host *mmc; struct resource *cmd_irqres = NULL; - struct resource *pio_irqres = NULL; struct resource *stat_irqres = NULL; struct resource *memres = NULL; struct resource *dmares = NULL; @@ -1175,12 +1195,10 @@ msmsdcc_probe(struct platform_device *pdev) dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "cmd_irq"); - pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, - "pio_irq"); stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq"); - if (!cmd_irqres || !pio_irqres || !memres) { + if (!cmd_irqres || !memres) { pr_err("%s: Invalid resource\n", __func__); return -ENXIO; } @@ -1200,17 +1218,20 @@ msmsdcc_probe(struct platform_device *pdev) host->plat = plat; host->mmc = mmc; host->curr.cmd = NULL; + init_timer(&host->busclk_timer); + host->busclk_timer.data = (unsigned long) host; + host->busclk_timer.function = msmsdcc_busclk_expired; + host->cmdpoll = 1; host->base = ioremap(memres->start, PAGE_SIZE); if (!host->base) { ret = -ENOMEM; - goto out; + goto host_free; } host->cmd_irqres = cmd_irqres; - host->pio_irqres = pio_irqres; host->memres = memres; host->dmares = dmares; spin_lock_init(&host->lock); @@ -1221,13 +1242,19 @@ msmsdcc_probe(struct platform_device *pdev) /* * Setup DMA */ - msmsdcc_init_dma(host); + if (host->dmares) { + ret = msmsdcc_init_dma(host); + if (ret) + goto ioremap_free; + } else { + host->dma.channel = -1; + } /* Get our clocks */ host->pclk = clk_get(&pdev->dev, "sdc_pclk"); if (IS_ERR(host->pclk)) { ret = PTR_ERR(host->pclk); - goto host_free; + goto dma_free; } host->clk = clk_get(&pdev->dev, "sdc_clk"); @@ -1236,17 +1263,17 @@ msmsdcc_probe(struct platform_device *pdev) goto pclk_put; } - /* Enable clocks */ - ret = msmsdcc_enable_clocks(host); - if (ret) - goto clk_put; - ret = clk_set_rate(host->clk, msmsdcc_fmin); if (ret) { pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); - goto clk_disable; + goto clk_put; } + /* Enable clocks */ + ret = msmsdcc_enable_clocks(host); + if (ret) + goto clk_put; + host->pclk_rate = clk_get_rate(host->pclk); host->clk_rate = clk_get_rate(host->clk); @@ -1316,16 +1343,12 @@ msmsdcc_probe(struct platform_device *pdev) host->eject = !host->oldstat; } - init_timer(&host->busclk_timer); - host->busclk_timer.data = (unsigned long) host; - host->busclk_timer.function = msmsdcc_busclk_expired; - ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) goto stat_irq_free; - ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, + ret = request_irq(cmd_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); if (ret) goto cmd_irq_free; @@ -1368,6 +1391,13 @@ msmsdcc_probe(struct platform_device *pdev) clk_put(host->clk); pclk_put: clk_put(host->pclk); +dma_free: + if (host->dmares) + dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata), + host->dma.nc, host->dma.nc_busaddr); +ioremap_free: + tasklet_kill(&host->dma_tlet); + iounmap(host->base); host_free: mmc_free_host(mmc); out: diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 42d7bbc977c5..402028d16b86 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h @@ -140,6 +140,11 @@ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|MCI_PROGDONEMASK) +#define MCI_IRQ_PIO \ + (MCI_RXDATAAVLBLMASK | MCI_TXDATAAVLBLMASK | MCI_RXFIFOEMPTYMASK | \ + MCI_TXFIFOEMPTYMASK | MCI_RXFIFOFULLMASK | MCI_TXFIFOFULLMASK | \ + MCI_RXFIFOHALFFULLMASK | MCI_TXFIFOHALFEMPTYMASK | \ + MCI_RXACTIVEMASK | MCI_TXACTIVEMASK) /* * The size of the FIFO in bytes. */ @@ -202,7 +207,6 @@ struct msmsdcc_stats { struct msmsdcc_host { struct resource *cmd_irqres; - struct resource *pio_irqres; struct resource *memres; struct resource *dmares; void __iomem *base; diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index a5bf60e01af4..211a4959c293 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -117,7 +117,7 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) host->pio_size = data->blocks * data->blksz; host->pio_ptr = sg_virt(data->sg); if (!nodma) - printk(KERN_DEBUG "%s: fallback to PIO for data " + pr_debug("%s: fallback to PIO for data " "at 0x%p size %d\n", mmc_hostname(host->mmc), host->pio_ptr, host->pio_size); @@ -471,7 +471,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev) if (mrq->data) err_status = mvsd_finish_data(host, mrq->data, err_status); if (err_status) { - printk(KERN_ERR "%s: unhandled error status %#04x\n", + pr_err("%s: unhandled error status %#04x\n", mmc_hostname(host->mmc), err_status); cmd->error = -ENOMSG; } @@ -489,7 +489,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev) if (irq_handled) return IRQ_HANDLED; - printk(KERN_ERR "%s: unhandled interrupt status=0x%04x en=0x%04x " + pr_err("%s: unhandled interrupt status=0x%04x en=0x%04x " "pio=%d\n", mmc_hostname(host->mmc), intr_status, host->intr_en, host->pio_size); return IRQ_NONE; @@ -505,9 +505,9 @@ static void mvsd_timeout_timer(unsigned long data) spin_lock_irqsave(&host->lock, flags); mrq = host->mrq; if (mrq) { - printk(KERN_ERR "%s: Timeout waiting for hardware interrupt.\n", + pr_err("%s: Timeout waiting for hardware interrupt.\n", mmc_hostname(host->mmc)); - printk(KERN_ERR "%s: hw_state=0x%04x, intr_status=0x%04x " + pr_err("%s: hw_state=0x%04x, intr_status=0x%04x " "intr_en=0x%04x\n", mmc_hostname(host->mmc), mvsd_read(MVSD_HW_STATE), mvsd_read(MVSD_NOR_INTR_STATUS), @@ -762,7 +762,7 @@ static int __init mvsd_probe(struct platform_device *pdev) ret = request_irq(irq, mvsd_irq, 0, DRIVER_NAME, host); if (ret) { - printk(KERN_ERR "%s: cannot assign irq %d\n", DRIVER_NAME, irq); + pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, irq); goto out; } else host->irq = irq; @@ -802,7 +802,7 @@ static int __init mvsd_probe(struct platform_device *pdev) if (ret) goto out; - printk(KERN_NOTICE "%s: %s driver initialized, ", + pr_notice("%s: %s driver initialized, ", mmc_hostname(mmc), DRIVER_NAME); if (host->gpio_card_detect) printk("using GPIO %d for card detection\n", diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 14aa213b00da..325ea61e12d3 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -40,6 +40,7 @@ #include <mach/mmc.h> #include <mach/dma.h> +#include <mach/hardware.h> #define DRIVER_NAME "mxc-mmc" @@ -842,7 +843,7 @@ static int mxcmci_probe(struct platform_device *pdev) int ret = 0, irq; dma_cap_mask_t mask; - printk(KERN_INFO "i.MX SDHC driver\n"); + pr_info("i.MX SDHC driver\n"); iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index d513d47364d0..99b449d26a4d 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -37,6 +37,7 @@ #include <linux/mmc/sdio.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> +#include <linux/module.h> #include <mach/mxs.h> #include <mach/common.h> diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index a6c329040140..2dba999caf2c 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -33,7 +33,7 @@ #include <plat/board.h> #include <plat/mmc.h> -#include <mach/gpio.h> +#include <asm/gpio.h> #include <plat/dma.h> #include <plat/mux.h> #include <plat/fpga.h> diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 21e4a799df48..101cd31c8220 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -450,15 +450,14 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) * framework is fixed, we need a workaround like this * (which is safe for MMC, but not in general). */ - if (regulator_is_enabled(host->vcc) > 0) { - regulator_enable(host->vcc); - regulator_disable(host->vcc); - } - if (host->vcc_aux) { - if (regulator_is_enabled(reg) > 0) { - regulator_enable(reg); - regulator_disable(reg); - } + if (regulator_is_enabled(host->vcc) > 0 || + (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { + int vdd = ffs(mmc_slot(host).ocr_mask) - 1; + + mmc_slot(host).set_power(host->dev, host->slot_id, + 1, vdd); + mmc_slot(host).set_power(host->dev, host->slot_id, + 0, 0); } } @@ -1264,14 +1263,14 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) host->reqs_blocked = 0; if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) { if (host->protect_card) { - printk(KERN_INFO "%s: cover is closed, " + pr_info("%s: cover is closed, " "card is now accessible\n", mmc_hostname(host->mmc)); host->protect_card = 0; } } else { if (!host->protect_card) { - printk(KERN_INFO "%s: cover is open, " + pr_info("%s: cover is open, " "card is now inaccessible\n", mmc_hostname(host->mmc)); host->protect_card = 1; @@ -1422,7 +1421,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, if (!next && data->host_cookie && data->host_cookie != host->next_data.cookie) { - printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d" + pr_warning("[%s] invalid cookie: data->host_cookie %d" " host->next_data.cookie %d\n", __func__, data->host_cookie, host->next_data.cookie); data->host_cookie = 0; @@ -1943,6 +1942,10 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) omap_hsmmc_context_save(host); mmc->caps |= MMC_CAP_DISABLE; + if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) { + dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n"); + mmc->caps2 |= MMC_CAP2_NO_MULTI_READ; + } pm_runtime_enable(host->dev); pm_runtime_get_sync(host->dev); @@ -2015,7 +2018,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) } /* Request IRQ for MMC operations */ - ret = request_irq(host->irq, omap_hsmmc_irq, IRQF_DISABLED, + ret = request_irq(host->irq, omap_hsmmc_irq, 0, mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); @@ -2043,8 +2046,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) if ((mmc_slot(host).card_detect_irq)) { ret = request_irq(mmc_slot(host).card_detect_irq, omap_hsmmc_cd_handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING - | IRQF_DISABLED, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 7257738fd7da..fc4356e00d46 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -558,7 +558,7 @@ static void pxamci_dma_irq(int dma, void *devid) if (dcsr & DCSR_ENDINTR) { writel(BUF_PART_FULL, host->base + MMC_PRTBUF); } else { - printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", + pr_err("%s: DMA error on channel %d (DCSR=%#x)\n", mmc_hostname(host->mmc), dma, dcsr); host->data->error = -EIO; pxamci_data_done(host, 0); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index a04f87d7ee3d..720f99334a7f 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -247,7 +247,7 @@ static void s3cmci_check_sdio_irq(struct s3cmci_host *host) { if (host->sdio_irqen) { if (gpio_get_value(S3C2410_GPE(8)) == 0) { - printk(KERN_DEBUG "%s: signalling irq\n", __func__); + pr_debug("%s: signalling irq\n", __func__); mmc_signal_sdio_irq(host->mmc); } } @@ -344,7 +344,7 @@ static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer) local_irq_save(flags); - //printk(KERN_DEBUG "%s: transfer %d\n", __func__, transfer); + /* pr_debug("%s: transfer %d\n", __func__, transfer); */ host->irq_disabled = transfer; @@ -913,9 +913,9 @@ request_done: } static void s3cmci_dma_setup(struct s3cmci_host *host, - enum s3c2410_dmasrc source) + enum dma_data_direction source) { - static enum s3c2410_dmasrc last_source = -1; + static enum dma_data_direction last_source = -1; static int setup_ok; if (last_source == source) @@ -1087,7 +1087,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); - s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW); + s3cmci_dma_setup(host, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 4dc0028086a3..4b976f00ea85 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -32,6 +32,16 @@ /* VENDOR SPEC register */ #define SDHCI_VENDOR_SPEC 0xC0 #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 +#define SDHCI_WTMK_LVL 0x44 +#define SDHCI_MIX_CTRL 0x48 + +/* + * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: + * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, + * but bit28 is used as the INT DMA ERR in fsl eSDHC design. + * Define this macro DMA error INT for fsl eSDHC + */ +#define SDHCI_INT_VENDOR_SPEC_DMA_ERR 0x10000000 /* * The CMDTYPE of the CMD register (offset 0xE) should be set to @@ -51,6 +61,7 @@ enum imx_esdhc_type { IMX35_ESDHC, IMX51_ESDHC, IMX53_ESDHC, + IMX6Q_USDHC, }; struct pltfm_imx_data { @@ -74,6 +85,9 @@ static struct platform_device_id imx_esdhc_devtype[] = { .name = "sdhci-esdhc-imx53", .driver_data = IMX53_ESDHC, }, { + .name = "sdhci-usdhc-imx6q", + .driver_data = IMX6Q_USDHC, + }, { /* sentinel */ } }; @@ -84,6 +98,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, + { .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); @@ -108,6 +123,11 @@ static inline int is_imx53_esdhc(struct pltfm_imx_data *data) 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) { void __iomem *base = host->ioaddr + (reg & ~0x3); @@ -135,6 +155,27 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) val |= SDHCI_CARD_PRESENT; } + if (unlikely(reg == SDHCI_CAPABILITIES)) { + /* In FSL esdhc IC module, only bit20 is used to indicate the + * ADMA2 capability of esdhc, but this bit is messed up on + * some SOCs (e.g. on MX25, MX35 this bit is set, but they + * don't actually support ADMA2). So set the BROKEN_ADMA + * uirk on MX25/35 platforms. + */ + + if (val & SDHCI_CAN_DO_ADMA1) { + val &= ~SDHCI_CAN_DO_ADMA1; + val |= SDHCI_CAN_DO_ADMA2; + } + } + + if (unlikely(reg == SDHCI_INT_STATUS)) { + if (val & SDHCI_INT_VENDOR_SPEC_DMA_ERR) { + val &= ~SDHCI_INT_VENDOR_SPEC_DMA_ERR; + val |= SDHCI_INT_ADMA_ERROR; + } + } + return val; } @@ -179,13 +220,28 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); } + if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { + if (val & SDHCI_INT_ADMA_ERROR) { + val &= ~SDHCI_INT_ADMA_ERROR; + val |= SDHCI_INT_VENDOR_SPEC_DMA_ERR; + } + } + writel(val, host->ioaddr + reg); } static u16 esdhc_readw_le(struct sdhci_host *host, int reg) { - if (unlikely(reg == SDHCI_HOST_VERSION)) - reg ^= 2; + if (unlikely(reg == SDHCI_HOST_VERSION)) { + 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); } @@ -216,8 +272,17 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) val |= SDHCI_CMD_ABORTCMD; - writel(val << 16 | imx_data->scratchpad, - host->ioaddr + SDHCI_TRANSFER_MODE); + + 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, + host->ioaddr + SDHCI_TRANSFER_MODE); + } return; case SDHCI_BLOCK_SIZE: val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); @@ -311,9 +376,10 @@ static struct sdhci_ops sdhci_esdhc_ops = { }; static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { - .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA + .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT + | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC + | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_BROKEN_CARD_DETECTION, - /* ADMA has issues. Might be fixable */ .ops = &sdhci_esdhc_ops, }; @@ -405,11 +471,19 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ - host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; + host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK + | SDHCI_QUIRK_BROKEN_ADMA; if (is_imx53_esdhc(imx_data)) imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; + /* + * The imx6q ROM code will change the default watermark level setting + * to something insane. Change it back here. + */ + if (is_imx6q_usdhc(imx_data)) + writel(0x08100810, host->ioaddr + SDHCI_WTMK_LVL); + boarddata = &imx_data->boarddata; if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { if (!host->mmc->parent->platform_data) { diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index fe604df65011..59e9d003e589 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -1,7 +1,7 @@ /* * Freescale eSDHC controller driver. * - * Copyright (c) 2007 Freescale Semiconductor, Inc. + * Copyright (c) 2007, 2010 Freescale Semiconductor, Inc. * Copyright (c) 2009 MontaVista Software, Inc. * * Authors: Xiaobo Xie <X.Xie@freescale.com> @@ -15,6 +15,7 @@ #include <linux/io.h> #include <linux/delay.h> +#include <linux/module.h> #include <linux/mmc/host.h> #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" @@ -22,11 +23,21 @@ static u16 esdhc_readw(struct sdhci_host *host, int reg) { u16 ret; + int base = reg & ~0x3; + int shift = (reg & 0x2) * 8; if (unlikely(reg == SDHCI_HOST_VERSION)) - ret = in_be16(host->ioaddr + reg); + ret = in_be32(host->ioaddr + base) & 0xffff; else - ret = sdhci_be32bs_readw(host, reg); + ret = (in_be32(host->ioaddr + base) >> shift) & 0xffff; + return ret; +} + +static u8 esdhc_readb(struct sdhci_host *host, int reg) +{ + int base = reg & ~0x3; + int shift = (reg & 0x3) * 8; + u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff; return ret; } @@ -74,7 +85,7 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) static struct sdhci_ops sdhci_esdhc_ops = { .read_l = sdhci_be32bs_readl, .read_w = esdhc_readw, - .read_b = sdhci_be32bs_readb, + .read_b = esdhc_readb, .write_l = sdhci_be32bs_writel, .write_w = esdhc_writew, .write_b = esdhc_writeb, diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index 735be131dca9..9b0d794a4f69 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -20,6 +20,7 @@ */ #include <linux/delay.h> +#include <linux/module.h> #include <linux/mmc/host.h> #include "sdhci-pltfm.h" diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 26c528648f3c..d833d9c2f7e3 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -14,6 +14,7 @@ #include <linux/delay.h> #include <linux/highmem.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/slab.h> @@ -21,6 +22,9 @@ #include <linux/mmc/host.h> #include <linux/scatterlist.h> #include <linux/io.h> +#include <linux/gpio.h> +#include <linux/sfi.h> +#include <linux/pm_runtime.h> #include "sdhci.h" @@ -43,6 +47,7 @@ struct sdhci_pci_slot; struct sdhci_pci_fixes { unsigned int quirks; + bool allow_runtime_pm; int (*probe) (struct sdhci_pci_chip *); @@ -59,12 +64,16 @@ struct sdhci_pci_slot { struct sdhci_host *host; int pci_bar; + int rst_n_gpio; + int cd_gpio; + int cd_irq; }; struct sdhci_pci_chip { struct pci_dev *pdev; unsigned int quirks; + bool allow_runtime_pm; const struct sdhci_pci_fixes *fixes; int num_slots; /* Slots on controller */ @@ -163,12 +172,129 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip) return 0; } +/* Medfield eMMC hardware reset GPIOs */ +static int mfd_emmc0_rst_gpio = -EINVAL; +static int mfd_emmc1_rst_gpio = -EINVAL; + +static int mfd_emmc_gpio_parse(struct sfi_table_header *table) +{ + struct sfi_table_simple *sb = (struct sfi_table_simple *)table; + struct sfi_gpio_table_entry *entry; + int i, num; + + num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); + entry = (struct sfi_gpio_table_entry *)sb->pentry; + + for (i = 0; i < num; i++, entry++) { + if (!strncmp(entry->pin_name, "emmc0_rst", SFI_NAME_LEN)) + mfd_emmc0_rst_gpio = entry->pin_no; + else if (!strncmp(entry->pin_name, "emmc1_rst", SFI_NAME_LEN)) + mfd_emmc1_rst_gpio = entry->pin_no; + } + + return 0; +} + +#ifdef CONFIG_PM_RUNTIME + +static irqreturn_t mfd_sd_cd(int irq, void *dev_id) +{ + struct sdhci_pci_slot *slot = dev_id; + struct sdhci_host *host = slot->host; + + mmc_detect_change(host->mmc, msecs_to_jiffies(200)); + return IRQ_HANDLED; +} + +#define MFLD_SD_CD_PIN 69 + +static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot) +{ + int err, irq, gpio = MFLD_SD_CD_PIN; + + slot->cd_gpio = -EINVAL; + slot->cd_irq = -EINVAL; + + err = gpio_request(gpio, "sd_cd"); + if (err < 0) + goto out; + + err = gpio_direction_input(gpio); + if (err < 0) + goto out_free; + + irq = gpio_to_irq(gpio); + if (irq < 0) + goto out_free; + + err = request_irq(irq, mfd_sd_cd, IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, "sd_cd", slot); + if (err) + goto out_free; + + slot->cd_gpio = gpio; + slot->cd_irq = irq; + slot->host->quirks2 |= SDHCI_QUIRK2_OWN_CARD_DETECTION; + + return 0; + +out_free: + gpio_free(gpio); +out: + dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); + return 0; +} + +static void mfd_sd_remove_slot(struct sdhci_pci_slot *slot, int dead) +{ + if (slot->cd_irq >= 0) + free_irq(slot->cd_irq, slot); + gpio_free(slot->cd_gpio); +} + +#else + +#define mfd_sd_probe_slot NULL +#define mfd_sd_remove_slot NULL + +#endif + static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) { - slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; + const char *name = NULL; + int gpio = -EINVAL; + + sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, mfd_emmc_gpio_parse); + + switch (slot->chip->pdev->device) { + case PCI_DEVICE_ID_INTEL_MFD_EMMC0: + gpio = mfd_emmc0_rst_gpio; + name = "eMMC0_reset"; + break; + case PCI_DEVICE_ID_INTEL_MFD_EMMC1: + gpio = mfd_emmc1_rst_gpio; + name = "eMMC1_reset"; + break; + } + + if (!gpio_request(gpio, name)) { + gpio_direction_output(gpio, 1); + slot->rst_n_gpio = gpio; + slot->host->mmc->caps |= MMC_CAP_HW_RESET; + } + + slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; + + slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC; + return 0; } +static void mfd_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead) +{ + gpio_free(slot->rst_n_gpio); +} + static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, .probe_slot = mrst_hc_probe_slot, @@ -181,15 +307,21 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .allow_runtime_pm = true, + .probe_slot = mfd_sd_probe_slot, + .remove_slot = mfd_sd_remove_slot, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .allow_runtime_pm = true, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .allow_runtime_pm = true, .probe_slot = mfd_emmc_probe_slot, + .remove_slot = mfd_emmc_remove_slot, }; /* O2Micro extra registers */ @@ -832,9 +964,25 @@ static int sdhci_pci_8bit_width(struct sdhci_host *host, int width) return 0; } +static void sdhci_pci_hw_reset(struct sdhci_host *host) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + int rst_n_gpio = slot->rst_n_gpio; + + if (!gpio_is_valid(rst_n_gpio)) + return; + gpio_set_value_cansleep(rst_n_gpio, 0); + /* For eMMC, minimum is 1us but give it 10us for good measure */ + udelay(10); + gpio_set_value_cansleep(rst_n_gpio, 1); + /* For eMMC, minimum is 200us but give it 300us for good measure */ + usleep_range(300, 1000); +} + static struct sdhci_ops sdhci_pci_ops = { .enable_dma = sdhci_pci_enable_dma, .platform_8bit_width = sdhci_pci_8bit_width, + .hw_reset = sdhci_pci_hw_reset, }; /*****************************************************************************\ @@ -944,6 +1092,95 @@ static int sdhci_pci_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ +#ifdef CONFIG_PM_RUNTIME + +static int sdhci_pci_runtime_suspend(struct device *dev) +{ + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + struct sdhci_pci_chip *chip; + struct sdhci_pci_slot *slot; + pm_message_t state = { .event = PM_EVENT_SUSPEND }; + int i, ret; + + chip = pci_get_drvdata(pdev); + if (!chip) + return 0; + + for (i = 0; i < chip->num_slots; i++) { + slot = chip->slots[i]; + if (!slot) + continue; + + ret = sdhci_runtime_suspend_host(slot->host); + + if (ret) { + for (i--; i >= 0; i--) + sdhci_runtime_resume_host(chip->slots[i]->host); + return ret; + } + } + + if (chip->fixes && chip->fixes->suspend) { + ret = chip->fixes->suspend(chip, state); + if (ret) { + for (i = chip->num_slots - 1; i >= 0; i--) + sdhci_runtime_resume_host(chip->slots[i]->host); + return ret; + } + } + + return 0; +} + +static int sdhci_pci_runtime_resume(struct device *dev) +{ + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + struct sdhci_pci_chip *chip; + struct sdhci_pci_slot *slot; + int i, ret; + + chip = pci_get_drvdata(pdev); + if (!chip) + return 0; + + if (chip->fixes && chip->fixes->resume) { + ret = chip->fixes->resume(chip); + if (ret) + return ret; + } + + for (i = 0; i < chip->num_slots; i++) { + slot = chip->slots[i]; + if (!slot) + continue; + + ret = sdhci_runtime_resume_host(slot->host); + if (ret) + return ret; + } + + return 0; +} + +static int sdhci_pci_runtime_idle(struct device *dev) +{ + return 0; +} + +#else + +#define sdhci_pci_runtime_suspend NULL +#define sdhci_pci_runtime_resume NULL +#define sdhci_pci_runtime_idle NULL + +#endif + +static const struct dev_pm_ops sdhci_pci_pm_ops = { + .runtime_suspend = sdhci_pci_runtime_suspend, + .runtime_resume = sdhci_pci_runtime_resume, + .runtime_idle = sdhci_pci_runtime_idle, +}; + /*****************************************************************************\ * * * Device probing/removal * @@ -988,6 +1225,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( slot->chip = chip; slot->host = host; slot->pci_bar = bar; + slot->rst_n_gpio = -EINVAL; host->hw_name = "PCI"; host->ops = &sdhci_pci_ops; @@ -1058,6 +1296,21 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) sdhci_free_host(slot->host); } +static void __devinit sdhci_pci_runtime_pm_allow(struct device *dev) +{ + pm_runtime_put_noidle(dev); + pm_runtime_allow(dev); + pm_runtime_set_autosuspend_delay(dev, 50); + pm_runtime_use_autosuspend(dev); + pm_suspend_ignore_children(dev, 1); +} + +static void __devexit sdhci_pci_runtime_pm_forbid(struct device *dev) +{ + pm_runtime_forbid(dev); + pm_runtime_get_noresume(dev); +} + static int __devinit sdhci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1107,8 +1360,10 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, chip->pdev = pdev; chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data; - if (chip->fixes) + if (chip->fixes) { chip->quirks = chip->fixes->quirks; + chip->allow_runtime_pm = chip->fixes->allow_runtime_pm; + } chip->num_slots = slots; pci_set_drvdata(pdev, chip); @@ -1133,6 +1388,9 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, chip->slots[i] = slot; } + if (chip->allow_runtime_pm) + sdhci_pci_runtime_pm_allow(&pdev->dev); + return 0; free: @@ -1152,6 +1410,9 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev) chip = pci_get_drvdata(pdev); if (chip) { + if (chip->allow_runtime_pm) + sdhci_pci_runtime_pm_forbid(&pdev->dev); + for (i = 0; i < chip->num_slots; i++) sdhci_pci_remove_slot(chip->slots[i]); @@ -1169,6 +1430,9 @@ static struct pci_driver sdhci_driver = { .remove = __devexit_p(sdhci_pci_remove), .suspend = sdhci_pci_suspend, .resume = sdhci_pci_resume, + .driver = { + .pm = &sdhci_pci_pm_ops + }, }; /*****************************************************************************\ diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 6414efeddca0..a9e12ea05583 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -29,6 +29,7 @@ */ #include <linux/err.h> +#include <linux/module.h> #include <linux/of.h> #ifdef CONFIG_PPC #include <asm/machdep.h> diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 38f58994f79a..d4bf6d30c7ba 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/module.h> #include <linux/io.h> #include <linux/gpio.h> #include <linux/mmc/card.h> @@ -59,7 +60,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) * tune timing of read data/command when crc error happen * no performance impact */ - if (pdata->clk_delay_sel == 1) { + if (pdata && pdata->clk_delay_sel == 1) { tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); tmp &= ~(SDCLK_DELAY_MASK << SDCLK_DELAY_SHIFT); @@ -71,7 +72,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); } - if (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING) { + if (pdata && (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING)) { tmp = readw(host->ioaddr + SD_FIFO_PARAM); tmp &= ~CLK_GATE_SETTING_BITS; writew(tmp, host->ioaddr + SD_FIFO_PARAM); diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index fc7e4a515629..cff4ad3e7a59 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -27,6 +27,7 @@ #include <linux/platform_data/pxa_sdhci.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/module.h> #include "sdhci.h" #include "sdhci-pltfm.h" diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index fe886d6c474a..3d00e722efc9 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -203,17 +203,23 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); } - /* reconfigure the hardware for new clock rate */ - - { - struct mmc_ios ios; - - ios.clock = clock; - - if (ourhost->pdata->cfg_card) - (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr, - &ios, NULL); - } + /* reprogram default hardware configuration */ + writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, + host->ioaddr + S3C64XX_SDHCI_CONTROL4); + + ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); + ctrl |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR | + S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK | + S3C_SDHCI_CTRL2_ENFBCLKRX | + S3C_SDHCI_CTRL2_DFCNT_NONE | + S3C_SDHCI_CTRL2_ENCLKOUTHOLD); + writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); + + /* reconfigure the controller for new clock rate */ + ctrl = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0); + if (clock < 25 * 1000000) + ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2); + writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3); } /** @@ -561,8 +567,10 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) err_req_regs: for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { - clk_disable(sc->clk_bus[ptr]); - clk_put(sc->clk_bus[ptr]); + if (sc->clk_bus[ptr]) { + clk_disable(sc->clk_bus[ptr]); + clk_put(sc->clk_bus[ptr]); + } } err_no_busclks: diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 60a4c97d3d18..63cc8b6a1c9e 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -17,6 +17,7 @@ #include <linux/delay.h> #include <linux/gpio.h> #include <linux/highmem.h> +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/platform_device.h> @@ -177,8 +178,6 @@ static int __devinit sdhci_probe(struct platform_device *pdev) sdhci->data->card_power_gpio); goto err_pgpio_direction; } - - gpio_set_value(sdhci->data->card_power_gpio, 1); } if (sdhci->data->card_int_gpio >= 0) { diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 18b0bd31de78..89699e861fc1 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -13,15 +13,21 @@ */ #include <linux/err.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <linux/gpio.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> +#include <linux/module.h> -#include <mach/gpio.h> +#include <asm/gpio.h> + +#include <mach/gpio-tegra.h> #include <mach/sdhci.h> #include "sdhci-pltfm.h" @@ -73,10 +79,8 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci) { - struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc)); - struct tegra_sdhci_platform_data *plat; - - plat = pdev->dev.platform_data; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); + struct tegra_sdhci_platform_data *plat = pltfm_host->priv; if (!gpio_is_valid(plat->wp_gpio)) return -1; @@ -94,12 +98,10 @@ static irqreturn_t carddetect_irq(int irq, void *data) static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) { - struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); - struct tegra_sdhci_platform_data *plat; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct tegra_sdhci_platform_data *plat = pltfm_host->priv; u32 ctrl; - plat = pdev->dev.platform_data; - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) { ctrl &= ~SDHCI_CTRL_4BITBUS; @@ -131,6 +133,36 @@ static struct sdhci_pltfm_data sdhci_tegra_pdata = { .ops = &tegra_sdhci_ops, }; +static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = { + { .compatible = "nvidia,tegra20-sdhci", }, + {} +}; +MODULE_DEVICE_TABLE(of, sdhci_dt_ids); + +static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata( + struct platform_device *pdev) +{ + struct tegra_sdhci_platform_data *plat; + struct device_node *np = pdev->dev.of_node; + + if (!np) + return NULL; + + plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); + if (!plat) { + dev_err(&pdev->dev, "Can't allocate platform data\n"); + return NULL; + } + + plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); + plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); + plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0); + if (of_find_property(np, "support-8bit", NULL)) + plat->is_8bit = 1; + + return plat; +} + static int __devinit sdhci_tegra_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; @@ -147,12 +179,17 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) plat = pdev->dev.platform_data; + if (plat == NULL) + plat = sdhci_tegra_dt_parse_pdata(pdev); + if (plat == NULL) { dev_err(mmc_dev(host->mmc), "missing platform data\n"); rc = -ENXIO; goto err_no_plat; } + pltfm_host->priv = plat; + if (gpio_is_valid(plat->power_gpio)) { rc = gpio_request(plat->power_gpio, "sdhci_power"); if (rc) { @@ -247,13 +284,11 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct tegra_sdhci_platform_data *plat; + struct tegra_sdhci_platform_data *plat = pltfm_host->priv; int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); sdhci_remove_host(host, dead); - plat = pdev->dev.platform_data; - if (gpio_is_valid(plat->wp_gpio)) { tegra_gpio_disable(plat->wp_gpio); gpio_free(plat->wp_gpio); @@ -282,6 +317,7 @@ static struct platform_driver sdhci_tegra_driver = { .driver = { .name = "sdhci-tegra", .owner = THIS_MODULE, + .of_match_table = sdhci_tegra_dt_match, }, .probe = sdhci_tegra_probe, .remove = __devexit_p(sdhci_tegra_remove), diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0e02cc1df12e..6d8eea323541 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -16,10 +16,12 @@ #include <linux/delay.h> #include <linux/highmem.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/scatterlist.h> #include <linux/regulator/consumer.h> +#include <linux/pm_runtime.h> #include <linux/leds.h> @@ -41,6 +43,7 @@ #define MAX_TUNING_LOOP 40 static unsigned int debug_quirks = 0; +static unsigned int debug_quirks2; static void sdhci_finish_data(struct sdhci_host *); @@ -49,53 +52,67 @@ static void sdhci_finish_command(struct sdhci_host *); static int sdhci_execute_tuning(struct mmc_host *mmc); static void sdhci_tuning_timer(unsigned long data); +#ifdef CONFIG_PM_RUNTIME +static int sdhci_runtime_pm_get(struct sdhci_host *host); +static int sdhci_runtime_pm_put(struct sdhci_host *host); +#else +static inline int sdhci_runtime_pm_get(struct sdhci_host *host) +{ + return 0; +} +static inline int sdhci_runtime_pm_put(struct sdhci_host *host) +{ + return 0; +} +#endif + static void sdhci_dumpregs(struct sdhci_host *host) { - printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", + pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", mmc_hostname(host->mmc)); - printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", + pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", sdhci_readl(host, SDHCI_DMA_ADDRESS), sdhci_readw(host, SDHCI_HOST_VERSION)); - printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", + pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", sdhci_readw(host, SDHCI_BLOCK_SIZE), sdhci_readw(host, SDHCI_BLOCK_COUNT)); - printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", + pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", sdhci_readl(host, SDHCI_ARGUMENT), sdhci_readw(host, SDHCI_TRANSFER_MODE)); - printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", + pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", sdhci_readl(host, SDHCI_PRESENT_STATE), sdhci_readb(host, SDHCI_HOST_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", + pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n", sdhci_readb(host, SDHCI_POWER_CONTROL), sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", + pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n", sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), sdhci_readw(host, SDHCI_CLOCK_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", + pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n", sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), sdhci_readl(host, SDHCI_INT_STATUS)); - printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", + pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", sdhci_readl(host, SDHCI_INT_ENABLE), sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); - printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", + pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", sdhci_readw(host, SDHCI_ACMD12_ERR), sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); - printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", + pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n", sdhci_readl(host, SDHCI_CAPABILITIES), sdhci_readl(host, SDHCI_CAPABILITIES_1)); - printk(KERN_DEBUG DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", + pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", sdhci_readw(host, SDHCI_COMMAND), sdhci_readl(host, SDHCI_MAX_CURRENT)); - printk(KERN_DEBUG DRIVER_NAME ": Host ctl2: 0x%08x\n", + pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n", sdhci_readw(host, SDHCI_HOST_CONTROL2)); if (host->flags & SDHCI_USE_ADMA) - printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", + pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", readl(host->ioaddr + SDHCI_ADMA_ERROR), readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); - printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n"); + pr_debug(DRIVER_NAME ": ===========================================\n"); } /*****************************************************************************\ @@ -132,6 +149,9 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) return; + if (host->quirks2 & SDHCI_QUIRK2_OWN_CARD_DETECTION) + return; + present = sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT; irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; @@ -180,7 +200,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) /* hw clears the bit when it's done */ while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { if (timeout == 0) { - printk(KERN_ERR "%s: Reset 0x%x never completed.\n", + pr_err("%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask); sdhci_dumpregs(host); return; @@ -251,11 +271,14 @@ static void sdhci_led_control(struct led_classdev *led, spin_lock_irqsave(&host->lock, flags); + if (host->runtime_suspended) + goto out; + if (brightness == LED_OFF) sdhci_deactivate_led(host); else sdhci_activate_led(host); - +out: spin_unlock_irqrestore(&host->lock, flags); } #endif @@ -654,7 +677,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) } if (count >= 0xF) { - printk(KERN_WARNING "%s: Too large timeout requested for CMD%d!\n", + pr_warning("%s: Too large timeout requested for CMD%d!\n", mmc_hostname(host->mmc), cmd->opcode); count = 0xE; } @@ -949,7 +972,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { if (timeout == 0) { - printk(KERN_ERR "%s: Controller never released " + pr_err("%s: Controller never released " "inhibit bit(s).\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); cmd->error = -EIO; @@ -971,7 +994,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) sdhci_set_transfer_mode(host, cmd); if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { - printk(KERN_ERR "%s: Unsupported response type!\n", + pr_err("%s: Unsupported response type!\n", mmc_hostname(host->mmc)); cmd->error = -EINVAL; tasklet_schedule(&host->finish_tasklet); @@ -1121,7 +1144,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) & SDHCI_CLOCK_INT_STABLE)) { if (timeout == 0) { - printk(KERN_ERR "%s: Internal clock never " + pr_err("%s: Internal clock never " "stabilised.\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); return; @@ -1209,6 +1232,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) host = mmc_priv(mmc); + sdhci_runtime_pm_get(host); + spin_lock_irqsave(&host->lock, flags); WARN_ON(host->mrq != NULL); @@ -1269,14 +1294,11 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_unlock_irqrestore(&host->lock, flags); } -static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) { - struct sdhci_host *host; unsigned long flags; u8 ctrl; - host = mmc_priv(mmc); - spin_lock_irqsave(&host->lock, flags); if (host->flags & SDHCI_DEVICE_DEAD) @@ -1426,7 +1448,16 @@ out: spin_unlock_irqrestore(&host->lock, flags); } -static int check_ro(struct sdhci_host *host) +static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_runtime_pm_get(host); + sdhci_do_set_ios(host, ios); + sdhci_runtime_pm_put(host); +} + +static int sdhci_check_ro(struct sdhci_host *host) { unsigned long flags; int is_readonly; @@ -1450,19 +1481,16 @@ static int check_ro(struct sdhci_host *host) #define SAMPLE_COUNT 5 -static int sdhci_get_ro(struct mmc_host *mmc) +static int sdhci_do_get_ro(struct sdhci_host *host) { - struct sdhci_host *host; int i, ro_count; - host = mmc_priv(mmc); - if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT)) - return check_ro(host); + return sdhci_check_ro(host); ro_count = 0; for (i = 0; i < SAMPLE_COUNT; i++) { - if (check_ro(host)) { + if (sdhci_check_ro(host)) { if (++ro_count > SAMPLE_COUNT / 2) return 1; } @@ -1471,38 +1499,64 @@ static int sdhci_get_ro(struct mmc_host *mmc) return 0; } -static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +static void sdhci_hw_reset(struct mmc_host *mmc) { - struct sdhci_host *host; - unsigned long flags; + struct sdhci_host *host = mmc_priv(mmc); - host = mmc_priv(mmc); + if (host->ops && host->ops->hw_reset) + host->ops->hw_reset(host); +} - spin_lock_irqsave(&host->lock, flags); +static int sdhci_get_ro(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + int ret; + sdhci_runtime_pm_get(host); + ret = sdhci_do_get_ro(host); + sdhci_runtime_pm_put(host); + return ret; +} + +static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) +{ if (host->flags & SDHCI_DEVICE_DEAD) goto out; if (enable) + host->flags |= SDHCI_SDIO_IRQ_ENABLED; + else + host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; + + /* SDIO IRQ will be enabled as appropriate in runtime resume */ + if (host->runtime_suspended) + goto out; + + if (enable) sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT); else sdhci_mask_irqs(host, SDHCI_INT_CARD_INT); out: mmiowb(); +} + +static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + spin_lock_irqsave(&host->lock, flags); + sdhci_enable_sdio_irq_nolock(host, enable); spin_unlock_irqrestore(&host->lock, flags); } -static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, - struct mmc_ios *ios) +static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, + struct mmc_ios *ios) { - struct sdhci_host *host; u8 pwr; u16 clk, ctrl; u32 present_state; - host = mmc_priv(mmc); - /* * Signal Voltage Switching is only applicable for Host Controllers * v3.00 and above. @@ -1528,7 +1582,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, if (!(ctrl & SDHCI_CTRL_VDD_180)) return 0; else { - printk(KERN_INFO DRIVER_NAME ": Switching to 3.3V " + pr_info(DRIVER_NAME ": Switching to 3.3V " "signalling voltage failed\n"); return -EIO; } @@ -1587,7 +1641,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, pwr |= SDHCI_POWER_ON; sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); - printk(KERN_INFO DRIVER_NAME ": Switching to 1.8V signalling " + pr_info(DRIVER_NAME ": Switching to 1.8V signalling " "voltage failed, retrying with S18R set to 0\n"); return -EAGAIN; } else @@ -1595,6 +1649,20 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, return 0; } +static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + int err; + + if (host->version < SDHCI_SPEC_300) + return 0; + sdhci_runtime_pm_get(host); + err = sdhci_do_start_signal_voltage_switch(host, ios); + sdhci_runtime_pm_put(host); + return err; +} + static int sdhci_execute_tuning(struct mmc_host *mmc) { struct sdhci_host *host; @@ -1606,6 +1674,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) host = mmc_priv(mmc); + sdhci_runtime_pm_get(host); disable_irq(host->irq); spin_lock(&host->lock); @@ -1623,6 +1692,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) else { spin_unlock(&host->lock); enable_irq(host->irq); + sdhci_runtime_pm_put(host); return 0; } @@ -1648,7 +1718,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) timeout = 150; do { struct mmc_command cmd = {0}; - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; if (!tuning_loop_counter && !timeout) break; @@ -1694,7 +1764,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) spin_lock(&host->lock); if (!host->tuning_done) { - printk(KERN_INFO DRIVER_NAME ": Timeout waiting for " + pr_info(DRIVER_NAME ": Timeout waiting for " "Buffer Read Ready interrupt during tuning " "procedure, falling back to fixed sampling " "clock\n"); @@ -1724,7 +1794,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); } else { if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { - printk(KERN_INFO DRIVER_NAME ": Tuning procedure" + pr_info(DRIVER_NAME ": Tuning procedure" " failed, falling back to fixed sampling" " clock\n"); err = -EIO; @@ -1766,18 +1836,16 @@ out: sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); spin_unlock(&host->lock); enable_irq(host->irq); + sdhci_runtime_pm_put(host); return err; } -static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) +static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable) { - struct sdhci_host *host; u16 ctrl; unsigned long flags; - host = mmc_priv(mmc); - /* Host Controller v3.00 defines preset value registers */ if (host->version < SDHCI_SPEC_300) return; @@ -1793,18 +1861,30 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + host->flags |= SDHCI_PV_ENABLED; } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + host->flags &= ~SDHCI_PV_ENABLED; } spin_unlock_irqrestore(&host->lock, flags); } +static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) +{ + struct sdhci_host *host = mmc_priv(mmc); + + sdhci_runtime_pm_get(host); + sdhci_do_enable_preset_value(host, enable); + sdhci_runtime_pm_put(host); +} + static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, .get_ro = sdhci_get_ro, + .hw_reset = sdhci_hw_reset, .enable_sdio_irq = sdhci_enable_sdio_irq, .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, .execute_tuning = sdhci_execute_tuning, @@ -1826,19 +1906,19 @@ static void sdhci_tasklet_card(unsigned long param) spin_lock_irqsave(&host->lock, flags); - if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { - if (host->mrq) { - printk(KERN_ERR "%s: Card removed during transfer!\n", - mmc_hostname(host->mmc)); - printk(KERN_ERR "%s: Resetting controller.\n", - mmc_hostname(host->mmc)); + /* Check host->mrq first in case we are runtime suspended */ + if (host->mrq && + !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { + pr_err("%s: Card removed during transfer!\n", + mmc_hostname(host->mmc)); + pr_err("%s: Resetting controller.\n", + mmc_hostname(host->mmc)); - sdhci_reset(host, SDHCI_RESET_CMD); - sdhci_reset(host, SDHCI_RESET_DATA); + sdhci_reset(host, SDHCI_RESET_CMD); + sdhci_reset(host, SDHCI_RESET_DATA); - host->mrq->cmd->error = -ENOMEDIUM; - tasklet_schedule(&host->finish_tasklet); - } + host->mrq->cmd->error = -ENOMEDIUM; + tasklet_schedule(&host->finish_tasklet); } spin_unlock_irqrestore(&host->lock, flags); @@ -1854,14 +1934,16 @@ static void sdhci_tasklet_finish(unsigned long param) host = (struct sdhci_host*)param; + spin_lock_irqsave(&host->lock, flags); + /* * If this tasklet gets rescheduled while running, it will * be run again afterwards but without any active request. */ - if (!host->mrq) + if (!host->mrq) { + spin_unlock_irqrestore(&host->lock, flags); return; - - spin_lock_irqsave(&host->lock, flags); + } del_timer(&host->timer); @@ -1905,6 +1987,7 @@ static void sdhci_tasklet_finish(unsigned long param) spin_unlock_irqrestore(&host->lock, flags); mmc_request_done(host->mmc, mrq); + sdhci_runtime_pm_put(host); } static void sdhci_timeout_timer(unsigned long data) @@ -1917,7 +2000,7 @@ static void sdhci_timeout_timer(unsigned long data) spin_lock_irqsave(&host->lock, flags); if (host->mrq) { - printk(KERN_ERR "%s: Timeout waiting for hardware " + pr_err("%s: Timeout waiting for hardware " "interrupt.\n", mmc_hostname(host->mmc)); sdhci_dumpregs(host); @@ -1963,7 +2046,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) BUG_ON(intmask == 0); if (!host->cmd) { - printk(KERN_ERR "%s: Got command interrupt 0x%08x even " + pr_err("%s: Got command interrupt 0x%08x even " "though no command operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); @@ -2063,7 +2146,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } } - printk(KERN_ERR "%s: Got data interrupt 0x%08x even " + pr_err("%s: Got data interrupt 0x%08x even " "though no data operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); @@ -2080,7 +2163,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) != MMC_BUS_TEST_R) host->data->error = -EILSEQ; else if (intmask & SDHCI_INT_ADMA_ERROR) { - printk(KERN_ERR "%s: ADMA error\n", mmc_hostname(host->mmc)); + pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); sdhci_show_adma_error(host); host->data->error = -EIO; } @@ -2136,12 +2219,19 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) static irqreturn_t sdhci_irq(int irq, void *dev_id) { irqreturn_t result; - struct sdhci_host* host = dev_id; + struct sdhci_host *host = dev_id; u32 intmask; int cardint = 0; spin_lock(&host->lock); + if (host->runtime_suspended) { + spin_unlock(&host->lock); + pr_warning("%s: got irq while runtime suspended\n", + mmc_hostname(host->mmc)); + return IRQ_HANDLED; + } + intmask = sdhci_readl(host, SDHCI_INT_STATUS); if (!intmask || intmask == 0xffffffff) { @@ -2194,7 +2284,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~SDHCI_INT_ERROR; if (intmask & SDHCI_INT_BUS_POWER) { - printk(KERN_ERR "%s: Card is consuming too much power!\n", + pr_err("%s: Card is consuming too much power!\n", mmc_hostname(host->mmc)); sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS); } @@ -2207,7 +2297,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~SDHCI_INT_CARD_INT; if (intmask) { - printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", + pr_err("%s: Unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), intmask); sdhci_dumpregs(host); @@ -2275,7 +2365,6 @@ int sdhci_resume_host(struct sdhci_host *host) return ret; } - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) host->ops->enable_dma(host); @@ -2314,6 +2403,90 @@ EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); #endif /* CONFIG_PM */ +#ifdef CONFIG_PM_RUNTIME + +static int sdhci_runtime_pm_get(struct sdhci_host *host) +{ + return pm_runtime_get_sync(host->mmc->parent); +} + +static int sdhci_runtime_pm_put(struct sdhci_host *host) +{ + pm_runtime_mark_last_busy(host->mmc->parent); + return pm_runtime_put_autosuspend(host->mmc->parent); +} + +int sdhci_runtime_suspend_host(struct sdhci_host *host) +{ + unsigned long flags; + int ret = 0; + + /* Disable tuning since we are suspending */ + if (host->version >= SDHCI_SPEC_300 && + host->tuning_mode == SDHCI_TUNING_MODE_1) { + del_timer_sync(&host->tuning_timer); + host->flags &= ~SDHCI_NEEDS_RETUNING; + } + + spin_lock_irqsave(&host->lock, flags); + sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); + spin_unlock_irqrestore(&host->lock, flags); + + synchronize_irq(host->irq); + + spin_lock_irqsave(&host->lock, flags); + host->runtime_suspended = true; + spin_unlock_irqrestore(&host->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host); + +int sdhci_runtime_resume_host(struct sdhci_host *host) +{ + unsigned long flags; + int ret = 0, host_flags = host->flags; + + if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { + if (host->ops->enable_dma) + host->ops->enable_dma(host); + } + + sdhci_init(host, 0); + + /* Force clock and power re-program */ + host->pwr = 0; + host->clock = 0; + sdhci_do_set_ios(host, &host->mmc->ios); + + sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); + if (host_flags & SDHCI_PV_ENABLED) + sdhci_do_enable_preset_value(host, true); + + /* Set the re-tuning expiration flag */ + if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && + (host->tuning_mode == SDHCI_TUNING_MODE_1)) + host->flags |= SDHCI_NEEDS_RETUNING; + + spin_lock_irqsave(&host->lock, flags); + + host->runtime_suspended = false; + + /* Enable SDIO IRQ */ + if ((host->flags & SDHCI_SDIO_IRQ_ENABLED)) + sdhci_enable_sdio_irq_nolock(host, true); + + /* Enable Card Detection */ + sdhci_enable_card_detection(host); + + spin_unlock_irqrestore(&host->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host); + +#endif + /*****************************************************************************\ * * * Device allocation/registration * @@ -2356,6 +2529,8 @@ int sdhci_add_host(struct sdhci_host *host) if (debug_quirks) host->quirks = debug_quirks; + if (debug_quirks2) + host->quirks2 = debug_quirks2; sdhci_reset(host, SDHCI_RESET_ALL); @@ -2363,7 +2538,7 @@ int sdhci_add_host(struct sdhci_host *host) host->version = (host->version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; if (host->version > SDHCI_SPEC_300) { - printk(KERN_ERR "%s: Unknown controller version (%d). " + pr_err("%s: Unknown controller version (%d). " "You may experience problems.\n", mmc_hostname(mmc), host->version); } @@ -2400,7 +2575,7 @@ int sdhci_add_host(struct sdhci_host *host) if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) { if (host->ops->enable_dma(host)) { - printk(KERN_WARNING "%s: No suitable DMA " + pr_warning("%s: No suitable DMA " "available. Falling back to PIO.\n", mmc_hostname(mmc)); host->flags &= @@ -2420,7 +2595,7 @@ int sdhci_add_host(struct sdhci_host *host) if (!host->adma_desc || !host->align_buffer) { kfree(host->adma_desc); kfree(host->align_buffer); - printk(KERN_WARNING "%s: Unable to allocate ADMA " + pr_warning("%s: Unable to allocate ADMA " "buffers. Falling back to standard DMA.\n", mmc_hostname(mmc)); host->flags &= ~SDHCI_USE_ADMA; @@ -2448,8 +2623,7 @@ int sdhci_add_host(struct sdhci_host *host) if (host->max_clk == 0 || host->quirks & SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) { if (!host->ops->get_max_clock) { - printk(KERN_ERR - "%s: Hardware doesn't specify base clock " + pr_err("%s: Hardware doesn't specify base clock " "frequency.\n", mmc_hostname(mmc)); return -ENODEV; } @@ -2495,8 +2669,7 @@ int sdhci_add_host(struct sdhci_host *host) host->timeout_clk = host->ops->get_timeout_clock(host); } else if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) { - printk(KERN_ERR - "%s: Hardware doesn't specify timeout clock " + pr_err("%s: Hardware doesn't specify timeout clock " "frequency.\n", mmc_hostname(mmc)); return -ENODEV; } @@ -2566,6 +2739,15 @@ int sdhci_add_host(struct sdhci_host *host) if (caps[1] & SDHCI_DRIVER_TYPE_D) mmc->caps |= MMC_CAP_DRIVER_TYPE_D; + /* + * If Power Off Notify capability is enabled by the host, + * set notify to short power off notify timeout value. + */ + if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY) + mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT; + else + mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE; + /* Initial value for re-tuning timer count */ host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >> SDHCI_RETUNING_TIMER_COUNT_SHIFT; @@ -2655,7 +2837,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->ocr_avail_mmc &= host->ocr_avail_mmc; if (mmc->ocr_avail == 0) { - printk(KERN_ERR "%s: Hardware doesn't report any " + pr_err("%s: Hardware doesn't report any " "support voltages.\n", mmc_hostname(mmc)); return -ENODEV; } @@ -2703,7 +2885,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; if (mmc->max_blk_size >= 3) { - printk(KERN_WARNING "%s: Invalid maximum block size, " + pr_warning("%s: Invalid maximum block size, " "assuming 512 bytes\n", mmc_hostname(mmc)); mmc->max_blk_size = 0; } @@ -2742,7 +2924,7 @@ int sdhci_add_host(struct sdhci_host *host) host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); if (IS_ERR(host->vmmc)) { - printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); + pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); host->vmmc = NULL; } else { regulator_enable(host->vmmc); @@ -2771,7 +2953,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc_add_host(mmc); - printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s\n", + pr_info("%s: SDHCI controller on %s [%s] using %s\n", mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), (host->flags & SDHCI_USE_ADMA) ? "ADMA" : (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); @@ -2804,7 +2986,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) host->flags |= SDHCI_DEVICE_DEAD; if (host->mrq) { - printk(KERN_ERR "%s: Controller removed during " + pr_err("%s: Controller removed during " " transfer!\n", mmc_hostname(host->mmc)); host->mrq->cmd->error = -ENOMEDIUM; @@ -2863,9 +3045,9 @@ EXPORT_SYMBOL_GPL(sdhci_free_host); static int __init sdhci_drv_init(void) { - printk(KERN_INFO DRIVER_NAME + pr_info(DRIVER_NAME ": Secure Digital Host Controller Interface driver\n"); - printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); + pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); return 0; } @@ -2878,9 +3060,11 @@ module_init(sdhci_drv_init); module_exit(sdhci_drv_exit); module_param(debug_quirks, uint, 0444); +module_param(debug_quirks2, uint, 0444); MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); MODULE_LICENSE("GPL"); MODULE_PARM_DESC(debug_quirks, "Force certain quirks."); +MODULE_PARM_DESC(debug_quirks2, "Force certain other quirks."); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 745c42fa41ed..0a5b65460d8a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -273,7 +273,7 @@ struct sdhci_ops { void (*platform_reset_enter)(struct sdhci_host *host, u8 mask); void (*platform_reset_exit)(struct sdhci_host *host, u8 mask); int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); - + void (*hw_reset)(struct sdhci_host *host); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS @@ -379,4 +379,9 @@ extern int sdhci_resume_host(struct sdhci_host *host); extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); #endif +#ifdef CONFIG_PM_RUNTIME +extern int sdhci_runtime_suspend_host(struct sdhci_host *host); +extern int sdhci_runtime_resume_host(struct sdhci_host *host); +#endif + #endif /* __SDHCI_HW_H */ diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 496b7efbc6b0..7009f17ad6cd 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -26,6 +26,7 @@ */ #include <linux/delay.h> #include <linux/highmem.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/ioport.h> #include <linux/scatterlist.h> diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 557886bee9ce..369366c8e205 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -31,6 +31,7 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/spinlock.h> +#include <linux/module.h> #define DRIVER_NAME "sh_mmcif" #define DRIVER_VERSION "2010-04-28" @@ -165,6 +166,8 @@ struct sh_mmcif_host { struct mmc_host *mmc; struct mmc_data *data; struct platform_device *pd; + struct sh_dmae_slave dma_slave_tx; + struct sh_dmae_slave dma_slave_rx; struct clk *hclk; unsigned int clk; int bus_width; @@ -323,25 +326,35 @@ static bool sh_mmcif_filter(struct dma_chan *chan, void *arg) static void sh_mmcif_request_dma(struct sh_mmcif_host *host, struct sh_mmcif_plat_data *pdata) { + struct sh_dmae_slave *tx, *rx; host->dma_active = false; /* We can only either use DMA for both Tx and Rx or not use it at all */ if (pdata->dma) { + dev_warn(&host->pd->dev, + "Update your platform to use embedded DMA slave IDs\n"); + tx = &pdata->dma->chan_priv_tx; + rx = &pdata->dma->chan_priv_rx; + } else { + tx = &host->dma_slave_tx; + tx->slave_id = pdata->slave_id_tx; + rx = &host->dma_slave_rx; + rx->slave_id = pdata->slave_id_rx; + } + if (tx->slave_id > 0 && rx->slave_id > 0) { dma_cap_mask_t mask; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - host->chan_tx = dma_request_channel(mask, sh_mmcif_filter, - &pdata->dma->chan_priv_tx); + host->chan_tx = dma_request_channel(mask, sh_mmcif_filter, tx); dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__, host->chan_tx); if (!host->chan_tx) return; - host->chan_rx = dma_request_channel(mask, sh_mmcif_filter, - &pdata->dma->chan_priv_rx); + host->chan_rx = dma_request_channel(mask, sh_mmcif_filter, rx); dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__, host->chan_rx); diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 0c4a672f5db6..41ae6466bd83 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -21,6 +21,7 @@ #include <linux/kernel.h> #include <linux/clk.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/mmc/host.h> #include <linux/mmc/sh_mobile_sdhi.h> @@ -96,7 +97,8 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct tmio_mmc_host *host; char clk_name[8]; - int i, irq, ret; + int irq, ret, i = 0; + bool multiplexed_isr = true; priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); if (priv == NULL) { @@ -153,27 +155,60 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) if (ret < 0) goto eprobe; - for (i = 0; i < 3; i++) { - irq = platform_get_irq(pdev, i); - if (irq < 0) { - if (i) { - continue; - } else { - ret = irq; - goto eirq; - } - } - ret = request_irq(irq, tmio_mmc_irq, 0, + /* + * Allow one or more specific (named) ISRs or + * one or more multiplexed (un-named) ISRs. + */ + + irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT); + if (irq >= 0) { + multiplexed_isr = false; + ret = request_irq(irq, tmio_mmc_card_detect_irq, 0, + dev_name(&pdev->dev), host); + if (ret) + goto eirq_card_detect; + } + + irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO); + if (irq >= 0) { + multiplexed_isr = false; + ret = request_irq(irq, tmio_mmc_sdio_irq, 0, + dev_name(&pdev->dev), host); + if (ret) + goto eirq_sdio; + } + + irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDCARD); + if (irq >= 0) { + multiplexed_isr = false; + ret = request_irq(irq, tmio_mmc_sdcard_irq, 0, dev_name(&pdev->dev), host); - if (ret) { - while (i--) { - irq = platform_get_irq(pdev, i); - if (irq >= 0) - free_irq(irq, host); - } - goto eirq; + if (ret) + goto eirq_sdcard; + } else if (!multiplexed_isr) { + dev_err(&pdev->dev, + "Principal SD-card IRQ is missing among named interrupts\n"); + ret = irq; + goto eirq_sdcard; + } + + if (multiplexed_isr) { + while (1) { + irq = platform_get_irq(pdev, i); + if (irq < 0) + break; + i++; + ret = request_irq(irq, tmio_mmc_irq, 0, + dev_name(&pdev->dev), host); + if (ret) + goto eirq_multiplexed; } + + /* There must be at least one IRQ source */ + if (!i) + goto eirq_multiplexed; } + dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n", mmc_hostname(host->mmc), (unsigned long) (platform_get_resource(pdev,IORESOURCE_MEM, 0)->start), @@ -181,7 +216,20 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) return ret; -eirq: +eirq_multiplexed: + while (i--) { + irq = platform_get_irq(pdev, i); + free_irq(irq, host); + } +eirq_sdcard: + irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO); + if (irq >= 0) + free_irq(irq, host); +eirq_sdio: + irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT); + if (irq >= 0) + free_irq(irq, host); +eirq_card_detect: tmio_mmc_host_remove(host); eprobe: clk_disable(priv->clk); @@ -197,16 +245,17 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) struct tmio_mmc_host *host = mmc_priv(mmc); struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - int i, irq; + int i = 0, irq; p->pdata = NULL; tmio_mmc_host_remove(host); - for (i = 0; i < 3; i++) { - irq = platform_get_irq(pdev, i); - if (irq >= 0) - free_irq(irq, host); + while (1) { + irq = platform_get_irq(pdev, i++); + if (irq < 0) + break; + free_irq(irq, host); } clk_disable(priv->clk); diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 457c26ea09de..f70d04664cac 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -16,6 +16,7 @@ #include <linux/mmc/host.h> #include <linux/highmem.h> #include <linux/scatterlist.h> +#include <linux/module.h> #include <asm/io.h> #define DRIVER_NAME "tifm_sd" @@ -631,7 +632,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) } if (host->req) { - printk(KERN_ERR "%s : unfinished request detected\n", + pr_err("%s : unfinished request detected\n", dev_name(&sock->dev)); mrq->cmd->error = -ETIMEDOUT; goto err_out; @@ -671,7 +672,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) r_data->flags & MMC_DATA_WRITE ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE)) { - printk(KERN_ERR "%s : scatterlist map failed\n", + pr_err("%s : scatterlist map failed\n", dev_name(&sock->dev)); mrq->cmd->error = -ENOMEM; goto err_out; @@ -683,7 +684,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); if (host->sg_len < 1) { - printk(KERN_ERR "%s : scatterlist map failed\n", + pr_err("%s : scatterlist map failed\n", dev_name(&sock->dev)); tifm_unmap_sg(sock, &host->bounce_buf, 1, r_data->flags & MMC_DATA_WRITE @@ -747,7 +748,7 @@ static void tifm_sd_end_cmd(unsigned long data) host->req = NULL; if (!mrq) { - printk(KERN_ERR " %s : no request to complete?\n", + pr_err(" %s : no request to complete?\n", dev_name(&sock->dev)); spin_unlock_irqrestore(&sock->lock, flags); return; @@ -786,8 +787,7 @@ static void tifm_sd_abort(unsigned long data) { struct tifm_sd *host = (struct tifm_sd*)data; - printk(KERN_ERR - "%s : card failed to respond for a long period of time " + pr_err("%s : card failed to respond for a long period of time " "(%x, %x)\n", dev_name(&host->dev->dev), host->req->cmd->opcode, host->cmd_flags); @@ -905,7 +905,7 @@ static int tifm_sd_initialize_host(struct tifm_sd *host) } if (rc) { - printk(KERN_ERR "%s : controller failed to reset\n", + pr_err("%s : controller failed to reset\n", dev_name(&sock->dev)); return -ENODEV; } @@ -931,8 +931,7 @@ static int tifm_sd_initialize_host(struct tifm_sd *host) } if (rc) { - printk(KERN_ERR - "%s : card not ready - probe failed on initialization\n", + pr_err("%s : card not ready - probe failed on initialization\n", dev_name(&sock->dev)); return -ENODEV; } @@ -953,7 +952,7 @@ static int tifm_sd_probe(struct tifm_dev *sock) if (!(TIFM_SOCK_STATE_OCCUPIED & readl(sock->addr + SOCK_PRESENT_STATE))) { - printk(KERN_WARNING "%s : card gone, unexpectedly\n", + pr_warning("%s : card gone, unexpectedly\n", dev_name(&sock->dev)); return rc; } diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 44a9668c4b7a..a4ea10242787 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -88,8 +88,8 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev) if (ret) goto cell_disable; - ret = request_irq(irq, tmio_mmc_irq, IRQF_DISABLED | - IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host); + ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING, + dev_name(&pdev->dev), host); if (ret) goto host_remove; diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index eeaf64391fbe..3020f98218f0 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -79,6 +79,10 @@ struct tmio_mmc_host { struct delayed_work delayed_reset_work; struct work_struct done; + /* Cache IRQ mask */ + u32 sdcard_irq_mask; + u32 sdio_irq_mask; + spinlock_t lock; /* protect host private data */ unsigned long last_req_ts; struct mutex ios_lock; /* protect set_ios() context */ @@ -93,6 +97,9 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); irqreturn_t tmio_mmc_irq(int irq, void *devid); +irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid); +irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid); +irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid); static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 1f16357e7301..d85a60cda167 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -48,14 +48,14 @@ void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i) { - u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) & ~(i & TMIO_MASK_IRQ); - sd_ctrl_write32(host, CTL_IRQ_MASK, mask); + host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ); + sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask); } void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i) { - u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) | (i & TMIO_MASK_IRQ); - sd_ctrl_write32(host, CTL_IRQ_MASK, mask); + host->sdcard_irq_mask |= (i & TMIO_MASK_IRQ); + sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask); } static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i) @@ -92,7 +92,7 @@ static int tmio_mmc_next_sg(struct tmio_mmc_host *host) static void pr_debug_status(u32 status) { int i = 0; - printk(KERN_DEBUG "status: %08x = ", status); + pr_debug("status: %08x = ", status); STATUS_TO_TEXT(CARD_REMOVE, status, i); STATUS_TO_TEXT(CARD_INSERT, status, i); STATUS_TO_TEXT(SIGSTATE, status, i); @@ -127,11 +127,13 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) if (enable) { host->sdio_irq_enabled = 1; + host->sdio_irq_mask = TMIO_SDIO_MASK_ALL & + ~TMIO_SDIO_STAT_IOIRQ; sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); - sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, - (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ)); + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); } else { - sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL); + host->sdio_irq_mask = TMIO_SDIO_MASK_ALL; + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); host->sdio_irq_enabled = 0; } @@ -543,45 +545,20 @@ out: spin_unlock(&host->lock); } -irqreturn_t tmio_mmc_irq(int irq, void *devid) +static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host, + int *ireg, int *status) { - struct tmio_mmc_host *host = devid; - struct mmc_host *mmc = host->mmc; - struct tmio_mmc_data *pdata = host->pdata; - unsigned int ireg, irq_mask, status; - unsigned int sdio_ireg, sdio_irq_mask, sdio_status; - - pr_debug("MMC IRQ begin\n"); - - status = sd_ctrl_read32(host, CTL_STATUS); - irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); - ireg = status & TMIO_MASK_IRQ & ~irq_mask; - - sdio_ireg = 0; - if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { - sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); - sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK); - sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask; + *status = sd_ctrl_read32(host, CTL_STATUS); + *ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; - sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL); - - if (sdio_ireg && !host->sdio_irq_enabled) { - pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", - sdio_status, sdio_irq_mask, sdio_ireg); - tmio_mmc_enable_sdio_irq(mmc, 0); - goto out; - } - - if (mmc->caps & MMC_CAP_SDIO_IRQ && - sdio_ireg & TMIO_SDIO_STAT_IOIRQ) - mmc_signal_sdio_irq(mmc); - - if (sdio_ireg) - goto out; - } + pr_debug_status(*status); + pr_debug_status(*ireg); +} - pr_debug_status(status); - pr_debug_status(ireg); +static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host, + int ireg, int status) +{ + struct mmc_host *mmc = host->mmc; /* Card insert / remove attempts */ if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { @@ -591,43 +568,102 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid) ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) && !work_pending(&mmc->detect.work)) mmc_detect_change(host->mmc, msecs_to_jiffies(100)); - goto out; + return true; } - /* CRC and other errors */ -/* if (ireg & TMIO_STAT_ERR_IRQ) - * handled |= tmio_error_irq(host, irq, stat); - */ + return false; +} + +irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid) +{ + unsigned int ireg, status; + struct tmio_mmc_host *host = devid; + + tmio_mmc_card_irq_status(host, &ireg, &status); + __tmio_mmc_card_detect_irq(host, ireg, status); + return IRQ_HANDLED; +} +EXPORT_SYMBOL(tmio_mmc_card_detect_irq); + +static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, + int ireg, int status) +{ /* Command completion */ if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) { tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT); tmio_mmc_cmd_irq(host, status); - goto out; + return true; } /* Data transfer */ if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); tmio_mmc_pio_irq(host); - goto out; + return true; } /* Data transfer completion */ if (ireg & TMIO_STAT_DATAEND) { tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND); tmio_mmc_data_irq(host); - goto out; + return true; } - pr_warning("tmio_mmc: Spurious irq, disabling! " - "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); - pr_debug_status(status); - tmio_mmc_disable_mmc_irqs(host, status & ~irq_mask); + return false; +} + +irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid) +{ + unsigned int ireg, status; + struct tmio_mmc_host *host = devid; + + tmio_mmc_card_irq_status(host, &ireg, &status); + __tmio_mmc_sdcard_irq(host, ireg, status); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL(tmio_mmc_sdcard_irq); + +irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid) +{ + struct tmio_mmc_host *host = devid; + struct mmc_host *mmc = host->mmc; + struct tmio_mmc_data *pdata = host->pdata; + unsigned int ireg, status; + + if (!(pdata->flags & TMIO_MMC_SDIO_IRQ)) + return IRQ_HANDLED; + + status = sd_ctrl_read16(host, CTL_SDIO_STATUS); + ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask; + + sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL); + + if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ) + mmc_signal_sdio_irq(mmc); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL(tmio_mmc_sdio_irq); + +irqreturn_t tmio_mmc_irq(int irq, void *devid) +{ + struct tmio_mmc_host *host = devid; + unsigned int ireg, status; + + pr_debug("MMC IRQ begin\n"); + + tmio_mmc_card_irq_status(host, &ireg, &status); + if (__tmio_mmc_card_detect_irq(host, ireg, status)) + return IRQ_HANDLED; + if (__tmio_mmc_sdcard_irq(host, ireg, status)) + return IRQ_HANDLED; + + tmio_mmc_sdio_irq(irq, devid); -out: return IRQ_HANDLED; } EXPORT_SYMBOL(tmio_mmc_irq); @@ -882,6 +918,7 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, tmio_mmc_clk_stop(_host); tmio_mmc_reset(_host); + _host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK); tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); if (pdata->flags & TMIO_MMC_SDIO_IRQ) tmio_mmc_enable_sdio_irq(mmc, 0); diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 4dfe2c02ea91..4b83c43f950d 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -9,6 +9,7 @@ */ #include <linux/pci.h> +#include <linux/module.h> #include <linux/dma-mapping.h> #include <linux/highmem.h> #include <linux/delay.h> @@ -1191,7 +1192,7 @@ static void __devexit via_sd_remove(struct pci_dev *pcidev) mmiowb(); if (sdhost->mrq) { - printk(KERN_ERR "%s: Controller removed during " + pr_err("%s: Controller removed during " "transfer\n", mmc_hostname(sdhost->mmc)); /* make sure all DMA is stopped */ diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 62e5a4d171e1..64acd9ce141c 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -194,7 +194,7 @@ static void wbsd_reset(struct wbsd_host *host) { u8 setup; - printk(KERN_ERR "%s: Resetting chip\n", mmc_hostname(host->mmc)); + pr_err("%s: Resetting chip\n", mmc_hostname(host->mmc)); /* * Soft reset of chip (SD/MMC part). @@ -721,7 +721,7 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) * Any leftover data? */ if (count) { - printk(KERN_ERR "%s: Incomplete DMA transfer. " + pr_err("%s: Incomplete DMA transfer. " "%d bytes left.\n", mmc_hostname(host->mmc), count); @@ -803,7 +803,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) default: #ifdef CONFIG_MMC_DEBUG - printk(KERN_WARNING "%s: Data command %d is not " + pr_warning("%s: Data command %d is not " "supported by this controller.\n", mmc_hostname(host->mmc), cmd->opcode); #endif @@ -1029,7 +1029,7 @@ static void wbsd_tasklet_card(unsigned long param) host->flags &= ~WBSD_FCARD_PRESENT; if (host->mrq) { - printk(KERN_ERR "%s: Card removed during transfer!\n", + pr_err("%s: Card removed during transfer!\n", mmc_hostname(host->mmc)); wbsd_reset(host); @@ -1429,7 +1429,7 @@ free: free_dma(dma); err: - printk(KERN_WARNING DRIVER_NAME ": Unable to allocate DMA %d. " + pr_warning(DRIVER_NAME ": Unable to allocate DMA %d. " "Falling back on FIFO.\n", dma); } @@ -1664,7 +1664,7 @@ static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, ret = wbsd_scan(host); if (ret) { if (pnp && (ret == -ENODEV)) { - printk(KERN_WARNING DRIVER_NAME + pr_warning(DRIVER_NAME ": Unable to confirm device presence. You may " "experience lock-ups.\n"); } else { @@ -1688,7 +1688,7 @@ static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, */ if (pnp) { if ((host->config != 0) && !wbsd_chip_validate(host)) { - printk(KERN_WARNING DRIVER_NAME + pr_warning(DRIVER_NAME ": PnP active but chip not configured! " "You probably have a buggy BIOS. " "Configuring chip manually.\n"); @@ -1720,7 +1720,7 @@ static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, mmc_add_host(mmc); - printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc)); + pr_info("%s: W83L51xD", mmc_hostname(mmc)); if (host->chip_id != 0) printk(" id %x", (int)host->chip_id); printk(" at 0x%x irq %d", (int)host->base, (int)host->irq); @@ -1909,7 +1909,7 @@ static int wbsd_pnp_resume(struct pnp_dev *pnp_dev) */ if (host->config != 0) { if (!wbsd_chip_validate(host)) { - printk(KERN_WARNING DRIVER_NAME + pr_warning(DRIVER_NAME ": PnP active but chip not configured! " "You probably have a buggy BIOS. " "Configuring chip manually.\n"); @@ -1973,9 +1973,9 @@ static int __init wbsd_drv_init(void) { int result; - printk(KERN_INFO DRIVER_NAME + pr_info(DRIVER_NAME ": Winbond W83L51xD SD/MMC card interface driver\n"); - printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); + pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); #ifdef CONFIG_PNP |