2005-04-17 02:20:36 +04:00
/*
2007-02-28 17:33:10 +03:00
* linux / drivers / mmc / core / core . c
2005-04-17 02:20:36 +04:00
*
* Copyright ( C ) 2003 - 2004 Russell King , All Rights Reserved .
2005-09-07 02:18:56 +04:00
* SD support Copyright ( C ) 2004 Ian Molton , All Rights Reserved .
2007-01-03 21:47:29 +03:00
* Copyright ( C ) 2005 - 2007 Pierre Ossman , All Rights Reserved .
2006-10-21 14:35:02 +04:00
* MMCv4 support Copyright ( C ) 2006 Philip Langdale , All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
* 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 .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/completion.h>
# include <linux/device.h>
# include <linux/delay.h>
# include <linux/pagemap.h>
# include <linux/err.h>
2005-09-07 02:18:53 +04:00
# include <asm/scatterlist.h>
# include <linux/scatterlist.h>
2005-04-17 02:20:36 +04:00
# include <linux/mmc/card.h>
# include <linux/mmc/host.h>
2006-12-25 00:46:55 +03:00
# include <linux/mmc/mmc.h>
# include <linux/mmc/sd.h>
2005-04-17 02:20:36 +04:00
2007-02-28 17:33:10 +03:00
# include "core.h"
2007-05-19 16:32:22 +04:00
# include "bus.h"
# include "host.h"
2007-05-26 15:48:18 +04:00
# include "sdio_bus.h"
2006-12-25 00:46:55 +03:00
# include "mmc_ops.h"
# include "sd_ops.h"
2007-05-21 22:23:20 +04:00
# include "sdio_ops.h"
2005-04-17 02:20:36 +04:00
2006-12-31 02:11:32 +03:00
extern int mmc_attach_mmc ( struct mmc_host * host , u32 ocr ) ;
extern int mmc_attach_sd ( struct mmc_host * host , u32 ocr ) ;
2007-05-21 22:23:20 +04:00
extern int mmc_attach_sdio ( struct mmc_host * host , u32 ocr ) ;
2005-04-17 02:20:36 +04:00
2007-05-19 16:32:22 +04:00
static struct workqueue_struct * workqueue ;
MMC core learns about SPI
Teach the MMC/SD/SDIO core about using SPI mode.
- Use mmc_host_is_spi() so enumeration works through SPI signaling
and protocols, not just the native versions.
- Provide the SPI response type flags with each request issued,
including requests from the new lock/unlock code.
- Understand that cmd->resp[0] and mmc_get_status() results for SPI
return different values than for "native" MMC/SD protocol; this
affects resetting, checking card lock status, and some others.
- Understand that some commands act a bit differently ... notably:
* OP_COND command doesn't return the OCR
* APP_CMD status doesn't have an R1_APP_CMD analogue
Those changes required some new and updated primitives:
- Provide utilities to access two SPI-only requests, and one
request that wasn't previously needed:
* mmc_spi_read_ocr() ... SPI only
* mmc_spi_set_crc() ... SPI only (override by module parm)
* mmc_send_cid() ... for use without broadcast mode
- Updated internal routines:
* Previous mmc_send_csd() modified into mmc_send_cxd_native();
it uses native "R2" responses, which include 16 bytes of data.
* Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data()
helper for command-and-data access
* Bugfix to that mmc_send_cxd_data() code: dma-to-stack is
unsafe/nonportable, so kmalloc a bounce buffer instead.
- Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper
- Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use
those helper routines based on whether they're native or SPI
The newest categories of cards supported by the MMC stack aren't expected
to work yet with SPI: MMC or SD cards with over 4GB data, and SDIO.
All those cards support SPI mode, so eventually they should work too.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
2007-08-08 20:11:32 +04:00
/*
* Enabling software CRCs on the data blocks can be a significant ( 30 % )
* performance cost , and for other reasons may not always be desired .
* So we allow it it to be disabled .
*/
int use_spi_crc = 1 ;
module_param ( use_spi_crc , bool , 0 ) ;
2007-05-19 16:32:22 +04:00
/*
* Internal function . Schedule delayed work in the MMC work queue .
*/
static int mmc_schedule_delayed_work ( struct delayed_work * work ,
unsigned long delay )
{
return queue_delayed_work ( workqueue , work , delay ) ;
}
/*
* Internal function . Flush all scheduled work from the MMC work queue .
*/
static void mmc_flush_scheduled_work ( void )
{
flush_workqueue ( workqueue ) ;
}
2005-04-17 02:20:36 +04:00
/**
2006-05-04 16:51:45 +04:00
* mmc_request_done - finish processing an MMC request
* @ host : MMC host which completed request
* @ mrq : MMC request which request
2005-04-17 02:20:36 +04:00
*
* MMC drivers should call this function when they have completed
2006-05-04 16:51:45 +04:00
* their processing of a request .
2005-04-17 02:20:36 +04:00
*/
void mmc_request_done ( struct mmc_host * host , struct mmc_request * mrq )
{
struct mmc_command * cmd = mrq - > cmd ;
2006-05-04 21:22:51 +04:00
int err = cmd - > error ;
MMC core learns about SPI
Teach the MMC/SD/SDIO core about using SPI mode.
- Use mmc_host_is_spi() so enumeration works through SPI signaling
and protocols, not just the native versions.
- Provide the SPI response type flags with each request issued,
including requests from the new lock/unlock code.
- Understand that cmd->resp[0] and mmc_get_status() results for SPI
return different values than for "native" MMC/SD protocol; this
affects resetting, checking card lock status, and some others.
- Understand that some commands act a bit differently ... notably:
* OP_COND command doesn't return the OCR
* APP_CMD status doesn't have an R1_APP_CMD analogue
Those changes required some new and updated primitives:
- Provide utilities to access two SPI-only requests, and one
request that wasn't previously needed:
* mmc_spi_read_ocr() ... SPI only
* mmc_spi_set_crc() ... SPI only (override by module parm)
* mmc_send_cid() ... for use without broadcast mode
- Updated internal routines:
* Previous mmc_send_csd() modified into mmc_send_cxd_native();
it uses native "R2" responses, which include 16 bytes of data.
* Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data()
helper for command-and-data access
* Bugfix to that mmc_send_cxd_data() code: dma-to-stack is
unsafe/nonportable, so kmalloc a bounce buffer instead.
- Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper
- Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use
those helper routines based on whether they're native or SPI
The newest categories of cards supported by the MMC stack aren't expected
to work yet with SPI: MMC or SD cards with over 4GB data, and SDIO.
All those cards support SPI mode, so eventually they should work too.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
2007-08-08 20:11:32 +04:00
if ( err & & cmd - > retries & & mmc_host_is_spi ( host ) ) {
if ( cmd - > resp [ 0 ] & R1_SPI_ILLEGAL_COMMAND )
cmd - > retries = 0 ;
}
2005-04-17 02:20:36 +04:00
if ( err & & cmd - > retries ) {
2007-07-24 23:46:49 +04:00
pr_debug ( " %s: req failed (CMD%u): %d, retrying... \n " ,
mmc_hostname ( host ) , cmd - > opcode , err ) ;
2005-04-17 02:20:36 +04:00
cmd - > retries - - ;
cmd - > error = 0 ;
host - > ops - > request ( host , mrq ) ;
2007-07-24 23:46:49 +04:00
} else {
pr_debug ( " %s: req done (CMD%u): %d: %08x %08x %08x %08x \n " ,
mmc_hostname ( host ) , cmd - > opcode , err ,
cmd - > resp [ 0 ] , cmd - > resp [ 1 ] ,
cmd - > resp [ 2 ] , cmd - > resp [ 3 ] ) ;
if ( mrq - > data ) {
pr_debug ( " %s: %d bytes transferred: %d \n " ,
mmc_hostname ( host ) ,
mrq - > data - > bytes_xfered , mrq - > data - > error ) ;
}
if ( mrq - > stop ) {
pr_debug ( " %s: (CMD%u): %d: %08x %08x %08x %08x \n " ,
mmc_hostname ( host ) , mrq - > stop - > opcode ,
mrq - > stop - > error ,
mrq - > stop - > resp [ 0 ] , mrq - > stop - > resp [ 1 ] ,
mrq - > stop - > resp [ 2 ] , mrq - > stop - > resp [ 3 ] ) ;
}
if ( mrq - > done )
mrq - > done ( mrq ) ;
2005-04-17 02:20:36 +04:00
}
}
EXPORT_SYMBOL ( mmc_request_done ) ;
2007-07-25 02:40:58 +04:00
static void
2005-04-17 02:20:36 +04:00
mmc_start_request ( struct mmc_host * host , struct mmc_request * mrq )
{
2007-04-14 00:47:01 +04:00
# ifdef CONFIG_MMC_DEBUG
unsigned int i , sz ;
# endif
2006-05-04 21:22:51 +04:00
pr_debug ( " %s: starting CMD%u arg %08x flags %08x \n " ,
mmc_hostname ( host ) , mrq - > cmd - > opcode ,
mrq - > cmd - > arg , mrq - > cmd - > flags ) ;
2005-04-17 02:20:36 +04:00
2007-07-24 23:46:49 +04:00
if ( mrq - > data ) {
pr_debug ( " %s: blksz %d blocks %d flags %08x "
" tsac %d ms nsac %d \n " ,
mmc_hostname ( host ) , mrq - > data - > blksz ,
mrq - > data - > blocks , mrq - > data - > flags ,
2007-08-07 16:06:18 +04:00
mrq - > data - > timeout_ns / 1000000 ,
2007-07-24 23:46:49 +04:00
mrq - > data - > timeout_clks ) ;
}
if ( mrq - > stop ) {
pr_debug ( " %s: CMD%u arg %08x flags %08x \n " ,
mmc_hostname ( host ) , mrq - > stop - > opcode ,
mrq - > stop - > arg , mrq - > stop - > flags ) ;
}
2006-12-26 17:11:23 +03:00
WARN_ON ( ! host - > claimed ) ;
2005-04-17 02:20:36 +04:00
mrq - > cmd - > error = 0 ;
mrq - > cmd - > mrq = mrq ;
if ( mrq - > data ) {
2006-11-21 19:54:23 +03:00
BUG_ON ( mrq - > data - > blksz > host - > max_blk_size ) ;
2006-11-21 19:55:45 +03:00
BUG_ON ( mrq - > data - > blocks > host - > max_blk_count ) ;
BUG_ON ( mrq - > data - > blocks * mrq - > data - > blksz >
host - > max_req_size ) ;
2006-11-21 19:54:23 +03:00
2007-04-14 00:47:01 +04:00
# ifdef CONFIG_MMC_DEBUG
sz = 0 ;
for ( i = 0 ; i < mrq - > data - > sg_len ; i + + )
sz + = mrq - > data - > sg [ i ] . length ;
BUG_ON ( sz ! = mrq - > data - > blocks * mrq - > data - > blksz ) ;
# endif
2005-04-17 02:20:36 +04:00
mrq - > cmd - > data = mrq - > data ;
mrq - > data - > error = 0 ;
mrq - > data - > mrq = mrq ;
if ( mrq - > stop ) {
mrq - > data - > stop = mrq - > stop ;
mrq - > stop - > error = 0 ;
mrq - > stop - > mrq = mrq ;
}
}
host - > ops - > request ( host , mrq ) ;
}
static void mmc_wait_done ( struct mmc_request * mrq )
{
complete ( mrq - > done_data ) ;
}
2007-07-11 22:22:11 +04:00
/**
* mmc_wait_for_req - start a request and wait for completion
* @ host : MMC host to start command
* @ mrq : MMC request to start
*
* Start a new MMC custom command request for a host , and wait
* for the command to complete . Does not attempt to parse the
* response .
*/
void mmc_wait_for_req ( struct mmc_host * host , struct mmc_request * mrq )
2005-04-17 02:20:36 +04:00
{
2006-07-03 11:25:35 +04:00
DECLARE_COMPLETION_ONSTACK ( complete ) ;
2005-04-17 02:20:36 +04:00
mrq - > done_data = & complete ;
mrq - > done = mmc_wait_done ;
mmc_start_request ( host , mrq ) ;
wait_for_completion ( & complete ) ;
}
EXPORT_SYMBOL ( mmc_wait_for_req ) ;
/**
* mmc_wait_for_cmd - start a command and wait for completion
* @ host : MMC host to start command
* @ cmd : MMC command to start
* @ retries : maximum number of retries
*
* Start a new MMC command for a host , and wait for the command
* to complete . Return any error that occurred while the command
* was executing . Do not attempt to parse the response .
*/
int mmc_wait_for_cmd ( struct mmc_host * host , struct mmc_command * cmd , int retries )
{
struct mmc_request mrq ;
2007-08-09 15:23:56 +04:00
WARN_ON ( ! host - > claimed ) ;
2005-04-17 02:20:36 +04:00
memset ( & mrq , 0 , sizeof ( struct mmc_request ) ) ;
memset ( cmd - > resp , 0 , sizeof ( cmd - > resp ) ) ;
cmd - > retries = retries ;
mrq . cmd = cmd ;
cmd - > data = NULL ;
mmc_wait_for_req ( host , & mrq ) ;
return cmd - > error ;
}
EXPORT_SYMBOL ( mmc_wait_for_cmd ) ;
2006-09-07 18:57:12 +04:00
/**
* mmc_set_data_timeout - set the timeout for a data command
* @ data : data phase for command
* @ card : the MMC card associated with the data transfer
2007-07-11 22:22:11 +04:00
*
* Computes the data timeout parameters according to the
* correct algorithm given the card type .
2006-09-07 18:57:12 +04:00
*/
2007-07-24 21:16:54 +04:00
void mmc_set_data_timeout ( struct mmc_data * data , const struct mmc_card * card )
2006-09-07 18:57:12 +04:00
{
unsigned int mult ;
2007-08-07 16:11:55 +04:00
/*
* SDIO cards only define an upper 1 s limit on access .
*/
if ( mmc_card_sdio ( card ) ) {
data - > timeout_ns = 1000000000 ;
data - > timeout_clks = 0 ;
return ;
}
2006-09-07 18:57:12 +04:00
/*
* SD cards use a 100 multiplier rather than 10
*/
mult = mmc_card_sd ( card ) ? 100 : 10 ;
/*
* Scale up the multiplier ( and therefore the timeout ) by
* the r2w factor for writes .
*/
2007-07-24 21:16:54 +04:00
if ( data - > flags & MMC_DATA_WRITE )
2006-09-07 18:57:12 +04:00
mult < < = card - > csd . r2w_factor ;
data - > timeout_ns = card - > csd . tacc_ns * mult ;
data - > timeout_clks = card - > csd . tacc_clks * mult ;
/*
* SD cards also have an upper limit on the timeout .
*/
if ( mmc_card_sd ( card ) ) {
unsigned int timeout_us , limit_us ;
timeout_us = data - > timeout_ns / 1000 ;
timeout_us + = data - > timeout_clks * 1000 /
( card - > host - > ios . clock / 1000 ) ;
2007-07-24 21:16:54 +04:00
if ( data - > flags & MMC_DATA_WRITE )
2006-09-07 18:57:12 +04:00
limit_us = 250000 ;
else
limit_us = 100000 ;
2007-01-04 17:57:32 +03:00
/*
* SDHC cards always use these fixed values .
*/
if ( timeout_us > limit_us | | mmc_card_blockaddr ( card ) ) {
2006-09-07 18:57:12 +04:00
data - > timeout_ns = limit_us * 1000 ;
data - > timeout_clks = 0 ;
}
}
}
EXPORT_SYMBOL ( mmc_set_data_timeout ) ;
2005-04-17 02:20:36 +04:00
/**
2007-06-30 18:21:52 +04:00
* __mmc_claim_host - exclusively claim a host
2005-04-17 02:20:36 +04:00
* @ host : mmc host to claim
2007-06-30 18:21:52 +04:00
* @ abort : whether or not the operation should be aborted
2005-04-17 02:20:36 +04:00
*
2007-06-30 18:21:52 +04:00
* Claim a host for a set of operations . If @ abort is non null and
* dereference a non - zero value then this will return prematurely with
* that non - zero value without acquiring the lock . Returns zero
* with the lock held otherwise .
2005-04-17 02:20:36 +04:00
*/
2007-06-30 18:21:52 +04:00
int __mmc_claim_host ( struct mmc_host * host , atomic_t * abort )
2005-04-17 02:20:36 +04:00
{
DECLARE_WAITQUEUE ( wait , current ) ;
unsigned long flags ;
2007-06-30 18:21:52 +04:00
int stop ;
2005-04-17 02:20:36 +04:00
2007-07-11 22:28:02 +04:00
might_sleep ( ) ;
2005-04-17 02:20:36 +04:00
add_wait_queue ( & host - > wq , & wait ) ;
spin_lock_irqsave ( & host - > lock , flags ) ;
while ( 1 ) {
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
2007-06-30 18:21:52 +04:00
stop = abort ? atomic_read ( abort ) : 0 ;
if ( stop | | ! host - > claimed )
2005-04-17 02:20:36 +04:00
break ;
spin_unlock_irqrestore ( & host - > lock , flags ) ;
schedule ( ) ;
spin_lock_irqsave ( & host - > lock , flags ) ;
}
set_current_state ( TASK_RUNNING ) ;
2007-06-30 18:21:52 +04:00
if ( ! stop )
host - > claimed = 1 ;
else
wake_up ( & host - > wq ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & host - > lock , flags ) ;
remove_wait_queue ( & host - > wq , & wait ) ;
2007-06-30 18:21:52 +04:00
return stop ;
2005-04-17 02:20:36 +04:00
}
2007-06-30 18:21:52 +04:00
EXPORT_SYMBOL ( __mmc_claim_host ) ;
2005-04-17 02:20:36 +04:00
/**
* mmc_release_host - release a host
* @ host : mmc host to release
*
* Release a MMC host , allowing others to claim the host
* for their operations .
*/
void mmc_release_host ( struct mmc_host * host )
{
unsigned long flags ;
2007-08-09 15:23:56 +04:00
WARN_ON ( ! host - > claimed ) ;
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & host - > lock , flags ) ;
2006-12-26 17:11:23 +03:00
host - > claimed = 0 ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & host - > lock , flags ) ;
wake_up ( & host - > wq ) ;
}
EXPORT_SYMBOL ( mmc_release_host ) ;
2006-12-31 02:11:32 +03:00
/*
* Internal function that does the actual ios call to the host driver ,
* optionally printing some debug output .
*/
2006-05-04 21:22:51 +04:00
static inline void mmc_set_ios ( struct mmc_host * host )
{
struct mmc_ios * ios = & host - > ios ;
2007-02-18 14:07:47 +03:00
pr_debug ( " %s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
" width %u timing %u \n " ,
2006-05-04 21:22:51 +04:00
mmc_hostname ( host ) , ios - > clock , ios - > bus_mode ,
ios - > power_mode , ios - > chip_select , ios - > vdd ,
2007-02-18 14:07:47 +03:00
ios - > bus_width , ios - > timing ) ;
2007-01-04 17:57:32 +03:00
2006-05-04 21:22:51 +04:00
host - > ops - > set_ios ( host , ios ) ;
}
2006-12-31 02:11:32 +03:00
/*
* Control chip select pin on a host .
*/
2006-12-25 00:46:55 +03:00
void mmc_set_chip_select ( struct mmc_host * host , int mode )
2005-04-17 02:20:36 +04:00
{
2006-12-25 00:46:55 +03:00
host - > ios . chip_select = mode ;
mmc_set_ios ( host ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-31 02:11:32 +03:00
/*
* Sets the host clock to the highest possible frequency that
* is below " hz " .
*/
void mmc_set_clock ( struct mmc_host * host , unsigned int hz )
{
WARN_ON ( hz < host - > f_min ) ;
if ( hz > host - > f_max )
hz = host - > f_max ;
host - > ios . clock = hz ;
mmc_set_ios ( host ) ;
}
/*
* Change the bus mode ( open drain / push - pull ) of a host .
*/
void mmc_set_bus_mode ( struct mmc_host * host , unsigned int mode )
{
host - > ios . bus_mode = mode ;
mmc_set_ios ( host ) ;
}
/*
* Change data bus width of a host .
*/
void mmc_set_bus_width ( struct mmc_host * host , unsigned int width )
{
host - > ios . bus_width = width ;
mmc_set_ios ( host ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Mask off any voltages we don ' t support and select
* the lowest voltage
*/
2006-12-31 02:11:32 +03:00
u32 mmc_select_voltage ( struct mmc_host * host , u32 ocr )
2005-04-17 02:20:36 +04:00
{
int bit ;
ocr & = host - > ocr_avail ;
bit = ffs ( ocr ) ;
if ( bit ) {
bit - = 1 ;
2006-11-02 21:43:27 +03:00
ocr & = 3 < < bit ;
2005-04-17 02:20:36 +04:00
host - > ios . vdd = bit ;
2006-05-04 21:22:51 +04:00
mmc_set_ios ( host ) ;
2005-04-17 02:20:36 +04:00
} else {
ocr = 0 ;
}
return ocr ;
}
2005-09-07 02:18:53 +04:00
/*
2006-12-31 02:11:32 +03:00
* Select timing parameters for host .
2005-09-07 02:18:53 +04:00
*/
2006-12-31 02:11:32 +03:00
void mmc_set_timing ( struct mmc_host * host , unsigned int timing )
2005-09-07 02:18:53 +04:00
{
2006-12-31 02:11:32 +03:00
host - > ios . timing = timing ;
mmc_set_ios ( host ) ;
2005-09-07 02:18:53 +04:00
}
2005-04-17 02:20:36 +04:00
/*
2005-12-14 17:57:35 +03:00
* Apply power to the MMC stack . This is a two - stage process .
* First , we enable power to the card without the clock running .
* We then wait a bit for the power to stabilise . Finally ,
* enable the bus drivers and clock to the card .
*
* We must _NOT_ enable the clock prior to power stablising .
*
* If a host does all the power sequencing itself , ignore the
* initial MMC_POWER_UP stage .
2005-04-17 02:20:36 +04:00
*/
static void mmc_power_up ( struct mmc_host * host )
{
int bit = fls ( host - > ocr_avail ) - 1 ;
host - > ios . vdd = bit ;
MMC core learns about SPI
Teach the MMC/SD/SDIO core about using SPI mode.
- Use mmc_host_is_spi() so enumeration works through SPI signaling
and protocols, not just the native versions.
- Provide the SPI response type flags with each request issued,
including requests from the new lock/unlock code.
- Understand that cmd->resp[0] and mmc_get_status() results for SPI
return different values than for "native" MMC/SD protocol; this
affects resetting, checking card lock status, and some others.
- Understand that some commands act a bit differently ... notably:
* OP_COND command doesn't return the OCR
* APP_CMD status doesn't have an R1_APP_CMD analogue
Those changes required some new and updated primitives:
- Provide utilities to access two SPI-only requests, and one
request that wasn't previously needed:
* mmc_spi_read_ocr() ... SPI only
* mmc_spi_set_crc() ... SPI only (override by module parm)
* mmc_send_cid() ... for use without broadcast mode
- Updated internal routines:
* Previous mmc_send_csd() modified into mmc_send_cxd_native();
it uses native "R2" responses, which include 16 bytes of data.
* Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data()
helper for command-and-data access
* Bugfix to that mmc_send_cxd_data() code: dma-to-stack is
unsafe/nonportable, so kmalloc a bounce buffer instead.
- Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper
- Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use
those helper routines based on whether they're native or SPI
The newest categories of cards supported by the MMC stack aren't expected
to work yet with SPI: MMC or SD cards with over 4GB data, and SDIO.
All those cards support SPI mode, so eventually they should work too.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
2007-08-08 20:11:32 +04:00
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 ;
}
2005-04-17 02:20:36 +04:00
host - > ios . power_mode = MMC_POWER_UP ;
2005-09-07 02:18:55 +04:00
host - > ios . bus_width = MMC_BUS_WIDTH_1 ;
2007-02-18 14:07:47 +03:00
host - > ios . timing = MMC_TIMING_LEGACY ;
2006-05-04 21:22:51 +04:00
mmc_set_ios ( host ) ;
2005-04-17 02:20:36 +04:00
2007-09-19 20:38:50 +04:00
/*
* This delay should be sufficient to allow the power supply
* to reach the minimum voltage .
*/
mmc_delay ( 2 ) ;
2005-04-17 02:20:36 +04:00
host - > ios . clock = host - > f_min ;
host - > ios . power_mode = MMC_POWER_ON ;
2006-05-04 21:22:51 +04:00
mmc_set_ios ( host ) ;
2005-04-17 02:20:36 +04:00
2007-09-19 20:38:50 +04:00
/*
* This delay must be at least 74 clock sizes , or 1 ms , or the
* time required to reach a stable voltage .
*/
2005-04-17 02:20:36 +04:00
mmc_delay ( 2 ) ;
}
static void mmc_power_off ( struct mmc_host * host )
{
host - > ios . clock = 0 ;
host - > ios . vdd = 0 ;
MMC core learns about SPI
Teach the MMC/SD/SDIO core about using SPI mode.
- Use mmc_host_is_spi() so enumeration works through SPI signaling
and protocols, not just the native versions.
- Provide the SPI response type flags with each request issued,
including requests from the new lock/unlock code.
- Understand that cmd->resp[0] and mmc_get_status() results for SPI
return different values than for "native" MMC/SD protocol; this
affects resetting, checking card lock status, and some others.
- Understand that some commands act a bit differently ... notably:
* OP_COND command doesn't return the OCR
* APP_CMD status doesn't have an R1_APP_CMD analogue
Those changes required some new and updated primitives:
- Provide utilities to access two SPI-only requests, and one
request that wasn't previously needed:
* mmc_spi_read_ocr() ... SPI only
* mmc_spi_set_crc() ... SPI only (override by module parm)
* mmc_send_cid() ... for use without broadcast mode
- Updated internal routines:
* Previous mmc_send_csd() modified into mmc_send_cxd_native();
it uses native "R2" responses, which include 16 bytes of data.
* Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data()
helper for command-and-data access
* Bugfix to that mmc_send_cxd_data() code: dma-to-stack is
unsafe/nonportable, so kmalloc a bounce buffer instead.
- Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper
- Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use
those helper routines based on whether they're native or SPI
The newest categories of cards supported by the MMC stack aren't expected
to work yet with SPI: MMC or SD cards with over 4GB data, and SDIO.
All those cards support SPI mode, so eventually they should work too.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
2007-08-08 20:11:32 +04:00
if ( ! mmc_host_is_spi ( host ) ) {
host - > ios . bus_mode = MMC_BUSMODE_OPENDRAIN ;
host - > ios . chip_select = MMC_CS_DONTCARE ;
}
2005-04-17 02:20:36 +04:00
host - > ios . power_mode = MMC_POWER_OFF ;
2005-09-07 02:18:55 +04:00
host - > ios . bus_width = MMC_BUS_WIDTH_1 ;
2007-02-18 14:07:47 +03:00
host - > ios . timing = MMC_TIMING_LEGACY ;
2006-05-04 21:22:51 +04:00
mmc_set_ios ( host ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-25 02:40:58 +04:00
/*
* Cleanup when the last reference to the bus operator is dropped .
*/
void __mmc_release_bus ( struct mmc_host * host )
{
BUG_ON ( ! host ) ;
BUG_ON ( host - > bus_refs ) ;
BUG_ON ( ! host - > bus_dead ) ;
host - > bus_ops = NULL ;
}
/*
* Increase reference count of bus operator
*/
static inline void mmc_bus_get ( struct mmc_host * host )
{
unsigned long flags ;
spin_lock_irqsave ( & host - > lock , flags ) ;
host - > bus_refs + + ;
spin_unlock_irqrestore ( & host - > lock , flags ) ;
}
/*
* Decrease reference count of bus operator and free it if
* it is the last reference .
*/
static inline void mmc_bus_put ( struct mmc_host * host )
{
unsigned long flags ;
spin_lock_irqsave ( & host - > lock , flags ) ;
host - > bus_refs - - ;
if ( ( host - > bus_refs = = 0 ) & & host - > bus_ops )
__mmc_release_bus ( host ) ;
spin_unlock_irqrestore ( & host - > lock , flags ) ;
}
2005-04-17 02:20:36 +04:00
/*
2006-12-31 02:11:32 +03:00
* Assign a mmc bus handler to a host . Only one bus handler may control a
* host at any given time .
2005-04-17 02:20:36 +04:00
*/
2006-12-31 02:11:32 +03:00
void mmc_attach_bus ( struct mmc_host * host , const struct mmc_bus_ops * ops )
2005-04-17 02:20:36 +04:00
{
2006-12-31 02:11:32 +03:00
unsigned long flags ;
2006-10-29 12:14:19 +03:00
2006-12-31 02:11:32 +03:00
BUG_ON ( ! host ) ;
BUG_ON ( ! ops ) ;
2007-01-03 21:47:29 +03:00
2007-08-09 15:23:56 +04:00
WARN_ON ( ! host - > claimed ) ;
2006-10-21 14:35:02 +04:00
2006-12-31 02:11:32 +03:00
spin_lock_irqsave ( & host - > lock , flags ) ;
2006-10-21 14:35:02 +04:00
2006-12-31 02:11:32 +03:00
BUG_ON ( host - > bus_ops ) ;
BUG_ON ( host - > bus_refs ) ;
2005-09-07 02:18:53 +04:00
2006-12-31 02:11:32 +03:00
host - > bus_ops = ops ;
host - > bus_refs = 1 ;
host - > bus_dead = 0 ;
2005-09-07 02:18:53 +04:00
2006-12-31 02:11:32 +03:00
spin_unlock_irqrestore ( & host - > lock , flags ) ;
2005-09-07 02:18:53 +04:00
}
2006-12-31 02:11:32 +03:00
/*
* Remove the current bus handler from a host . Assumes that there are
* no interesting cards left , so the bus is powered down .
*/
void mmc_detach_bus ( struct mmc_host * host )
2006-11-09 01:03:10 +03:00
{
2006-12-31 02:11:32 +03:00
unsigned long flags ;
2006-11-09 01:03:10 +03:00
2006-12-31 02:11:32 +03:00
BUG_ON ( ! host ) ;
2006-11-09 01:03:10 +03:00
2007-08-09 15:23:56 +04:00
WARN_ON ( ! host - > claimed ) ;
WARN_ON ( ! host - > bus_ops ) ;
2007-02-18 14:07:47 +03:00
2006-12-31 02:11:32 +03:00
spin_lock_irqsave ( & host - > lock , flags ) ;
2006-11-09 01:03:10 +03:00
2006-12-31 02:11:32 +03:00
host - > bus_dead = 1 ;
2006-11-09 01:03:10 +03:00
2006-12-31 02:11:32 +03:00
spin_unlock_irqrestore ( & host - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
2006-12-31 02:11:32 +03:00
mmc_power_off ( host ) ;
2005-04-17 02:20:36 +04:00
2006-12-31 02:11:32 +03:00
mmc_bus_put ( host ) ;
2005-04-17 02:20:36 +04:00
}
/**
* mmc_detect_change - process change of state on a MMC socket
* @ host : host which changed state .
2005-09-08 20:53:01 +04:00
* @ delay : optional delay to wait before detection ( jiffies )
2005-04-17 02:20:36 +04:00
*
2007-07-11 22:22:11 +04:00
* MMC drivers should call this when they detect a card has been
* inserted or removed . The MMC layer will confirm that any
* present card is still functional , and initialize any newly
* inserted .
2005-04-17 02:20:36 +04:00
*/
2005-09-08 20:53:01 +04:00
void mmc_detect_change ( struct mmc_host * host , unsigned long delay )
2005-04-17 02:20:36 +04:00
{
2007-02-11 22:43:19 +03:00
# ifdef CONFIG_MMC_DEBUG
2007-05-09 00:35:17 +04:00
unsigned long flags ;
2007-05-09 13:32:34 +04:00
spin_lock_irqsave ( & host - > lock , flags ) ;
2007-08-09 15:23:56 +04:00
WARN_ON ( host - > removed ) ;
2007-05-09 13:32:34 +04:00
spin_unlock_irqrestore ( & host - > lock , flags ) ;
2007-02-11 22:43:19 +03:00
# endif
2006-11-22 17:57:56 +03:00
mmc_schedule_delayed_work ( & host - > detect , delay ) ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( mmc_detect_change ) ;
2007-05-19 16:06:24 +04:00
void mmc_rescan ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2006-11-22 17:57:56 +03:00
struct mmc_host * host =
container_of ( work , struct mmc_host , detect . work ) ;
2006-12-31 02:11:32 +03:00
u32 ocr ;
int err ;
2005-04-17 02:20:36 +04:00
2006-12-31 02:11:32 +03:00
mmc_bus_get ( host ) ;
2007-01-03 21:47:29 +03:00
2006-12-31 02:11:32 +03:00
if ( host - > bus_ops = = NULL ) {
2005-04-17 02:20:36 +04:00
/*
2006-12-31 02:11:32 +03:00
* Only we can add a new handler , so it ' s safe to
* release the lock here .
2005-04-17 02:20:36 +04:00
*/
2006-12-31 02:11:32 +03:00
mmc_bus_put ( host ) ;
2005-04-17 02:20:36 +04:00
2006-12-31 02:11:32 +03:00
mmc_claim_host ( host ) ;
2005-04-17 02:20:36 +04:00
2006-12-31 02:11:32 +03:00
mmc_power_up ( host ) ;
mmc_go_idle ( host ) ;
2005-04-17 02:20:36 +04:00
2006-12-31 02:11:32 +03:00
mmc_send_if_cond ( host , host - > ocr_avail ) ;
2005-04-17 02:20:36 +04:00
2007-05-21 22:23:20 +04:00
/*
* First we search for SDIO . . .
*/
err = mmc_send_io_op_cond ( host , 0 , & ocr ) ;
if ( ! err ) {
if ( mmc_attach_sdio ( host , ocr ) )
mmc_power_off ( host ) ;
return ;
}
/*
* . . . then normal SD . . .
*/
2006-12-31 02:11:32 +03:00
err = mmc_send_app_op_cond ( host , 0 , & ocr ) ;
2007-07-23 00:18:46 +04:00
if ( ! err ) {
2006-12-31 02:11:32 +03:00
if ( mmc_attach_sd ( host , ocr ) )
mmc_power_off ( host ) ;
2007-05-21 22:23:20 +04:00
return ;
}
/*
* . . . and finally MMC .
*/
err = mmc_send_op_cond ( host , 0 , & ocr ) ;
if ( ! err ) {
if ( mmc_attach_mmc ( host , ocr ) )
2006-12-31 02:11:32 +03:00
mmc_power_off ( host ) ;
2007-05-21 22:23:20 +04:00
return ;
2006-12-31 02:11:32 +03:00
}
2007-05-21 22:23:20 +04:00
mmc_release_host ( host ) ;
mmc_power_off ( host ) ;
2006-12-31 02:11:32 +03:00
} else {
if ( host - > bus_ops - > detect & & ! host - > bus_dead )
host - > bus_ops - > detect ( host ) ;
mmc_bus_put ( host ) ;
}
2005-04-17 02:20:36 +04:00
}
2007-05-19 16:06:24 +04:00
void mmc_start_host ( struct mmc_host * host )
2005-04-17 02:20:36 +04:00
{
2007-05-19 16:06:24 +04:00
mmc_power_off ( host ) ;
mmc_detect_change ( host , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-19 16:06:24 +04:00
void mmc_stop_host ( struct mmc_host * host )
2005-04-17 02:20:36 +04:00
{
2007-02-11 22:43:19 +03:00
# ifdef CONFIG_MMC_DEBUG
2007-05-09 00:35:17 +04:00
unsigned long flags ;
spin_lock_irqsave ( & host - > lock , flags ) ;
2007-02-11 22:43:19 +03:00
host - > removed = 1 ;
2007-05-09 00:35:17 +04:00
spin_unlock_irqrestore ( & host - > lock , flags ) ;
2007-02-11 22:43:19 +03:00
# endif
mmc_flush_scheduled_work ( ) ;
2006-12-31 02:11:32 +03:00
mmc_bus_get ( host ) ;
if ( host - > bus_ops & & ! host - > bus_dead ) {
if ( host - > bus_ops - > remove )
host - > bus_ops - > remove ( host ) ;
mmc_claim_host ( host ) ;
mmc_detach_bus ( host ) ;
mmc_release_host ( host ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-31 02:11:32 +03:00
mmc_bus_put ( host ) ;
BUG_ON ( host - > card ) ;
2005-04-17 02:20:36 +04:00
mmc_power_off ( host ) ;
}
# ifdef CONFIG_PM
/**
* mmc_suspend_host - suspend a host
* @ host : mmc host
* @ state : suspend mode ( PM_SUSPEND_xxx )
*/
2005-04-17 02:25:29 +04:00
int mmc_suspend_host ( struct mmc_host * host , pm_message_t state )
2005-04-17 02:20:36 +04:00
{
2007-04-28 19:30:50 +04:00
mmc_flush_scheduled_work ( ) ;
2006-12-31 02:11:32 +03:00
mmc_bus_get ( host ) ;
if ( host - > bus_ops & & ! host - > bus_dead ) {
2007-05-01 18:00:02 +04:00
if ( host - > bus_ops - > suspend )
host - > bus_ops - > suspend ( host ) ;
if ( ! host - > bus_ops - > resume ) {
if ( host - > bus_ops - > remove )
host - > bus_ops - > remove ( host ) ;
mmc_claim_host ( host ) ;
mmc_detach_bus ( host ) ;
mmc_release_host ( host ) ;
}
2007-04-28 19:30:50 +04:00
}
2006-12-31 02:11:32 +03:00
mmc_bus_put ( host ) ;
2005-04-17 02:20:36 +04:00
mmc_power_off ( host ) ;
return 0 ;
}
EXPORT_SYMBOL ( mmc_suspend_host ) ;
/**
* mmc_resume_host - resume a previously suspended host
* @ host : mmc host
*/
int mmc_resume_host ( struct mmc_host * host )
{
2007-05-01 18:00:02 +04:00
mmc_bus_get ( host ) ;
if ( host - > bus_ops & & ! host - > bus_dead ) {
mmc_power_up ( host ) ;
BUG_ON ( ! host - > bus_ops - > resume ) ;
host - > bus_ops - > resume ( host ) ;
}
mmc_bus_put ( host ) ;
/*
* We add a slight delay here so that resume can progress
* in parallel .
*/
mmc_detect_change ( host , 1 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
EXPORT_SYMBOL ( mmc_resume_host ) ;
# endif
2007-05-19 16:32:22 +04:00
static int __init mmc_init ( void )
{
int ret ;
workqueue = create_singlethread_workqueue ( " kmmcd " ) ;
if ( ! workqueue )
return - ENOMEM ;
ret = mmc_register_bus ( ) ;
2007-05-26 15:48:18 +04:00
if ( ret )
goto destroy_workqueue ;
ret = mmc_register_host_class ( ) ;
if ( ret )
goto unregister_bus ;
ret = sdio_register_bus ( ) ;
if ( ret )
goto unregister_host_class ;
return 0 ;
unregister_host_class :
mmc_unregister_host_class ( ) ;
unregister_bus :
mmc_unregister_bus ( ) ;
destroy_workqueue :
destroy_workqueue ( workqueue ) ;
2007-05-19 16:32:22 +04:00
return ret ;
}
static void __exit mmc_exit ( void )
{
2007-05-26 15:48:18 +04:00
sdio_unregister_bus ( ) ;
2007-05-19 16:32:22 +04:00
mmc_unregister_host_class ( ) ;
mmc_unregister_bus ( ) ;
destroy_workqueue ( workqueue ) ;
}
2007-06-16 10:07:53 +04:00
subsys_initcall ( mmc_init ) ;
2007-05-19 16:32:22 +04:00
module_exit ( mmc_exit ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;