From 2c96a293bbd6b34698c6710ea8607049956247c4 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 11 Aug 2011 15:25:41 +0000 Subject: mmc: atmel-mci: change namespace Homogenize namespace to atmci. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci-regs.h | 206 +++++++++++++------------- drivers/mmc/host/atmel-mci.c | 301 +++++++++++++++++++------------------- 2 files changed, 254 insertions(+), 253 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index fc8a0fe7c5c..29331ab67dc 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -17,112 +17,112 @@ #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_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ +# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ +# 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_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_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 + ATMCI_##reg) +#define atmci_writel(port,reg,value) \ + __raw_writel((value), (port)->regs + ATMCI_##reg) #endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */ diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index fa8cae1d700..c2a0949f325 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -39,7 +39,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 { @@ -166,7 +166,7 @@ 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]; }; /** @@ -223,7 +223,7 @@ struct atmel_mci_slot { * Enable or disable features/registers based on * whether the processor supports them */ -static bool mci_has_rwproof(void) +static bool atmci_has_rwproof(void) { if (cpu_is_at91sam9261() || cpu_is_at91rm9200()) return false; @@ -352,7 +352,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 +363,47 @@ 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); + buf[ATMCI_BLKR / 4], + buf[ATMCI_BLKR / 4] & 0xffff, + (buf[ATMCI_BLKR / 4] >> 16) & 0xffff); if (atmci_is_mci2()) - seq_printf(s, "CSTOR:\t0x%08x\n", buf[MCI_CSTOR / 4]); + 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()) { 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" : ""); - 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 +466,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 +482,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 +499,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, DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc))); } /* @@ -512,13 +513,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,28 +527,28 @@ 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; @@ -563,14 +564,14 @@ 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, ARGR, cmd->arg); + atmci_writel(host, 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_writel(host, IER, ATMCI_CMDRDY); } #ifdef CONFIG_MMC_ATMELMCI_DMA @@ -595,7 +596,7 @@ static void atmci_stop_dma(struct atmel_mci *host) } else { /* Data transfer was stopped by the interrupt handler */ atmci_set_pending(host, EVENT_XFER_COMPLETE); - mci_writel(host, IER, MCI_NOTBUSY); + atmci_writel(host, IER, ATMCI_NOTBUSY); } } @@ -609,7 +610,7 @@ static void atmci_dma_complete(void *arg) if (atmci_is_mci2()) /* Disable DMA hardware handshaking on MCI */ - mci_writel(host, DMA, mci_readl(host, DMA) & ~MCI_DMAEN); + atmci_writel(host, DMA, atmci_readl(host, DMA) & ~ATMCI_DMAEN); atmci_dma_cleanup(host); @@ -641,7 +642,7 @@ static void atmci_dma_complete(void *arg) * completion callback" rule of the dma engine * framework. */ - mci_writel(host, IER, MCI_NOTBUSY); + atmci_writel(host, IER, ATMCI_NOTBUSY); } } @@ -660,7 +661,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) * non-word-aligned buffers or lengths. Also, we don't bother * with all the DMA setup overhead for short transfers. */ - if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD) + if (data->blocks * data->blksz < ATATMCI_DMA_THRESHOLD) return -EINVAL; if (data->blksz & 3) return -EINVAL; @@ -679,7 +680,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) return -ENODEV; if (atmci_is_mci2()) - mci_writel(host, DMA, MCI_DMA_CHKSIZE(3) | MCI_DMAEN); + atmci_writel(host, DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN); if (data->flags & MMC_DATA_READ) direction = DMA_FROM_DEVICE; @@ -729,7 +730,7 @@ static void atmci_stop_dma(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, IER, ATMCI_NOTBUSY); } #endif /* CONFIG_MMC_ATMELMCI_DMA */ @@ -766,9 +767,9 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) host->sg = data->sg; host->pio_offset = 0; if (data->flags & MMC_DATA_READ) - iflags |= MCI_RXRDY; + iflags |= ATMCI_RXRDY; else - iflags |= MCI_TXRDY; + iflags |= ATMCI_TXRDY; } return iflags; @@ -792,24 +793,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); + atmci_writel(host, CR, ATMCI_CR_SWRST); + atmci_writel(host, CR, ATMCI_CR_MCIEN); + atmci_writel(host, MR, host->mode_reg); if (atmci_is_mci2()) - mci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, CFG, host->cfg_reg); host->need_reset = false; } - mci_writel(host, SDCR, slot->sdc_reg); + atmci_writel(host, SDCR, slot->sdc_reg); - iflags = mci_readl(host, IMR); - if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB)) + iflags = atmci_readl(host, 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, CMDR, ATMCI_CMDR_SPCMD_INIT); + while (!(atmci_readl(host, SR) & ATMCI_CMDRDY)) cpu_relax(); } iflags = 0; @@ -818,15 +819,15 @@ 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, 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 |= MCI_CMDRDY; + iflags |= ATMCI_CMDRDY; cmd = mrq->cmd; cmdflags = atmci_prepare_command(slot->mmc, cmd); atmci_start_command(host, cmd, cmdflags); @@ -836,13 +837,13 @@ static void atmci_start_request(struct atmel_mci *host, 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 +852,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, IER, iflags); } static void atmci_queue_request(struct atmel_mci *host, @@ -909,13 +910,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 +927,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); + atmci_writel(host, CR, ATMCI_CR_SWRST); + atmci_writel(host, CR, ATMCI_CR_MCIEN); if (atmci_is_mci2()) - mci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, CFG, host->cfg_reg); } /* @@ -937,7 +938,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 +953,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 (atmci_has_rwproof()) + host->mode_reg |= (ATMCI_MR_WRPROOF | ATMCI_MR_RDPROOF); if (atmci_is_mci2()) { /* 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); + atmci_writel(host, MR, host->mode_reg); if (atmci_is_mci2()) - mci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, CFG, host->cfg_reg); } else { host->need_clock_update = true; } @@ -984,16 +985,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, CR, ATMCI_CR_MCIDIS); if (host->mode_reg) { - mci_readl(host, MR); + atmci_readl(host, MR); clk_disable(host->mck); } host->mode_reg = 0; @@ -1057,9 +1058,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, IER, slot->sdio_irq); else - mci_writel(host, IDR, slot->sdio_irq); + atmci_writel(host, IDR, slot->sdio_irq); } static const struct mmc_host_ops atmci_ops = { @@ -1086,9 +1087,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); + atmci_writel(host, MR, host->mode_reg); if (atmci_is_mci2()) - mci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, CFG, host->cfg_reg); } host->cur_slot->mrq = NULL; @@ -1117,16 +1118,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, RSPR); + cmd->resp[1] = atmci_readl(host, RSPR); + cmd->resp[2] = atmci_readl(host, RSPR); + cmd->resp[3] = atmci_readl(host, 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; @@ -1138,8 +1139,8 @@ static void atmci_command_complete(struct atmel_mci *host, if (cmd->data) { atmci_stop_dma(host); host->data = NULL; - mci_writel(host, IDR, MCI_NOTBUSY - | MCI_TXRDY | MCI_RXRDY + atmci_writel(host, IDR, ATMCI_NOTBUSY + | ATMCI_TXRDY | ATMCI_RXRDY | ATMCI_DATA_ERROR_FLAGS); } } @@ -1191,11 +1192,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); + atmci_writel(host, CR, ATMCI_CR_SWRST); + atmci_writel(host, CR, ATMCI_CR_MCIEN); + atmci_writel(host, MR, host->mode_reg); if (atmci_is_mci2()) - mci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, CFG, host->cfg_reg); host->data = NULL; host->cmd = NULL; @@ -1261,7 +1262,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, IMR)); do { prev_state = state; @@ -1291,7 +1292,7 @@ static void atmci_tasklet_func(unsigned long priv) EVENT_DATA_ERROR)) { atmci_stop_dma(host); if (data->stop) - send_stop_cmd(host, data); + atmci_send_stop_cmd(host, data); state = STATE_DATA_ERROR; break; } @@ -1313,11 +1314,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 +1331,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, IDR, ATMCI_DATA_ERROR_FLAGS); } if (!data->stop) { @@ -1340,7 +1341,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 +1381,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, RDR); if (likely(offset + 4 <= sg->length)) { put_unaligned(value, (u32 *)(buf + offset)); @@ -1412,9 +1413,9 @@ static void atmci_read_data_pio(struct atmel_mci *host) nbytes += offset; } - status = mci_readl(host, SR); + status = atmci_readl(host, SR); if (status & ATMCI_DATA_ERROR_FLAGS) { - mci_writel(host, IDR, (MCI_NOTBUSY | MCI_RXRDY + atmci_writel(host, IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY | ATMCI_DATA_ERROR_FLAGS)); host->data_status = status; data->bytes_xfered += nbytes; @@ -1423,7 +1424,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 +1432,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, IDR, ATMCI_RXRDY); + atmci_writel(host, IER, ATMCI_NOTBUSY); data->bytes_xfered += nbytes; smp_wmb(); atmci_set_pending(host, EVENT_XFER_COMPLETE); @@ -1451,7 +1452,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, TDR, value); offset += 4; nbytes += 4; @@ -1472,20 +1473,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, 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, TDR, value); nbytes += offset; } - status = mci_readl(host, SR); + status = atmci_readl(host, SR); if (status & ATMCI_DATA_ERROR_FLAGS) { - mci_writel(host, IDR, (MCI_NOTBUSY | MCI_TXRDY + atmci_writel(host, IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY | ATMCI_DATA_ERROR_FLAGS)); host->data_status = status; data->bytes_xfered += nbytes; @@ -1494,7 +1495,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 +1503,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, IDR, ATMCI_TXRDY); + atmci_writel(host, IER, ATMCI_NOTBUSY); data->bytes_xfered += nbytes; smp_wmb(); atmci_set_pending(host, EVENT_XFER_COMPLETE); @@ -1511,7 +1512,7 @@ done: static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) { - mci_writel(host, IDR, MCI_CMDRDY); + atmci_writel(host, IDR, ATMCI_CMDRDY); host->cmd_status = status; smp_wmb(); @@ -1523,7 +1524,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 +1540,40 @@ 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, SR); + mask = atmci_readl(host, 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, IDR, ATMCI_DATA_ERROR_FLAGS + | ATMCI_RXRDY | ATMCI_TXRDY); + pending &= atmci_readl(host, 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_NOTBUSY) { + atmci_writel(host, 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); @@ -1705,7 +1706,7 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot, } #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 +1731,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"); @@ -1789,7 +1790,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, CR, ATMCI_CR_SWRST); host->bus_hz = clk_get_rate(host->mck); clk_disable(host->mck); @@ -1810,13 +1811,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++; } @@ -1854,15 +1855,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, IDR, ~0UL); + atmci_writel(host, CR, ATMCI_CR_MCIDIS); + atmci_readl(host, SR); clk_disable(host->mck); #ifdef CONFIG_MMC_ATMELMCI_DMA @@ -1885,7 +1886,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 +1917,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; -- cgit v1.2.3-18-g5258 From 03fc9a7f0c48a05ca548cd277835d7da97ed6936 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 11 Aug 2011 15:25:42 +0000 Subject: mmc: atmel-mci: change atmci_readl and atmci_writel macros Change atmci_readl and atmci_writel macros: remove string concatenation. We can use these macros with registers which are not prefixed by ATMCI_. This is the case if we want to write PDC registers which are common to several devices so they are not prefixed with ATMCI_. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci-regs.h | 4 +- drivers/mmc/host/atmel-mci.c | 126 +++++++++++++++++++------------------- 2 files changed, 65 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index 29331ab67dc..8574e910d1f 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -121,8 +121,8 @@ /* Register access macros */ #define atmci_readl(port,reg) \ - __raw_readl((port)->regs + ATMCI_##reg) + __raw_readl((port)->regs + reg) #define atmci_writel(port,reg,value) \ - __raw_writel((value), (port)->regs + ATMCI_##reg) + __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 c2a0949f325..87eeccc6d9a 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -499,7 +499,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]); - atmci_writel(host, DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc))); + atmci_writel(host, ATMCI_DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc))); } /* @@ -564,14 +564,14 @@ static void atmci_start_command(struct atmel_mci *host, "start command: ARGR=0x%08x CMDR=0x%08x\n", cmd->arg, cmd_flags); - atmci_writel(host, ARGR, cmd->arg); - atmci_writel(host, CMDR, cmd_flags); + atmci_writel(host, ATMCI_ARGR, cmd->arg); + atmci_writel(host, ATMCI_CMDR, cmd_flags); } static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) { atmci_start_command(host, data->stop, host->stop_cmdr); - atmci_writel(host, IER, ATMCI_CMDRDY); + atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); } #ifdef CONFIG_MMC_ATMELMCI_DMA @@ -596,7 +596,7 @@ static void atmci_stop_dma(struct atmel_mci *host) } else { /* Data transfer was stopped by the interrupt handler */ atmci_set_pending(host, EVENT_XFER_COMPLETE); - atmci_writel(host, IER, ATMCI_NOTBUSY); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } } @@ -610,7 +610,7 @@ static void atmci_dma_complete(void *arg) if (atmci_is_mci2()) /* Disable DMA hardware handshaking on MCI */ - atmci_writel(host, DMA, atmci_readl(host, DMA) & ~ATMCI_DMAEN); + atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN); atmci_dma_cleanup(host); @@ -642,7 +642,7 @@ static void atmci_dma_complete(void *arg) * completion callback" rule of the dma engine * framework. */ - atmci_writel(host, IER, ATMCI_NOTBUSY); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } } @@ -680,7 +680,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) return -ENODEV; if (atmci_is_mci2()) - atmci_writel(host, DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN); + atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN); if (data->flags & MMC_DATA_READ) direction = DMA_FROM_DEVICE; @@ -730,7 +730,7 @@ static void atmci_stop_dma(struct atmel_mci *host) { /* Data transfer was stopped by the interrupt handler */ atmci_set_pending(host, EVENT_XFER_COMPLETE); - atmci_writel(host, IER, ATMCI_NOTBUSY); + atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); } #endif /* CONFIG_MMC_ATMELMCI_DMA */ @@ -793,24 +793,24 @@ static void atmci_start_request(struct atmel_mci *host, host->data_status = 0; if (host->need_reset) { - atmci_writel(host, CR, ATMCI_CR_SWRST); - atmci_writel(host, CR, ATMCI_CR_MCIEN); - atmci_writel(host, MR, host->mode_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 (atmci_is_mci2()) - atmci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, ATMCI_CFG, host->cfg_reg); host->need_reset = false; } - atmci_writel(host, SDCR, slot->sdc_reg); + atmci_writel(host, ATMCI_SDCR, slot->sdc_reg); - iflags = atmci_readl(host, IMR); + 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) */ - atmci_writel(host, CMDR, ATMCI_CMDR_SPCMD_INIT); - while (!(atmci_readl(host, SR) & ATMCI_CMDRDY)) + atmci_writel(host, ATMCI_CMDR, ATMCI_CMDR_SPCMD_INIT); + while (!(atmci_readl(host, ATMCI_SR) & ATMCI_CMDRDY)) cpu_relax(); } iflags = 0; @@ -819,7 +819,7 @@ static void atmci_start_request(struct atmel_mci *host, atmci_set_timeout(host, slot, data); /* Must set block count/size before sending command */ - atmci_writel(host, BLKR, ATMCI_BCNT(data->blocks) + atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz)); dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n", ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz)); @@ -852,7 +852,7 @@ static void atmci_start_request(struct atmel_mci *host, * conditions (e.g. command and data complete, but stop not * prepared yet.) */ - atmci_writel(host, IER, iflags); + atmci_writel(host, ATMCI_IER, iflags); } static void atmci_queue_request(struct atmel_mci *host, @@ -927,10 +927,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); - atmci_writel(host, CR, ATMCI_CR_SWRST); - atmci_writel(host, CR, ATMCI_CR_MCIEN); + atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); + atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); if (atmci_is_mci2()) - atmci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, ATMCI_CFG, host->cfg_reg); } /* @@ -972,9 +972,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } if (list_empty(&host->queue)) { - atmci_writel(host, MR, host->mode_reg); + atmci_writel(host, ATMCI_MR, host->mode_reg); if (atmci_is_mci2()) - atmci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, ATMCI_CFG, host->cfg_reg); } else { host->need_clock_update = true; } @@ -992,9 +992,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } if (!any_slot_active) { - atmci_writel(host, CR, ATMCI_CR_MCIDIS); + atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); if (host->mode_reg) { - atmci_readl(host, MR); + atmci_readl(host, ATMCI_MR); clk_disable(host->mck); } host->mode_reg = 0; @@ -1058,9 +1058,9 @@ static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable) struct atmel_mci *host = slot->host; if (enable) - atmci_writel(host, IER, slot->sdio_irq); + atmci_writel(host, ATMCI_IER, slot->sdio_irq); else - atmci_writel(host, IDR, slot->sdio_irq); + atmci_writel(host, ATMCI_IDR, slot->sdio_irq); } static const struct mmc_host_ops atmci_ops = { @@ -1087,9 +1087,9 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) * busy transferring data. */ if (host->need_clock_update) { - atmci_writel(host, MR, host->mode_reg); + atmci_writel(host, ATMCI_MR, host->mode_reg); if (atmci_is_mci2()) - atmci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, ATMCI_CFG, host->cfg_reg); } host->cur_slot->mrq = NULL; @@ -1118,10 +1118,10 @@ 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] = atmci_readl(host, RSPR); - cmd->resp[1] = atmci_readl(host, RSPR); - cmd->resp[2] = atmci_readl(host, RSPR); - cmd->resp[3] = atmci_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 & ATMCI_RTOE) cmd->error = -ETIMEDOUT; @@ -1139,7 +1139,7 @@ static void atmci_command_complete(struct atmel_mci *host, if (cmd->data) { atmci_stop_dma(host); host->data = NULL; - atmci_writel(host, IDR, ATMCI_NOTBUSY + atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY | ATMCI_TXRDY | ATMCI_RXRDY | ATMCI_DATA_ERROR_FLAGS); } @@ -1192,11 +1192,11 @@ static void atmci_detect_change(unsigned long data) * Reset controller to terminate any ongoing * commands or data transfers. */ - atmci_writel(host, CR, ATMCI_CR_SWRST); - atmci_writel(host, CR, ATMCI_CR_MCIEN); - atmci_writel(host, MR, host->mode_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 (atmci_is_mci2()) - atmci_writel(host, CFG, host->cfg_reg); + atmci_writel(host, ATMCI_CFG, host->cfg_reg); host->data = NULL; host->cmd = NULL; @@ -1262,7 +1262,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, - atmci_readl(host, IMR)); + atmci_readl(host, ATMCI_IMR)); do { prev_state = state; @@ -1331,7 +1331,7 @@ static void atmci_tasklet_func(unsigned long priv) } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; - atmci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS); + atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS); } if (!data->stop) { @@ -1381,7 +1381,7 @@ static void atmci_read_data_pio(struct atmel_mci *host) unsigned int nbytes = 0; do { - value = atmci_readl(host, RDR); + value = atmci_readl(host, ATMCI_RDR); if (likely(offset + 4 <= sg->length)) { put_unaligned(value, (u32 *)(buf + offset)); @@ -1413,9 +1413,9 @@ static void atmci_read_data_pio(struct atmel_mci *host) nbytes += offset; } - status = atmci_readl(host, SR); + status = atmci_readl(host, ATMCI_SR); if (status & ATMCI_DATA_ERROR_FLAGS) { - atmci_writel(host, IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY + atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY | ATMCI_DATA_ERROR_FLAGS)); host->data_status = status; data->bytes_xfered += nbytes; @@ -1432,8 +1432,8 @@ static void atmci_read_data_pio(struct atmel_mci *host) return; done: - atmci_writel(host, IDR, ATMCI_RXRDY); - atmci_writel(host, IER, ATMCI_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); @@ -1452,7 +1452,7 @@ static void atmci_write_data_pio(struct atmel_mci *host) do { if (likely(offset + 4 <= sg->length)) { value = get_unaligned((u32 *)(buf + offset)); - atmci_writel(host, TDR, value); + atmci_writel(host, ATMCI_TDR, value); offset += 4; nbytes += 4; @@ -1473,20 +1473,20 @@ static void atmci_write_data_pio(struct atmel_mci *host) host->sg = sg = sg_next(sg); if (!sg) { - atmci_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); - atmci_writel(host, TDR, value); + atmci_writel(host, ATMCI_TDR, value); nbytes += offset; } - status = atmci_readl(host, SR); + status = atmci_readl(host, ATMCI_SR); if (status & ATMCI_DATA_ERROR_FLAGS) { - atmci_writel(host, IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY + atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY | ATMCI_DATA_ERROR_FLAGS)); host->data_status = status; data->bytes_xfered += nbytes; @@ -1503,8 +1503,8 @@ static void atmci_write_data_pio(struct atmel_mci *host) return; done: - atmci_writel(host, IDR, ATMCI_TXRDY); - atmci_writel(host, IER, ATMCI_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); @@ -1512,7 +1512,7 @@ done: static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status) { - atmci_writel(host, IDR, ATMCI_CMDRDY); + atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY); host->cmd_status = status; smp_wmb(); @@ -1540,16 +1540,16 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) unsigned int pass_count = 0; do { - status = atmci_readl(host, SR); - mask = atmci_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) { - atmci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS + atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS | ATMCI_RXRDY | ATMCI_TXRDY); - pending &= atmci_readl(host, IMR); + pending &= atmci_readl(host, ATMCI_IMR); host->data_status = status; smp_wmb(); @@ -1557,7 +1557,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) tasklet_schedule(&host->tasklet); } if (pending & ATMCI_NOTBUSY) { - atmci_writel(host, IDR, + atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY); if (!host->data_status) host->data_status = status; @@ -1790,7 +1790,7 @@ static int __init atmci_probe(struct platform_device *pdev) goto err_ioremap; clk_enable(host->mck); - atmci_writel(host, CR, ATMCI_CR_SWRST); + atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); host->bus_hz = clk_get_rate(host->mck); clk_disable(host->mck); @@ -1861,9 +1861,9 @@ static int __exit atmci_remove(struct platform_device *pdev) } clk_enable(host->mck); - atmci_writel(host, IDR, ~0UL); - atmci_writel(host, CR, ATMCI_CR_MCIDIS); - atmci_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 -- cgit v1.2.3-18-g5258 From b9867f371c5e1197f2109daf64168e3af41df8a5 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 11 Aug 2011 15:25:43 +0000 Subject: mmc: atmel-mci: indentation Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci-regs.h | 136 +++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index 8574e910d1f..7310b207a44 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -18,103 +18,103 @@ /* MCI Register Definitions */ #define ATMCI_CR 0x0000 /* Control */ -# define ATMCI_CR_MCIEN ( 1 << 0) /* MCI Enable */ +# 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_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_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_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_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_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_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_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_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_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_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_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_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_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_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ -# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ -# 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_OVRE ( 1 << 30) /* RX Overrun Error */ -# define ATMCI_UNRE ( 1 << 31) /* TX Underrun Error */ +# 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_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ +# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ +# 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_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_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_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_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ +#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_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ /* This is not including the FIFO Aperture on MCI2 */ #define ATMCI_REGS_SIZE 0x100 -- cgit v1.2.3-18-g5258 From 796211b7953bd1036670359f31cd97f309322107 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 11 Aug 2011 15:25:44 +0000 Subject: mmc: atmel-mci: add pdc support and runtime capabilities detection Add pdc support for atmel-mci. It makes at91-mci driver useless because it was only used for the old atmel MCI core which has pdc but no dma support. To allow removing at91-mci, the capabilities of the MCI core are detected at runtime -- then the driver will use pio, pdc or dma transfers. Warning: at91rm9200 is not supported, to support it we need to use swab32 on data but I have no board to test it. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci-regs.h | 14 + drivers/mmc/host/atmel-mci.c | 527 +++++++++++++++++++++++++++++--------- 2 files changed, 423 insertions(+), 118 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index 7310b207a44..000b3ad0f5c 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -88,8 +88,14 @@ # 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 */ @@ -97,6 +103,13 @@ # 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] */ @@ -114,6 +127,7 @@ #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 */ diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 87eeccc6d9a..57596782061 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -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; @@ -167,6 +194,12 @@ struct atmel_mci { struct platform_device *pdev; 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); }; /** @@ -219,31 +252,6 @@ struct atmel_mci_slot { #define atmci_set_pending(host, event) \ set_bit(event, &host->pending_events) -/* - * Enable or disable features/registers based on - * whether the processor supports them - */ -static bool atmci_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. @@ -379,7 +387,7 @@ static int atmci_regs_show(struct seq_file *s, void *v) buf[ATMCI_BLKR / 4], buf[ATMCI_BLKR / 4] & 0xffff, (buf[ATMCI_BLKR / 4] >> 16) & 0xffff); - if (atmci_is_mci2()) + 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 */ @@ -387,7 +395,7 @@ static int atmci_regs_show(struct seq_file *s, void *v) 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[ATMCI_DMA / 4]; @@ -396,6 +404,9 @@ static int atmci_regs_show(struct seq_file *s, void *v) ((val >> 4) & 3) ? 1 << (((val >> 4) & 3) + 1) : 1, val & ATMCI_DMAEN ? " DMAEN" : ""); + } + if (host->caps.has_cfg_reg) { + u32 val; val = buf[ATMCI_CFG / 4]; seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n", @@ -574,33 +585,109 @@ static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) 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) { - struct mmc_data *data = host->data; + 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 += 0x10; + counter_reg += 0x10; + } + + atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); + if (host->data_size <= PAGE_SIZE) { + 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, PAGE_SIZE / 4); + host->data_size -= PAGE_SIZE; + 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) +{ + 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); + 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; @@ -608,7 +695,7 @@ 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 */ atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN); @@ -646,7 +733,90 @@ static void atmci_dma_complete(void *arg) } } -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); + BUG_ON(sg_len < host->data_size / PAGE_SIZE); + 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; @@ -655,20 +825,29 @@ 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 * non-word-aligned buffers or lengths. Also, we don't bother * with all the DMA setup overhead for short transfers. */ - if (data->blocks * data->blksz < ATATMCI_DMA_THRESHOLD) - return -EINVAL; + if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD) + 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 */ @@ -679,7 +858,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) if (!chan) return -ENODEV; - if (atmci_is_mci2()) + if (host->caps.has_dma) atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN); if (data->flags & MMC_DATA_READ) @@ -688,7 +867,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, @@ -700,13 +879,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; @@ -717,64 +915,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) +static void atmci_stop_transfer(struct atmel_mci *host) { - return -ENOSYS; -} - -static void atmci_submit_data(struct atmel_mci *host) {} - -static void atmci_stop_dma(struct atmel_mci *host) -{ - /* Data transfer was stopped by the interrupt handler */ atmci_set_pending(host, EVENT_XFER_COMPLETE); 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 |= ATMCI_RXRDY; - else - iflags |= ATMCI_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) { @@ -796,7 +969,7 @@ static void atmci_start_request(struct atmel_mci *host, 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 (atmci_is_mci2()) + if (host->caps.has_cfg_reg) atmci_writel(host, ATMCI_CFG, host->cfg_reg); host->need_reset = false; } @@ -824,7 +997,7 @@ static void atmci_start_request(struct atmel_mci *host, dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n", ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz)); - iflags |= atmci_prepare_data(host, data); + iflags |= host->prepare_data(host, data); } iflags |= ATMCI_CMDRDY; @@ -833,7 +1006,7 @@ static void atmci_start_request(struct atmel_mci *host, atmci_start_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); @@ -929,7 +1102,7 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) clk_enable(host->mck); atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); - if (atmci_is_mci2()) + if (host->caps.has_cfg_reg) atmci_writel(host, ATMCI_CFG, host->cfg_reg); } @@ -960,10 +1133,10 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) * stopping the clock when the FIFO is full/empty. * This state is not expected to last for long. */ - if (atmci_has_rwproof()) + 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 |= ATMCI_CFG_HSMODE; @@ -973,7 +1146,7 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (list_empty(&host->queue)) { atmci_writel(host, ATMCI_MR, host->mode_reg); - if (atmci_is_mci2()) + if (host->caps.has_cfg_reg) atmci_writel(host, ATMCI_CFG, host->cfg_reg); } else { host->need_clock_update = true; @@ -1088,7 +1261,7 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) */ if (host->need_clock_update) { atmci_writel(host, ATMCI_MR, host->mode_reg); - if (atmci_is_mci2()) + if (host->caps.has_cfg_reg) atmci_writel(host, ATMCI_CFG, host->cfg_reg); } @@ -1137,7 +1310,7 @@ 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; atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY | ATMCI_TXRDY | ATMCI_RXRDY @@ -1195,7 +1368,7 @@ static void atmci_detect_change(unsigned long data) 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 (atmci_is_mci2()) + if (host->caps.has_cfg_reg) atmci_writel(host, ATMCI_CFG, host->cfg_reg); host->data = NULL; @@ -1211,7 +1384,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: @@ -1290,7 +1463,7 @@ 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) atmci_send_stop_cmd(host, data); state = STATE_DATA_ERROR; @@ -1556,6 +1729,56 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) atmci_set_pending(host, EVENT_DATA_ERROR); tasklet_schedule(&host->tasklet); } + + 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_TXBUFE) { + atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE); + /* + * 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_TXBUFE); + } else { + atmci_pdc_complete(host); + } + } + + 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_RXBUFF) { + atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF); + /* + * 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_RXBUFF); + } else { + atmci_pdc_complete(host); + } + } + if (pending & ATMCI_NOTBUSY) { atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY); @@ -1622,7 +1845,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; @@ -1705,7 +1928,6 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot, mmc_free_host(slot->mmc); } -#ifdef CONFIG_MMC_ATMELMCI_DMA static bool atmci_filter(struct dma_chan *chan, void *slave) { struct mci_dma_data *sl = slave; @@ -1747,9 +1969,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) { @@ -1802,7 +2075,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); @@ -1834,10 +2127,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); -- cgit v1.2.3-18-g5258 From 11d1488b01b803254842b756ff7662085b37970e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 11 Aug 2011 15:25:45 +0000 Subject: mmc: atmel-mci: change atmci_start_command to atmci_send_command Rename atmci_start_command() to atmci_send_command() which is more appropriate; atmci_start_command suggests we're sending a start command. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 57596782061..caae967dcaf 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -565,7 +565,7 @@ static u32 atmci_prepare_command(struct mmc_host *mmc, 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); @@ -581,7 +581,7 @@ static void atmci_start_command(struct atmel_mci *host, static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) { - atmci_start_command(host, data->stop, host->stop_cmdr); + atmci_send_command(host, data->stop, host->stop_cmdr); atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY); } @@ -1003,7 +1003,7 @@ static void atmci_start_request(struct atmel_mci *host, 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) host->submit_data(host, data); -- cgit v1.2.3-18-g5258 From 1ebbe3d31fd96865b4d4874f3c74fef0e386fb79 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 11 Aug 2011 15:25:46 +0000 Subject: mmc: atmel-mci: use ATMEL_PDC_SCND_BUF_OFF instead of a literal value Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index caae967dcaf..c0a0659261a 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -603,8 +603,8 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host, } if (buf_nb == PDC_SECOND_BUF) { - pointer_reg += 0x10; - counter_reg += 0x10; + pointer_reg += ATMEL_PDC_SCND_BUF_OFF; + counter_reg += ATMEL_PDC_SCND_BUF_OFF; } atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); -- cgit v1.2.3-18-g5258 From 341fa4c3affe1171005597847a86e4c26dea8bb1 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 11 Aug 2011 15:25:47 +0000 Subject: mmc: atmel-mci: correct sg buffer size evaluation Assuming that a sg buffer size is a page size is false so use sg_dma_len. A 4096 bytes can be required with two 2048-bytes sg buffer. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index c0a0659261a..96004c9fe3a 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -608,7 +608,7 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host, } atmci_writel(host, pointer_reg, sg_dma_address(host->sg)); - if (host->data_size <= PAGE_SIZE) { + 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); @@ -620,8 +620,8 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host, host->data_size = 0; } else { /* We assume the size of a page is 32-bits aligned */ - atmci_writel(host, counter_reg, PAGE_SIZE / 4); - host->data_size -= PAGE_SIZE; + 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); } @@ -808,7 +808,6 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data) /* Configure PDC */ host->data_size = data->blocks * data->blksz; sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir); - BUG_ON(sg_len < host->data_size / PAGE_SIZE); if (host->data_size) atmci_pdc_set_both_buf(host, ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT)); -- cgit v1.2.3-18-g5258 From 7e8ba228d9f43a4e4b3ed0e6aa3399e8f30d7bc1 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 11 Aug 2011 15:25:48 +0000 Subject: mmc: atmel-mci: fix a potential issue about pending PDC interrupts This patch fixes a potential issue about PDC interrupts. For example we have a ENDRX pending interrupt and a RXBUFF pending interrupt. We have received the RXBUFF interrupt but the transfer is not finished (so we didn't have time to give a new buffer to the PDC controller). Then we will compute ENDRX interrupt and we will give a new buffer to the PDC controller, just after we will compute the RXBUFF interrupt and give one or two new buffers to the PDC controller but we are not sure that the first buffer given has been filled. So in this situation we may have "lost" one sg buffer. It's the same for transmission. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 96004c9fe3a..a7ee5027146 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1729,17 +1729,9 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) tasklet_schedule(&host->tasklet); } - 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_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 @@ -1747,24 +1739,24 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) */ 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); } - } - - if (pending & ATMCI_ENDRX) { - atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX); + } else if (pending & ATMCI_ENDTX) { + atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX); if (host->data_size) { atmci_pdc_set_single_buf(host, - XFER_RECEIVE, PDC_SECOND_BUF); - atmci_writel(host, ATMCI_IER, ATMCI_ENDRX); + 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 @@ -1772,12 +1764,22 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id) */ 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); -- cgit v1.2.3-18-g5258 From 51c5d8d1499b8442e863fe756f76e7f4ea7476fb Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 4 Aug 2011 16:49:03 +0100 Subject: mmc: at91_mci: remove the use of irq_to_gpio Remove the use of irq_to_gpio() in the card detection interrupt handler. The information is available in the board structure and we can avoid using a function that has little meaning. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Chris Ball --- drivers/mmc/host/at91_mci.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index a4aa3af86fe..a8b4d2aa18e 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, -- cgit v1.2.3-18-g5258 From 97e4ba6a5ea903a221d87bcabdaf01efb0a609a5 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 11 Aug 2011 16:51:46 -0400 Subject: mmc: sdhci-esdhc-imx: Enable ADMA2 Eanble the ADMA2 mode for freescale esdhc imx driver, tested on MX25 3DS board, MX51 BBG board and MX53 LOCO board. This patch is only used to enable the ADMA2 for MX51/53 platforms. MX25/35 can't support the ADMA2 mode, set BROKEN_ADMA quirk on MX25/35 platforms. The ADMA mode supported or not can be distinguished by bit 20 of the Capability Register (offset 0x40) in the FSL eSDHC module. Signed-off-by: Richard Zhu Tested-and-acked-by: Eric Miao Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-esdhc-imx.c | 44 +++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 4dc0028086a..4557aa1567a 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -33,6 +33,14 @@ #define SDHCI_VENDOR_SPEC 0xC0 #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 +/* + * 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 * "11" when the STOP CMD12 is issued on imx53 to abort one @@ -135,6 +143,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,6 +208,13 @@ 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); } @@ -311,9 +347,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,7 +442,8 @@ 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; -- cgit v1.2.3-18-g5258 From 1b676f70c108cda90cf9d114d16c677584400efc Mon Sep 17 00:00:00 2001 From: Per Forlin Date: Fri, 19 Aug 2011 14:52:37 +0200 Subject: mmc: core: add random fault injection This adds support to inject data errors after a completed host transfer. The mmc core will return error even though the host transfer is successful. This simple fault injection proved to be very useful to test the non-blocking error handling in the mmc_blk_issue_rw_rq(). Random faults can also test how the host driver handles pre_req() and post_req() in case of errors. Signed-off-by: Per Forlin Acked-by: Akinobu Mita Reviewed-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 41 +++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/debugfs.c | 25 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index b27b94078c2..eb3069dfea8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -83,6 +85,43 @@ static void mmc_flush_scheduled_work(void) flush_workqueue(workqueue); } +#ifdef CONFIG_FAIL_MMC_REQUEST + +/* + * Internal function. Inject random data errors. + * If mmc_data is NULL no errors are injected. + */ +static void mmc_should_fail_request(struct mmc_host *host, + struct mmc_request *mrq) +{ + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + static const int data_errors[] = { + -ETIMEDOUT, + -EILSEQ, + -EIO, + }; + + if (!data) + return; + + if (cmd->error || data->error || + !should_fail(&host->fail_mmc_request, data->blksz * data->blocks)) + return; + + data->error = data_errors[random32() % ARRAY_SIZE(data_errors)]; + data->bytes_xfered = (random32() % (data->bytes_xfered >> 9)) << 9; +} + +#else /* CONFIG_FAIL_MMC_REQUEST */ + +static inline void mmc_should_fail_request(struct mmc_host *host, + struct mmc_request *mrq) +{ +} + +#endif /* CONFIG_FAIL_MMC_REQUEST */ + /** * mmc_request_done - finish processing an MMC request * @host: MMC host which completed request @@ -109,6 +148,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) cmd->error = 0; host->ops->request(host, mrq); } else { + mmc_should_fail_request(host, mrq); + led_trigger_event(host->led, LED_OFF); pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 998797ed67a..5acd707699c 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -158,6 +159,23 @@ static int mmc_clock_opt_set(void *data, u64 val) return 0; } +#ifdef CONFIG_FAIL_MMC_REQUEST + +static DECLARE_FAULT_ATTR(fail_mmc_request); + +#ifdef KERNEL +/* + * Internal function. Pass the boot param fail_mmc_request to + * the setup fault injection attributes routine. + */ +static int __init setup_fail_mmc_request(char *str) +{ + return setup_fault_attr(&fail_mmc_request, str); +} +__setup("fail_mmc_request=", setup_fail_mmc_request); +#endif /* KERNEL */ +#endif /* CONFIG_FAIL_MMC_REQUEST */ + DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set, "%llu\n"); @@ -187,6 +205,13 @@ void mmc_add_host_debugfs(struct mmc_host *host) if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), root, &host->clk_delay)) goto err_node; +#endif +#ifdef CONFIG_FAIL_MMC_REQUEST + host->fail_mmc_request = fail_mmc_request; + if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request", + root, + &host->fail_mmc_request))) + goto err_node; #endif return; -- cgit v1.2.3-18-g5258 From 08da834a24312157f512224691ad1fddd11c1073 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 20 Jul 2011 17:39:22 +0100 Subject: mmc: enable runtime PM by default Now that we have improved the runtime power management powerup/powerdown code, we believe that MMC_CAP_POWER_OFF_CARD is no longer necessary: runtime PM should now work everywhere. The only hard evidence for introducing MMC_CAP_POWER_OFF_CARD was the Marvell sd8686 wifi chip, which was believed to require external gpio manipulation which wasn't supported by some boards. After further investigation it was realized (and confirmed by Marvell folks) that sd8686 requirements can be fulfilled by changing the reset sequence itself, even if no external gpio is manipulated. For further information, see the following thread: http://www.mail-archive.com/linux-mmc@vger.kernel.org/msg04289.html Enable this trivially for a release or two. If no problems are reported, we will follow up with a more extensive patch to remove this flag altogether. If problems are reported, we can look at whitelist/blacklist possibilities as before. Signed-off-by: Daniel Drake Acked-by: Ohad Ben-Cohen Signed-off-by: Chris Ball --- drivers/mmc/core/host.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 793d0a0dad8..ca2e4f50f61 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -301,6 +301,17 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->max_blk_size = 512; host->max_blk_count = PAGE_CACHE_SIZE / 512; + /* + * Enable runtime power management by default. This flag was added due + * to runtime power management causing disruption for some users, but + * the power on/off code has been improved since then. + * + * We'll enable this flag by default as an experiment, and if no + * problems are reported, we will follow up later and remove the flag + * altogether. + */ + host->caps = MMC_CAP_POWER_OFF_CARD; + return host; free: -- cgit v1.2.3-18-g5258 From 275173b225ae663e54d8dc5c93d79265aad19f89 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 23 Aug 2011 12:15:33 -0600 Subject: mmc: sdhci-tegra: Add Device Tree probing support Add hooks to read gpio configuration out of the device tree node. [grant.likely: Rewrite of original patch from John Bonesio] Signed-off-by: Grant Likely [swarren: Fixed tegra_sdhci_get_ro() to retrieve pdata correctly] [swarren: Reworked to avoid #ifdef CONFIG_OF] [swarren: Reworked binding based on fsl-imx-esdhc.txt] [swarren: Documented binding] Signed-off-by: Stephen Warren Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-tegra.c | 51 +++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 18b0bd31de7..8a114b6211c 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -73,10 +74,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 +93,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 +128,34 @@ 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); + + return plat; +} + static int __devinit sdhci_tegra_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; @@ -147,12 +172,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 +277,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 +310,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), -- cgit v1.2.3-18-g5258 From 2b795518bd7bcd1990b8f8b7225c9bb8eb5a30c1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 24 Aug 2011 08:41:08 +0200 Subject: mmc: Kconfig: remove i.MX individual SoC dependency The individual SoC dependency in Kconfig hardly scales anymore. Instead of having such a fine grained dependency just depend on ARCH_MXC and risk that the uninformed user has to look in the help text to figure out which driver is the correct one. Signed-off-by: Sascha Hauer Signed-off-by: Chris Ball --- drivers/mmc/host/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 8c87096531e..c226d549fd2 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -131,12 +131,12 @@ config MMC_SDHCI_CNS3XXX config MMC_SDHCI_ESDHC_IMX tristate "SDHCI platform support for the Freescale eSDHC i.MX controller" - depends on ARCH_MX25 || ARCH_MX35 || ARCH_MX5 + 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. + bus, found on i.MX25, i.MX35 and i.MX5x. If you have a controller with this interface, 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. -- cgit v1.2.3-18-g5258 From 7513cd7af8df412d05349c5e44dc7638974211d8 Mon Sep 17 00:00:00 2001 From: Venkatraman S Date: Tue, 23 Aug 2011 21:16:02 +0530 Subject: mmc: queue: declare mmc_alloc_sg as static Fix the sparse warning "drivers/mmc/card/queue.c:111:20: warning: symbol 'mmc_alloc_sg' was not declared. Should it be static?" Signed-off-by: Venkatraman S Signed-off-by: Chris Ball --- drivers/mmc/card/queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 45fb362e3f0..5196312bb55 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -108,7 +108,7 @@ static void mmc_request(struct request_queue *q) wake_up_process(mq->thread); } -struct scatterlist *mmc_alloc_sg(int sg_len, int *err) +static struct scatterlist *mmc_alloc_sg(int sg_len, int *err) { struct scatterlist *sg; -- cgit v1.2.3-18-g5258 From ad5fd97288655b5628052c1fa906419417c86100 Mon Sep 17 00:00:00 2001 From: Venkatraman S Date: Thu, 25 Aug 2011 00:30:50 +0530 Subject: mmc: fix integer assignments to pointer Fix the sparse warning output "warning: Using plain integer as NULL pointer" Signed-off-by: Venkatraman S Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 4 ++-- drivers/mmc/core/core.c | 2 +- drivers/mmc/core/mmc_ops.c | 4 ++-- drivers/mmc/core/sd_ops.c | 8 ++++---- drivers/mmc/core/sdio_ops.c | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 4c1a648d00f..9b907263668 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -291,7 +291,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, struct mmc_card *card; struct mmc_command cmd = {0}; struct mmc_data data = {0}; - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; struct scatterlist sg; int err; @@ -466,7 +466,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) u32 result; __be32 *blocks; - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; unsigned int timeout_us; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index eb3069dfea8..557856b6f95 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -371,7 +371,7 @@ EXPORT_SYMBOL(mmc_wait_for_req); */ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) { - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; WARN_ON(!host->claimed); diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 770c3d06f5d..7aa13d01a83 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -233,7 +233,7 @@ static int mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, u32 opcode, void *buf, unsigned len) { - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; @@ -454,7 +454,7 @@ static int mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, u8 len) { - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 021fed15380..46a785419fa 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -67,7 +67,7 @@ EXPORT_SYMBOL_GPL(mmc_app_cmd); int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, struct mmc_command *cmd, int retries) { - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; int i, err; @@ -244,7 +244,7 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) int mmc_app_send_scr(struct mmc_card *card, u32 *scr) { int err; - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; @@ -303,7 +303,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) int mmc_sd_switch(struct mmc_card *card, int mode, int group, u8 value, u8 *resp) { - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; @@ -348,7 +348,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, int mmc_app_sd_status(struct mmc_card *card, void *ssr) { int err; - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index f087d876c57..4addbe987bc 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -121,7 +121,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) { - struct mmc_request mrq = {0}; + struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg; -- cgit v1.2.3-18-g5258 From 54680fe7f6ad0fb0c52e330484e2cf1609587862 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 25 Aug 2011 10:27:25 +0900 Subject: mmc: tmio: Cache interrupt masks This avoids the need to look up the masks each time an interrupt is handled. As suggested by Guennadi. Cc: Guennadi Liakhovetski Acked-by: Magnus Damm Signed-off-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.h | 4 ++++ drivers/mmc/host/tmio_mmc_pio.c | 34 ++++++++++++++++++---------------- 2 files changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index eeaf64391fb..1cf8db558d0 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 */ diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 1f16357e730..f0c7830b830 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) @@ -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; } @@ -548,26 +550,25 @@ irqreturn_t tmio_mmc_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, irq_mask, status; - unsigned int sdio_ireg, sdio_irq_mask, sdio_status; + unsigned int ireg, status; + unsigned int sdio_ireg, 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; + ireg = status & TMIO_MASK_IRQ & ~host->sdcard_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; + sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & + ~host->sdio_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); + sdio_status, host->sdio_irq_mask, sdio_ireg); tmio_mmc_enable_sdio_irq(mmc, 0); goto out; } @@ -623,9 +624,9 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid) } pr_warning("tmio_mmc: Spurious irq, disabling! " - "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); + "0x%08x 0x%08x 0x%08x\n", status, host->sdcard_irq_mask, ireg); pr_debug_status(status); - tmio_mmc_disable_mmc_irqs(host, status & ~irq_mask); + tmio_mmc_disable_mmc_irqs(host, status & ~host->sdcard_irq_mask); out: return IRQ_HANDLED; @@ -882,6 +883,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); -- cgit v1.2.3-18-g5258 From 7729c7a232a95360fa17ffe8beb1adb621bc0ba0 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 25 Aug 2011 10:27:26 +0900 Subject: mmc: tmio: Provide separate interrupt handlers Provide separate interrupt handlers which may be used by platforms where SDHI has three interrupt sources. This patch also removes the commented-out handling of CRC and other errors. Cc: Guennadi Liakhovetski Acked-by: Magnus Damm Signed-off-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.h | 3 + drivers/mmc/host/tmio_mmc_pio.c | 131 +++++++++++++++++++++++++--------------- 2 files changed, 86 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 1cf8db558d0..3020f98218f 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -97,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 f0c7830b830..6275e3d76d3 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -545,44 +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, status; - unsigned int sdio_ireg, sdio_status; - - pr_debug("MMC IRQ begin\n"); - - status = sd_ctrl_read32(host, CTL_STATUS); - ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; + *status = sd_ctrl_read32(host, CTL_STATUS); + *ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; - sdio_ireg = 0; - if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { - sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); - sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & - ~host->sdio_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, host->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)) { @@ -592,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, host->sdcard_irq_mask, ireg); - pr_debug_status(status); - tmio_mmc_disable_mmc_irqs(host, status & ~host->sdcard_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); -- cgit v1.2.3-18-g5258 From d5098cb63b3f13da2a2b230b3566ac7b5dfa4f28 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 26 Aug 2011 10:42:39 +0200 Subject: mmc: sdhi: Allow named IRQs to use specific handlers Allow named IRQs to use corresponding specific handlers. If named IRQs are used, at least an "sdcard" IRQ has to be specified by the platform. If names are not used, an arbitrary number of IRQs can be provided by the platform, in which case the generic ISR will be used for each of them. Cc: Guennadi Liakhovetski Acked-by: Magnus Damm Signed-off-by: Simon Horman [g.liakhovetski@gmx.de: style and typo corrections, platform data check] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mobile_sdhi.c | 98 +++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 0c4a672f5db..75bffc4768f 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -96,7 +96,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 +154,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 +215,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 +244,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); -- cgit v1.2.3-18-g5258 From 435f3e385962e2b34855e9b34f8b95717c1016a2 Mon Sep 17 00:00:00 2001 From: Alexander Tarasikov Date: Sun, 21 Aug 2011 15:52:43 +0400 Subject: mmc: msm_sdcc: Fix a typo in MSM SDCC driver gpio setup The use of && instead of || caused a NULL pointer dereference if gpio setup was not passed via platform data Signed-off-by: Alexander Tarasikov Acked-by: Sahitya Tummala Signed-off-by: David Brown Signed-off-by: Chris Ball --- drivers/mmc/host/msm_sdcc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index a4c865a5286..d06539dff7c 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -939,7 +939,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; -- cgit v1.2.3-18-g5258 From e91957e70d2aea529ff2055b8fbd575f2d7b8c3b Mon Sep 17 00:00:00 2001 From: Alexander Tarasikov Date: Sun, 21 Aug 2011 15:52:44 +0400 Subject: msm: Implement init_card operation for MSM SDCC This allows boards with non-standard sdio cards to fill the CIS/CCCR data. It is particularly important for old msm72k boards using wl1251. Also drop the obsolete embedded_sdio_data structure from the header as it was intended to surve a similiar purpose but was not implemented. Signed-off-by: Alexander Tarasikov Acked-by: Sahitya Tummala [davidb: minor formatting cleanup] Signed-off-by: David Brown Signed-off-by: Chris Ball --- drivers/mmc/host/msm_sdcc.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index d06539dff7c..cfe0c893ef0 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1052,10 +1052,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 -- cgit v1.2.3-18-g5258 From dce7c756c84160424b3aea5ec36f221946bdc6f7 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Mon, 2 May 2011 18:06:05 +0530 Subject: mmc: msm_sdcc: Handle error cases in probe Signed-off-by: Sahitya Tummala Signed-off-by: David Brown Signed-off-by: Chris Ball --- drivers/mmc/host/msm_sdcc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index cfe0c893ef0..0f0b4fdb62a 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1215,7 +1215,7 @@ msmsdcc_probe(struct platform_device *pdev) host->base = ioremap(memres->start, PAGE_SIZE); if (!host->base) { ret = -ENOMEM; - goto out; + goto host_free; } host->cmd_irqres = cmd_irqres; @@ -1230,13 +1230,15 @@ msmsdcc_probe(struct platform_device *pdev) /* * Setup DMA */ - msmsdcc_init_dma(host); + ret = msmsdcc_init_dma(host); + if (ret) + goto ioremap_free; /* 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"); @@ -1377,6 +1379,12 @@ msmsdcc_probe(struct platform_device *pdev) clk_put(host->clk); pclk_put: clk_put(host->pclk); +dma_free: + 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: -- cgit v1.2.3-18-g5258 From 514d9eda92654430369060b91f7472bb198e7904 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Mon, 2 May 2011 18:07:01 +0530 Subject: mmc: msm_sdcc: Enable SDC host->clk only after setting the rate. For clocks that support rates which can be set (most clocks other than _pclk AHB clocks), a rate must be set using clk_set_rate() before the clock is enabled for the first time with clk_enable(). Subsequent calls to clk_enable() need not be preceded with the clk_set_rate() calls unless we wish to change the clock rate that is set previously. SDC host->clk is currently enabled without setting the clock rate even once. This patch fixes this, by ensuring that the clock rate for this clock is first set before enabling the clock. Signed-off-by: Murali Palnati Signed-off-by: Sahitya Tummala Signed-off-by: David Brown Signed-off-by: Chris Ball --- drivers/mmc/host/msm_sdcc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 0f0b4fdb62a..de00001a534 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1247,17 +1247,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); -- cgit v1.2.3-18-g5258 From 4a92fe80becbbee650cfad8457ad0e5cd97ed974 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Mon, 2 May 2011 18:07:43 +0530 Subject: msm: mmc: Remove "pio_irq" resource On some targets, MCI_IRQ_MASK1 is not routed to the MSM in which case only "cmd_irq" must be used even for PIO. With this change, all the targets will use only "cmd_irq" for both CMD and PIO. Signed-off-by: Sahitya Tummala Signed-off-by: David Brown Signed-off-by: Chris Ball --- drivers/mmc/host/msm_sdcc.c | 8 ++------ drivers/mmc/host/msm_sdcc.h | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index de00001a534..1f1eff9bda5 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1159,7 +1159,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; @@ -1184,12 +1183,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; } @@ -1219,7 +1216,6 @@ msmsdcc_probe(struct platform_device *pdev) } host->cmd_irqres = cmd_irqres; - host->pio_irqres = pio_irqres; host->memres = memres; host->dmares = dmares; spin_lock_init(&host->lock); @@ -1336,7 +1332,7 @@ msmsdcc_probe(struct platform_device *pdev) 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; diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 42d7bbc977c..fa626ed915a 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h @@ -202,7 +202,6 @@ struct msmsdcc_stats { struct msmsdcc_host { struct resource *cmd_irqres; - struct resource *pio_irqres; struct resource *memres; struct resource *dmares; void __iomem *base; -- cgit v1.2.3-18-g5258 From 4a268e0879c4044523757b6ac94b56fc7955a116 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Mon, 2 May 2011 18:09:18 +0530 Subject: mmc: msm_sdcc: Use MCI_INT_MASK0 for PIO interrupts Not all targets have IRQ1 line routed from the SD controller to the processor. So we cannot rely on IRQ1 for PIO interrupts. This patch moves all PIO interrupts to IRQ0 and enables the PIO mode. Signed-off-by: Murali Palnati Signed-off-by: Sahitya Tummala Signed-off-by: David Brown Signed-off-by: Chris Ball --- drivers/mmc/host/msm_sdcc.c | 20 ++++++++++++++++---- drivers/mmc/host/msm_sdcc.h | 5 +++++ 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 1f1eff9bda5..c405e93335e 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) { @@ -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) diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index fa626ed915a..402028d16b8 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. */ -- cgit v1.2.3-18-g5258 From 19207f056d6dd390f96749e643a222d48517f7b1 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Mon, 2 May 2011 18:10:01 +0530 Subject: mmc: msm_sdcc: Change initialization order of busclk_timer in probe Intialize busclk_timer before it is accessed in probe. Signed-off-by: Sahitya Tummala Signed-off-by: David Brown Signed-off-by: Chris Ball --- drivers/mmc/host/msm_sdcc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index c405e93335e..a835ac0269e 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1218,6 +1218,10 @@ 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; @@ -1335,10 +1339,6 @@ 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) -- cgit v1.2.3-18-g5258 From 190657c9f464b9f99a05a6ed8476c8bbccbc6a8b Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Mon, 2 May 2011 18:10:40 +0530 Subject: mmc: msm_sdcc: Handle dma resource not present case If DMA resource is not available then SDCC driver should atleast work in PIO data transfer mode. Signed-off-by: Subhash Jadavani Signed-off-by: Sahitya Tummala Signed-off-by: David Brown Signed-off-by: Chris Ball --- drivers/mmc/host/msm_sdcc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index a835ac0269e..61c7d385fd3 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1242,9 +1242,13 @@ msmsdcc_probe(struct platform_device *pdev) /* * Setup DMA */ - ret = msmsdcc_init_dma(host); - if (ret) - goto ioremap_free; + 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"); @@ -1388,8 +1392,9 @@ msmsdcc_probe(struct platform_device *pdev) pclk_put: clk_put(host->pclk); dma_free: - dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata), - host->dma.nc, host->dma.nc_busaddr); + 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); -- cgit v1.2.3-18-g5258 From 1a5c8e1f4f09e67118f81885a22ceb7bbd2df4ee Mon Sep 17 00:00:00 2001 From: Shashidhar Hiremath Date: Mon, 29 Aug 2011 13:11:46 +0530 Subject: mmc: dw_mmc: Support SDIO interrupts for all slots The Patch adds the support for SDIO interrupts for all slots. It includes enabling of SDIO interrupts through dw_mci_enable_sdio_irq and the handling of the slot specific interrupts in the Interrupt Service Routine. Signed-off-by: Shashidhar Hiremath Acked-by: James Hogan Signed-off-by: Chris Ball --- drivers/mmc/host/dw_mmc.c | 36 ++++++++++++++++++++++++++++++++---- drivers/mmc/host/dw_mmc.h | 2 +- 2 files changed, 33 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index ff0f714b012..0ed1d28922f 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) @@ -1406,6 +1424,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 +1496,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 diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 027d3773539..bfa3c1cd05a 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -82,7 +82,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) -- cgit v1.2.3-18-g5258 From 55cd65e48b62c6f08edbb93d5cadf96e876ebcc2 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 30 Aug 2011 13:17:16 -0600 Subject: mmc: sdhci-tegra: Add 8-bit support to device tree binding. The previous patch which implemented a DT binding for sdhci-tegra did not allow all platform data fields to be initialized from DT. The following were missing: is_8bit: Implemented by this patch. pm_flags: Not implemented yet. There are no mainline users of this field. I'm not quite sure what it's for, and hence how to represent this in DT; the value ends up being assigned to host->mmc->pm_caps. While we're at it, fix the binding documentation to refer to "SD/MMC" instead of "eSDHC", since that's the correct name; "eSDHC" was cut/paste from the Freescale binding docs. Signed-off-by: Stephen Warren Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-tegra.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 8a114b6211c..d105b52bfec 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -152,6 +153,8 @@ static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata( 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; } -- cgit v1.2.3-18-g5258 From 041beb1d531f538bf62377e2ca2b4ecbaa479d75 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 7 Sep 2011 10:22:09 +0100 Subject: mmc: core: add a short delay in mmc_power_off Stress-testing the runtime power management of libertas_sdio through a rmmod/insmod loop revealed that it is quite easy to cause an ETIMEDOUT failure in mmc_sdio_power_restore() leading to: libertas_sdio: probe of mmc1:0001:1 failed with error -16 Experimentation shows that a very short delay (100us) is needed in the power down path before the card can be successfully booted again. We know that this setup is lacking poweroff clamps on the card's power lines, but as only a short delay is needed, apply this unconditionally. Also bump up to 1ms sleep for extra legroom. Signed-off-by: Daniel Drake Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 557856b6f95..7289e999d1f 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1214,6 +1214,13 @@ static void mmc_power_off(struct mmc_host *host) host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); + /* + * Some configurations, such as the 802.11 SDIO card in the OLPC + * XO-1.5, require a short delay after poweroff before the card + * can be successfully turned on again. + */ + mmc_delay(1); + mmc_host_clk_release(host); } -- cgit v1.2.3-18-g5258 From 6fe47179a07009ee3ee7c8b962966fee420becc8 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Wed, 14 Sep 2011 12:39:17 +0530 Subject: mmc: sdhci-s3c: add default controller configuration The default controller configuration which was previously setup by platform helper functions is moved into the driver. Cc: Ben Dooks Signed-off-by: Thomas Abraham Acked-by: Kukjin Kim Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index fe886d6c474..82709b6da86 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); } /** -- cgit v1.2.3-18-g5258 From c3805467aad7ce4e31c2b935046843de08cfc026 Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Thu, 8 Sep 2011 22:08:39 +0530 Subject: mmc: core: Put eMMC in Sleep mode before suspend Put MMC to sleep if it supports SLEEP/AWAKE (CMD5) in the mmc suspend so that Vcc (NAND core) can be cut to minimize power consumption. eMMC put into SLEEP can respond to CMD0 or H/W reset or CMD5. Current implemention on resume from suspend relies on CMD0 in mmc_init_card to get out of SLEEP mode. Signed-off-by: Balaji T K Acked-by: Venkatraman S Reviewed-by: Subhash Jadavani Acked-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 5700b1cbdfe..f73fceea5db 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -553,6 +553,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * need to tell some cards to go back to the idle * state. We wait 1ms to give cards time to * respond. + * mmc_go_idle is needed for eMMC that are asleep */ mmc_go_idle(host); @@ -900,16 +901,20 @@ static void mmc_detect(struct mmc_host *host) */ static int mmc_suspend(struct mmc_host *host) { + int err = 0; + BUG_ON(!host); BUG_ON(!host->card); mmc_claim_host(host); - if (!mmc_host_is_spi(host)) + if (mmc_card_can_sleep(host)) + err = mmc_card_sleep(host); + else if (!mmc_host_is_spi(host)) mmc_deselect_cards(host); host->card->state &= ~MMC_STATE_HIGHSPEED; mmc_release_host(host); - return 0; + return err; } /* -- cgit v1.2.3-18-g5258 From e51cbc9eab260ed50548925f6879c04e81123928 Mon Sep 17 00:00:00 2001 From: Xu lei Date: Fri, 9 Sep 2011 20:05:46 +0800 Subject: mmc: sdhci-of-esdhc: Access Freescale eSDHC registers as 32-bit Freescale eSDHC registers only support 32-bit accesses, this patch ensures that all Freescale eSDHC register accesses are 32-bit. Signed-off-by: Xu lei Signed-off-by: Roy Zang Signed-off-by: Kumar Gala Acked-by: Anton Vorontsov Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-of-esdhc.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index fe604df6501..40036f6e859 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 @@ -22,11 +22,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 +84,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, -- cgit v1.2.3-18-g5258 From 46cbd56ad4a686c52eeab427faf7e28415bbf28f Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 12 Sep 2011 16:52:49 +0530 Subject: mmc: sdhci-spear: Don't set power gpio to 1 on probe Currently if card_power_gpio is passed from platform data, it is acquired and its value is either set or reset. After that we overwrite it with 1, which is not required. So, this patch removes the extra line which sets its value. Signed-off-by: Viresh Kumar Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-spear.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 60a4c97d3d1..a0630c32a05 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -177,8 +177,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) { -- cgit v1.2.3-18-g5258 From 7f7e4129c23f0419257184dff6fec89d2d5a8964 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 21 Sep 2011 14:08:13 -0400 Subject: mmc: core: Fix hangs related to insert/remove of cards During a rescan operation mmc_attach(sd|mmc|sdio) functions are called. The error handling in these function can trigger a detach of the bus, which also meant a power off. This is not notified by the rescan operation which then continues to the next attach function. If a power off has been done, the framework must never send any new commands to the host driver, without first doing a new power up. This will most likely trigger any host driver to hang. Moving power off out of detach and instead handle power off separately when it is actually needed, solves the issue. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Cc: Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 10 +++++----- drivers/mmc/core/core.h | 1 + drivers/mmc/core/mmc.c | 1 + drivers/mmc/core/sd.c | 1 + drivers/mmc/core/sdio.c | 1 + 5 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 7289e999d1f..5ae6b159dbe 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1192,7 +1192,7 @@ static void mmc_power_up(struct mmc_host *host) mmc_host_clk_release(host); } -static void mmc_power_off(struct mmc_host *host) +void mmc_power_off(struct mmc_host *host) { mmc_host_clk_hold(host); @@ -1289,8 +1289,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) } /* - * Remove the current bus handler from a host. Assumes that there are - * no interesting cards left, so the bus is powered down. + * Remove the current bus handler from a host. */ void mmc_detach_bus(struct mmc_host *host) { @@ -1307,8 +1306,6 @@ void mmc_detach_bus(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); - mmc_power_off(host); - mmc_bus_put(host); } @@ -1893,6 +1890,7 @@ void mmc_stop_host(struct mmc_host *host) mmc_claim_host(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); mmc_bus_put(host); return; @@ -2022,6 +2020,7 @@ int mmc_suspend_host(struct mmc_host *host) host->bus_ops->remove(host); mmc_claim_host(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); host->pm_flags = 0; err = 0; @@ -2109,6 +2108,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, host->bus_ops->remove(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); host->pm_flags = 0; break; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index d9411ed2a39..14664f1fb16 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -43,6 +43,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11); void mmc_set_timing(struct mmc_host *host, unsigned int timing); void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); +void mmc_power_off(struct mmc_host *host); static inline void mmc_delay(unsigned int ms) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index f73fceea5db..3b7c069a4ea 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -892,6 +892,7 @@ static void mmc_detect(struct mmc_host *host) mmc_claim_host(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); } } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 0370e03e314..4c281a4bf05 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1043,6 +1043,7 @@ static void mmc_sd_detect(struct mmc_host *host) mmc_claim_host(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); } } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 262fff01917..ac492ac974e 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -597,6 +597,7 @@ out: mmc_claim_host(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); } } -- cgit v1.2.3-18-g5258 From 329f22371460587c59b866dcbffce5b498b61f38 Mon Sep 17 00:00:00 2001 From: Tanmay Upadhyay Date: Wed, 14 Sep 2011 11:29:02 +0530 Subject: mmc: sdhci-pxa: Check pdata before using its members Signed-off-by: Tanmay Upadhyay Acked-by: Zhangfei Gao Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pxav2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 38f58994f79..1114fe2f0a5 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -59,7 +59,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 +71,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); -- cgit v1.2.3-18-g5258 From 9a0da648ff3a5020406ac7784eb3b519014f66f6 Mon Sep 17 00:00:00 2001 From: Stefan Nilsson XK Date: Thu, 15 Sep 2011 17:43:04 +0200 Subject: mmc: sdio: Workaround for dev with broken CMD53 Adds a quirk which can be turned on for SDIO devices that do not support 512 byte requests in byte mode during CMD53. These requests will always be sent in block mode instead. This patch also enables this quirk for ST-Ericsson CW1200 WLAN device. Signed-off-by: Stefan Nilsson XK Signed-off-by: Ulf HANSSON Acked-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/core/quirks.c | 11 +++++++++++ drivers/mmc/core/sdio_ops.c | 7 +++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c index 3a596217029..6c3cf98a62e 100644 --- a/drivers/mmc/core/quirks.c +++ b/drivers/mmc/core/quirks.c @@ -21,6 +21,14 @@ #define SDIO_DEVICE_ID_TI_WL1271 0x4076 #endif +#ifndef SDIO_VENDOR_ID_STE +#define SDIO_VENDOR_ID_STE 0x0020 +#endif + +#ifndef SDIO_DEVICE_ID_STE_CW1200 +#define SDIO_DEVICE_ID_STE_CW1200 0x2280 +#endif + /* * This hook just adds a quirk for all sdio devices */ @@ -46,6 +54,9 @@ static const struct mmc_fixup mmc_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk, MMC_QUIRK_DISABLE_CD), + SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200, + add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512), + END_FIXUP }; diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 4addbe987bc..b0517cc0620 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -144,8 +144,11 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, cmd.arg |= fn << 28; cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; cmd.arg |= addr << 9; - if (blocks == 1 && blksz <= 512) - cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ + if (blocks == 1 && blksz < 512) + cmd.arg |= blksz; /* byte mode */ + else if (blocks == 1 && blksz == 512 && + !(mmc_card_broken_byte_mode_512(card))) + cmd.arg |= 0; /* byte mode, 0==512 */ else cmd.arg |= 0x08000000 | blocks; /* block mode */ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; -- cgit v1.2.3-18-g5258 From 44669034815a7ad263542ac605c581a10b22d146 Mon Sep 17 00:00:00 2001 From: Stefan Nilsson XK Date: Thu, 15 Sep 2011 17:50:38 +0200 Subject: mmc: core: Set correct bus mode before card init Earlier all cards where initiated with bus mode set as OPENDRAIN, and then later switched to PUSHPULL. According to the MMC/SD/SDIO specifications only MMC cards use OPENDRAIN during init. For both SD and SDIO the bus mode shall be PUSHPULL before attempting to init the card. The consequence of having incorrect bus mode can lead to not being able to detect the card. Therefore the default behavior have now been changed to PUSHPULL in mmc_power_up, and will only be temporarily switched when trying to attach or init a MMC card. Signed-off-by: Stefan Nilsson XK Signed-off-by: Ulf HANSSON Acked-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 8 +++----- drivers/mmc/core/mmc.c | 8 ++++++++ drivers/mmc/core/sd.c | 2 -- drivers/mmc/core/sdio.c | 2 -- 4 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 5ae6b159dbe..45ea968e7dd 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1160,13 +1160,11 @@ static void mmc_power_up(struct mmc_host *host) bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; - if (mmc_host_is_spi(host)) { + if (mmc_host_is_spi(host)) host->ios.chip_select = MMC_CS_HIGH; - host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; - } else { + else host->ios.chip_select = MMC_CS_DONTCARE; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - } + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3b7c069a4ea..b74e6f14b3a 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -548,6 +548,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, BUG_ON(!host); WARN_ON(!host->claimed); + /* Set correct bus mode for MMC before attempting init */ + if (!mmc_host_is_spi(host)) + mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); + /* * Since we're changing the OCR value, we seem to * need to tell some cards to go back to the idle @@ -1022,6 +1026,10 @@ int mmc_attach_mmc(struct mmc_host *host) BUG_ON(!host); WARN_ON(!host->claimed); + /* Set correct bus mode for MMC before attempting attach */ + if (!mmc_host_is_spi(host)) + mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); + err = mmc_send_op_cond(host, 0, &ocr); if (err) return err; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 4c281a4bf05..342b18c4afc 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -929,8 +929,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, err = mmc_send_relative_addr(host, &card->rca); if (err) return err; - - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); } if (!oldcard) { diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index ac492ac974e..698d813cff3 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -408,8 +408,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, */ if (oldcard) oldcard->rca = card->rca; - - mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); } /* -- cgit v1.2.3-18-g5258 From 7c8a2829c22a270acadc6aa3a937e2e7956b19f5 Mon Sep 17 00:00:00 2001 From: Per Forlin Date: Mon, 29 Aug 2011 15:35:58 +0200 Subject: mmc: core: clarify how to use post_req in case of errors The err condition in post_req() is set to undo a call made to pre_req() that hasn't been started yet. The err condition is not set if an MMC request returns an error. Signed-off-by: Per Forlin Acked-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 45ea968e7dd..0b4c2ed22bc 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -320,8 +320,14 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, mmc_wait_for_req_done(host, host->areq->mrq); err = host->areq->err_check(host->card, host->areq); if (err) { + /* post process the completed failed request */ mmc_post_req(host, host->areq->mrq, 0); if (areq) + /* + * Cancel the new prepared request, because + * it can't run until the failed + * request has been properly handled. + */ mmc_post_req(host, areq->mrq, -EINVAL); host->areq = NULL; -- cgit v1.2.3-18-g5258 From 8e3336b1e4378f7d205af9b25dcc9e645c8a9609 Mon Sep 17 00:00:00 2001 From: Per Forlin Date: Mon, 29 Aug 2011 15:35:59 +0200 Subject: mmc: mmci: simplify err check in mmci_post_request The error condition indicates that mmci_post_request() should cleanup after the mmci_pre_request(). In this case the resources allocated by device_prep_slave_sg() are freed by calling dmaengine_terminate_all(). dma_unmap_sg() should always be performed if the host_cookie is set. Signed-off-by: Per Forlin Acked-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/host/mmci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 56e9a416826..40e4c055812 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -529,7 +529,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; -- cgit v1.2.3-18-g5258 From b2499518b5ad7e28bb3ed348fd3f370eeb1e36c0 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 29 Aug 2011 16:42:11 +0300 Subject: mmc: core: add eMMC hardware reset support eMMC's may have a hardware reset line. This patch provides a host controller operation to implement hardware reset and a function to reset and reinitialize the card. Also, for MMC, the reset is always performed before initialization. The host must set the new host capability MMC_CAP_HW_RESET to enable hardware reset. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/mmc.c | 4 ++- 2 files changed, 97 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 0b4c2ed22bc..da6bd95fa4b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1776,6 +1776,94 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) } EXPORT_SYMBOL(mmc_set_blocklen); +static void mmc_hw_reset_for_init(struct mmc_host *host) +{ + if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) + return; + mmc_host_clk_hold(host); + host->ops->hw_reset(host); + mmc_host_clk_release(host); +} + +int mmc_can_reset(struct mmc_card *card) +{ + u8 rst_n_function; + + if (!mmc_card_mmc(card)) + return 0; + rst_n_function = card->ext_csd.rst_n_function; + if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED) + return 0; + return 1; +} +EXPORT_SYMBOL(mmc_can_reset); + +static int mmc_do_hw_reset(struct mmc_host *host, int check) +{ + struct mmc_card *card = host->card; + + if (!host->bus_ops->power_restore) + return -EOPNOTSUPP; + + if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) + return -EOPNOTSUPP; + + if (!card) + return -EINVAL; + + if (!mmc_can_reset(card)) + return -EOPNOTSUPP; + + mmc_host_clk_hold(host); + mmc_set_clock(host, host->f_init); + + host->ops->hw_reset(host); + + /* If the reset has happened, then a status command will fail */ + if (check) { + struct mmc_command cmd = {0}; + int err; + + cmd.opcode = MMC_SEND_STATUS; + if (!mmc_host_is_spi(card->host)) + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; + err = mmc_wait_for_cmd(card->host, &cmd, 0); + if (!err) { + mmc_host_clk_release(host); + return -ENOSYS; + } + } + + host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR); + if (mmc_host_is_spi(host)) { + host->ios.chip_select = MMC_CS_HIGH; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + } else { + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + } + host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; + mmc_set_ios(host); + + mmc_host_clk_release(host); + + return host->bus_ops->power_restore(host); +} + +int mmc_hw_reset(struct mmc_host *host) +{ + return mmc_do_hw_reset(host, 0); +} +EXPORT_SYMBOL(mmc_hw_reset); + +int mmc_hw_reset_check(struct mmc_host *host) +{ + return mmc_do_hw_reset(host, 1); +} +EXPORT_SYMBOL(mmc_hw_reset_check); + static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) { host->f_init = freq; @@ -1786,6 +1874,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) #endif mmc_power_up(host); + /* + * Some eMMCs (with VCCQ always on) may not be reset after power up, so + * do a hardware reset if possible. + */ + mmc_hw_reset_for_init(host); + /* * sdio_reset sends CMD52 to reset card. Since we do not know * if the card is being re-initialized, just send it. CMD52 diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b74e6f14b3a..7adc30da836 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -402,8 +402,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) ext_csd[EXT_CSD_TRIM_MULT]; } - if (card->ext_csd.rev >= 5) + if (card->ext_csd.rev >= 5) { card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; + card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; + } if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; -- cgit v1.2.3-18-g5258 From 20758b66dce76af0527363186f44b464d83e5666 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 29 Aug 2011 16:42:12 +0300 Subject: mmc: sdhci: add eMMC hardware reset support Add an SDHCI operation for hardware reset and connect it to the host controller operation. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 9 +++++++++ drivers/mmc/host/sdhci.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0e02cc1df12..d66a7a11a4f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1471,6 +1471,14 @@ static int sdhci_get_ro(struct mmc_host *mmc) return 0; } +static void sdhci_hw_reset(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (host->ops && host->ops->hw_reset) + host->ops->hw_reset(host); +} + static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct sdhci_host *host; @@ -1805,6 +1813,7 @@ 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, diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 745c42fa41e..7bd919c33cc 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 -- cgit v1.2.3-18-g5258 From 0f2016558e4f9a8d2f9b1202064915205f4dd450 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 29 Aug 2011 16:42:13 +0300 Subject: mmc: sdhci-pci: add eMMC hardware reset support Implement eMMC hardware reset for Medfield. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 72 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 26c528648f3..3b30c515cbc 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "sdhci.h" @@ -59,6 +61,7 @@ struct sdhci_pci_slot { struct sdhci_host *host; int pci_bar; + int rst_n_gpio; }; struct sdhci_pci_chip { @@ -163,12 +166,63 @@ 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; +} + static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) { + 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; + 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, @@ -190,6 +244,7 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .probe_slot = mfd_emmc_probe_slot, + .remove_slot = mfd_emmc_remove_slot, }; /* O2Micro extra registers */ @@ -832,9 +887,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, }; /*****************************************************************************\ @@ -988,6 +1059,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; -- cgit v1.2.3-18-g5258 From 2311344c33cb8add492881900ca427b62f5a7eae Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 29 Aug 2011 16:42:14 +0300 Subject: mmc: mmc-test: add eMMC hardware reset test MMC core provides a checking function that checks if the reset has happended. Add a test to use that function. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/card/mmc_test.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 2bf229acd3b..9cdce636713 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -2328,6 +2328,31 @@ static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test) return mmc_test_rw_multiple_sg_len(test, &test_data); } +/* + * eMMC hardware reset. + */ +static int mmc_test_hw_reset(struct mmc_test_card *test) +{ + struct mmc_card *card = test->card; + struct mmc_host *host = card->host; + int err; + + err = mmc_hw_reset_check(host); + if (!err) + return RESULT_OK; + + if (err == -ENOSYS) + return RESULT_FAIL; + + if (err != -EOPNOTSUPP) + return err; + + if (!mmc_can_reset(card)) + return RESULT_UNSUP_CARD; + + return RESULT_UNSUP_HOST; +} + static const struct mmc_test_case mmc_test_cases[] = { { .name = "Basic write (no data verification)", @@ -2650,6 +2675,11 @@ static const struct mmc_test_case mmc_test_cases[] = { .run = mmc_test_profile_sglen_r_nonblock_perf, .cleanup = mmc_test_area_cleanup, }, + + { + .name = "eMMC hardware reset", + .run = mmc_test_hw_reset, + }, }; static DEFINE_MUTEX(mmc_test_lock); -- cgit v1.2.3-18-g5258 From 67716327eec7e9d573e7cb2d806545d6f7c1a38d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 29 Aug 2011 16:42:15 +0300 Subject: mmc: block: add eMMC hardware reset support For cards that support hardware reset (just eMMC), try a reset and retry before returning an I/O error. However this is not done for ECC errors and is never done twice for the same operation type (READ, WRITE, DISCARD, SECURE DISCARD) until that type of operation again succeeds. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 201 +++++++++++++++++++++++++++++++++-------------- drivers/mmc/core/core.c | 4 +- 2 files changed, 144 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 9b907263668..66c7596c554 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -94,6 +94,11 @@ struct mmc_blk_data { unsigned int read_only; unsigned int part_type; unsigned int name_idx; + unsigned int reset_done; +#define MMC_BLK_READ BIT(0) +#define MMC_BLK_WRITE BIT(1) +#define MMC_BLK_DISCARD BIT(2) +#define MMC_BLK_SECDISCARD BIT(3) /* * Only set in main mmc_blk_data associated @@ -109,11 +114,11 @@ static DEFINE_MUTEX(open_lock); enum mmc_blk_status { MMC_BLK_SUCCESS = 0, MMC_BLK_PARTIAL, - MMC_BLK_RETRY, - MMC_BLK_RETRY_SINGLE, - MMC_BLK_DATA_ERR, MMC_BLK_CMD_ERR, + MMC_BLK_RETRY, MMC_BLK_ABORT, + MMC_BLK_DATA_ERR, + MMC_BLK_ECC_ERR, }; module_param(perdev_minors, int, 0444); @@ -454,7 +459,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, card->ext_csd.part_time); if (ret) return ret; -} + } main_md->part_curr = md->part_type; return 0; @@ -616,7 +621,7 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error, * Otherwise we don't understand what happened, so abort. */ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, - struct mmc_blk_request *brq) + struct mmc_blk_request *brq, int *ecc_err) { bool prev_cmd_status_valid = true; u32 status, stop_status = 0; @@ -641,6 +646,12 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, if (err) return ERR_ABORT; + /* Flag ECC errors */ + if ((status & R1_CARD_ECC_FAILED) || + (brq->stop.resp[0] & R1_CARD_ECC_FAILED) || + (brq->cmd.resp[0] & R1_CARD_ECC_FAILED)) + *ecc_err = 1; + /* * Check the current card state. If it is in some data transfer * mode, tell it to stop (and hopefully transition back to TRAN.) @@ -658,6 +669,8 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, */ if (err) return ERR_ABORT; + if (stop_status & R1_CARD_ECC_FAILED) + *ecc_err = 1; } /* Check for set block count errors */ @@ -670,6 +683,10 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error, prev_cmd_status_valid, status); + /* Data errors */ + if (!brq->stop.error) + return ERR_CONTINUE; + /* Now for stop errors. These aren't fatal to the transfer. */ pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n", req->rq_disk->disk_name, brq->stop.error, @@ -686,12 +703,45 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, return ERR_CONTINUE; } +static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, + int type) +{ + int err; + + if (md->reset_done & type) + return -EEXIST; + + md->reset_done |= type; + err = mmc_hw_reset(host); + /* Ensure we switch back to the correct partition */ + if (err != -EOPNOTSUPP) { + struct mmc_blk_data *main_md = mmc_get_drvdata(host->card); + int part_err; + + main_md->part_curr = main_md->part_type; + part_err = mmc_blk_part_switch(host->card, md); + if (part_err) { + /* + * We have failed to get back into the correct + * partition, so we need to abort the whole request. + */ + return -ENODEV; + } + } + return err; +} + +static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type) +{ + md->reset_done &= ~type; +} + static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; unsigned int from, nr, arg; - int err = 0; + int err = 0, type = MMC_BLK_DISCARD; if (!mmc_can_erase(card)) { err = -EOPNOTSUPP; @@ -705,7 +755,7 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) arg = MMC_TRIM_ARG; else arg = MMC_ERASE_ARG; - +retry: if (card->quirks & MMC_QUIRK_INAND_CMD38) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, INAND_CMD38_ARG_EXT_CSD, @@ -718,6 +768,10 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) } err = mmc_erase(card, from, nr, arg); out: + if (err == -EIO && !mmc_blk_reset(md, card->host, type)) + goto retry; + if (!err) + mmc_blk_reset_success(md, type); spin_lock_irq(&md->lock); __blk_end_request(req, err, blk_rq_bytes(req)); spin_unlock_irq(&md->lock); @@ -731,7 +785,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; unsigned int from, nr, arg; - int err = 0; + int err = 0, type = MMC_BLK_SECDISCARD; if (!mmc_can_secure_erase_trim(card)) { err = -EOPNOTSUPP; @@ -745,7 +799,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, arg = MMC_SECURE_TRIM1_ARG; else arg = MMC_SECURE_ERASE_ARG; - +retry: if (card->quirks & MMC_QUIRK_INAND_CMD38) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, INAND_CMD38_ARG_EXT_CSD, @@ -769,6 +823,10 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG); } out: + if (err == -EIO && !mmc_blk_reset(md, card->host, type)) + goto retry; + if (!err) + mmc_blk_reset_success(md, type); spin_lock_irq(&md->lock); __blk_end_request(req, err, blk_rq_bytes(req)); spin_unlock_irq(&md->lock); @@ -825,11 +883,11 @@ static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq, static int mmc_blk_err_check(struct mmc_card *card, struct mmc_async_req *areq) { - enum mmc_blk_status ret = MMC_BLK_SUCCESS; struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req, mmc_active); struct mmc_blk_request *brq = &mq_mrq->brq; struct request *req = mq_mrq->req; + int ecc_err = 0; /* * sbc.error indicates a problem with the set block count @@ -841,8 +899,9 @@ static int mmc_blk_err_check(struct mmc_card *card, * stop.error indicates a problem with the stop command. Data * may have been transferred, or may still be transferring. */ - if (brq->sbc.error || brq->cmd.error || brq->stop.error) { - switch (mmc_blk_cmd_recovery(card, req, brq)) { + if (brq->sbc.error || brq->cmd.error || brq->stop.error || + brq->data.error) { + switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err)) { case ERR_RETRY: return MMC_BLK_RETRY; case ERR_ABORT: @@ -894,23 +953,21 @@ static int mmc_blk_err_check(struct mmc_card *card, brq->cmd.resp[0], brq->stop.resp[0]); if (rq_data_dir(req) == READ) { - if (brq->data.blocks > 1) { - /* Redo read one sector at a time */ - pr_warning("%s: retrying using single block read\n", - req->rq_disk->disk_name); - return MMC_BLK_RETRY_SINGLE; - } + if (ecc_err) + return MMC_BLK_ECC_ERR; return MMC_BLK_DATA_ERR; } else { return MMC_BLK_CMD_ERR; } } - if (ret == MMC_BLK_SUCCESS && - blk_rq_bytes(req) != brq->data.bytes_xfered) - ret = MMC_BLK_PARTIAL; + if (!brq->data.bytes_xfered) + return MMC_BLK_RETRY; - return ret; + if (blk_rq_bytes(req) != brq->data.bytes_xfered) + return MMC_BLK_PARTIAL; + + return MMC_BLK_SUCCESS; } static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, @@ -1049,12 +1106,41 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, mmc_queue_bounce_pre(mqrq); } +static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, + struct mmc_blk_request *brq, struct request *req, + int ret) +{ + /* + * If this is an SD card and we're writing, we can first + * mark the known good sectors as ok. + * + * If the card is not SD, we can still ok written sectors + * as reported by the controller (which might be less than + * the real number of written sectors, but never more). + */ + if (mmc_card_sd(card)) { + u32 blocks; + + blocks = mmc_sd_num_wr_blocks(card); + if (blocks != (u32)-1) { + spin_lock_irq(&md->lock); + ret = __blk_end_request(req, 0, blocks << 9); + spin_unlock_irq(&md->lock); + } + } else { + spin_lock_irq(&md->lock); + ret = __blk_end_request(req, 0, brq->data.bytes_xfered); + spin_unlock_irq(&md->lock); + } + return ret; +} + static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) { struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; struct mmc_blk_request *brq = &mq->mqrq_cur->brq; - int ret = 1, disable_multi = 0, retry = 0; + int ret = 1, disable_multi = 0, retry = 0, type; enum mmc_blk_status status; struct mmc_queue_req *mq_rq; struct request *req; @@ -1076,6 +1162,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) mq_rq = container_of(areq, struct mmc_queue_req, mmc_active); brq = &mq_rq->brq; req = mq_rq->req; + type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; mmc_queue_bounce_post(mq_rq); switch (status) { @@ -1084,17 +1171,17 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) /* * A block was successfully transferred. */ + mmc_blk_reset_success(md, type); spin_lock_irq(&md->lock); ret = __blk_end_request(req, 0, brq->data.bytes_xfered); spin_unlock_irq(&md->lock); + /* + * If the blk_end_request function returns non-zero even + * though all data has been transferred and no errors + * were returned by the host controller, it's a bug. + */ if (status == MMC_BLK_SUCCESS && ret) { - /* - * The blk_end_request has returned non zero - * even though all data is transfered and no - * erros returned by host. - * If this happen it's a bug. - */ printk(KERN_ERR "%s BUG rq_tot %d d_xfer %d\n", __func__, blk_rq_bytes(req), brq->data.bytes_xfered); @@ -1103,16 +1190,36 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) } break; case MMC_BLK_CMD_ERR: - goto cmd_err; - case MMC_BLK_RETRY_SINGLE: - disable_multi = 1; - break; + ret = mmc_blk_cmd_err(md, card, brq, req, ret); + if (!mmc_blk_reset(md, card->host, type)) + break; + goto cmd_abort; case MMC_BLK_RETRY: if (retry++ < 5) break; + /* Fall through */ case MMC_BLK_ABORT: + if (!mmc_blk_reset(md, card->host, type)) + break; goto cmd_abort; - case MMC_BLK_DATA_ERR: + case MMC_BLK_DATA_ERR: { + int err; + + err = mmc_blk_reset(md, card->host, type); + if (!err) + break; + if (err == -ENODEV) + goto cmd_abort; + /* Fall through */ + } + case MMC_BLK_ECC_ERR: + if (brq->data.blocks > 1) { + /* Redo read one sector at a time */ + pr_warning("%s: retrying using single block read\n", + req->rq_disk->disk_name); + disable_multi = 1; + break; + } /* * After an error, we redo I/O one sector at a * time, so we only reach here after trying to @@ -1129,7 +1236,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) if (ret) { /* - * In case of a none complete request + * In case of a incomplete request * prepare it again and resend. */ mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq); @@ -1139,30 +1246,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) return 1; - cmd_err: - /* - * If this is an SD card and we're writing, we can first - * mark the known good sectors as ok. - * - * If the card is not SD, we can still ok written sectors - * as reported by the controller (which might be less than - * the real number of written sectors, but never more). - */ - if (mmc_card_sd(card)) { - u32 blocks; - - blocks = mmc_sd_num_wr_blocks(card); - if (blocks != (u32)-1) { - spin_lock_irq(&md->lock); - ret = __blk_end_request(req, 0, blocks << 9); - spin_unlock_irq(&md->lock); - } - } else { - spin_lock_irq(&md->lock); - ret = __blk_end_request(req, 0, brq->data.bytes_xfered); - spin_unlock_irq(&md->lock); - } - cmd_abort: spin_lock_irq(&md->lock); while (ret) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index da6bd95fa4b..9698d8a2e16 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1529,7 +1529,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, if (err) { printk(KERN_ERR "mmc_erase: group start error %d, " "status %#x\n", err, cmd.resp[0]); - err = -EINVAL; + err = -EIO; goto out; } @@ -1544,7 +1544,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, if (err) { printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n", err, cmd.resp[0]); - err = -EINVAL; + err = -EIO; goto out; } -- cgit v1.2.3-18-g5258 From 714c4a6e3a0f730834ec8a8bc83b2a6da33f54dc Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 30 Aug 2011 18:26:39 +0200 Subject: mmc: sh_mmcif: simplify platform data Provide platforms with a simplified way to specify MMCIF DMA slave IDs in a way, similar to SDHI and other sh_dma clients. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mmcif.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 557886bee9c..bd91c94ea18 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -165,6 +165,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 +325,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); -- cgit v1.2.3-18-g5258 From cd8a3666987ba20908bbeb7c78ed9ba82b365643 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Fri, 2 Sep 2011 16:06:08 +0800 Subject: mmc: core: add sd uhs string for mmc_ios_show This is a minor fix. It makes mmc_ios_show print proper string when the host's timing is one of the newly added UHS-I modes. Signed-off-by: Aaron Lu Signed-off-by: Chris Ball --- drivers/mmc/core/debugfs.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 5acd707699c..96c603b0526 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -114,6 +114,15 @@ static int mmc_ios_show(struct seq_file *s, void *data) case MMC_TIMING_SD_HS: str = "sd high-speed"; break; + case MMC_TIMING_UHS_SDR50: + str = "sd uhs SDR50"; + break; + case MMC_TIMING_UHS_SDR104: + str = "sd uhs SDR104"; + break; + case MMC_TIMING_UHS_DDR50: + str = "sd uhs DDR50"; + break; default: str = "invalid"; break; -- cgit v1.2.3-18-g5258 From 95a2482a9baaf55a3403d2e76f2abd7c0a32298c Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 19 Sep 2011 17:32:21 +0800 Subject: mmc: sdhci-esdhc-imx: add basic imx6q usdhc support This patch adds the basic support for imx6q usdhc, which is a derivative of esdhc controller. Signed-off-by: Shawn Guo Signed-off-by: Chris Ball --- drivers/mmc/host/Kconfig | 6 +++--- drivers/mmc/host/sdhci-esdhc-imx.c | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index c226d549fd2..87d5067ba62 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" + 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 i.MX25, i.MX35 and i.MX5x. + 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. diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 4557aa1567a..ae57769ba50 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -32,6 +32,7 @@ /* VENDOR SPEC register */ #define SDHCI_VENDOR_SPEC 0xC0 #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 +#define SDHCI_MIX_CTRL 0x48 /* * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: @@ -59,6 +60,7 @@ enum imx_esdhc_type { IMX35_ESDHC, IMX51_ESDHC, IMX53_ESDHC, + IMX6Q_USDHC, }; struct pltfm_imx_data { @@ -81,6 +83,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 */ } @@ -92,6 +97,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); @@ -116,6 +122,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); @@ -220,8 +231,16 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int 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); } @@ -252,8 +271,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); -- cgit v1.2.3-18-g5258 From 34f5050800d600551cca9bcfb463cc6699d82d04 Mon Sep 17 00:00:00 2001 From: Per Forlin Date: Tue, 13 Sep 2011 23:03:29 +0200 Subject: mmc: add module param to set fault injection attributes Replace setup("fail_mmc_request") and faulty "ifdef KERNEL" with a simple module_param(). The module param mmc_core.fail_request may be used to set the fault injection attributes during boot time or module load time. Signed-off-by: Per Forlin Reviewed-by: Akinobu Mita Signed-off-by: Chris Ball --- drivers/mmc/core/debugfs.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 96c603b0526..da69aac4cc8 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -20,6 +20,14 @@ #include "core.h" #include "mmc_ops.h" +#ifdef CONFIG_FAIL_MMC_REQUEST + +static DECLARE_FAULT_ATTR(fail_default_attr); +static char *fail_request; +module_param(fail_request, charp, 0); + +#endif /* CONFIG_FAIL_MMC_REQUEST */ + /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */ static int mmc_ios_show(struct seq_file *s, void *data) { @@ -168,23 +176,6 @@ static int mmc_clock_opt_set(void *data, u64 val) return 0; } -#ifdef CONFIG_FAIL_MMC_REQUEST - -static DECLARE_FAULT_ATTR(fail_mmc_request); - -#ifdef KERNEL -/* - * Internal function. Pass the boot param fail_mmc_request to - * the setup fault injection attributes routine. - */ -static int __init setup_fail_mmc_request(char *str) -{ - return setup_fault_attr(&fail_mmc_request, str); -} -__setup("fail_mmc_request=", setup_fail_mmc_request); -#endif /* KERNEL */ -#endif /* CONFIG_FAIL_MMC_REQUEST */ - DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set, "%llu\n"); @@ -216,7 +207,9 @@ void mmc_add_host_debugfs(struct mmc_host *host) goto err_node; #endif #ifdef CONFIG_FAIL_MMC_REQUEST - host->fail_mmc_request = fail_mmc_request; + if (fail_request) + setup_fault_attr(&fail_default_attr, fail_request); + host->fail_mmc_request = fail_default_attr; if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request", root, &host->fail_mmc_request))) -- cgit v1.2.3-18-g5258 From b87d8dbf6c410b5f2d9b6893c85baa06aa131c7c Mon Sep 17 00:00:00 2001 From: Girish K S Date: Fri, 23 Sep 2011 20:41:47 +0530 Subject: mmc: core: eMMC 4.5 Power Class Selection Feature This patch adds the power class selection feature available for mmc versions 4.0 and above. During the enumeration stage before switching to the lower data bus, check if the power class is supported for the current bus width. If the power class is available then switch to the power class and use the higher data bus. If power class is not supported then switch to the lower data bus in a worst case. Signed-off-by: Girish K S Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 7adc30da836..c2334d636fe 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -531,6 +531,86 @@ static struct device_type mmc_type = { .groups = mmc_attr_groups, }; +/* + * Select the PowerClass for the current bus width + * If power class is defined for 4/8 bit bus in the + * extended CSD register, select it by executing the + * mmc_switch command. + */ +static int mmc_select_powerclass(struct mmc_card *card, + unsigned int bus_width, u8 *ext_csd) +{ + int err = 0; + unsigned int pwrclass_val; + unsigned int index = 0; + struct mmc_host *host; + + BUG_ON(!card); + + host = card->host; + BUG_ON(!host); + + if (ext_csd == NULL) + return 0; + + /* Power class selection is supported for versions >= 4.0 */ + if (card->csd.mmca_vsn < CSD_SPEC_VER_4) + return 0; + + /* Power class values are defined only for 4/8 bit bus */ + if (bus_width == EXT_CSD_BUS_WIDTH_1) + return 0; + + switch (1 << host->ios.vdd) { + case MMC_VDD_165_195: + if (host->ios.clock <= 26000000) + index = EXT_CSD_PWR_CL_26_195; + else if (host->ios.clock <= 52000000) + index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? + EXT_CSD_PWR_CL_52_195 : + EXT_CSD_PWR_CL_DDR_52_195; + else if (host->ios.clock <= 200000000) + index = EXT_CSD_PWR_CL_200_195; + break; + case MMC_VDD_32_33: + case MMC_VDD_33_34: + case MMC_VDD_34_35: + case MMC_VDD_35_36: + if (host->ios.clock <= 26000000) + index = EXT_CSD_PWR_CL_26_360; + else if (host->ios.clock <= 52000000) + index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? + EXT_CSD_PWR_CL_52_360 : + EXT_CSD_PWR_CL_DDR_52_360; + else if (host->ios.clock <= 200000000) + index = EXT_CSD_PWR_CL_200_360; + break; + default: + pr_warning("%s: Voltage range not supported " + "for power class.\n", mmc_hostname(host)); + return -EINVAL; + } + + pwrclass_val = ext_csd[index]; + + if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8)) + pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >> + EXT_CSD_PWR_CL_8BIT_SHIFT; + else + pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >> + EXT_CSD_PWR_CL_4BIT_SHIFT; + + /* If the power class is different from the default value */ + if (pwrclass_val > 0) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_POWER_CLASS, + pwrclass_val, + 0); + } + + return err; +} + /* * Handle the detection and initialisation of a card. * @@ -787,6 +867,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, bus_width = bus_widths[idx]; if (bus_width == MMC_BUS_WIDTH_1) ddr = 0; /* no DDR for 1-bit width */ + err = mmc_select_powerclass(card, ext_csd_bits[idx][0], + ext_csd); + if (err) + pr_err("%s: power class selection to " + "bus width %d failed\n", + mmc_hostname(card->host), + 1 << bus_width); + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx][0], @@ -810,6 +898,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } if (!err && ddr) { + err = mmc_select_powerclass(card, ext_csd_bits[idx][1], + ext_csd); + if (err) + pr_err("%s: power class selection to " + "bus width %d ddr %d failed\n", + mmc_hostname(card->host), + 1 << bus_width, ddr); + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx][1], -- cgit v1.2.3-18-g5258 From 0d7d85ca6e5dc7bd426d1d5989a44e93e8c7a0d3 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 23 Sep 2011 12:48:20 +0300 Subject: mmc: block: fix boot partition switch error path In the case of a switch error, do not update partition config as though the switch succeeded, and ensure blk_end_request is called on the failed request. Signed-off-by: Adrian Hunter Acked-by: Andrei Warkentin Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 66c7596c554..d7eb2c08233 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -447,18 +447,23 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, { int ret; struct mmc_blk_data *main_md = mmc_get_drvdata(card); + if (main_md->part_curr == md->part_type) return 0; if (mmc_card_mmc(card)) { - card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; - card->ext_csd.part_config |= md->part_type; + u8 part_config = card->ext_csd.part_config; + + part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; + part_config |= md->part_type; ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_PART_CONFIG, card->ext_csd.part_config, + EXT_CSD_PART_CONFIG, part_config, card->ext_csd.part_time); if (ret) return ret; + + card->ext_csd.part_config = part_config; } main_md->part_curr = md->part_type; @@ -1273,6 +1278,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ret = mmc_blk_part_switch(card, md); if (ret) { + if (req) { + spin_lock_irq(&md->lock); + __blk_end_request_all(req, -EIO); + spin_unlock_irq(&md->lock); + } ret = 0; goto out; } -- cgit v1.2.3-18-g5258 From f7c56ef2af5ae7e4c24c3c79427b38d18ba1d294 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 23 Sep 2011 12:48:21 +0300 Subject: mmc: block: support no access to boot partitions Intel Medfield platform blocks access to eMMC boot partitions which results in switch errors. Since there is no access, mmcboot0/1 devices should not be created. Add a host capability to reflect that. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 2 +- drivers/mmc/host/sdhci-pci.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index d7eb2c08233..aa66d3f3abb 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1480,7 +1480,7 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) if (!mmc_card_mmc(card)) return 0; - if (card->ext_csd.boot_size) { + if (card->ext_csd.boot_size && mmc_boot_partition_access(card->host)) { ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0, card->ext_csd.boot_size >> 9, true, diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 3b30c515cbc..f8a17f98f3a 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -215,6 +215,8 @@ static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; + slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC; + return 0; } -- cgit v1.2.3-18-g5258 From d9618e9f1a057efdfc52514d6cd7af56e9bddc17 Mon Sep 17 00:00:00 2001 From: Yong Zhang Date: Thu, 22 Sep 2011 16:59:04 +0800 Subject: mmc: irq: Remove IRQF_DISABLED Since commit [e58aa3d2: genirq: Run irq handlers with interrupts disabled], we run all interrupt handlers with interrupts disabled and we even check and yell when an interrupt handler returns with interrupts enabled (see commit [b738a50a: genirq: Warn when handler enables interrupts]). So now this flag is a NOOP and can be removed. Signed-off-by: Yong Zhang Acked-by: Kishore Kadiyala Acked-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/omap_hsmmc.c | 5 ++--- drivers/mmc/host/tmio_mmc.c | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 21e4a799df4..75c63955fa7 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2015,7 +2015,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 +2043,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/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 44a9668c4b7..a4ea1024278 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; -- cgit v1.2.3-18-g5258 From 5238acbe36dd5100fb6b035a995ae5fc89dd0708 Mon Sep 17 00:00:00 2001 From: Andrei Warkentin Date: Sat, 24 Sep 2011 12:12:30 -0400 Subject: mmc: core: ext_csd.raw_* used in comparison but never set f39b2dd9d ("mmc: core: Bus width testing needs to handle suspend/resume") added code to only compare read-only ext_csd fields in bus width testing code, yet it's comparing some fields that are never set. The affected fields are ext_csd.raw_erased_mem_count and ext_csd.raw_partition_support. Signed-off-by: Andrei Warkentin Acked-by: Philip Rakity Cc: Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c2334d636fe..c632b1faf70 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -359,6 +359,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) * card has the Enhanced area enabled. If so, export enhanced * area offset and size to user by adding sysfs interface. */ + card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { u8 hc_erase_grp_sz = @@ -407,6 +408,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; } + card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; else -- cgit v1.2.3-18-g5258 From e0c368d571d946ff40f068344b5c2df90c93dd2e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 6 Oct 2011 23:41:38 +0900 Subject: mmc: core: general purpose MMC partition support. It allows gerneral purpose partitions in MMC Device. And I try to simply make mmc_blk_alloc_parts using mmc_part structure suggested by Andrei Warkentin. After patching, we see general purpose partitions like this: > cat /proc/partitions 179 0 847872 mmcblk0 179 192 4096 mmcblk0gp3 179 160 4096 mmcblk0gp2 179 128 4096 mmcblk0gp1 179 96 1052672 mmcblk0gp0 179 64 1024 mmcblk0boot1 179 32 1024 mmcblk0boot0 Signed-off-by: Namjae Jeon Acked-by: Andrei Warkentin Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 31 ++++++++++++++++------------- drivers/mmc/core/mmc.c | 52 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index aa66d3f3abb..2cf1ba6db91 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1473,26 +1473,29 @@ static int mmc_blk_alloc_part(struct mmc_card *card, return 0; } +/* MMC Physical partitions consist of two boot partitions and + * up to four general purpose partitions. + * For each partition enabled in EXT_CSD a block device will be allocatedi + * to provide access to the partition. + */ + static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) { - int ret = 0; + int idx, ret = 0; if (!mmc_card_mmc(card)) return 0; - if (card->ext_csd.boot_size && mmc_boot_partition_access(card->host)) { - ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0, - card->ext_csd.boot_size >> 9, - true, - "boot0"); - if (ret) - return ret; - ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT1, - card->ext_csd.boot_size >> 9, - true, - "boot1"); - if (ret) - return ret; + for (idx = 0; idx < card->nr_parts; idx++) { + if (card->part[idx].size) { + ret = mmc_blk_alloc_part(card, md, + card->part[idx].part_cfg, + card->part[idx].size >> 9, + card->part[idx].force_ro, + card->part[idx].name); + if (ret) + return ret; + } } return ret; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c632b1faf70..2a4c9a4d3c0 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -239,7 +239,9 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) */ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) { - int err = 0; + int err = 0, idx; + unsigned int part_size; + u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0; BUG_ON(!card); @@ -340,7 +342,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) * There are two boot regions of equal size, defined in * multiples of 128K. */ - card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; + if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) { + for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) { + part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; + mmc_part_add(card, part_size, + EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, + "boot%d", idx, true); + } + } } card->ext_csd.raw_hc_erase_gap_size = @@ -362,9 +371,9 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { - u8 hc_erase_grp_sz = + hc_erase_grp_sz = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; - u8 hc_wp_grp_sz = + hc_wp_grp_sz = ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; card->ext_csd.enhanced_area_en = 1; @@ -393,6 +402,41 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.enhanced_area_offset = -EINVAL; card->ext_csd.enhanced_area_size = -EINVAL; } + + /* + * General purpose partition feature support -- + * If ext_csd has the size of general purpose partitions, + * set size, part_cfg, partition name in mmc_part. + */ + if (ext_csd[EXT_CSD_PARTITION_SUPPORT] & + EXT_CSD_PART_SUPPORT_PART_EN) { + if (card->ext_csd.enhanced_area_en != 1) { + hc_erase_grp_sz = + ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; + hc_wp_grp_sz = + ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; + + card->ext_csd.enhanced_area_en = 1; + } + + for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) { + if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] && + !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] && + !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]) + continue; + part_size = + (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2] + << 16) + + (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] + << 8) + + ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3]; + part_size *= (size_t)(hc_erase_grp_sz * + hc_wp_grp_sz); + mmc_part_add(card, part_size << 19, + EXT_CSD_PART_CONFIG_ACC_GP0 + idx, + "gp%d", idx, false); + } + } card->ext_csd.sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.sec_erase_mult = -- cgit v1.2.3-18-g5258 From 3f102ae926c01bccc9520a62cff833fde889ed6a Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Sun, 9 Oct 2011 10:35:16 -0400 Subject: mmc: using module_param requires the inclusion of moduleparam.h Commit "mmc: add module param to set fault injection attributes" adds a module_param to this file. But it is relying on the old implicit "module.h is everywhere" behaviour, and without the explicit include of moduleparam.h, the pending module.h split up produces this error: core/debugfs.c:28:35: error: expected ')' before numeric constant Signed-off-by: Stephen Rothwell Signed-off-by: Paul Gortmaker Signed-off-by: Chris Ball --- drivers/mmc/core/debugfs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index da69aac4cc8..6045ea46936 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -7,6 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include #include #include #include -- cgit v1.2.3-18-g5258 From 88b47679746b81534002bcba42da97ab82b5d12a Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 3 Jul 2011 15:15:51 -0400 Subject: mmc: Add module.h to drivers/mmc users assuming implicit presence. We are cleaning up the implicit presence of module.h; these guys are some of the people who just assume it will be there. Call it out explitly for those that really need it. Signed-off-by: Paul Gortmaker Signed-off-by: Chris Ball --- drivers/mmc/card/mmc_test.c | 1 + drivers/mmc/host/mmc_spi.c | 1 + drivers/mmc/host/mxs-mmc.c | 1 + drivers/mmc/host/sdhci-of-esdhc.c | 1 + drivers/mmc/host/sdhci-of-hlwd.c | 1 + drivers/mmc/host/sdhci-pci.c | 1 + drivers/mmc/host/sdhci-pltfm.c | 1 + drivers/mmc/host/sdhci-pxav2.c | 1 + drivers/mmc/host/sdhci-pxav3.c | 1 + drivers/mmc/host/sdhci-spear.c | 1 + drivers/mmc/host/sdhci-tegra.c | 1 + drivers/mmc/host/sdhci.c | 1 + drivers/mmc/host/sdricoh_cs.c | 1 + drivers/mmc/host/sh_mmcif.c | 1 + drivers/mmc/host/sh_mobile_sdhi.c | 1 + drivers/mmc/host/tifm_sd.c | 1 + drivers/mmc/host/via-sdmmc.c | 1 + 17 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 9cdce636713..d8705add3c9 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -22,6 +22,7 @@ #include #include #include +#include #define RESULT_OK 0 #define RESULT_FAIL 1 diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 7c1e16aaf17..92946b84e9f 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index d513d47364d..99b449d26a4 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 40036f6e859..59e9d003e58 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -15,6 +15,7 @@ #include #include +#include #include #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index 735be131dca..9b0d794a4f6 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -20,6 +20,7 @@ */ #include +#include #include #include "sdhci-pltfm.h" diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index f8a17f98f3a..4487b8430aa 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 6414efeddca..a9e12ea0558 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -29,6 +29,7 @@ */ #include +#include #include #ifdef CONFIG_PPC #include diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 1114fe2f0a5..d4bf6d30c7b 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index fc7e4a51562..cff4ad3e7a5 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "sdhci.h" #include "sdhci-pltfm.h" diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index a0630c32a05..63cc8b6a1c9 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index d105b52bfec..e9e061bf7d0 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index d66a7a11a4f..9394860602f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 496b7efbc6b..7009f17ad6c 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -26,6 +26,7 @@ */ #include #include +#include #include #include #include diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index bd91c94ea18..369366c8e20 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -31,6 +31,7 @@ #include #include #include +#include #define DRIVER_NAME "sh_mmcif" #define DRIVER_VERSION "2010-04-28" diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 75bffc4768f..41ae6466bd8 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 457c26ea09d..90c6b1b5da4 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #define DRIVER_NAME "tifm_sd" diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 4dfe2c02ea9..faf3594745f 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include -- cgit v1.2.3-18-g5258 From 08a7e1dfaa63bf5132b5b7231fcf9a33473c78f5 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 3 Oct 2011 15:33:33 +0300 Subject: mmc: core: move ->request() call from atomic context mmc_request_done() is sometimes called from interrupt or other atomic context. Mostly all mmc_request_done() does is complete(), however it contains code to retry on error, which uses ->request(). As the error path is certainly not performance critical, this may be moved to the waiting function mmc_wait_for_req_done(). This allows ->request() to use runtime PM get_sync() and guarantee it is never in an atomic context. Signed-off-by: Adrian Hunter Acked-by: Ulf Hansson Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9698d8a2e16..ec769490300 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -141,12 +141,12 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) } if (err && cmd->retries) { - pr_debug("%s: req failed (CMD%u): %d, retrying...\n", - mmc_hostname(host), cmd->opcode, err); - - cmd->retries--; - cmd->error = 0; - host->ops->request(host, mrq); + /* + * Request starter must handle retries - see + * mmc_wait_for_req_done(). + */ + if (mrq->done) + mrq->done(mrq); } else { mmc_should_fail_request(host, mrq); @@ -253,7 +253,21 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) static void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) { - wait_for_completion(&mrq->completion); + struct mmc_command *cmd; + + while (1) { + wait_for_completion(&mrq->completion); + + cmd = mrq->cmd; + if (!cmd->error || !cmd->retries) + break; + + pr_debug("%s: req failed (CMD%u): %d, retrying...\n", + mmc_hostname(host), cmd->opcode, cmd->error); + cmd->retries--; + cmd->error = 0; + host->ops->request(host, mrq); + } } /** -- cgit v1.2.3-18-g5258 From 66fd8ad5100b5003046aa744a4f12fa31bb831f9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 3 Oct 2011 15:33:34 +0300 Subject: mmc: sdhci-pci: add runtime pm support Ths patch allows runtime PM for sdhci-pci, runtime suspending after inactivity of 50ms and ensuring runtime resume before SDHC registers are accessed. During runtime suspend, interrupts are masked. The host controller state is restored at runtime resume. For Medfield, the host controller's card detect mechanism is supplanted by an always-on GPIO which provides for card detect wake-up. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 182 +++++++++++++++++++++++++++++- drivers/mmc/host/sdhci.c | 255 +++++++++++++++++++++++++++++++++++-------- drivers/mmc/host/sdhci.h | 5 + 3 files changed, 397 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 4487b8430aa..f49b184308c 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "sdhci.h" @@ -63,6 +64,8 @@ struct sdhci_pci_slot { int pci_bar; int rst_n_gpio; + int cd_gpio; + int cd_irq; }; struct sdhci_pci_chip { @@ -190,6 +193,70 @@ static int mfd_emmc_gpio_parse(struct sfi_table_header *table) 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) { const char *name = NULL; @@ -214,7 +281,7 @@ static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) slot->host->mmc->caps |= MMC_CAP_HW_RESET; } - slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; + slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC; @@ -238,6 +305,8 @@ 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, + .probe_slot = mfd_sd_probe_slot, + .remove_slot = mfd_sd_remove_slot, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { @@ -1018,6 +1087,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 * @@ -1133,6 +1291,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) { @@ -1208,6 +1381,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, chip->slots[i] = slot; } + sdhci_pci_runtime_pm_allow(&pdev->dev); + return 0; free: @@ -1224,6 +1399,8 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev) int i; struct sdhci_pci_chip *chip; + sdhci_pci_runtime_pm_forbid(&pdev->dev); + chip = pci_get_drvdata(pdev); if (chip) { @@ -1244,6 +1421,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.c b/drivers/mmc/host/sdhci.c index 9394860602f..155deb8629a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -42,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 *); @@ -50,6 +52,20 @@ 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", @@ -133,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; @@ -252,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 @@ -1210,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); @@ -1270,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) @@ -1427,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; @@ -1451,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; } @@ -1480,38 +1507,56 @@ static void sdhci_hw_reset(struct mmc_host *mmc) host->ops->hw_reset(host); } -static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +static int sdhci_get_ro(struct mmc_host *mmc) { - struct sdhci_host *host; - unsigned long flags; - - host = mmc_priv(mmc); + struct sdhci_host *host = mmc_priv(mmc); + int ret; - spin_lock_irqsave(&host->lock, flags); + 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. @@ -1604,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; @@ -1615,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); @@ -1632,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; } @@ -1657,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; @@ -1775,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; @@ -1802,14 +1861,25 @@ 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, @@ -1836,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)) { + printk(KERN_ERR "%s: Card removed during transfer!\n", + mmc_hostname(host->mmc)); + printk(KERN_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); @@ -1864,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); @@ -1915,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) @@ -2146,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); + printk(KERN_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) { @@ -2285,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); @@ -2324,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 * @@ -2366,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); @@ -2888,9 +3053,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 "); 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 7bd919c33cc..0a5b65460d8 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -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 */ -- cgit v1.2.3-18-g5258 From b23cf0bd55b0c6b703982446f679e00d6d929524 Mon Sep 17 00:00:00 2001 From: Seungwon Jeon Date: Fri, 23 Sep 2011 14:15:29 +0900 Subject: mmc: core: Add default timeout value for CMD6 EXT_CSD[248] includes the default maximum timeout for CMD6. This field is added at eMMC4.5 Spec. And it can be used for default timeout except for some operations which don't define the timeout (i.e. background operation, sanitize, flush cache) in eMMC4.5 Spec. Signed-off-by: Seungwon Jeon Signed-off-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 2a4c9a4d3c0..7dde373d143 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -458,6 +458,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) else card->erased_byte = 0x0; + if (card->ext_csd.rev >= 6) + card->ext_csd.generic_cmd6_time = 10 * + ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; + else + card->ext_csd.generic_cmd6_time = 0; + out: return err; } @@ -801,7 +807,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ if (card->ext_csd.enhanced_area_en) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_ERASE_GROUP_DEF, 1, 0); + EXT_CSD_ERASE_GROUP_DEF, 1, + card->ext_csd.generic_cmd6_time); if (err && err != -EBADMSG) goto free_card; @@ -844,7 +851,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if ((card->ext_csd.hs_max_dtr != 0) && (host->caps & MMC_CAP_MMC_HIGHSPEED)) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 1, 0); + EXT_CSD_HS_TIMING, 1, + card->ext_csd.generic_cmd6_time); if (err && err != -EBADMSG) goto free_card; @@ -924,7 +932,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx][0], - 0); + card->ext_csd.generic_cmd6_time); if (!err) { mmc_set_bus_width(card->host, bus_width); @@ -955,7 +963,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx][1], - 0); + card->ext_csd.generic_cmd6_time); } if (err) { printk(KERN_WARNING "%s: switch to bus width %d ddr %d " -- cgit v1.2.3-18-g5258 From a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993 Mon Sep 17 00:00:00 2001 From: Girish K S Date: Tue, 11 Oct 2011 11:44:09 +0530 Subject: mmc: replace printk with appropriate display macro All the files using printk function for displaying kernel messages in the mmc driver have been replaced with corresponding macro. Signed-off-by: Girish K S Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 10 ++--- drivers/mmc/card/mmc_test.c | 34 +++++++-------- drivers/mmc/card/queue.c | 4 +- drivers/mmc/card/sdio_uart.c | 10 ++--- drivers/mmc/core/bus.c | 6 +-- drivers/mmc/core/core.c | 10 ++--- drivers/mmc/core/mmc.c | 24 +++++------ drivers/mmc/core/mmc_ops.c | 4 +- drivers/mmc/core/sd.c | 40 +++++++++--------- drivers/mmc/core/sdio.c | 6 +-- drivers/mmc/core/sdio_bus.c | 2 +- drivers/mmc/core/sdio_cis.c | 4 +- drivers/mmc/core/sdio_irq.c | 6 +-- drivers/mmc/host/au1xmmc.c | 10 ++--- drivers/mmc/host/dw_mmc.c | 2 +- drivers/mmc/host/imxmmc.c | 2 +- drivers/mmc/host/mmci.c | 2 +- drivers/mmc/host/msm_sdcc.c | 8 ++-- drivers/mmc/host/mvsdio.c | 14 +++---- drivers/mmc/host/mxcmmc.c | 2 +- drivers/mmc/host/omap_hsmmc.c | 6 +-- drivers/mmc/host/pxamci.c | 2 +- drivers/mmc/host/s3cmci.c | 4 +- drivers/mmc/host/sdhci.c | 92 ++++++++++++++++++++--------------------- drivers/mmc/host/tifm_sd.c | 18 ++++---- drivers/mmc/host/tmio_mmc_pio.c | 2 +- drivers/mmc/host/via-sdmmc.c | 2 +- drivers/mmc/host/wbsd.c | 22 +++++----- 28 files changed, 172 insertions(+), 176 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 2cf1ba6db91..049445eb4f7 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -937,7 +937,7 @@ static int mmc_blk_err_check(struct mmc_card *card, do { int err = get_card_status(card, &status, 5); if (err) { - printk(KERN_ERR "%s: error %d requesting status\n", + pr_err("%s: error %d requesting status\n", req->rq_disk->disk_name, err); return MMC_BLK_CMD_ERR; } @@ -1187,7 +1187,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) * were returned by the host controller, it's a bug. */ if (status == MMC_BLK_SUCCESS && ret) { - printk(KERN_ERR "%s BUG rq_tot %d d_xfer %d\n", + pr_err("%s BUG rq_tot %d d_xfer %d\n", __func__, blk_rq_bytes(req), brq->data.bytes_xfered); rqc = NULL; @@ -1467,7 +1467,7 @@ static int mmc_blk_alloc_part(struct mmc_card *card, string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2, cap_str, sizeof(cap_str)); - printk(KERN_INFO "%s: %s %s partition %u %s\n", + pr_info("%s: %s %s partition %u %s\n", part_md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), part_md->part_type, cap_str); return 0; @@ -1511,7 +1511,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) mmc_release_host(card->host); if (err) { - printk(KERN_ERR "%s: unable to set block size to 512: %d\n", + pr_err("%s: unable to set block size to 512: %d\n", md->disk->disk_name, err); return -EINVAL; } @@ -1613,7 +1613,7 @@ static int mmc_blk_probe(struct mmc_card *card) string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2, cap_str, sizeof(cap_str)); - printk(KERN_INFO "%s: %s %s %s %s\n", + pr_info("%s: %s %s %s %s\n", md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), cap_str, md->read_only ? "(ro)" : ""); diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index d8705add3c9..b038c4a9468 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -251,7 +251,7 @@ static int mmc_test_wait_busy(struct mmc_test_card *test) if (!busy && mmc_test_busy(&cmd)) { busy = 1; if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) - printk(KERN_INFO "%s: Warning: Host did not " + pr_info("%s: Warning: Host did not " "wait for busy state to end.\n", mmc_hostname(test->card->host)); } @@ -553,7 +553,7 @@ static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes, rate = mmc_test_rate(bytes, &ts); iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */ - printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " + pr_info("%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " "seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n", mmc_hostname(test->card->host), sectors, sectors >> 1, (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec, @@ -579,7 +579,7 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes, rate = mmc_test_rate(tot, &ts); iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */ - printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " + pr_info("%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " "%lu.%09lu seconds (%u kB/s, %u KiB/s, " "%u.%02u IOPS, sg_len %d)\n", mmc_hostname(test->card->host), count, sectors, count, @@ -1409,7 +1409,7 @@ static int mmc_test_multi_read_high(struct mmc_test_card *test) static int mmc_test_no_highmem(struct mmc_test_card *test) { - printk(KERN_INFO "%s: Highmem not configured - test skipped\n", + pr_info("%s: Highmem not configured - test skipped\n", mmc_hostname(test->card->host)); return 0; } @@ -1436,7 +1436,7 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz, t->max_seg_sz, &t->sg_len, min_sg_len); } if (err) - printk(KERN_INFO "%s: Failed to map sg list\n", + pr_info("%s: Failed to map sg list\n", mmc_hostname(test->card->host)); return err; } @@ -2136,7 +2136,7 @@ static int mmc_test_rw_multiple(struct mmc_test_card *test, return ret; err: - printk(KERN_INFO "[%s] error\n", __func__); + pr_info("[%s] error\n", __func__); return ret; } @@ -2150,7 +2150,7 @@ static int mmc_test_rw_multiple_size(struct mmc_test_card *test, if (rw->do_nonblock_req && ((!pre_req && post_req) || (pre_req && !post_req))) { - printk(KERN_INFO "error: only one of pre/post is defined\n"); + pr_info("error: only one of pre/post is defined\n"); return -EINVAL; } @@ -2691,7 +2691,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) { int i, ret; - printk(KERN_INFO "%s: Starting tests of card %s...\n", + pr_info("%s: Starting tests of card %s...\n", mmc_hostname(test->card->host), mmc_card_id(test->card)); mmc_claim_host(test->card->host); @@ -2702,14 +2702,14 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) if (testcase && ((i + 1) != testcase)) continue; - printk(KERN_INFO "%s: Test case %d. %s...\n", + pr_info("%s: Test case %d. %s...\n", mmc_hostname(test->card->host), i + 1, mmc_test_cases[i].name); if (mmc_test_cases[i].prepare) { ret = mmc_test_cases[i].prepare(test); if (ret) { - printk(KERN_INFO "%s: Result: Prepare " + pr_info("%s: Result: Prepare " "stage failed! (%d)\n", mmc_hostname(test->card->host), ret); @@ -2739,25 +2739,25 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) ret = mmc_test_cases[i].run(test); switch (ret) { case RESULT_OK: - printk(KERN_INFO "%s: Result: OK\n", + pr_info("%s: Result: OK\n", mmc_hostname(test->card->host)); break; case RESULT_FAIL: - printk(KERN_INFO "%s: Result: FAILED\n", + pr_info("%s: Result: FAILED\n", mmc_hostname(test->card->host)); break; case RESULT_UNSUP_HOST: - printk(KERN_INFO "%s: Result: UNSUPPORTED " + pr_info("%s: Result: UNSUPPORTED " "(by host)\n", mmc_hostname(test->card->host)); break; case RESULT_UNSUP_CARD: - printk(KERN_INFO "%s: Result: UNSUPPORTED " + pr_info("%s: Result: UNSUPPORTED " "(by card)\n", mmc_hostname(test->card->host)); break; default: - printk(KERN_INFO "%s: Result: ERROR (%d)\n", + pr_info("%s: Result: ERROR (%d)\n", mmc_hostname(test->card->host), ret); } @@ -2768,7 +2768,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) if (mmc_test_cases[i].cleanup) { ret = mmc_test_cases[i].cleanup(test); if (ret) { - printk(KERN_INFO "%s: Warning: Cleanup " + pr_info("%s: Warning: Cleanup " "stage failed! (%d)\n", mmc_hostname(test->card->host), ret); @@ -2778,7 +2778,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) mmc_release_host(test->card->host); - printk(KERN_INFO "%s: Tests completed.\n", + pr_info("%s: Tests completed.\n", mmc_hostname(test->card->host)); } diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 5196312bb55..fed290ecc24 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -197,13 +197,13 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, if (bouncesz > 512) { mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mqrq_cur->bounce_buf) { - printk(KERN_WARNING "%s: unable to " + pr_warning("%s: unable to " "allocate bounce cur buffer\n", mmc_card_name(card)); } mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); if (!mqrq_prev->bounce_buf) { - printk(KERN_WARNING "%s: unable to " + pr_warning("%s: unable to " "allocate bounce prev buffer\n", mmc_card_name(card)); kfree(mqrq_cur->bounce_buf); diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index c8c9edb3d7c..2c151e18c9e 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -1082,7 +1082,7 @@ static int sdio_uart_probe(struct sdio_func *func, return -ENOMEM; if (func->class == SDIO_CLASS_UART) { - printk(KERN_WARNING "%s: need info on UART class basic setup\n", + pr_warning("%s: need info on UART class basic setup\n", sdio_func_id(func)); kfree(port); return -ENOSYS; @@ -1101,23 +1101,23 @@ static int sdio_uart_probe(struct sdio_func *func, break; } if (!tpl) { - printk(KERN_WARNING + pr_warning( "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n", sdio_func_id(func)); kfree(port); return -EINVAL; } - printk(KERN_DEBUG "%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", + pr_debug("%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", sdio_func_id(func), tpl->data[2], tpl->data[3]); port->regs_offset = (tpl->data[4] << 0) | (tpl->data[5] << 8) | (tpl->data[6] << 16); - printk(KERN_DEBUG "%s: regs offset = 0x%x\n", + pr_debug("%s: regs offset = 0x%x\n", sdio_func_id(func), port->regs_offset); port->uartclk = tpl->data[7] * 115200; if (port->uartclk == 0) port->uartclk = 115200; - printk(KERN_DEBUG "%s: clk %d baudcode %u 4800-div %u\n", + pr_debug("%s: clk %d baudcode %u 4800-div %u\n", sdio_func_id(func), port->uartclk, tpl->data[7], tpl->data[8] | (tpl->data[9] << 8)); } else { diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 393d817ed04..46b6e84d953 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -295,7 +295,7 @@ int mmc_add_card(struct mmc_card *card) } if (mmc_host_is_spi(card->host)) { - printk(KERN_INFO "%s: new %s%s%s card on SPI\n", + pr_info("%s: new %s%s%s card on SPI\n", mmc_hostname(card->host), mmc_card_highspeed(card) ? "high speed " : "", mmc_card_ddr_mode(card) ? "DDR " : "", @@ -334,10 +334,10 @@ void mmc_remove_card(struct mmc_card *card) if (mmc_card_present(card)) { if (mmc_host_is_spi(card->host)) { - printk(KERN_INFO "%s: SPI card removed\n", + pr_info("%s: SPI card removed\n", mmc_hostname(card->host)); } else { - printk(KERN_INFO "%s: card %04x removed\n", + pr_info("%s: card %04x removed\n", mmc_hostname(card->host), card->rca); } device_del(&card->dev); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index ec769490300..61d7730bc8b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1541,7 +1541,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { - printk(KERN_ERR "mmc_erase: group start error %d, " + pr_err("mmc_erase: group start error %d, " "status %#x\n", err, cmd.resp[0]); err = -EIO; goto out; @@ -1556,7 +1556,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { - printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n", + pr_err("mmc_erase: group end error %d, status %#x\n", err, cmd.resp[0]); err = -EIO; goto out; @@ -1569,7 +1569,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty); err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { - printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n", + pr_err("mmc_erase: erase error %d, status %#x\n", err, cmd.resp[0]); err = -EIO; goto out; @@ -1586,7 +1586,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, /* Do not retry else we can't see errors */ err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err || (cmd.resp[0] & 0xFDF92000)) { - printk(KERN_ERR "error %d requesting status %#x\n", + pr_err("error %d requesting status %#x\n", err, cmd.resp[0]); err = -EIO; goto out; @@ -2177,7 +2177,7 @@ int mmc_resume_host(struct mmc_host *host) BUG_ON(!host->bus_ops->resume); err = host->bus_ops->resume(host); if (err) { - printk(KERN_WARNING "%s: error %d during resume " + pr_warning("%s: error %d during resume " "(card was removed?)\n", mmc_hostname(host), err); err = 0; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 7dde373d143..4e869d371a0 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -101,7 +101,7 @@ static int mmc_decode_cid(struct mmc_card *card) break; default: - printk(KERN_ERR "%s: card has unknown MMCA version %d\n", + pr_err("%s: card has unknown MMCA version %d\n", mmc_hostname(card->host), card->csd.mmca_vsn); return -EINVAL; } @@ -135,7 +135,7 @@ static int mmc_decode_csd(struct mmc_card *card) */ csd->structure = UNSTUFF_BITS(resp, 126, 2); if (csd->structure == 0) { - printk(KERN_ERR "%s: unrecognised CSD structure version %d\n", + pr_err("%s: unrecognised CSD structure version %d\n", mmc_hostname(card->host), csd->structure); return -EINVAL; } @@ -195,7 +195,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) */ ext_csd = kmalloc(512, GFP_KERNEL); if (!ext_csd) { - printk(KERN_ERR "%s: could not allocate a buffer to " + pr_err("%s: could not allocate a buffer to " "receive the ext_csd.\n", mmc_hostname(card->host)); return -ENOMEM; } @@ -217,12 +217,12 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) * stored in their CSD. */ if (card->csd.capacity == (4096 * 512)) { - printk(KERN_ERR "%s: unable to read EXT_CSD " + pr_err("%s: unable to read EXT_CSD " "on a possible high capacity card. " "Card will be ignored.\n", mmc_hostname(card->host)); } else { - printk(KERN_WARNING "%s: unable to read " + pr_warning("%s: unable to read " "EXT_CSD, performance might " "suffer.\n", mmc_hostname(card->host)); @@ -252,7 +252,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; if (card->csd.structure == 3) { if (card->ext_csd.raw_ext_csd_structure > 2) { - printk(KERN_ERR "%s: unrecognised EXT_CSD structure " + pr_err("%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), card->ext_csd.raw_ext_csd_structure); err = -EINVAL; @@ -262,7 +262,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.rev = ext_csd[EXT_CSD_REV]; if (card->ext_csd.rev > 6) { - printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n", + pr_err("%s: unrecognised EXT_CSD revision %d\n", mmc_hostname(card->host), card->ext_csd.rev); err = -EINVAL; goto out; @@ -308,7 +308,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) break; default: /* MMC v4 spec says this cannot happen */ - printk(KERN_WARNING "%s: card is mmc v4 but doesn't " + pr_warning("%s: card is mmc v4 but doesn't " "support any high-speed modes.\n", mmc_hostname(card->host)); } @@ -857,7 +857,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, goto free_card; if (err) { - printk(KERN_WARNING "%s: switch to highspeed failed\n", + pr_warning("%s: switch to highspeed failed\n", mmc_hostname(card->host)); err = 0; } else { @@ -966,7 +966,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, card->ext_csd.generic_cmd6_time); } if (err) { - printk(KERN_WARNING "%s: switch to bus width %d ddr %d " + pr_warning("%s: switch to bus width %d ddr %d " "failed\n", mmc_hostname(card->host), 1 << bus_width, ddr); goto free_card; @@ -1204,7 +1204,7 @@ int mmc_attach_mmc(struct mmc_host *host) * support. */ if (ocr & 0x7F) { - printk(KERN_WARNING "%s: card claims to support voltages " + pr_warning("%s: card claims to support voltages " "below the defined range. These will be ignored.\n", mmc_hostname(host)); ocr &= ~0x7F; @@ -1243,7 +1243,7 @@ remove_card: err: mmc_detach_bus(host); - printk(KERN_ERR "%s: error %d whilst initialising MMC card\n", + pr_err("%s: error %d whilst initialising MMC card\n", mmc_hostname(host), err); return err; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 7aa13d01a83..4e11d56b3f7 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -414,7 +414,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, return -EBADMSG; } else { if (status & 0xFDFFA000) - printk(KERN_WARNING "%s: unexpected status %#x after " + pr_warning("%s: unexpected status %#x after " "switch", mmc_hostname(card->host), status); if (status & R1_SWITCH_ERROR) return -EBADMSG; @@ -476,7 +476,7 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, else if (len == 4) test_buf = testdata_4bit; else { - printk(KERN_ERR "%s: Invalid bus_width %d\n", + pr_err("%s: Invalid bus_width %d\n", mmc_hostname(host), len); kfree(data_buf); return -EINVAL; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 342b18c4afc..25b93729413 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -163,7 +163,7 @@ static int mmc_decode_csd(struct mmc_card *card) csd->erase_size = 1; break; default: - printk(KERN_ERR "%s: unrecognised CSD structure version %d\n", + pr_err("%s: unrecognised CSD structure version %d\n", mmc_hostname(card->host), csd_struct); return -EINVAL; } @@ -187,7 +187,7 @@ static int mmc_decode_scr(struct mmc_card *card) scr_struct = UNSTUFF_BITS(resp, 60, 4); if (scr_struct != 0) { - printk(KERN_ERR "%s: unrecognised SCR structure version %d\n", + pr_err("%s: unrecognised SCR structure version %d\n", mmc_hostname(card->host), scr_struct); return -EINVAL; } @@ -218,7 +218,7 @@ static int mmc_read_ssr(struct mmc_card *card) u32 *ssr; if (!(card->csd.cmdclass & CCC_APP_SPEC)) { - printk(KERN_WARNING "%s: card lacks mandatory SD Status " + pr_warning("%s: card lacks mandatory SD Status " "function.\n", mmc_hostname(card->host)); return 0; } @@ -229,7 +229,7 @@ static int mmc_read_ssr(struct mmc_card *card) err = mmc_app_sd_status(card, ssr); if (err) { - printk(KERN_WARNING "%s: problem reading SD Status " + pr_warning("%s: problem reading SD Status " "register.\n", mmc_hostname(card->host)); err = 0; goto out; @@ -253,7 +253,7 @@ static int mmc_read_ssr(struct mmc_card *card) card->ssr.erase_offset = eo * 1000; } } else { - printk(KERN_WARNING "%s: SD Status: Invalid Allocation Unit " + pr_warning("%s: SD Status: Invalid Allocation Unit " "size.\n", mmc_hostname(card->host)); } out: @@ -273,7 +273,7 @@ static int mmc_read_switch(struct mmc_card *card) return 0; if (!(card->csd.cmdclass & CCC_SWITCH)) { - printk(KERN_WARNING "%s: card lacks mandatory switch " + pr_warning("%s: card lacks mandatory switch " "function, performance might suffer.\n", mmc_hostname(card->host)); return 0; @@ -283,7 +283,7 @@ static int mmc_read_switch(struct mmc_card *card) status = kmalloc(64, GFP_KERNEL); if (!status) { - printk(KERN_ERR "%s: could not allocate a buffer for " + pr_err("%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); return -ENOMEM; @@ -299,7 +299,7 @@ static int mmc_read_switch(struct mmc_card *card) if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) goto out; - printk(KERN_WARNING "%s: problem reading Bus Speed modes.\n", + pr_warning("%s: problem reading Bus Speed modes.\n", mmc_hostname(card->host)); err = 0; @@ -319,7 +319,7 @@ static int mmc_read_switch(struct mmc_card *card) if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) goto out; - printk(KERN_WARNING "%s: problem reading " + pr_warning("%s: problem reading " "Driver Strength.\n", mmc_hostname(card->host)); err = 0; @@ -339,7 +339,7 @@ static int mmc_read_switch(struct mmc_card *card) if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) goto out; - printk(KERN_WARNING "%s: problem reading " + pr_warning("%s: problem reading " "Current Limit.\n", mmc_hostname(card->host)); err = 0; @@ -383,7 +383,7 @@ int mmc_sd_switch_hs(struct mmc_card *card) status = kmalloc(64, GFP_KERNEL); if (!status) { - printk(KERN_ERR "%s: could not allocate a buffer for " + pr_err("%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); return -ENOMEM; } @@ -393,7 +393,7 @@ int mmc_sd_switch_hs(struct mmc_card *card) goto out; if ((status[16] & 0xF) != 1) { - printk(KERN_WARNING "%s: Problem switching card " + pr_warning("%s: Problem switching card " "into high-speed mode!\n", mmc_hostname(card->host)); err = 0; @@ -459,7 +459,7 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) return err; if ((status[15] & 0xF) != drive_strength) { - printk(KERN_WARNING "%s: Problem setting drive strength!\n", + pr_warning("%s: Problem setting drive strength!\n", mmc_hostname(card->host)); return 0; } @@ -538,7 +538,7 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status) return err; if ((status[16] & 0xF) != card->sd_bus_speed) - printk(KERN_WARNING "%s: Problem setting bus speed mode!\n", + pr_warning("%s: Problem setting bus speed mode!\n", mmc_hostname(card->host)); else { mmc_set_timing(card->host, timing); @@ -600,7 +600,7 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status) return err; if (((status[15] >> 4) & 0x0F) != current_limit) - printk(KERN_WARNING "%s: Problem setting current limit!\n", + pr_warning("%s: Problem setting current limit!\n", mmc_hostname(card->host)); return 0; @@ -622,7 +622,7 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) status = kmalloc(64, GFP_KERNEL); if (!status) { - printk(KERN_ERR "%s: could not allocate a buffer for " + pr_err("%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); return -ENOMEM; } @@ -852,7 +852,7 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, ro = host->ops->get_ro(host); if (ro < 0) { - printk(KERN_WARNING "%s: host does not " + pr_warning("%s: host does not " "support reading read-only " "switch. assuming write-enable.\n", mmc_hostname(host)); @@ -1166,7 +1166,7 @@ int mmc_attach_sd(struct mmc_host *host) * support. */ if (ocr & 0x7F) { - printk(KERN_WARNING "%s: card claims to support voltages " + pr_warning("%s: card claims to support voltages " "below the defined range. These will be ignored.\n", mmc_hostname(host)); ocr &= ~0x7F; @@ -1174,7 +1174,7 @@ int mmc_attach_sd(struct mmc_host *host) if ((ocr & MMC_VDD_165_195) && !(host->ocr_avail_sd & MMC_VDD_165_195)) { - printk(KERN_WARNING "%s: SD card claims to support the " + pr_warning("%s: SD card claims to support the " "incompletely defined 'low voltage range'. This " "will be ignored.\n", mmc_hostname(host)); ocr &= ~MMC_VDD_165_195; @@ -1213,7 +1213,7 @@ remove_card: err: mmc_detach_bus(host); - printk(KERN_ERR "%s: error %d whilst initialising SD card\n", + pr_err("%s: error %d whilst initialising SD card\n", mmc_hostname(host), err); return err; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 698d813cff3..925bab052b0 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -112,7 +112,7 @@ static int sdio_read_cccr(struct mmc_card *card) cccr_vsn = data & 0x0f; if (cccr_vsn > SDIO_CCCR_REV_1_20) { - printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n", + pr_err("%s: unrecognised CCCR structure version %d\n", mmc_hostname(card->host), cccr_vsn); return -EINVAL; } @@ -777,7 +777,7 @@ int mmc_attach_sdio(struct mmc_host *host) * support. */ if (ocr & 0x7F) { - printk(KERN_WARNING "%s: card claims to support voltages " + pr_warning("%s: card claims to support voltages " "below the defined range. These will be ignored.\n", mmc_hostname(host)); ocr &= ~0x7F; @@ -874,7 +874,7 @@ remove: err: mmc_detach_bus(host); - printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", + pr_err("%s: error %d whilst initialising SDIO card\n", mmc_hostname(host), err); return err; diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index e4e6822d09e..c643b2f78bf 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -173,7 +173,7 @@ static int sdio_bus_remove(struct device *dev) drv->remove(func); if (func->irq_handler) { - printk(KERN_WARNING "WARNING: driver %s did not remove " + pr_warning("WARNING: driver %s did not remove " "its interrupt handler!\n", drv->name); sdio_claim_host(func); sdio_release_irq(func); diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index 541bdb89e0c..f1c7ed8f4d8 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -132,7 +132,7 @@ static int cis_tpl_parse(struct mmc_card *card, struct sdio_func *func, ret = -EINVAL; } if (ret && ret != -EILSEQ && ret != -ENOENT) { - printk(KERN_ERR "%s: bad %s tuple 0x%02x (%u bytes)\n", + pr_err("%s: bad %s tuple 0x%02x (%u bytes)\n", mmc_hostname(card->host), tpl_descr, code, size); } } else { @@ -313,7 +313,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) if (ret == -ENOENT) { /* warn about unknown tuples */ - printk(KERN_WARNING "%s: queuing unknown" + pr_warning("%s: queuing unknown" " CIS tuple 0x%02x (%u bytes)\n", mmc_hostname(card->host), tpl_code, tpl_link); diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 03ead028d2c..b644dd59c16 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -45,7 +45,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending); if (ret) { - printk(KERN_DEBUG "%s: error %d reading SDIO_CCCR_INTx\n", + pr_debug("%s: error %d reading SDIO_CCCR_INTx\n", mmc_card_id(card), ret); return ret; } @@ -55,7 +55,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) if (pending & (1 << i)) { func = card->sdio_func[i - 1]; if (!func) { - printk(KERN_WARNING "%s: pending IRQ for " + pr_warning("%s: pending IRQ for " "non-existent function\n", mmc_card_id(card)); ret = -EINVAL; @@ -63,7 +63,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) func->irq_handler(func); count++; } else { - printk(KERN_WARNING "%s: pending IRQ with no handler\n", + pr_warning("%s: pending IRQ with no handler\n", sdio_func_id(func)); ret = -EINVAL; } diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index ef72e874ca3..707bc7dddd2 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 @@ -268,7 +268,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; } @@ -1031,7 +1031,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) #ifdef CONFIG_SOC_AU1200 ret = au1xmmc_dbdma_init(host); if (ret) - printk(KERN_INFO DRIVER_NAME ": DBDMA init failed; using PIO\n"); + pr_info(DRIVER_NAME ": DBDMA init failed; using PIO\n"); #endif #ifdef CONFIG_LEDS_CLASS @@ -1056,7 +1056,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"); @@ -1188,7 +1188,7 @@ static int __init au1xmmc_init(void) */ memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev); if (!memid) - printk(KERN_ERR "au1xmmc: cannot add memory dbdma dev\n"); + pr_err("au1xmmc: cannot add memory dbdma dev\n"); #endif return platform_driver_register(&au1xmmc_driver); } diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 0ed1d28922f..701f14e8b54 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1701,7 +1701,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); diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 881f7ba545a..ea0f3cedef2 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/mmci.c b/drivers/mmc/host/mmci.c index 40e4c055812..4602771658c 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -464,7 +464,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; diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 61c7d385fd3..80d8eb143b4 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -389,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; @@ -475,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; @@ -1113,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; } @@ -1123,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); } diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index a5bf60e01af..211a4959c29 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 14aa213b00d..f48743de467 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -842,7 +842,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/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 75c63955fa7..3c900f34c13 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1264,14 +1264,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 +1422,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; diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 7257738fd7d..fc4356e00d4 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 a04f87d7ee3..d2856b6b2a6 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; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 155deb8629a..2cc3ffa7d76 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -68,51 +68,51 @@ static inline int sdhci_runtime_pm_put(struct sdhci_host *host) 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"); } /*****************************************************************************\ @@ -200,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; @@ -677,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; } @@ -972,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; @@ -994,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); @@ -1144,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; @@ -1582,7 +1582,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, 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; } @@ -1641,7 +1641,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, 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 @@ -1764,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"); @@ -1794,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; @@ -1909,9 +1909,9 @@ static void sdhci_tasklet_card(unsigned long param) /* Check host->mrq first in case we are runtime suspended */ if (host->mrq && !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { - printk(KERN_ERR "%s: Card removed during transfer!\n", + pr_err("%s: Card removed during transfer!\n", mmc_hostname(host->mmc)); - printk(KERN_ERR "%s: Resetting controller.\n", + pr_err("%s: Resetting controller.\n", mmc_hostname(host->mmc)); sdhci_reset(host, SDHCI_RESET_CMD); @@ -2000,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); @@ -2046,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); @@ -2146,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); @@ -2163,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; } @@ -2227,7 +2227,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) if (host->runtime_suspended) { spin_unlock(&host->lock); - printk(KERN_WARNING "%s: got irq while runtime suspended\n", + pr_warning("%s: got irq while runtime suspended\n", mmc_hostname(host->mmc)); return IRQ_HANDLED; } @@ -2284,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); } @@ -2297,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); @@ -2538,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); } @@ -2575,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 &= @@ -2595,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; @@ -2623,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; } @@ -2670,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; } @@ -2830,7 +2828,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; } @@ -2878,7 +2876,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; } @@ -2917,7 +2915,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); @@ -2946,7 +2944,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"); @@ -2979,7 +2977,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; @@ -3038,9 +3036,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; } diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 90c6b1b5da4..f70d04664ca 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -632,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; @@ -672,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; @@ -684,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 @@ -748,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; @@ -787,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); @@ -906,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; } @@ -932,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; } @@ -954,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_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 6275e3d76d3..d85a60cda16 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -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); diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index faf3594745f..4b83c43f950 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -1192,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 62e5a4d171e..64acd9ce141 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 -- cgit v1.2.3-18-g5258 From 326adda53a50ece492c3edaa60afc26fba5e3232 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Wed, 12 Oct 2011 13:14:29 +0900 Subject: mmc: sdhci-s3c: fix potential NULL dereference sc->clk_bus[ptr] could be NULL. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 82709b6da86..3d00e722efc 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -567,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: -- cgit v1.2.3-18-g5258 From bec8726abc72bf30d2743a722aa37cd69e7a0580 Mon Sep 17 00:00:00 2001 From: Girish K S Date: Thu, 13 Oct 2011 12:04:16 +0530 Subject: mmc: core: Add Power Off Notify Feature eMMC 4.5 This patch adds support for the power off notify feature, available in eMMC 4.5 devices. If the host has support for this feature, then the mmc core will notify the device by setting the POWER_OFF_NOTIFICATION byte in the extended csd register with a value of 1 (POWER_ON). For suspend mode short timeout is used, whereas for the normal poweroff long timeout is used. Signed-off-by: Girish K S Signed-off-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 34 ++++++++++++++++++++++++++++++++++ drivers/mmc/core/mmc.c | 23 +++++++++++++++++++++-- drivers/mmc/host/sdhci.c | 9 +++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 61d7730bc8b..a3c4e0fe943 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1212,11 +1212,43 @@ static void mmc_power_up(struct mmc_host *host) void mmc_power_off(struct mmc_host *host) { + struct mmc_card *card; + unsigned int notify_type; + unsigned int timeout; + int err; + mmc_host_clk_hold(host); + card = host->card; host->ios.clock = 0; host->ios.vdd = 0; + if (card && mmc_card_mmc(card) && + (card->poweroff_notify_state == MMC_POWERED_ON)) { + + if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) { + notify_type = EXT_CSD_POWER_OFF_SHORT; + timeout = card->ext_csd.generic_cmd6_time; + card->poweroff_notify_state = MMC_POWEROFF_SHORT; + } else { + notify_type = EXT_CSD_POWER_OFF_LONG; + timeout = card->ext_csd.power_off_longtime; + card->poweroff_notify_state = MMC_POWEROFF_LONG; + } + + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_POWER_OFF_NOTIFICATION, + notify_type, timeout); + + if (err && err != -EBADMSG) + pr_err("Device failed to respond within %d poweroff " + "time. Forcefully powering down the device\n", + timeout); + + /* Set the card state to no notification after the poweroff */ + card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION; + } + /* * Reset ocr mask to be the highest possible voltage supported for * this mmc host. This value will be used at next power up. @@ -2208,6 +2240,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, spin_lock_irqsave(&host->lock, flags); host->rescan_disable = 1; + host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT; spin_unlock_irqrestore(&host->lock, flags); cancel_delayed_work_sync(&host->detect); @@ -2231,6 +2264,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, spin_lock_irqsave(&host->lock, flags); host->rescan_disable = 0; + host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG; spin_unlock_irqrestore(&host->lock, flags); mmc_detect_change(host, 0); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 4e869d371a0..f8ea9387d75 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -458,10 +458,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) else card->erased_byte = 0x0; - if (card->ext_csd.rev >= 6) + if (card->ext_csd.rev >= 6) { card->ext_csd.generic_cmd6_time = 10 * ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; - else + card->ext_csd.power_off_longtime = 10 * + ext_csd[EXT_CSD_POWER_OFF_LONG_TIME]; + } else card->ext_csd.generic_cmd6_time = 0; out: @@ -845,6 +847,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, goto free_card; } + /* + * If the host supports the power_off_notify capability then + * set the notification byte in the ext_csd register of device + */ + if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) && + (card->poweroff_notify_state == MMC_NO_POWER_NOTIFICATION)) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_POWER_OFF_NOTIFICATION, + EXT_CSD_POWER_ON, + card->ext_csd.generic_cmd6_time); + if (err && err != -EBADMSG) + goto free_card; + } + + if (!err) + card->poweroff_notify_state = MMC_POWERED_ON; + /* * Activate high speed (if supported) */ diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2cc3ffa7d76..6d8eea32354 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2739,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; -- cgit v1.2.3-18-g5258 From e840ce134ba5c617af97a2adbedefb0a9c0bb5a7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 6 May 2011 12:14:10 +0300 Subject: mmc: omap_hsmmc: ensure pbias configuration is always done Go through the driver's set_power() functions rather than calling regulator_enable/disable() directly because otherwise pbias configuration for MMC1 is not done. Signed-off-by: Adrian Hunter Acked-by: Balaji T K Signed-off-by: Chris Ball --- drivers/mmc/host/omap_hsmmc.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 3c900f34c13..bb334be562d 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); } } -- cgit v1.2.3-18-g5258 From c43fd7746698a10aa6435d62ec28f977dd6246cc Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 17 Oct 2011 10:52:44 +0300 Subject: mmc: sdhci-pci: add flag for devices that can support runtime PM Only allow runtime PM for devices that specifically indicate that they support it. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index f49b184308c..d833d9c2f7e 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -47,6 +47,7 @@ struct sdhci_pci_slot; struct sdhci_pci_fixes { unsigned int quirks; + bool allow_runtime_pm; int (*probe) (struct sdhci_pci_chip *); @@ -72,6 +73,7 @@ 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 */ @@ -305,16 +307,19 @@ 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, }; @@ -1355,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); @@ -1381,7 +1388,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, chip->slots[i] = slot; } - sdhci_pci_runtime_pm_allow(&pdev->dev); + if (chip->allow_runtime_pm) + sdhci_pci_runtime_pm_allow(&pdev->dev); return 0; @@ -1399,11 +1407,12 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev) int i; struct sdhci_pci_chip *chip; - sdhci_pci_runtime_pm_forbid(&pdev->dev); - 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]); -- cgit v1.2.3-18-g5258 From 4e0a5adf46ee7810af2e1b7e4e8c2a298652618e Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Mon, 17 Oct 2011 19:36:23 +0900 Subject: mmc: dw_mmc: modify DATA register offset In dw_mmc 2.40a spec, Data register's offset is changed. Before we used Data register offset 0x100. but if somebody uses a 2.40a controller, we must use 0x200 for Data register. This patch adds a version-id checking point and uses SDMMC_DATA(x) instead of SDMMC_DATA. It assumes 2.40a is the latest version. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Acked-by: James Hogan Signed-off-by: Chris Ball --- drivers/mmc/host/dw_mmc.c | 66 ++++++++++++++++++++++++++++++++--------------- drivers/mmc/host/dw_mmc.h | 13 +++++++++- 2 files changed, 57 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 701f14e8b54..3aaeb084191 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1043,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; } } @@ -1060,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); } } @@ -1089,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; @@ -1100,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); } } @@ -1117,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; } } @@ -1134,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); } } @@ -1163,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; @@ -1174,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); } } @@ -1191,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; } } @@ -1208,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); } } @@ -1237,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; @@ -1248,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); } } @@ -1951,6 +1963,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 bfa3c1cd05a..72c071f6e00 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)) @@ -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) \ -- cgit v1.2.3-18-g5258 From d9ddd62943ee07a75d0428ffcf52f1a747a28c39 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 14 Oct 2011 14:15:48 +0900 Subject: mmc: core: mmc sanitize feature support for v4.5 In the v4.5, there's no secure erase & trim support. Instead it supports the sanitize feature. Signed-off-by: Kyungmin Park Signed-off-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 9 ++++++++- drivers/mmc/card/queue.c | 2 +- drivers/mmc/core/core.c | 8 ++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 049445eb4f7..e85816e1634 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -792,11 +792,18 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, unsigned int from, nr, arg; int err = 0, type = MMC_BLK_SECDISCARD; - if (!mmc_can_secure_erase_trim(card)) { + if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) { err = -EOPNOTSUPP; goto out; } + /* The sanitize operation is supported at v4.5 only */ + if (mmc_can_sanitize(card)) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_SANITIZE_START, 1, 0); + goto out; + } + from = blk_rq_pos(req); nr = blk_rq_sectors(req); diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index fed290ecc24..dcad59cbfef 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -140,7 +140,7 @@ static void mmc_queue_setup_discard(struct request_queue *q, /* granularity must not be greater than max. discard */ if (card->pref_erase > max_discard) q->limits.discard_granularity = 0; - if (mmc_can_secure_erase_trim(card)) + if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card)) queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q); } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index a3c4e0fe943..d9836e5a4e5 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1713,6 +1713,14 @@ int mmc_can_trim(struct mmc_card *card) } EXPORT_SYMBOL(mmc_can_trim); +int mmc_can_sanitize(struct mmc_card *card) +{ + if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE) + return 1; + return 0; +} +EXPORT_SYMBOL(mmc_can_sanitize); + int mmc_can_secure_erase_trim(struct mmc_card *card) { if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN) -- cgit v1.2.3-18-g5258 From b3bf915308ca2b50f3beec6cc824083870f0f4b5 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Tue, 18 Oct 2011 09:34:04 +0900 Subject: mmc: core: new discard feature support at eMMC v4.5 MMC v4.5 supports the DISCARD feature (CMD38). It's different from trim and there's no check bit. Currently it's only supported at v4.5. Signed-off-by: Kyungmin Park Signed-off-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 4 +++- drivers/mmc/core/core.c | 14 ++++++++++++++ drivers/mmc/core/mmc.c | 4 ++++ 3 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index e85816e1634..370472797ff 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -756,7 +756,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) from = blk_rq_pos(req); nr = blk_rq_sectors(req); - if (mmc_can_trim(card)) + if (mmc_can_discard(card)) + arg = MMC_DISCARD_ARG; + else if (mmc_can_trim(card)) arg = MMC_TRIM_ARG; else arg = MMC_ERASE_ARG; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index d9836e5a4e5..772de2cdfd1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1709,10 +1709,24 @@ int mmc_can_trim(struct mmc_card *card) { if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) return 1; + if (mmc_can_discard(card)) + return 1; return 0; } EXPORT_SYMBOL(mmc_can_trim); +int mmc_can_discard(struct mmc_card *card) +{ + /* + * As there's no way to detect the discard support bit at v4.5 + * use the s/w feature support filed. + */ + if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE) + return 1; + return 0; +} +EXPORT_SYMBOL(mmc_can_discard); + int mmc_can_sanitize(struct mmc_card *card) { if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index f8ea9387d75..54088768776 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -452,6 +452,10 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; } + /* eMMC v4.5 or later */ + if (card->ext_csd.rev >= 6) + card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; + card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; -- cgit v1.2.3-18-g5258 From 71fe3eb0d006861bdae57e93975b6ae3d9b55e99 Mon Sep 17 00:00:00 2001 From: Seungwon Jeon Date: Tue, 18 Oct 2011 13:20:57 +0900 Subject: mmc: core: Modify the timeout value for writing power class This patch will apply the generic CMD6 timeout to switch command for power class. Signed-off-by: Seungwon Jeon Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 54088768776..79390151920 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -663,7 +663,7 @@ static int mmc_select_powerclass(struct mmc_card *card, err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_POWER_CLASS, pwrclass_val, - 0); + card->ext_csd.generic_cmd6_time); } return err; -- cgit v1.2.3-18-g5258 From 881d1c25f765938a95def5afe39486ce39f9fc96 Mon Sep 17 00:00:00 2001 From: Seungwon Jeon Date: Fri, 14 Oct 2011 14:03:21 +0900 Subject: mmc: core: Add cache control for eMMC4.5 device This patch adds cache feature of eMMC4.5 Spec. If device supports cache capability, host can utilize some specific operations. Signed-off-by: Seungwon Jeon Signed-off-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 14 ++++++----- drivers/mmc/core/core.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/mmc.c | 23 ++++++++++++++++++ 3 files changed, 94 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 370472797ff..c0cb225bbb4 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -851,16 +851,18 @@ out: static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) { struct mmc_blk_data *md = mq->data; + struct mmc_card *card = md->queue.card; + int ret = 0; + + ret = mmc_flush_cache(card); + if (ret) + ret = -EIO; - /* - * No-op, only service this because we need REQ_FUA for reliable - * writes. - */ spin_lock_irq(&md->lock); - __blk_end_request_all(req, 0); + __blk_end_request_all(req, ret); spin_unlock_irq(&md->lock); - return 1; + return ret ? 0 : 1; } /* diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 772de2cdfd1..235bb6a1f97 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2158,6 +2158,65 @@ int mmc_card_can_sleep(struct mmc_host *host) } EXPORT_SYMBOL(mmc_card_can_sleep); +/* + * Flush the cache to the non-volatile storage. + */ +int mmc_flush_cache(struct mmc_card *card) +{ + struct mmc_host *host = card->host; + int err = 0; + + if (!(host->caps2 & MMC_CAP2_CACHE_CTRL)) + return err; + + if (mmc_card_mmc(card) && + (card->ext_csd.cache_size > 0) && + (card->ext_csd.cache_ctrl & 1)) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_FLUSH_CACHE, 1, 0); + if (err) + pr_err("%s: cache flush error %d\n", + mmc_hostname(card->host), err); + } + + return err; +} +EXPORT_SYMBOL(mmc_flush_cache); + +/* + * Turn the cache ON/OFF. + * Turning the cache OFF shall trigger flushing of the data + * to the non-volatile storage. + */ +int mmc_cache_ctrl(struct mmc_host *host, u8 enable) +{ + struct mmc_card *card = host->card; + int err = 0; + + if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) || + mmc_card_is_removable(host)) + return err; + + if (card && mmc_card_mmc(card) && + (card->ext_csd.cache_size > 0)) { + enable = !!enable; + + if (card->ext_csd.cache_ctrl ^ enable) + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_CACHE_CTRL, enable, 0); + if (err) + pr_err("%s: cache %s error %d\n", + mmc_hostname(card->host), + enable ? "on" : "off", + err); + else + card->ext_csd.cache_ctrl = enable; + } + + return err; +} +EXPORT_SYMBOL(mmc_cache_ctrl); + #ifdef CONFIG_PM /** @@ -2172,6 +2231,9 @@ int mmc_suspend_host(struct mmc_host *host) cancel_delayed_work(&host->disable); cancel_delayed_work(&host->detect); mmc_flush_scheduled_work(); + err = mmc_cache_ctrl(host, 0); + if (err) + goto out; mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { @@ -2197,6 +2259,7 @@ int mmc_suspend_host(struct mmc_host *host) if (!err && !mmc_card_keep_power(host)) mmc_power_off(host); +out: return err; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 79390151920..de5900aa81c 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -470,6 +470,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } else card->ext_csd.generic_cmd6_time = 0; + card->ext_csd.cache_size = + ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 | + ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 | + ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 | + ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24; + out: return err; } @@ -1020,6 +1026,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } } + /* + * If cache size is higher than 0, this indicates + * the existence of cache and it can be turned on. + */ + if ((host->caps2 & MMC_CAP2_CACHE_CTRL) && + card->ext_csd.cache_size > 0) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_CACHE_CTRL, 1, 0); + if (err && err != -EBADMSG) + goto free_card; + + /* + * Only if no error, cache is turned on successfully. + */ + card->ext_csd.cache_ctrl = err ? 0 : 1; + } + if (!oldcard) host->card = card; -- cgit v1.2.3-18-g5258 From eb0d8f135b6730d6d0324a064664d121334290e7 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Tue, 18 Oct 2011 01:26:42 -0400 Subject: mmc: core: support HPI send command HPI command is defined in eMMC4.41. This feature is important for eMMC4.5 devices. Signed-off-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/mmc.c | 31 +++++++++++++++++++++++++ drivers/mmc/core/mmc_ops.c | 31 +++++++++++++++++++++++++ drivers/mmc/core/mmc_ops.h | 1 + 4 files changed, 120 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 235bb6a1f97..fe65bb377e2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -379,6 +379,63 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) } EXPORT_SYMBOL(mmc_wait_for_req); +/** + * mmc_interrupt_hpi - Issue for High priority Interrupt + * @card: the MMC card associated with the HPI transfer + * + * Issued High Priority Interrupt, and check for card status + * util out-of prg-state. + */ +int mmc_interrupt_hpi(struct mmc_card *card) +{ + int err; + u32 status; + + BUG_ON(!card); + + if (!card->ext_csd.hpi_en) { + pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host)); + return 1; + } + + mmc_claim_host(card->host); + err = mmc_send_status(card, &status); + if (err) { + pr_err("%s: Get card status fail\n", mmc_hostname(card->host)); + goto out; + } + + /* + * If the card status is in PRG-state, we can send the HPI command. + */ + if (R1_CURRENT_STATE(status) == R1_STATE_PRG) { + do { + /* + * We don't know when the HPI command will finish + * processing, so we need to resend HPI until out + * of prg-state, and keep checking the card status + * with SEND_STATUS. If a timeout error occurs when + * sending the HPI command, we are already out of + * prg-state. + */ + err = mmc_send_hpi_cmd(card, &status); + if (err) + pr_debug("%s: abort HPI (%d error)\n", + mmc_hostname(card->host), err); + + err = mmc_send_status(card, &status); + if (err) + break; + } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); + } else + pr_debug("%s: Left prg-state\n", mmc_hostname(card->host)); + +out: + mmc_release_host(card->host); + return err; +} +EXPORT_SYMBOL(mmc_interrupt_hpi); + /** * mmc_wait_for_cmd - start a command and wait for completion * @host: MMC host to start command diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index de5900aa81c..fb5bf01dd1b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -448,6 +448,21 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } if (card->ext_csd.rev >= 5) { + /* check whether the eMMC card supports HPI */ + if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { + card->ext_csd.hpi = 1; + if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) + card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; + else + card->ext_csd.hpi_cmd = MMC_SEND_STATUS; + /* + * Indicate the maximum timeout to close + * a command interrupted by HPI + */ + card->ext_csd.out_of_int_time = + ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; + } + card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; } @@ -895,6 +910,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } } + /* + * Enable HPI feature (if supported) + */ + if (card->ext_csd.hpi) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HPI_MGMT, 1, 0); + if (err && err != -EBADMSG) + goto free_card; + if (err) { + pr_warning("%s: Enabling HPI failed\n", + mmc_hostname(card->host)); + err = 0; + } else + card->ext_csd.hpi_en = 1; + } + /* * Compute bus speed. */ diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 4e11d56b3f7..007863eea4f 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -547,3 +547,34 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width) err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); return err; } + +int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) +{ + struct mmc_command cmd = {0}; + unsigned int opcode; + unsigned int flags; + int err; + + opcode = card->ext_csd.hpi_cmd; + if (opcode == MMC_STOP_TRANSMISSION) + flags = MMC_RSP_R1 | MMC_CMD_AC; + else if (opcode == MMC_SEND_STATUS) + flags = MMC_RSP_R1 | MMC_CMD_AC; + + cmd.opcode = opcode; + cmd.arg = card->rca << 16 | 1; + cmd.flags = flags; + cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time; + + err = mmc_wait_for_cmd(card->host, &cmd, 0); + if (err) { + pr_warn("%s: error %d interrupting operation. " + "HPI command response %#x\n", mmc_hostname(card->host), + err, cmd.resp[0]); + return err; + } + if (status) + *status = cmd.resp[0]; + + return 0; +} diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 9276946fa5b..3dd8941c298 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -26,6 +26,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_card_sleepawake(struct mmc_host *host, int sleep); int mmc_bus_test(struct mmc_card *card, u8 bus_width); +int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); #endif -- cgit v1.2.3-18-g5258 From f2815f68dabbb373fd1c9f0fd4a609d486697c2b Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Wed, 10 Aug 2011 11:16:01 +0530 Subject: mmc: sd: Handle SD3.0 cards not supporting UHS-I bus speed mode Here is Essential conditions to indicate Version 3.00 Card (SD_SPEC=2 and SD_SPEC3=1) : (1) The card shall support CMD6 (2) The card shall support CMD8 (3) The card shall support CMD42 (4) User area capacity shall be up to 2GB (SDSC) or 32GB (SDHC) User area capacity shall be more than or equal to 32GB and up to 2TB (SDXC) (5) Speed Class shall be supported (SDHC or SDXC) So even if SD card doesn't support any of the newly defined UHS-I bus speed mode, it can advertise itself as SD3.0 cards as long as it supports all the essential conditions of SD3.0 cards. Given this, these type of cards should atleast run in High Speed mode @50MHZ if it supports HS. But current initialization sequence for SD3.0 cards is such that these non-UHS-I SD3.0 cards runs in Default Speed mode @25MHz. This patch makes sure that these non-UHS-I SD3.0 cards run in High Speed Mode @50MHz. Tested this patch with SanDisk Extreme SDHC 8GB Class 10 card. Reported-by: "Hiremath, Vaibhav" Signed-off-by: Subhash Jadavani Signed-off-by: Chris Ball --- drivers/mmc/core/sd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 25b93729413..a230e7f9d77 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -306,6 +306,9 @@ static int mmc_read_switch(struct mmc_card *card) goto out; } + if (status[13] & UHS_SDR50_BUS_SPEED) + card->sw_caps.hs_max_dtr = 50000000; + if (card->scr.sda_spec3) { card->sw_caps.sd3_bus_mode = status[13]; @@ -348,9 +351,6 @@ static int mmc_read_switch(struct mmc_card *card) } card->sw_caps.sd3_curr_limit = status[7]; - } else { - if (status[13] & 0x02) - card->sw_caps.hs_max_dtr = 50000000; } out: -- cgit v1.2.3-18-g5258 From b4625dab2c618eb87e177761dda3182b4cfaa604 Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Thu, 20 Oct 2011 19:16:32 -0700 Subject: mmc: recognise SDIO cards with SDIO_CCCR_REV 3.00 Table 6-2: CCCR bit Definitions, address 00h. Part E1 SDIO Simplified Specification Version 3.00, Feb. 25, 2011. This patch has been tested with Marvell WLAN device SD8797. Signed-off-by: Bing Zhao Signed-off-by: Chris Ball --- drivers/mmc/core/sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 925bab052b0..3ab565e32a6 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -111,7 +111,7 @@ static int sdio_read_cccr(struct mmc_card *card) cccr_vsn = data & 0x0f; - if (cccr_vsn > SDIO_CCCR_REV_1_20) { + if (cccr_vsn > SDIO_CCCR_REV_3_00) { pr_err("%s: unrecognised CCCR structure version %d\n", mmc_hostname(card->host), cccr_vsn); return -EINVAL; -- cgit v1.2.3-18-g5258 From b6ad726e3fe69e1ff3c3b2ad272ba3e4c376cd6a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 13 Oct 2011 16:03:58 +0200 Subject: mmc: core: Prevent too long response times for suspend While trying to suspend the mmc host there could still be ongoing requests that we need to wait for. At the same time a device driver must respond to a suspend request rather quickly. Instead of potentially wait "forever" by claiming the host we now "try" to claim the host instead. If it fails, -EBUSY is returned. Signed-off-by: Ulf Hansson Reviewed-by: Sujit Reddy Thumma Acked-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index fe65bb377e2..5278ffb20e7 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2294,21 +2294,33 @@ int mmc_suspend_host(struct mmc_host *host) mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { - if (host->bus_ops->suspend) - err = host->bus_ops->suspend(host); - if (err == -ENOSYS || !host->bus_ops->resume) { - /* - * We simply "remove" the card in this case. - * It will be redetected on resume. - */ - if (host->bus_ops->remove) - host->bus_ops->remove(host); - mmc_claim_host(host); - mmc_detach_bus(host); - mmc_power_off(host); - mmc_release_host(host); - host->pm_flags = 0; - err = 0; + + /* + * A long response time is not acceptable for device drivers + * when doing suspend. Prevent mmc_claim_host in the suspend + * sequence, to potentially wait "forever" by trying to + * pre-claim the host. + */ + if (mmc_try_claim_host(host)) { + if (host->bus_ops->suspend) + err = host->bus_ops->suspend(host); + if (err == -ENOSYS || !host->bus_ops->resume) { + /* + * We simply "remove" the card in this case. + * It will be redetected on resume. + */ + if (host->bus_ops->remove) + host->bus_ops->remove(host); + mmc_claim_host(host); + mmc_detach_bus(host); + mmc_power_off(host); + mmc_release_host(host); + host->pm_flags = 0; + err = 0; + } + mmc_do_release_host(host); + } else { + err = -EBUSY; } } mmc_bus_put(host); -- cgit v1.2.3-18-g5258 From 2bf22b39823c1d173dda31111a4eb2ce36daaf39 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 6 Oct 2011 14:50:33 -0600 Subject: mmc: core: add workaround for controllers with broken multiblock reads Due to hardware bugs, some MMC host controllers don't support multiple-block reads[1]. To resolve, add a new MMC capability flag, MMC_CAP2_NO_MULTI_READ, which can be set by affected host controller drivers. When this capability is set, all reads will be issued one sector at a time. 1. See for example Advisory 2.1.1.128 "MMC: Multiple Block Read Operation Issue" in _OMAP3530/3525/3515/3503 Silicon Errata_ Revision F (October 2010) (SPRZ278F), available from http://focus.ti.com/lit/er/sprz278f/sprz278f.pdf Signed-off-by: Paul Walmsley Cc: Dave Hylands Tested-by: Steve Sakoman Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c0cb225bbb4..a1cb21f9530 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1030,13 +1030,20 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, if (brq->data.blocks > card->host->max_blk_count) brq->data.blocks = card->host->max_blk_count; - /* - * After a read error, we redo the request one sector at a time - * in order to accurately determine which sectors can be read - * successfully. - */ - if (disable_multi && brq->data.blocks > 1) - brq->data.blocks = 1; + if (brq->data.blocks > 1) { + /* + * After a read error, we redo the request one sector + * at a time in order to accurately determine which + * sectors can be read successfully. + */ + if (disable_multi) + brq->data.blocks = 1; + + /* Some controllers can't do multiblock reads due to hw bugs */ + if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ && + rq_data_dir(req) == READ) + brq->data.blocks = 1; + } if (brq->data.blocks > 1 || do_rel_wr) { /* SPI multiblock writes terminate using a special -- cgit v1.2.3-18-g5258 From 9b68256cdef75204aa8a4583aa79dd7c081796b3 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 6 Oct 2011 14:50:35 -0600 Subject: mmc: omap_hsmmc: if multiblock reads are broken, disable them When device data indicates that multiple block reads are not supported on a given HSMMC controller instance, log a message to the console, and pass the appropriate MMC capability flag to the MMC core. Signed-off-by: Paul Walmsley Cc: Dave Hylands Tested-by: Steve Sakoman Signed-off-by: Chris Ball --- drivers/mmc/host/omap_hsmmc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index bb334be562d..e8ff1239668 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1942,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); -- cgit v1.2.3-18-g5258 From 336c716ae2272c9a26a6f82976d0e077d8ca824e Mon Sep 17 00:00:00 2001 From: Seungwon Jeon Date: Tue, 25 Oct 2011 09:43:12 +0900 Subject: mmc: core: Cleanup eMMC4.5 conditionals Code cleanup, putting all eMMC 4.5 detection cases together. This patch removes one if-statement and assembles all. And it also removes variable initialization below else-statement -- all members of card structure are already set to zero at card-init. Signed-off-by: Seungwon Jeon Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index fb5bf01dd1b..36270449dd9 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -467,29 +467,27 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; } - /* eMMC v4.5 or later */ - if (card->ext_csd.rev >= 6) - card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; - card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; else card->erased_byte = 0x0; + /* eMMC v4.5 or later */ if (card->ext_csd.rev >= 6) { + card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; + card->ext_csd.generic_cmd6_time = 10 * ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; card->ext_csd.power_off_longtime = 10 * ext_csd[EXT_CSD_POWER_OFF_LONG_TIME]; - } else - card->ext_csd.generic_cmd6_time = 0; - card->ext_csd.cache_size = - ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 | - ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 | - ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 | - ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24; + card->ext_csd.cache_size = + ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 | + ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 | + ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 | + ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24; + } out: return err; -- cgit v1.2.3-18-g5258