2006-10-04 13:15:37 +04:00
/*
* tifm_sd . c - TI FlashMedia driver
*
* Copyright ( C ) 2006 Alex Dubov < oakad @ yahoo . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
2007-04-12 11:05:26 +04:00
* Special thanks to Brad Campbell for extensive testing of this driver .
*
2006-10-04 13:15:37 +04:00
*/
# include <linux/tifm.h>
# include <linux/mmc/host.h>
# include <linux/highmem.h>
2007-04-12 11:05:25 +04:00
# include <linux/scatterlist.h>
2011-07-03 23:15:51 +04:00
# include <linux/module.h>
2006-10-24 14:17:06 +04:00
# include <asm/io.h>
2006-10-04 13:15:37 +04:00
# define DRIVER_NAME "tifm_sd"
2007-04-12 10:59:12 +04:00
# define DRIVER_VERSION "0.8"
2006-10-04 13:15:37 +04:00
2012-01-13 03:02:20 +04:00
static bool no_dma = 0 ;
static bool fixed_timeout = 0 ;
2006-10-04 13:15:37 +04:00
module_param ( no_dma , bool , 0644 ) ;
module_param ( fixed_timeout , bool , 0644 ) ;
/* Constants here are mostly from OMAP5912 datasheet */
# define TIFM_MMCSD_RESET 0x0002
# define TIFM_MMCSD_CLKMASK 0x03ff
# define TIFM_MMCSD_POWER 0x0800
# define TIFM_MMCSD_4BBUS 0x8000
# define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */
# define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */
# define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */
# define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */
# define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */
# define TIFM_MMCSD_READ 0x8000
2007-02-11 08:16:40 +03:00
# define TIFM_MMCSD_ERRMASK 0x01e0 /* set bits: CCRC, CTO, DCRC, DTO */
2006-10-04 13:15:37 +04:00
# define TIFM_MMCSD_EOC 0x0001 /* end of command phase */
2007-04-12 11:05:26 +04:00
# define TIFM_MMCSD_CD 0x0002 /* card detect */
2006-10-04 13:15:37 +04:00
# define TIFM_MMCSD_CB 0x0004 /* card enter busy state */
# define TIFM_MMCSD_BRS 0x0008 /* block received/sent */
# define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */
# define TIFM_MMCSD_DTO 0x0020 /* data time-out */
# define TIFM_MMCSD_DCRC 0x0040 /* data crc error */
# define TIFM_MMCSD_CTO 0x0080 /* command time-out */
# define TIFM_MMCSD_CCRC 0x0100 /* command crc error */
# define TIFM_MMCSD_AF 0x0400 /* fifo almost full */
# define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */
2007-04-12 11:05:26 +04:00
# define TIFM_MMCSD_OCRB 0x1000 /* OCR busy */
# define TIFM_MMCSD_CIRQ 0x2000 /* card irq (cmd40/sdio) */
2006-10-04 13:15:37 +04:00
# define TIFM_MMCSD_CERR 0x4000 /* card status error */
2007-04-12 10:59:23 +04:00
# define TIFM_MMCSD_ODTO 0x0040 /* open drain / extended timeout */
# define TIFM_MMCSD_CARD_RO 0x0200 /* card is read-only */
2006-10-04 13:15:37 +04:00
# define TIFM_MMCSD_FIFO_SIZE 0x0020
# define TIFM_MMCSD_RSP_R0 0x0000
# define TIFM_MMCSD_RSP_R1 0x0100
# define TIFM_MMCSD_RSP_R2 0x0200
# define TIFM_MMCSD_RSP_R3 0x0300
# define TIFM_MMCSD_RSP_R4 0x0400
# define TIFM_MMCSD_RSP_R5 0x0500
# define TIFM_MMCSD_RSP_R6 0x0600
# define TIFM_MMCSD_RSP_BUSY 0x0800
# define TIFM_MMCSD_CMD_BC 0x0000
# define TIFM_MMCSD_CMD_BCR 0x1000
# define TIFM_MMCSD_CMD_AC 0x2000
# define TIFM_MMCSD_CMD_ADTC 0x3000
2007-04-12 11:05:25 +04:00
# define TIFM_MMCSD_MAX_BLOCK_SIZE 0x0800UL
2006-10-04 13:15:37 +04:00
enum {
2007-04-12 11:05:23 +04:00
CMD_READY = 0x0001 ,
FIFO_READY = 0x0002 ,
BRS_READY = 0x0004 ,
SCMD_ACTIVE = 0x0008 ,
SCMD_READY = 0x0010 ,
CARD_BUSY = 0x0020 ,
DATA_CARRY = 0x0040
2007-04-12 10:59:23 +04:00
} ;
2006-10-04 13:15:37 +04:00
struct tifm_sd {
2007-04-12 11:05:26 +04:00
struct tifm_dev * dev ;
2006-10-04 13:15:37 +04:00
2007-04-12 11:05:26 +04:00
unsigned short eject : 1 ,
open_drain : 1 ,
no_dma : 1 ;
unsigned short cmd_flags ;
2007-04-12 11:05:23 +04:00
2007-04-12 11:05:26 +04:00
unsigned int clk_freq ;
unsigned int clk_div ;
unsigned long timeout_jiffies ;
2006-10-04 13:15:37 +04:00
2006-12-08 08:50:51 +03:00
struct tasklet_struct finish_tasklet ;
2006-12-08 08:50:49 +03:00
struct timer_list timer ;
2006-10-04 13:15:37 +04:00
struct mmc_request * req ;
2007-04-12 11:05:25 +04:00
int sg_len ;
int sg_pos ;
unsigned int block_pos ;
struct scatterlist bounce_buf ;
unsigned char bounce_buf_data [ TIFM_MMCSD_MAX_BLOCK_SIZE ] ;
2006-10-04 13:15:37 +04:00
} ;
2007-04-12 11:05:25 +04:00
/* for some reason, host won't respond correctly to readw/writew */
static void tifm_sd_read_fifo ( struct tifm_sd * host , struct page * pg ,
unsigned int off , unsigned int cnt )
2006-12-08 08:50:48 +03:00
{
2007-04-12 11:05:25 +04:00
struct tifm_dev * sock = host - > dev ;
unsigned char * buf ;
unsigned int pos = 0 , val ;
2011-11-27 09:27:00 +04:00
buf = kmap_atomic ( pg ) + off ;
2007-04-12 11:05:25 +04:00
if ( host - > cmd_flags & DATA_CARRY ) {
buf [ pos + + ] = host - > bounce_buf_data [ 0 ] ;
host - > cmd_flags & = ~ DATA_CARRY ;
}
while ( pos < cnt ) {
val = readl ( sock - > addr + SOCK_MMCSD_DATA ) ;
buf [ pos + + ] = val & 0xff ;
if ( pos = = cnt ) {
host - > bounce_buf_data [ 0 ] = ( val > > 8 ) & 0xff ;
host - > cmd_flags | = DATA_CARRY ;
break ;
}
buf [ pos + + ] = ( val > > 8 ) & 0xff ;
}
2011-11-27 09:27:00 +04:00
kunmap_atomic ( buf - off ) ;
2006-12-08 08:50:48 +03:00
}
2007-04-12 11:05:25 +04:00
static void tifm_sd_write_fifo ( struct tifm_sd * host , struct page * pg ,
unsigned int off , unsigned int cnt )
2006-10-04 13:15:37 +04:00
{
2007-04-12 11:05:25 +04:00
struct tifm_dev * sock = host - > dev ;
unsigned char * buf ;
unsigned int pos = 0 , val ;
2011-11-27 09:27:00 +04:00
buf = kmap_atomic ( pg ) + off ;
2007-04-12 11:05:25 +04:00
if ( host - > cmd_flags & DATA_CARRY ) {
val = host - > bounce_buf_data [ 0 ] | ( ( buf [ pos + + ] < < 8 ) & 0xff00 ) ;
writel ( val , sock - > addr + SOCK_MMCSD_DATA ) ;
host - > cmd_flags & = ~ DATA_CARRY ;
}
while ( pos < cnt ) {
val = buf [ pos + + ] ;
if ( pos = = cnt ) {
host - > bounce_buf_data [ 0 ] = val & 0xff ;
host - > cmd_flags | = DATA_CARRY ;
break ;
2006-10-04 13:15:37 +04:00
}
2007-04-12 11:05:25 +04:00
val | = ( buf [ pos + + ] < < 8 ) & 0xff00 ;
writel ( val , sock - > addr + SOCK_MMCSD_DATA ) ;
}
2011-11-27 09:27:00 +04:00
kunmap_atomic ( buf - off ) ;
2007-04-12 11:05:25 +04:00
}
static void tifm_sd_transfer_data ( struct tifm_sd * host )
{
struct mmc_data * r_data = host - > req - > cmd - > data ;
struct scatterlist * sg = r_data - > sg ;
unsigned int off , cnt , t_size = TIFM_MMCSD_FIFO_SIZE * 2 ;
unsigned int p_off , p_cnt ;
struct page * pg ;
if ( host - > sg_pos = = host - > sg_len )
return ;
while ( t_size ) {
cnt = sg [ host - > sg_pos ] . length - host - > block_pos ;
if ( ! cnt ) {
host - > block_pos = 0 ;
host - > sg_pos + + ;
if ( host - > sg_pos = = host - > sg_len ) {
if ( ( r_data - > flags & MMC_DATA_WRITE )
2008-03-15 18:00:38 +03:00
& & ( host - > cmd_flags & DATA_CARRY ) )
2007-04-12 11:05:25 +04:00
writel ( host - > bounce_buf_data [ 0 ] ,
host - > dev - > addr
+ SOCK_MMCSD_DATA ) ;
return ;
2006-10-04 13:15:37 +04:00
}
2007-04-12 11:05:25 +04:00
cnt = sg [ host - > sg_pos ] . length ;
2006-10-04 13:15:37 +04:00
}
2007-04-12 11:05:25 +04:00
off = sg [ host - > sg_pos ] . offset + host - > block_pos ;
2007-10-22 23:19:53 +04:00
pg = nth_page ( sg_page ( & sg [ host - > sg_pos ] ) , off > > PAGE_SHIFT ) ;
2007-04-12 11:05:25 +04:00
p_off = offset_in_page ( off ) ;
p_cnt = PAGE_SIZE - p_off ;
p_cnt = min ( p_cnt , cnt ) ;
p_cnt = min ( p_cnt , t_size ) ;
if ( r_data - > flags & MMC_DATA_READ )
tifm_sd_read_fifo ( host , pg , p_off , p_cnt ) ;
else if ( r_data - > flags & MMC_DATA_WRITE )
tifm_sd_write_fifo ( host , pg , p_off , p_cnt ) ;
t_size - = p_cnt ;
host - > block_pos + = p_cnt ;
2006-10-04 13:15:37 +04:00
}
2007-04-12 11:05:25 +04:00
}
static void tifm_sd_copy_page ( struct page * dst , unsigned int dst_off ,
struct page * src , unsigned int src_off ,
unsigned int count )
{
2011-11-27 09:27:00 +04:00
unsigned char * src_buf = kmap_atomic ( src ) + src_off ;
unsigned char * dst_buf = kmap_atomic ( dst ) + dst_off ;
2007-04-12 11:05:25 +04:00
memcpy ( dst_buf , src_buf , count ) ;
2011-11-27 09:27:00 +04:00
kunmap_atomic ( dst_buf - dst_off ) ;
kunmap_atomic ( src_buf - src_off ) ;
2007-04-12 11:05:25 +04:00
}
static void tifm_sd_bounce_block ( struct tifm_sd * host , struct mmc_data * r_data )
{
struct scatterlist * sg = r_data - > sg ;
unsigned int t_size = r_data - > blksz ;
unsigned int off , cnt ;
unsigned int p_off , p_cnt ;
struct page * pg ;
dev_dbg ( & host - > dev - > dev , " bouncing block \n " ) ;
while ( t_size ) {
cnt = sg [ host - > sg_pos ] . length - host - > block_pos ;
if ( ! cnt ) {
host - > block_pos = 0 ;
host - > sg_pos + + ;
if ( host - > sg_pos = = host - > sg_len )
return ;
cnt = sg [ host - > sg_pos ] . length ;
}
off = sg [ host - > sg_pos ] . offset + host - > block_pos ;
2007-10-22 23:19:53 +04:00
pg = nth_page ( sg_page ( & sg [ host - > sg_pos ] ) , off > > PAGE_SHIFT ) ;
2007-04-12 11:05:25 +04:00
p_off = offset_in_page ( off ) ;
p_cnt = PAGE_SIZE - p_off ;
p_cnt = min ( p_cnt , cnt ) ;
p_cnt = min ( p_cnt , t_size ) ;
if ( r_data - > flags & MMC_DATA_WRITE )
2007-10-22 23:19:53 +04:00
tifm_sd_copy_page ( sg_page ( & host - > bounce_buf ) ,
2007-04-12 11:05:25 +04:00
r_data - > blksz - t_size ,
pg , p_off , p_cnt ) ;
else if ( r_data - > flags & MMC_DATA_READ )
2007-10-22 23:19:53 +04:00
tifm_sd_copy_page ( pg , p_off , sg_page ( & host - > bounce_buf ) ,
2007-04-12 11:05:25 +04:00
r_data - > blksz - t_size , p_cnt ) ;
t_size - = p_cnt ;
host - > block_pos + = p_cnt ;
}
}
2007-05-01 18:14:29 +04:00
static int tifm_sd_set_dma_data ( struct tifm_sd * host , struct mmc_data * r_data )
2007-04-12 11:05:25 +04:00
{
struct tifm_dev * sock = host - > dev ;
unsigned int t_size = TIFM_DMA_TSIZE * r_data - > blksz ;
unsigned int dma_len , dma_blk_cnt , dma_off ;
struct scatterlist * sg = NULL ;
unsigned long flags ;
if ( host - > sg_pos = = host - > sg_len )
return 1 ;
if ( host - > cmd_flags & DATA_CARRY ) {
host - > cmd_flags & = ~ DATA_CARRY ;
local_irq_save ( flags ) ;
tifm_sd_bounce_block ( host , r_data ) ;
local_irq_restore ( flags ) ;
if ( host - > sg_pos = = host - > sg_len )
return 1 ;
}
dma_len = sg_dma_len ( & r_data - > sg [ host - > sg_pos ] ) - host - > block_pos ;
if ( ! dma_len ) {
host - > block_pos = 0 ;
host - > sg_pos + + ;
if ( host - > sg_pos = = host - > sg_len )
return 1 ;
dma_len = sg_dma_len ( & r_data - > sg [ host - > sg_pos ] ) ;
}
if ( dma_len < t_size ) {
dma_blk_cnt = dma_len / r_data - > blksz ;
dma_off = host - > block_pos ;
host - > block_pos + = dma_blk_cnt * r_data - > blksz ;
} else {
dma_blk_cnt = TIFM_DMA_TSIZE ;
dma_off = host - > block_pos ;
host - > block_pos + = t_size ;
}
if ( dma_blk_cnt )
sg = & r_data - > sg [ host - > sg_pos ] ;
else if ( dma_len ) {
if ( r_data - > flags & MMC_DATA_WRITE ) {
local_irq_save ( flags ) ;
tifm_sd_bounce_block ( host , r_data ) ;
local_irq_restore ( flags ) ;
} else
host - > cmd_flags | = DATA_CARRY ;
sg = & host - > bounce_buf ;
dma_off = 0 ;
dma_blk_cnt = 1 ;
} else
return 1 ;
dev_dbg ( & sock - > dev , " setting dma for %d blocks \n " , dma_blk_cnt ) ;
writel ( sg_dma_address ( sg ) + dma_off , sock - > addr + SOCK_DMA_ADDRESS ) ;
if ( r_data - > flags & MMC_DATA_WRITE )
writel ( ( dma_blk_cnt < < 8 ) | TIFM_DMA_TX | TIFM_DMA_EN ,
sock - > addr + SOCK_DMA_CONTROL ) ;
else
writel ( ( dma_blk_cnt < < 8 ) | TIFM_DMA_EN ,
sock - > addr + SOCK_DMA_CONTROL ) ;
2006-10-04 13:15:37 +04:00
return 0 ;
}
static unsigned int tifm_sd_op_flags ( struct mmc_command * cmd )
{
unsigned int rc = 0 ;
switch ( mmc_resp_type ( cmd ) ) {
case MMC_RSP_NONE :
rc | = TIFM_MMCSD_RSP_R0 ;
break ;
case MMC_RSP_R1B :
rc | = TIFM_MMCSD_RSP_BUSY ; // deliberate fall-through
case MMC_RSP_R1 :
rc | = TIFM_MMCSD_RSP_R1 ;
break ;
case MMC_RSP_R2 :
rc | = TIFM_MMCSD_RSP_R2 ;
break ;
case MMC_RSP_R3 :
rc | = TIFM_MMCSD_RSP_R3 ;
break ;
default :
BUG ( ) ;
}
switch ( mmc_cmd_type ( cmd ) ) {
case MMC_CMD_BC :
rc | = TIFM_MMCSD_CMD_BC ;
break ;
case MMC_CMD_BCR :
rc | = TIFM_MMCSD_CMD_BCR ;
break ;
case MMC_CMD_AC :
rc | = TIFM_MMCSD_CMD_AC ;
break ;
case MMC_CMD_ADTC :
rc | = TIFM_MMCSD_CMD_ADTC ;
break ;
default :
BUG ( ) ;
}
return rc ;
}
static void tifm_sd_exec ( struct tifm_sd * host , struct mmc_command * cmd )
{
struct tifm_dev * sock = host - > dev ;
2007-04-12 10:59:23 +04:00
unsigned int cmd_mask = tifm_sd_op_flags ( cmd ) ;
if ( host - > open_drain )
cmd_mask | = TIFM_MMCSD_ODTO ;
2006-10-04 13:15:37 +04:00
if ( cmd - > data & & ( cmd - > data - > flags & MMC_DATA_READ ) )
cmd_mask | = TIFM_MMCSD_READ ;
dev_dbg ( & sock - > dev , " executing opcode 0x%x, arg: 0x%x, mask: 0x%x \n " ,
2006-12-08 08:50:52 +03:00
cmd - > opcode , cmd - > arg , cmd_mask ) ;
2006-10-04 13:15:37 +04:00
writel ( ( cmd - > arg > > 16 ) & 0xffff , sock - > addr + SOCK_MMCSD_ARG_HIGH ) ;
writel ( cmd - > arg & 0xffff , sock - > addr + SOCK_MMCSD_ARG_LOW ) ;
writel ( cmd - > opcode | cmd_mask , sock - > addr + SOCK_MMCSD_COMMAND ) ;
}
static void tifm_sd_fetch_resp ( struct mmc_command * cmd , struct tifm_dev * sock )
{
cmd - > resp [ 0 ] = ( readl ( sock - > addr + SOCK_MMCSD_RESPONSE + 0x1c ) < < 16 )
| readl ( sock - > addr + SOCK_MMCSD_RESPONSE + 0x18 ) ;
cmd - > resp [ 1 ] = ( readl ( sock - > addr + SOCK_MMCSD_RESPONSE + 0x14 ) < < 16 )
| readl ( sock - > addr + SOCK_MMCSD_RESPONSE + 0x10 ) ;
cmd - > resp [ 2 ] = ( readl ( sock - > addr + SOCK_MMCSD_RESPONSE + 0x0c ) < < 16 )
| readl ( sock - > addr + SOCK_MMCSD_RESPONSE + 0x08 ) ;
cmd - > resp [ 3 ] = ( readl ( sock - > addr + SOCK_MMCSD_RESPONSE + 0x04 ) < < 16 )
| readl ( sock - > addr + SOCK_MMCSD_RESPONSE + 0x00 ) ;
}
2007-04-12 11:05:23 +04:00
static void tifm_sd_check_status ( struct tifm_sd * host )
2006-10-04 13:15:37 +04:00
{
2007-04-12 11:05:23 +04:00
struct tifm_dev * sock = host - > dev ;
2006-10-04 13:15:37 +04:00
struct mmc_command * cmd = host - > req - > cmd ;
2007-07-23 00:18:46 +04:00
if ( cmd - > error )
2007-04-12 11:05:23 +04:00
goto finish_request ;
if ( ! ( host - > cmd_flags & CMD_READY ) )
2006-10-04 13:15:37 +04:00
return ;
2007-04-12 11:05:23 +04:00
if ( cmd - > data ) {
2007-07-23 00:18:46 +04:00
if ( cmd - > data - > error ) {
2007-04-12 11:05:23 +04:00
if ( ( host - > cmd_flags & SCMD_ACTIVE )
& & ! ( host - > cmd_flags & SCMD_READY ) )
return ;
goto finish_request ;
2006-10-04 13:15:37 +04:00
}
2007-04-12 11:05:23 +04:00
if ( ! ( host - > cmd_flags & BRS_READY ) )
return ;
if ( ! ( host - > no_dma | | ( host - > cmd_flags & FIFO_READY ) ) )
return ;
if ( cmd - > data - > flags & MMC_DATA_WRITE ) {
if ( host - > req - > stop ) {
if ( ! ( host - > cmd_flags & SCMD_ACTIVE ) ) {
host - > cmd_flags | = SCMD_ACTIVE ;
writel ( TIFM_MMCSD_EOFB
| readl ( sock - > addr
+ SOCK_MMCSD_INT_ENABLE ) ,
sock - > addr
+ SOCK_MMCSD_INT_ENABLE ) ;
2006-12-08 08:50:47 +03:00
tifm_sd_exec ( host , host - > req - > stop ) ;
2007-04-12 11:05:23 +04:00
return ;
2006-12-08 08:50:47 +03:00
} else {
2007-04-12 11:05:23 +04:00
if ( ! ( host - > cmd_flags & SCMD_READY )
| | ( host - > cmd_flags & CARD_BUSY ) )
return ;
writel ( ( ~ TIFM_MMCSD_EOFB )
& readl ( sock - > addr
+ SOCK_MMCSD_INT_ENABLE ) ,
sock - > addr
+ SOCK_MMCSD_INT_ENABLE ) ;
2006-12-08 08:50:47 +03:00
}
} else {
2007-04-12 11:05:23 +04:00
if ( host - > cmd_flags & CARD_BUSY )
return ;
writel ( ( ~ TIFM_MMCSD_EOFB )
& readl ( sock - > addr
+ SOCK_MMCSD_INT_ENABLE ) ,
sock - > addr + SOCK_MMCSD_INT_ENABLE ) ;
2006-12-08 08:50:47 +03:00
}
2007-04-12 11:05:23 +04:00
} else {
2006-12-08 08:50:47 +03:00
if ( host - > req - > stop ) {
2007-04-12 11:05:23 +04:00
if ( ! ( host - > cmd_flags & SCMD_ACTIVE ) ) {
host - > cmd_flags | = SCMD_ACTIVE ;
tifm_sd_exec ( host , host - > req - > stop ) ;
return ;
} else {
if ( ! ( host - > cmd_flags & SCMD_READY ) )
return ;
}
2006-12-08 08:50:47 +03:00
}
2006-10-04 13:15:37 +04:00
}
}
2007-04-12 11:05:23 +04:00
finish_request :
tasklet_schedule ( & host - > finish_tasklet ) ;
2006-10-04 13:15:37 +04:00
}
/* Called from interrupt handler */
2007-04-12 10:59:12 +04:00
static void tifm_sd_data_event ( struct tifm_dev * sock )
2006-10-04 13:15:37 +04:00
{
struct tifm_sd * host ;
2007-04-12 10:59:12 +04:00
unsigned int fifo_status = 0 ;
2007-04-12 11:05:23 +04:00
struct mmc_data * r_data = NULL ;
2006-10-04 13:15:37 +04:00
spin_lock ( & sock - > lock ) ;
host = mmc_priv ( ( struct mmc_host * ) tifm_get_drvdata ( sock ) ) ;
2007-04-12 10:59:12 +04:00
fifo_status = readl ( sock - > addr + SOCK_DMA_FIFO_STATUS ) ;
2007-04-12 11:05:23 +04:00
dev_dbg ( & sock - > dev , " data event: fifo_status %x, flags %x \n " ,
fifo_status , host - > cmd_flags ) ;
2007-04-12 10:59:12 +04:00
2007-04-12 11:05:23 +04:00
if ( host - > req ) {
r_data = host - > req - > cmd - > data ;
2007-04-12 10:59:12 +04:00
2007-04-12 11:05:23 +04:00
if ( r_data & & ( fifo_status & TIFM_FIFO_READY ) ) {
2007-04-12 11:05:25 +04:00
if ( tifm_sd_set_dma_data ( host , r_data ) ) {
host - > cmd_flags | = FIFO_READY ;
tifm_sd_check_status ( host ) ;
}
2007-04-12 11:05:23 +04:00
}
}
2007-04-12 10:59:12 +04:00
2007-04-12 11:05:23 +04:00
writel ( fifo_status , sock - > addr + SOCK_DMA_FIFO_STATUS ) ;
2007-04-12 10:59:12 +04:00
spin_unlock ( & sock - > lock ) ;
}
/* Called from interrupt handler */
static void tifm_sd_card_event ( struct tifm_dev * sock )
{
struct tifm_sd * host ;
unsigned int host_status = 0 ;
2007-07-23 00:18:46 +04:00
int cmd_error = 0 ;
2007-04-12 11:05:23 +04:00
struct mmc_command * cmd = NULL ;
unsigned long flags ;
2007-04-12 10:59:12 +04:00
spin_lock ( & sock - > lock ) ;
host = mmc_priv ( ( struct mmc_host * ) tifm_get_drvdata ( sock ) ) ;
2007-04-12 11:05:23 +04:00
host_status = readl ( sock - > addr + SOCK_MMCSD_STATUS ) ;
dev_dbg ( & sock - > dev , " host event: host_status %x, flags %x \n " ,
host_status , host - > cmd_flags ) ;
2006-10-04 13:15:37 +04:00
2007-04-12 11:05:23 +04:00
if ( host - > req ) {
cmd = host - > req - > cmd ;
2006-10-04 13:15:37 +04:00
if ( host_status & TIFM_MMCSD_ERRMASK ) {
2007-04-12 11:05:23 +04:00
writel ( host_status & TIFM_MMCSD_ERRMASK ,
sock - > addr + SOCK_MMCSD_STATUS ) ;
if ( host_status & TIFM_MMCSD_CTO )
2007-07-23 00:18:46 +04:00
cmd_error = - ETIMEDOUT ;
2007-04-12 11:05:23 +04:00
else if ( host_status & TIFM_MMCSD_CCRC )
2007-07-23 00:18:46 +04:00
cmd_error = - EILSEQ ;
2007-04-12 11:05:23 +04:00
if ( cmd - > data ) {
if ( host_status & TIFM_MMCSD_DTO )
2007-07-23 00:18:46 +04:00
cmd - > data - > error = - ETIMEDOUT ;
2007-04-12 11:05:23 +04:00
else if ( host_status & TIFM_MMCSD_DCRC )
2007-07-23 00:18:46 +04:00
cmd - > data - > error = - EILSEQ ;
2007-04-12 11:05:23 +04:00
}
2006-10-04 13:15:37 +04:00
writel ( TIFM_FIFO_INT_SETALL ,
sock - > addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR ) ;
writel ( TIFM_DMA_RESET , sock - > addr + SOCK_DMA_CONTROL ) ;
if ( host - > req - > stop ) {
2007-04-12 11:05:23 +04:00
if ( host - > cmd_flags & SCMD_ACTIVE ) {
host - > req - > stop - > error = cmd_error ;
host - > cmd_flags | = SCMD_READY ;
} else {
cmd - > error = cmd_error ;
host - > cmd_flags | = SCMD_ACTIVE ;
2006-10-04 13:15:37 +04:00
tifm_sd_exec ( host , host - > req - > stop ) ;
goto done ;
}
2007-04-12 11:05:23 +04:00
} else
cmd - > error = cmd_error ;
} else {
if ( host_status & ( TIFM_MMCSD_EOC | TIFM_MMCSD_CERR ) ) {
if ( ! ( host - > cmd_flags & CMD_READY ) ) {
host - > cmd_flags | = CMD_READY ;
tifm_sd_fetch_resp ( cmd , sock ) ;
} else if ( host - > cmd_flags & SCMD_ACTIVE ) {
host - > cmd_flags | = SCMD_READY ;
tifm_sd_fetch_resp ( host - > req - > stop ,
sock ) ;
}
2006-10-04 13:15:37 +04:00
}
2007-04-12 11:05:23 +04:00
if ( host_status & TIFM_MMCSD_BRS )
host - > cmd_flags | = BRS_READY ;
2006-10-04 13:15:37 +04:00
}
2007-04-12 11:05:23 +04:00
if ( host - > no_dma & & cmd - > data ) {
if ( host_status & TIFM_MMCSD_AE )
writel ( host_status & TIFM_MMCSD_AE ,
sock - > addr + SOCK_MMCSD_STATUS ) ;
if ( host_status & ( TIFM_MMCSD_AE | TIFM_MMCSD_AF
| TIFM_MMCSD_BRS ) ) {
local_irq_save ( flags ) ;
2007-04-12 11:05:25 +04:00
tifm_sd_transfer_data ( host ) ;
2007-04-12 11:05:23 +04:00
local_irq_restore ( flags ) ;
host_status & = ~ TIFM_MMCSD_AE ;
}
2006-10-04 13:15:37 +04:00
}
2007-04-12 11:05:23 +04:00
if ( host_status & TIFM_MMCSD_EOFB )
host - > cmd_flags & = ~ CARD_BUSY ;
else if ( host_status & TIFM_MMCSD_CB )
host - > cmd_flags | = CARD_BUSY ;
tifm_sd_check_status ( host ) ;
}
2006-10-04 13:15:37 +04:00
done :
2007-04-12 11:05:23 +04:00
writel ( host_status , sock - > addr + SOCK_MMCSD_STATUS ) ;
2006-10-04 13:15:37 +04:00
spin_unlock ( & sock - > lock ) ;
}
static void tifm_sd_set_data_timeout ( struct tifm_sd * host ,
2006-12-08 08:50:52 +03:00
struct mmc_data * data )
2006-10-04 13:15:37 +04:00
{
struct tifm_dev * sock = host - > dev ;
unsigned int data_timeout = data - > timeout_clks ;
if ( fixed_timeout )
return ;
data_timeout + = data - > timeout_ns /
2006-12-08 08:50:50 +03:00
( ( 1000000000UL / host - > clk_freq ) * host - > clk_div ) ;
2006-10-04 13:15:37 +04:00
if ( data_timeout < 0xffff ) {
writel ( data_timeout , sock - > addr + SOCK_MMCSD_DATA_TO ) ;
2006-12-08 08:50:50 +03:00
writel ( ( ~ TIFM_MMCSD_DPE )
& readl ( sock - > addr + SOCK_MMCSD_SDIO_MODE_CONFIG ) ,
sock - > addr + SOCK_MMCSD_SDIO_MODE_CONFIG ) ;
2006-10-04 13:15:37 +04:00
} else {
data_timeout = ( data_timeout > > 10 ) + 1 ;
2006-12-08 08:50:52 +03:00
if ( data_timeout > 0xffff )
2006-10-04 13:15:37 +04:00
data_timeout = 0 ; /* set to unlimited */
writel ( data_timeout , sock - > addr + SOCK_MMCSD_DATA_TO ) ;
2006-12-08 08:50:50 +03:00
writel ( TIFM_MMCSD_DPE
| readl ( sock - > addr + SOCK_MMCSD_SDIO_MODE_CONFIG ) ,
sock - > addr + SOCK_MMCSD_SDIO_MODE_CONFIG ) ;
2006-10-04 13:15:37 +04:00
}
}
static void tifm_sd_request ( struct mmc_host * mmc , struct mmc_request * mrq )
{
struct tifm_sd * host = mmc_priv ( mmc ) ;
struct tifm_dev * sock = host - > dev ;
unsigned long flags ;
struct mmc_data * r_data = mrq - > cmd - > data ;
spin_lock_irqsave ( & sock - > lock , flags ) ;
2007-04-12 10:59:23 +04:00
if ( host - > eject ) {
2007-07-24 22:38:53 +04:00
mrq - > cmd - > error = - ENOMEDIUM ;
2006-10-04 13:15:37 +04:00
goto err_out ;
}
if ( host - > req ) {
2011-10-11 10:14:09 +04:00
pr_err ( " %s : unfinished request detected \n " ,
2008-11-08 23:37:46 +03:00
dev_name ( & sock - > dev ) ) ;
2007-07-24 22:38:53 +04:00
mrq - > cmd - > error = - ETIMEDOUT ;
goto err_out ;
}
2007-04-12 11:05:25 +04:00
host - > cmd_flags = 0 ;
host - > block_pos = 0 ;
host - > sg_pos = 0 ;
2007-11-14 15:55:36 +03:00
if ( mrq - > data & & ! is_power_of_2 ( mrq - > data - > blksz ) )
host - > no_dma = 1 ;
else
host - > no_dma = no_dma ? 1 : 0 ;
2006-10-04 13:15:37 +04:00
if ( r_data ) {
tifm_sd_set_data_timeout ( host , r_data ) ;
2007-04-12 11:05:25 +04:00
if ( ( r_data - > flags & MMC_DATA_WRITE ) & & ! mrq - > stop )
writel ( TIFM_MMCSD_EOFB
| readl ( sock - > addr + SOCK_MMCSD_INT_ENABLE ) ,
sock - > addr + SOCK_MMCSD_INT_ENABLE ) ;
2007-04-12 10:59:24 +04:00
2007-04-12 11:05:25 +04:00
if ( host - > no_dma ) {
2007-04-12 10:59:24 +04:00
writel ( TIFM_MMCSD_BUFINT
| readl ( sock - > addr + SOCK_MMCSD_INT_ENABLE ) ,
sock - > addr + SOCK_MMCSD_INT_ENABLE ) ;
writel ( ( ( TIFM_MMCSD_FIFO_SIZE - 1 ) < < 8 )
| ( TIFM_MMCSD_FIFO_SIZE - 1 ) ,
sock - > addr + SOCK_MMCSD_BUFFER_CONFIG ) ;
2007-04-12 11:05:25 +04:00
host - > sg_len = r_data - > sg_len ;
2007-04-12 10:59:24 +04:00
} else {
2007-04-12 11:05:25 +04:00
sg_init_one ( & host - > bounce_buf , host - > bounce_buf_data ,
r_data - > blksz ) ;
if ( 1 ! = tifm_map_sg ( sock , & host - > bounce_buf , 1 ,
r_data - > flags & MMC_DATA_WRITE
? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE ) ) {
2011-10-11 10:14:09 +04:00
pr_err ( " %s : scatterlist map failed \n " ,
2008-11-08 23:37:46 +03:00
dev_name ( & sock - > dev ) ) ;
2007-11-14 15:55:36 +03:00
mrq - > cmd - > error = - ENOMEM ;
2007-04-12 11:05:25 +04:00
goto err_out ;
}
host - > sg_len = tifm_map_sg ( sock , r_data - > sg ,
r_data - > sg_len ,
r_data - > flags
& MMC_DATA_WRITE
? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE ) ;
if ( host - > sg_len < 1 ) {
2011-10-11 10:14:09 +04:00
pr_err ( " %s : scatterlist map failed \n " ,
2008-11-08 23:37:46 +03:00
dev_name ( & sock - > dev ) ) ;
2007-04-12 11:05:25 +04:00
tifm_unmap_sg ( sock , & host - > bounce_buf , 1 ,
r_data - > flags & MMC_DATA_WRITE
? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE ) ;
2007-11-14 15:55:36 +03:00
mrq - > cmd - > error = - ENOMEM ;
2007-04-12 10:59:24 +04:00
goto err_out ;
}
2006-10-04 13:15:37 +04:00
2007-04-12 11:05:25 +04:00
writel ( TIFM_FIFO_INT_SETALL ,
sock - > addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR ) ;
writel ( ilog2 ( r_data - > blksz ) - 2 ,
sock - > addr + SOCK_FIFO_PAGE_SIZE ) ;
writel ( TIFM_FIFO_ENABLE ,
sock - > addr + SOCK_FIFO_CONTROL ) ;
writel ( TIFM_FIFO_INTMASK ,
sock - > addr + SOCK_DMA_FIFO_INT_ENABLE_SET ) ;
if ( r_data - > flags & MMC_DATA_WRITE )
writel ( TIFM_MMCSD_TXDE ,
sock - > addr + SOCK_MMCSD_BUFFER_CONFIG ) ;
else
writel ( TIFM_MMCSD_RXDE ,
sock - > addr + SOCK_MMCSD_BUFFER_CONFIG ) ;
tifm_sd_set_dma_data ( host , r_data ) ;
2007-04-12 10:59:24 +04:00
}
2007-04-12 11:05:25 +04:00
writel ( r_data - > blocks - 1 ,
sock - > addr + SOCK_MMCSD_NUM_BLOCKS ) ;
writel ( r_data - > blksz - 1 ,
sock - > addr + SOCK_MMCSD_BLOCK_LEN ) ;
2006-10-04 13:15:37 +04:00
}
host - > req = mrq ;
2006-12-08 08:50:49 +03:00
mod_timer ( & host - > timer , jiffies + host - > timeout_jiffies ) ;
2006-10-04 13:15:37 +04:00
writel ( TIFM_CTRL_LED | readl ( sock - > addr + SOCK_CONTROL ) ,
2006-12-08 08:50:52 +03:00
sock - > addr + SOCK_CONTROL ) ;
2006-10-04 13:15:37 +04:00
tifm_sd_exec ( host , mrq - > cmd ) ;
spin_unlock_irqrestore ( & sock - > lock , flags ) ;
return ;
err_out :
2007-07-24 22:38:53 +04:00
spin_unlock_irqrestore ( & sock - > lock , flags ) ;
2006-10-04 13:15:37 +04:00
mmc_request_done ( mmc , mrq ) ;
}
2006-12-08 08:50:51 +03:00
static void tifm_sd_end_cmd ( unsigned long data )
2006-10-04 13:15:37 +04:00
{
2006-12-08 08:50:51 +03:00
struct tifm_sd * host = ( struct tifm_sd * ) data ;
2006-10-04 13:15:37 +04:00
struct tifm_dev * sock = host - > dev ;
struct mmc_host * mmc = tifm_get_drvdata ( sock ) ;
struct mmc_request * mrq ;
2006-10-09 23:29:43 +04:00
struct mmc_data * r_data = NULL ;
2006-10-04 13:15:37 +04:00
unsigned long flags ;
spin_lock_irqsave ( & sock - > lock , flags ) ;
2006-12-08 08:50:49 +03:00
del_timer ( & host - > timer ) ;
2006-10-04 13:15:37 +04:00
mrq = host - > req ;
2006-10-09 23:29:43 +04:00
host - > req = NULL ;
2006-10-04 13:15:37 +04:00
if ( ! mrq ) {
2011-10-11 10:14:09 +04:00
pr_err ( " %s : no request to complete? \n " ,
2008-11-08 23:37:46 +03:00
dev_name ( & sock - > dev ) ) ;
2006-10-04 13:15:37 +04:00
spin_unlock_irqrestore ( & sock - > lock , flags ) ;
return ;
}
r_data = mrq - > cmd - > data ;
if ( r_data ) {
2007-04-12 10:59:24 +04:00
if ( host - > no_dma ) {
2007-04-12 11:05:25 +04:00
writel ( ( ~ TIFM_MMCSD_BUFINT )
& readl ( sock - > addr + SOCK_MMCSD_INT_ENABLE ) ,
sock - > addr + SOCK_MMCSD_INT_ENABLE ) ;
2006-10-04 13:15:37 +04:00
} else {
2007-04-12 11:05:25 +04:00
tifm_unmap_sg ( sock , & host - > bounce_buf , 1 ,
( r_data - > flags & MMC_DATA_WRITE )
? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE ) ;
2007-04-12 10:59:24 +04:00
tifm_unmap_sg ( sock , r_data - > sg , r_data - > sg_len ,
( r_data - > flags & MMC_DATA_WRITE )
? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE ) ;
2006-10-04 13:15:37 +04:00
}
2007-04-12 11:05:25 +04:00
r_data - > bytes_xfered = r_data - > blocks
- readl ( sock - > addr + SOCK_MMCSD_NUM_BLOCKS ) - 1 ;
r_data - > bytes_xfered * = r_data - > blksz ;
r_data - > bytes_xfered + = r_data - > blksz
- readl ( sock - > addr + SOCK_MMCSD_BLOCK_LEN ) + 1 ;
2006-10-04 13:15:37 +04:00
}
writel ( ( ~ TIFM_CTRL_LED ) & readl ( sock - > addr + SOCK_CONTROL ) ,
2006-12-08 08:50:52 +03:00
sock - > addr + SOCK_CONTROL ) ;
2006-10-04 13:15:37 +04:00
spin_unlock_irqrestore ( & sock - > lock , flags ) ;
mmc_request_done ( mmc , mrq ) ;
}
2017-10-24 18:03:45 +03:00
static void tifm_sd_abort ( struct timer_list * t )
2006-10-04 13:15:37 +04:00
{
2017-10-24 18:03:45 +03:00
struct tifm_sd * host = from_timer ( host , t , timer ) ;
2006-12-08 08:50:51 +03:00
2011-10-11 10:14:09 +04:00
pr_err ( " %s : card failed to respond for a long period of time "
2007-04-12 11:05:26 +04:00
" (%x, %x) \n " ,
2008-11-08 23:37:46 +03:00
dev_name ( & host - > dev - > dev ) , host - > req - > cmd - > opcode , host - > cmd_flags ) ;
2006-12-08 08:50:51 +03:00
tifm_eject ( host - > dev ) ;
2006-10-04 13:15:37 +04:00
}
static void tifm_sd_ios ( struct mmc_host * mmc , struct mmc_ios * ios )
{
struct tifm_sd * host = mmc_priv ( mmc ) ;
struct tifm_dev * sock = host - > dev ;
unsigned int clk_div1 , clk_div2 ;
unsigned long flags ;
spin_lock_irqsave ( & sock - > lock , flags ) ;
2007-04-12 11:05:26 +04:00
dev_dbg ( & sock - > dev , " ios: clock = %u, vdd = %x, bus_mode = %x, "
" chip_select = %x, power_mode = %x, bus_width = %x \n " ,
ios - > clock , ios - > vdd , ios - > bus_mode , ios - > chip_select ,
ios - > power_mode , ios - > bus_width ) ;
2006-10-04 13:15:37 +04:00
if ( ios - > bus_width = = MMC_BUS_WIDTH_4 ) {
writel ( TIFM_MMCSD_4BBUS | readl ( sock - > addr + SOCK_MMCSD_CONFIG ) ,
sock - > addr + SOCK_MMCSD_CONFIG ) ;
} else {
2006-12-08 08:50:52 +03:00
writel ( ( ~ TIFM_MMCSD_4BBUS )
& readl ( sock - > addr + SOCK_MMCSD_CONFIG ) ,
sock - > addr + SOCK_MMCSD_CONFIG ) ;
2006-10-04 13:15:37 +04:00
}
if ( ios - > clock ) {
clk_div1 = 20000000 / ios - > clock ;
if ( ! clk_div1 )
clk_div1 = 1 ;
clk_div2 = 24000000 / ios - > clock ;
if ( ! clk_div2 )
clk_div2 = 1 ;
if ( ( 20000000 / clk_div1 ) > ios - > clock )
clk_div1 + + ;
if ( ( 24000000 / clk_div2 ) > ios - > clock )
clk_div2 + + ;
if ( ( 20000000 / clk_div1 ) > ( 24000000 / clk_div2 ) ) {
host - > clk_freq = 20000000 ;
host - > clk_div = clk_div1 ;
2006-12-08 08:50:52 +03:00
writel ( ( ~ TIFM_CTRL_FAST_CLK )
& readl ( sock - > addr + SOCK_CONTROL ) ,
sock - > addr + SOCK_CONTROL ) ;
2006-10-04 13:15:37 +04:00
} else {
host - > clk_freq = 24000000 ;
host - > clk_div = clk_div2 ;
2006-12-08 08:50:52 +03:00
writel ( TIFM_CTRL_FAST_CLK
| readl ( sock - > addr + SOCK_CONTROL ) ,
sock - > addr + SOCK_CONTROL ) ;
2006-10-04 13:15:37 +04:00
}
} else {
host - > clk_div = 0 ;
}
host - > clk_div & = TIFM_MMCSD_CLKMASK ;
2006-12-08 08:50:52 +03:00
writel ( host - > clk_div
| ( ( ~ TIFM_MMCSD_CLKMASK )
& readl ( sock - > addr + SOCK_MMCSD_CONFIG ) ) ,
sock - > addr + SOCK_MMCSD_CONFIG ) ;
2006-10-04 13:15:37 +04:00
2007-04-12 10:59:23 +04:00
host - > open_drain = ( ios - > bus_mode = = MMC_BUSMODE_OPENDRAIN ) ;
2006-10-04 13:15:37 +04:00
/* chip_select : maybe later */
//vdd
//power is set before probe / after remove
spin_unlock_irqrestore ( & sock - > lock , flags ) ;
}
static int tifm_sd_ro ( struct mmc_host * mmc )
{
2007-04-12 10:59:23 +04:00
int rc = 0 ;
2006-10-04 13:15:37 +04:00
struct tifm_sd * host = mmc_priv ( mmc ) ;
struct tifm_dev * sock = host - > dev ;
unsigned long flags ;
spin_lock_irqsave ( & sock - > lock , flags ) ;
2007-04-12 10:59:23 +04:00
if ( TIFM_MMCSD_CARD_RO & readl ( sock - > addr + SOCK_PRESENT_STATE ) )
rc = 1 ;
2006-10-04 13:15:37 +04:00
spin_unlock_irqrestore ( & sock - > lock , flags ) ;
return rc ;
}
2007-04-12 10:59:24 +04:00
static const struct mmc_host_ops tifm_sd_ops = {
2006-10-04 13:15:37 +04:00
. request = tifm_sd_request ,
. set_ios = tifm_sd_ios ,
. get_ro = tifm_sd_ro
} ;
2006-12-08 08:50:51 +03:00
static int tifm_sd_initialize_host ( struct tifm_sd * host )
2006-10-04 13:15:37 +04:00
{
2006-12-08 08:50:51 +03:00
int rc ;
unsigned int host_status = 0 ;
2006-10-04 13:15:37 +04:00
struct tifm_dev * sock = host - > dev ;
2006-12-08 08:50:51 +03:00
writel ( 0 , sock - > addr + SOCK_MMCSD_INT_ENABLE ) ;
mmiowb ( ) ;
host - > clk_div = 61 ;
host - > clk_freq = 20000000 ;
writel ( TIFM_MMCSD_RESET , sock - > addr + SOCK_MMCSD_SYSTEM_CONTROL ) ;
writel ( host - > clk_div | TIFM_MMCSD_POWER ,
sock - > addr + SOCK_MMCSD_CONFIG ) ;
/* wait up to 0.51 sec for reset */
2007-04-12 11:05:24 +04:00
for ( rc = 32 ; rc < = 256 ; rc < < = 1 ) {
2006-12-08 08:50:51 +03:00
if ( 1 & readl ( sock - > addr + SOCK_MMCSD_SYSTEM_STATUS ) ) {
rc = 0 ;
break ;
}
msleep ( rc ) ;
}
if ( rc ) {
2011-10-11 10:14:09 +04:00
pr_err ( " %s : controller failed to reset \n " ,
2008-11-08 23:37:46 +03:00
dev_name ( & sock - > dev ) ) ;
2006-12-08 08:50:51 +03:00
return - ENODEV ;
}
writel ( 0 , sock - > addr + SOCK_MMCSD_NUM_BLOCKS ) ;
writel ( host - > clk_div | TIFM_MMCSD_POWER ,
sock - > addr + SOCK_MMCSD_CONFIG ) ;
writel ( TIFM_MMCSD_RXDE , sock - > addr + SOCK_MMCSD_BUFFER_CONFIG ) ;
// command timeout fixed to 64 clocks for now
writel ( 64 , sock - > addr + SOCK_MMCSD_COMMAND_TO ) ;
writel ( TIFM_MMCSD_INAB , sock - > addr + SOCK_MMCSD_COMMAND ) ;
2007-04-12 11:05:24 +04:00
for ( rc = 16 ; rc < = 64 ; rc < < = 1 ) {
2006-12-08 08:50:51 +03:00
host_status = readl ( sock - > addr + SOCK_MMCSD_STATUS ) ;
writel ( host_status , sock - > addr + SOCK_MMCSD_STATUS ) ;
if ( ! ( host_status & TIFM_MMCSD_ERRMASK )
& & ( host_status & TIFM_MMCSD_EOC ) ) {
rc = 0 ;
break ;
}
msleep ( rc ) ;
}
if ( rc ) {
2011-10-11 10:14:09 +04:00
pr_err ( " %s : card not ready - probe failed on initialization \n " ,
2008-11-08 23:37:46 +03:00
dev_name ( & sock - > dev ) ) ;
2006-12-08 08:50:51 +03:00
return - ENODEV ;
}
2007-04-12 11:05:24 +04:00
writel ( TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC
| TIFM_MMCSD_ERRMASK ,
2006-12-08 08:50:51 +03:00
sock - > addr + SOCK_MMCSD_INT_ENABLE ) ;
mmiowb ( ) ;
return 0 ;
2006-10-04 13:15:37 +04:00
}
static int tifm_sd_probe ( struct tifm_dev * sock )
{
struct mmc_host * mmc ;
struct tifm_sd * host ;
int rc = - EIO ;
2006-12-08 08:50:52 +03:00
if ( ! ( TIFM_SOCK_STATE_OCCUPIED
& readl ( sock - > addr + SOCK_PRESENT_STATE ) ) ) {
2014-09-13 01:56:56 +04:00
pr_warn ( " %s : card gone, unexpectedly \n " ,
dev_name ( & sock - > dev ) ) ;
2006-10-04 13:15:37 +04:00
return rc ;
}
mmc = mmc_alloc_host ( sizeof ( struct tifm_sd ) , & sock - > dev ) ;
if ( ! mmc )
return - ENOMEM ;
host = mmc_priv ( mmc ) ;
tifm_set_drvdata ( sock , mmc ) ;
2006-12-08 08:50:51 +03:00
host - > dev = sock ;
2006-10-04 13:15:37 +04:00
host - > timeout_jiffies = msecs_to_jiffies ( 1000 ) ;
2007-04-12 10:59:24 +04:00
tasklet_init ( & host - > finish_tasklet , tifm_sd_end_cmd ,
2006-12-08 08:50:51 +03:00
( unsigned long ) host ) ;
2017-10-24 18:03:45 +03:00
timer_setup ( & host - > timer , tifm_sd_abort , 0 ) ;
2006-12-08 08:50:51 +03:00
2006-10-04 13:15:37 +04:00
mmc - > ops = & tifm_sd_ops ;
mmc - > ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 ;
2008-07-06 03:10:27 +04:00
mmc - > caps = MMC_CAP_4_BIT_DATA ;
2006-10-04 13:15:37 +04:00
mmc - > f_min = 20000000 / 60 ;
mmc - > f_max = 24000000 ;
2007-04-12 11:05:25 +04:00
mmc - > max_blk_count = 2048 ;
2010-09-10 09:33:59 +04:00
mmc - > max_segs = mmc - > max_blk_count ;
2007-04-12 11:05:25 +04:00
mmc - > max_blk_size = min ( TIFM_MMCSD_MAX_BLOCK_SIZE , PAGE_SIZE ) ;
mmc - > max_seg_size = mmc - > max_blk_count * mmc - > max_blk_size ;
mmc - > max_req_size = mmc - > max_seg_size ;
2007-04-12 10:59:12 +04:00
sock - > card_event = tifm_sd_card_event ;
sock - > data_event = tifm_sd_data_event ;
2006-12-08 08:50:51 +03:00
rc = tifm_sd_initialize_host ( host ) ;
2006-10-04 13:15:37 +04:00
2006-12-08 08:50:51 +03:00
if ( ! rc )
rc = mmc_add_host ( mmc ) ;
2007-04-12 11:05:26 +04:00
if ( ! rc )
return 0 ;
2006-10-04 13:15:37 +04:00
2006-12-08 08:50:51 +03:00
mmc_free_host ( mmc ) ;
2006-10-04 13:15:37 +04:00
return rc ;
}
static void tifm_sd_remove ( struct tifm_dev * sock )
{
struct mmc_host * mmc = tifm_get_drvdata ( sock ) ;
struct tifm_sd * host = mmc_priv ( mmc ) ;
2007-04-12 10:59:21 +04:00
unsigned long flags ;
2006-10-04 13:15:37 +04:00
2007-04-12 10:59:22 +04:00
spin_lock_irqsave ( & sock - > lock , flags ) ;
2007-04-12 10:59:23 +04:00
host - > eject = 1 ;
2007-04-12 10:59:21 +04:00
writel ( 0 , sock - > addr + SOCK_MMCSD_INT_ENABLE ) ;
mmiowb ( ) ;
2007-04-12 10:59:22 +04:00
spin_unlock_irqrestore ( & sock - > lock , flags ) ;
tasklet_kill ( & host - > finish_tasklet ) ;
2007-04-12 10:59:21 +04:00
spin_lock_irqsave ( & sock - > lock , flags ) ;
if ( host - > req ) {
writel ( TIFM_FIFO_INT_SETALL ,
sock - > addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR ) ;
writel ( 0 , sock - > addr + SOCK_DMA_FIFO_INT_ENABLE_SET ) ;
2007-07-23 00:18:46 +04:00
host - > req - > cmd - > error = - ENOMEDIUM ;
2007-04-12 10:59:22 +04:00
if ( host - > req - > stop )
2007-07-23 00:18:46 +04:00
host - > req - > stop - > error = - ENOMEDIUM ;
2007-04-12 10:59:21 +04:00
tasklet_schedule ( & host - > finish_tasklet ) ;
}
spin_unlock_irqrestore ( & sock - > lock , flags ) ;
2006-12-08 08:50:51 +03:00
mmc_remove_host ( mmc ) ;
2007-04-12 10:59:22 +04:00
dev_dbg ( & sock - > dev , " after remove \n " ) ;
2006-10-04 13:15:37 +04:00
mmc_free_host ( mmc ) ;
}
2006-12-10 17:55:38 +03:00
# ifdef CONFIG_PM
static int tifm_sd_suspend ( struct tifm_dev * sock , pm_message_t state )
{
2013-09-25 16:30:03 +04:00
return 0 ;
2006-12-10 17:55:38 +03:00
}
static int tifm_sd_resume ( struct tifm_dev * sock )
{
struct mmc_host * mmc = tifm_get_drvdata ( sock ) ;
struct tifm_sd * host = mmc_priv ( mmc ) ;
2007-04-12 11:05:24 +04:00
int rc ;
2006-12-10 17:55:38 +03:00
2007-04-12 11:05:24 +04:00
rc = tifm_sd_initialize_host ( host ) ;
dev_dbg ( & sock - > dev , " resume initialize %d \n " , rc ) ;
if ( rc )
host - > eject = 1 ;
return rc ;
2006-12-10 17:55:38 +03:00
}
# else
# define tifm_sd_suspend NULL
# define tifm_sd_resume NULL
# endif /* CONFIG_PM */
2007-04-12 10:59:14 +04:00
static struct tifm_device_id tifm_sd_id_tbl [ ] = {
{ TIFM_TYPE_SD } , { }
2006-10-04 13:15:37 +04:00
} ;
static struct tifm_driver tifm_sd_driver = {
. driver = {
. name = DRIVER_NAME ,
. owner = THIS_MODULE
} ,
. id_table = tifm_sd_id_tbl ,
. probe = tifm_sd_probe ,
2006-12-10 17:55:38 +03:00
. remove = tifm_sd_remove ,
. suspend = tifm_sd_suspend ,
. resume = tifm_sd_resume
2006-10-04 13:15:37 +04:00
} ;
static int __init tifm_sd_init ( void )
{
return tifm_register_driver ( & tifm_sd_driver ) ;
}
static void __exit tifm_sd_exit ( void )
{
tifm_unregister_driver ( & tifm_sd_driver ) ;
}
MODULE_AUTHOR ( " Alex Dubov " ) ;
MODULE_DESCRIPTION ( " TI FlashMedia SD driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( tifm , tifm_sd_id_tbl ) ;
MODULE_VERSION ( DRIVER_VERSION ) ;
module_init ( tifm_sd_init ) ;
module_exit ( tifm_sd_exit ) ;