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 .
2008-06-28 14:52:45 +04:00
* Copyright ( C ) 2005 - 2008 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>
2007-09-24 09:15:48 +04:00
# include <linux/leds.h>
2005-09-07 02:18:53 +04:00
# include <linux/scatterlist.h>
2008-11-26 22:54:17 +03:00
# include <linux/log2.h>
2009-03-11 14:30:43 +03:00
# include <linux/regulator/consumer.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
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 ) ;
2009-12-15 05:01:29 +03:00
/*
* We normally treat cards as removed during suspend if they are not
* known to be on a non - removable bus , to avoid the risk of writing
* back data to a different card after resume . Allow this to be
* overridden if necessary .
*/
# ifdef CONFIG_MMC_UNSAFE_RESUME
int mmc_assume_removable ;
# else
int mmc_assume_removable = 1 ;
# endif
module_param_named ( removable , mmc_assume_removable , bool , 0644 ) ;
MODULE_PARM_DESC (
removable ,
" MMC/SD cards are removable and may be removed during suspend " ) ;
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 {
2007-09-24 09:15:48 +04:00
led_trigger_event ( host - > led , LED_OFF ) ;
2007-07-24 23:46:49 +04:00
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 ;
2008-07-29 03:09:37 +04:00
struct scatterlist * sg ;
2007-04-14 00:47:01 +04:00
# 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
2007-09-24 09:15:48 +04:00
led_trigger_event ( host - > led , LED_FULL ) ;
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 ;
2008-07-29 03:09:37 +04:00
for_each_sg ( mrq - > data - > sg , sg , mrq - > data - > sg_len , i )
sz + = sg - > length ;
2007-04-14 00:47:01 +04:00
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 )
2008-10-26 14:37:25 +03:00
/*
* The limit is really 250 ms , but that is
* insufficient for some crappy cards .
*/
limit_us = 300000 ;
2006-09-07 18:57:12 +04:00
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 ;
}
}
2009-03-11 16:28:39 +03:00
/*
* Some cards need very high timeouts if driven in SPI mode .
* The worst observed timeout was 900 ms after writing a
* continuous stream of data until the internal logic
* overflowed .
*/
if ( mmc_host_is_spi ( card - > host ) ) {
if ( data - > flags & MMC_DATA_WRITE ) {
if ( data - > timeout_ns < 1000000000 )
data - > timeout_ns = 1000000000 ; /* 1s */
} else {
if ( data - > timeout_ns < 100000000 )
data - > timeout_ns = 100000000 ; /* 100ms */
}
}
2006-09-07 18:57:12 +04:00
}
EXPORT_SYMBOL ( mmc_set_data_timeout ) ;
2008-06-28 14:52:45 +04:00
/**
* mmc_align_data_size - pads a transfer size to a more optimal value
* @ card : the MMC card associated with the data transfer
* @ sz : original transfer size
*
* Pads the original data size with a number of extra bytes in
* order to avoid controller bugs and / or performance hits
* ( e . g . some controllers revert to PIO for certain sizes ) .
*
* Returns the improved size , which might be unmodified .
*
* Note that this function is only relevant when issuing a
* single scatter gather entry .
*/
unsigned int mmc_align_data_size ( struct mmc_card * card , unsigned int sz )
{
/*
* FIXME : We don ' t have a system for the controller to tell
* the core about its problems yet , so for now we just 32 - bit
* align the size .
*/
sz = ( ( sz + 3 ) / 4 ) * 4 ;
return sz ;
}
EXPORT_SYMBOL ( mmc_align_data_size ) ;
2009-09-23 03:44:29 +04:00
/**
* mmc_host_enable - enable a host .
* @ host : mmc host to enable
*
* Hosts that support power saving can use the ' enable ' and ' disable '
* methods to exit and enter power saving states . For more information
* see comments for struct mmc_host_ops .
*/
int mmc_host_enable ( struct mmc_host * host )
{
if ( ! ( host - > caps & MMC_CAP_DISABLE ) )
return 0 ;
if ( host - > en_dis_recurs )
return 0 ;
if ( host - > nesting_cnt + + )
return 0 ;
cancel_delayed_work_sync ( & host - > disable ) ;
if ( host - > enabled )
return 0 ;
if ( host - > ops - > enable ) {
int err ;
host - > en_dis_recurs = 1 ;
err = host - > ops - > enable ( host ) ;
host - > en_dis_recurs = 0 ;
if ( err ) {
pr_debug ( " %s: enable error %d \n " ,
mmc_hostname ( host ) , err ) ;
return err ;
}
}
host - > enabled = 1 ;
return 0 ;
}
EXPORT_SYMBOL ( mmc_host_enable ) ;
static int mmc_host_do_disable ( struct mmc_host * host , int lazy )
{
if ( host - > ops - > disable ) {
int err ;
host - > en_dis_recurs = 1 ;
err = host - > ops - > disable ( host , lazy ) ;
host - > en_dis_recurs = 0 ;
if ( err < 0 ) {
pr_debug ( " %s: disable error %d \n " ,
mmc_hostname ( host ) , err ) ;
return err ;
}
if ( err > 0 ) {
unsigned long delay = msecs_to_jiffies ( err ) ;
mmc_schedule_delayed_work ( & host - > disable , delay ) ;
}
}
host - > enabled = 0 ;
return 0 ;
}
/**
* mmc_host_disable - disable a host .
* @ host : mmc host to disable
*
* Hosts that support power saving can use the ' enable ' and ' disable '
* methods to exit and enter power saving states . For more information
* see comments for struct mmc_host_ops .
*/
int mmc_host_disable ( struct mmc_host * host )
{
int err ;
if ( ! ( host - > caps & MMC_CAP_DISABLE ) )
return 0 ;
if ( host - > en_dis_recurs )
return 0 ;
if ( - - host - > nesting_cnt )
return 0 ;
if ( ! host - > enabled )
return 0 ;
err = mmc_host_do_disable ( host , 0 ) ;
return err ;
}
EXPORT_SYMBOL ( mmc_host_disable ) ;
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 ;
2009-09-23 03:44:30 +04:00
if ( stop | | ! host - > claimed | | host - > claimer = = current )
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 ) ;
2009-09-23 03:44:30 +04:00
if ( ! stop ) {
2007-06-30 18:21:52 +04:00
host - > claimed = 1 ;
2009-09-23 03:44:30 +04:00
host - > claimer = current ;
host - > claim_cnt + = 1 ;
} else
2007-06-30 18:21:52 +04:00
wake_up ( & host - > wq ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & host - > lock , flags ) ;
remove_wait_queue ( & host - > wq , & wait ) ;
2009-09-23 03:44:29 +04:00
if ( ! stop )
mmc_host_enable ( host ) ;
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
2009-09-23 03:44:30 +04:00
/**
* mmc_try_claim_host - try exclusively to claim a host
* @ host : mmc host to claim
*
* Returns % 1 if the host is claimed , % 0 otherwise .
*/
int mmc_try_claim_host ( struct mmc_host * host )
2009-09-23 03:44:29 +04:00
{
int claimed_host = 0 ;
unsigned long flags ;
spin_lock_irqsave ( & host - > lock , flags ) ;
2009-09-23 03:44:30 +04:00
if ( ! host - > claimed | | host - > claimer = = current ) {
2009-09-23 03:44:29 +04:00
host - > claimed = 1 ;
2009-09-23 03:44:30 +04:00
host - > claimer = current ;
host - > claim_cnt + = 1 ;
2009-09-23 03:44:29 +04:00
claimed_host = 1 ;
}
spin_unlock_irqrestore ( & host - > lock , flags ) ;
return claimed_host ;
}
2009-09-23 03:44:30 +04:00
EXPORT_SYMBOL ( mmc_try_claim_host ) ;
2009-09-23 03:44:29 +04:00
static void mmc_do_release_host ( struct mmc_host * host )
{
unsigned long flags ;
spin_lock_irqsave ( & host - > lock , flags ) ;
2009-09-23 03:44:30 +04:00
if ( - - host - > claim_cnt ) {
/* Release for nested claim */
spin_unlock_irqrestore ( & host - > lock , flags ) ;
} else {
host - > claimed = 0 ;
host - > claimer = NULL ;
spin_unlock_irqrestore ( & host - > lock , flags ) ;
wake_up ( & host - > wq ) ;
}
2009-09-23 03:44:29 +04:00
}
void mmc_host_deeper_disable ( struct work_struct * work )
{
struct mmc_host * host =
container_of ( work , struct mmc_host , disable . work ) ;
/* If the host is claimed then we do not want to disable it anymore */
if ( ! mmc_try_claim_host ( host ) )
return ;
mmc_host_do_disable ( host , 1 ) ;
mmc_do_release_host ( host ) ;
}
/**
* mmc_host_lazy_disable - lazily disable a host .
* @ host : mmc host to disable
*
* Hosts that support power saving can use the ' enable ' and ' disable '
* methods to exit and enter power saving states . For more information
* see comments for struct mmc_host_ops .
*/
int mmc_host_lazy_disable ( struct mmc_host * host )
{
if ( ! ( host - > caps & MMC_CAP_DISABLE ) )
return 0 ;
if ( host - > en_dis_recurs )
return 0 ;
if ( - - host - > nesting_cnt )
return 0 ;
if ( ! host - > enabled )
return 0 ;
if ( host - > disable_delay ) {
mmc_schedule_delayed_work ( & host - > disable ,
msecs_to_jiffies ( host - > disable_delay ) ) ;
return 0 ;
} else
return mmc_host_do_disable ( host , 1 ) ;
}
EXPORT_SYMBOL ( mmc_host_lazy_disable ) ;
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 )
{
2007-08-09 15:23:56 +04:00
WARN_ON ( ! host - > claimed ) ;
2005-04-17 02:20:36 +04:00
2009-09-23 03:44:29 +04:00
mmc_host_lazy_disable ( host ) ;
2005-04-17 02:20:36 +04:00
2009-09-23 03:44:29 +04:00
mmc_do_release_host ( host ) ;
2005-04-17 02:20:36 +04:00
}
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 ) ;
}
2008-11-26 22:54:17 +03:00
/**
* mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
* @ vdd : voltage ( mV )
* @ low_bits : prefer low bits in boundary cases
*
* This function returns the OCR bit number according to the provided @ vdd
* value . If conversion is not possible a negative errno value returned .
*
* Depending on the @ low_bits flag the function prefers low or high OCR bits
* on boundary voltages . For example ,
* with @ low_bits = true , 3300 mV translates to ilog2 ( MMC_VDD_32_33 ) ;
* with @ low_bits = false , 3300 mV translates to ilog2 ( MMC_VDD_33_34 ) ;
*
* Any value in the [ 1951 : 1999 ] range translates to the ilog2 ( MMC_VDD_20_21 ) .
*/
static int mmc_vdd_to_ocrbitnum ( int vdd , bool low_bits )
{
const int max_bit = ilog2 ( MMC_VDD_35_36 ) ;
int bit ;
if ( vdd < 1650 | | vdd > 3600 )
return - EINVAL ;
if ( vdd > = 1650 & & vdd < = 1950 )
return ilog2 ( MMC_VDD_165_195 ) ;
if ( low_bits )
vdd - = 1 ;
/* Base 2000 mV, step 100 mV, bit's base 8. */
bit = ( vdd - 2000 ) / 100 + 8 ;
if ( bit > max_bit )
return max_bit ;
return bit ;
}
/**
* mmc_vddrange_to_ocrmask - Convert a voltage range to the OCR mask
* @ vdd_min : minimum voltage value ( mV )
* @ vdd_max : maximum voltage value ( mV )
*
* This function returns the OCR mask bits according to the provided @ vdd_min
* and @ vdd_max values . If conversion is not possible the function returns 0.
*
* Notes wrt boundary cases :
* This function sets the OCR bits for all boundary voltages , for example
* [ 3300 : 3400 ] range is translated to MMC_VDD_32_33 | MMC_VDD_33_34 |
* MMC_VDD_34_35 mask .
*/
u32 mmc_vddrange_to_ocrmask ( int vdd_min , int vdd_max )
{
u32 mask = 0 ;
if ( vdd_max < vdd_min )
return 0 ;
/* Prefer high bits for the boundary vdd_max values. */
vdd_max = mmc_vdd_to_ocrbitnum ( vdd_max , false ) ;
if ( vdd_max < 0 )
return 0 ;
/* Prefer low bits for the boundary vdd_min values. */
vdd_min = mmc_vdd_to_ocrbitnum ( vdd_min , true ) ;
if ( vdd_min < 0 )
return 0 ;
/* Fill the mask, from max bit to min bit. */
while ( vdd_max > = vdd_min )
mask | = 1 < < vdd_max - - ;
return mask ;
}
EXPORT_SYMBOL ( mmc_vddrange_to_ocrmask ) ;
2009-03-11 14:30:43 +03:00
# ifdef CONFIG_REGULATOR
/**
* mmc_regulator_get_ocrmask - return mask of supported voltages
* @ supply : regulator to use
*
* This returns either a negative errno , or a mask of voltages that
* can be provided to MMC / SD / SDIO devices using the specified voltage
* regulator . This would normally be called before registering the
* MMC host adapter .
*/
int mmc_regulator_get_ocrmask ( struct regulator * supply )
{
int result = 0 ;
int count ;
int i ;
count = regulator_count_voltages ( supply ) ;
if ( count < 0 )
return count ;
for ( i = 0 ; i < count ; i + + ) {
int vdd_uV ;
int vdd_mV ;
vdd_uV = regulator_list_voltage ( supply , i ) ;
if ( vdd_uV < = 0 )
continue ;
vdd_mV = vdd_uV / 1000 ;
result | = mmc_vddrange_to_ocrmask ( vdd_mV , vdd_mV ) ;
}
return result ;
}
EXPORT_SYMBOL ( mmc_regulator_get_ocrmask ) ;
/**
* mmc_regulator_set_ocr - set regulator to match host - > ios voltage
* @ vdd_bit : zero for power off , else a bit number ( host - > ios . vdd )
* @ supply : regulator to use
*
* Returns zero on success , else negative errno .
*
* MMC host drivers may use this to enable or disable a regulator using
* a particular supply voltage . This would normally be called from the
* set_ios ( ) method .
*/
int mmc_regulator_set_ocr ( struct regulator * supply , unsigned short vdd_bit )
{
int result = 0 ;
int min_uV , max_uV ;
int enabled ;
enabled = regulator_is_enabled ( supply ) ;
if ( enabled < 0 )
return enabled ;
if ( vdd_bit ) {
int tmp ;
int voltage ;
/* REVISIT mmc_vddrange_to_ocrmask() may have set some
* bits this regulator doesn ' t quite support . . . don ' t
* be too picky , most cards and regulators are OK with
* a 0.1 V range goof ( it ' s a small error percentage ) .
*/
tmp = vdd_bit - ilog2 ( MMC_VDD_165_195 ) ;
if ( tmp = = 0 ) {
min_uV = 1650 * 1000 ;
max_uV = 1950 * 1000 ;
} else {
min_uV = 1900 * 1000 + tmp * 100 * 1000 ;
max_uV = min_uV + 100 * 1000 ;
}
/* avoid needless changes to this voltage; the regulator
* might not allow this operation
*/
voltage = regulator_get_voltage ( supply ) ;
if ( voltage < 0 )
result = voltage ;
else if ( voltage < min_uV | | voltage > max_uV )
result = regulator_set_voltage ( supply , min_uV , max_uV ) ;
else
result = 0 ;
if ( result = = 0 & & ! enabled )
result = regulator_enable ( supply ) ;
} else if ( enabled ) {
result = regulator_disable ( supply ) ;
}
return result ;
}
EXPORT_SYMBOL ( mmc_regulator_set_ocr ) ;
# endif
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 {
2008-12-31 20:50:30 +03:00
pr_warning ( " %s: host doesn't support card's voltages \n " ,
mmc_hostname ( host ) ) ;
2005-04-17 02:20:36 +04:00
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 )
{
2009-09-23 03:44:18 +04:00
int bit ;
/* If ocr is set, we use it */
if ( host - > ocr )
bit = ffs ( host - > ocr ) - 1 ;
else
bit = fls ( host - > ocr_avail ) - 1 ;
2005-04-17 02:20:36 +04:00
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 .
*/
2009-03-10 04:21:21 +03:00
mmc_delay ( 10 ) ;
2005-04-17 02:20:36 +04:00
2009-04-09 10:32:02 +04:00
if ( host - > f_min > 400000 ) {
pr_warning ( " %s: Minimum clock frequency too high for "
" identification mode \n " , mmc_hostname ( host ) ) ;
host - > ios . clock = host - > f_min ;
} else
host - > ios . clock = 400000 ;
2005-04-17 02:20:36 +04:00
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 .
*/
2009-03-10 04:21:21 +03:00
mmc_delay ( 10 ) ;
2005-04-17 02:20:36 +04:00
}
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 .
*/
2008-04-13 22:15:47 +04:00
static void __mmc_release_bus ( struct mmc_host * host )
2007-07-25 02:40:58 +04:00
{
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
2009-03-31 18:51:21 +04:00
/* if there is a card registered, check whether it is still present */
if ( ( host - > bus_ops ! = NULL ) & & host - > bus_ops - > detect & & ! host - > bus_dead )
host - > bus_ops - > detect ( host ) ;
mmc_bus_put ( host ) ;
mmc_bus_get ( host ) ;
/* if there still is a card present, stop here */
if ( host - > bus_ops ! = NULL ) {
2006-12-31 02:11:32 +03:00
mmc_bus_put ( host ) ;
2009-03-31 18:51:21 +04:00
goto out ;
}
2005-04-17 02:20:36 +04:00
2009-03-31 18:51:21 +04:00
/* detect a newly inserted card */
2008-06-17 18:17:15 +04:00
2009-03-31 18:51:21 +04:00
/*
* Only we can add a new handler , so it ' s safe to
* release the lock here .
*/
mmc_bus_put ( host ) ;
2005-04-17 02:20:36 +04:00
2009-03-31 18:51:21 +04:00
if ( host - > ops - > get_cd & & host - > ops - > get_cd ( host ) = = 0 )
goto out ;
2005-04-17 02:20:36 +04:00
2009-03-31 18:51:21 +04:00
mmc_claim_host ( host ) ;
2005-04-17 02:20:36 +04:00
2009-03-31 18:51:21 +04:00
mmc_power_up ( host ) ;
2010-03-11 02:20:37 +03:00
sdio_reset ( host ) ;
2009-03-31 18:51:21 +04:00
mmc_go_idle ( host ) ;
2007-05-21 22:23:20 +04:00
2009-03-31 18:51:21 +04:00
mmc_send_if_cond ( host , host - > ocr_avail ) ;
2007-05-21 22:23:20 +04:00
2009-03-31 18:51:21 +04:00
/*
* First we search for SDIO . . .
*/
err = mmc_send_io_op_cond ( host , 0 , & ocr ) ;
if ( ! err ) {
2010-08-11 05:01:40 +04:00
if ( mmc_attach_sdio ( host , ocr ) ) {
mmc_claim_host ( host ) ;
/* try SDMEM (but not MMC) even if SDIO is broken */
if ( mmc_send_app_op_cond ( host , 0 , & ocr ) )
goto out_fail ;
if ( mmc_attach_sd ( host , ocr ) )
mmc_power_off ( host ) ;
}
2009-03-31 18:51:21 +04:00
goto out ;
}
2007-05-21 22:23:20 +04:00
2009-03-31 18:51:21 +04:00
/*
* . . . then normal SD . . .
*/
err = mmc_send_app_op_cond ( host , 0 , & ocr ) ;
if ( ! err ) {
if ( mmc_attach_sd ( host , ocr ) )
mmc_power_off ( host ) ;
goto out ;
}
2006-12-31 02:11:32 +03:00
2009-03-31 18:51:21 +04:00
/*
* . . . and finally MMC .
*/
err = mmc_send_op_cond ( host , 0 , & ocr ) ;
if ( ! err ) {
if ( mmc_attach_mmc ( host , ocr ) )
mmc_power_off ( host ) ;
goto out ;
2006-12-31 02:11:32 +03:00
}
2009-03-31 18:51:21 +04:00
2010-08-11 05:01:40 +04:00
out_fail :
2009-03-31 18:51:21 +04:00
mmc_release_host ( host ) ;
mmc_power_off ( host ) ;
2008-06-17 18:17:15 +04:00
out :
if ( host - > caps & MMC_CAP_NEEDS_POLL )
mmc_schedule_delayed_work ( & host - > detect , HZ ) ;
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
2009-09-23 03:44:29 +04:00
if ( host - > caps & MMC_CAP_DISABLE )
cancel_delayed_work ( & host - > disable ) ;
2009-02-19 14:17:03 +03:00
cancel_delayed_work ( & host - > detect ) ;
2007-02-11 22:43:19 +03:00
mmc_flush_scheduled_work ( ) ;
2010-03-06 00:43:31 +03:00
/* clear pm flags now and let card drivers set them as needed */
host - > pm_flags = 0 ;
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 ) ;
2009-09-23 03:44:36 +04:00
mmc_bus_put ( host ) ;
return ;
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 ) ;
}
2009-09-23 03:44:33 +04:00
void mmc_power_save_host ( struct mmc_host * host )
{
mmc_bus_get ( host ) ;
if ( ! host - > bus_ops | | host - > bus_dead | | ! host - > bus_ops - > power_restore ) {
mmc_bus_put ( host ) ;
return ;
}
if ( host - > bus_ops - > power_save )
host - > bus_ops - > power_save ( host ) ;
mmc_bus_put ( host ) ;
mmc_power_off ( host ) ;
}
EXPORT_SYMBOL ( mmc_power_save_host ) ;
void mmc_power_restore_host ( struct mmc_host * host )
{
mmc_bus_get ( host ) ;
if ( ! host - > bus_ops | | host - > bus_dead | | ! host - > bus_ops - > power_restore ) {
mmc_bus_put ( host ) ;
return ;
}
mmc_power_up ( host ) ;
host - > bus_ops - > power_restore ( host ) ;
mmc_bus_put ( host ) ;
}
EXPORT_SYMBOL ( mmc_power_restore_host ) ;
2009-09-23 03:44:34 +04:00
int mmc_card_awake ( struct mmc_host * host )
{
int err = - ENOSYS ;
mmc_bus_get ( host ) ;
if ( host - > bus_ops & & ! host - > bus_dead & & host - > bus_ops - > awake )
err = host - > bus_ops - > awake ( host ) ;
mmc_bus_put ( host ) ;
return err ;
}
EXPORT_SYMBOL ( mmc_card_awake ) ;
int mmc_card_sleep ( struct mmc_host * host )
{
int err = - ENOSYS ;
mmc_bus_get ( host ) ;
if ( host - > bus_ops & & ! host - > bus_dead & & host - > bus_ops - > awake )
err = host - > bus_ops - > sleep ( host ) ;
mmc_bus_put ( host ) ;
return err ;
}
EXPORT_SYMBOL ( mmc_card_sleep ) ;
int mmc_card_can_sleep ( struct mmc_host * host )
{
struct mmc_card * card = host - > card ;
if ( card & & mmc_card_mmc ( card ) & & card - > ext_csd . rev > = 3 )
return 1 ;
return 0 ;
}
EXPORT_SYMBOL ( mmc_card_can_sleep ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PM
/**
* mmc_suspend_host - suspend a host
* @ host : mmc host
*/
2010-05-27 01:42:08 +04:00
int mmc_suspend_host ( struct mmc_host * host )
2005-04-17 02:20:36 +04:00
{
2009-09-23 03:45:29 +04:00
int err = 0 ;
2009-09-23 03:44:29 +04:00
if ( host - > caps & MMC_CAP_DISABLE )
cancel_delayed_work ( & host - > disable ) ;
2009-02-19 14:17:03 +03:00
cancel_delayed_work ( & host - > detect ) ;
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 )
2009-09-23 03:45:29 +04:00
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 .
*/
2007-05-01 18:00:02 +04:00
if ( host - > bus_ops - > remove )
host - > bus_ops - > remove ( host ) ;
mmc_claim_host ( host ) ;
mmc_detach_bus ( host ) ;
mmc_release_host ( host ) ;
2010-03-06 00:43:31 +03:00
host - > pm_flags = 0 ;
2009-09-23 03:45:29 +04:00
err = 0 ;
2007-05-01 18:00:02 +04:00
}
2007-04-28 19:30:50 +04:00
}
2006-12-31 02:11:32 +03:00
mmc_bus_put ( host ) ;
2010-03-06 00:43:31 +03:00
if ( ! err & & ! ( host - > pm_flags & MMC_PM_KEEP_POWER ) )
2009-09-23 03:45:29 +04:00
mmc_power_off ( host ) ;
2005-04-17 02:20:36 +04:00
2009-09-23 03:45:29 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( mmc_suspend_host ) ;
/**
* mmc_resume_host - resume a previously suspended host
* @ host : mmc host
*/
int mmc_resume_host ( struct mmc_host * host )
{
2009-09-23 03:45:29 +04:00
int err = 0 ;
2007-05-01 18:00:02 +04:00
mmc_bus_get ( host ) ;
if ( host - > bus_ops & & ! host - > bus_dead ) {
2010-03-06 00:43:31 +03:00
if ( ! ( host - > pm_flags & MMC_PM_KEEP_POWER ) ) {
mmc_power_up ( host ) ;
mmc_select_voltage ( host , host - > ocr ) ;
}
2007-05-01 18:00:02 +04:00
BUG_ON ( ! host - > bus_ops - > resume ) ;
2009-09-23 03:45:29 +04:00
err = host - > bus_ops - > resume ( host ) ;
if ( err ) {
printk ( KERN_WARNING " %s: error %d during resume "
" (card was removed?) \n " ,
mmc_hostname ( host ) , err ) ;
if ( host - > bus_ops - > remove )
host - > bus_ops - > remove ( host ) ;
mmc_claim_host ( host ) ;
mmc_detach_bus ( host ) ;
mmc_release_host ( host ) ;
/* no need to bother upper layers */
err = 0 ;
}
2007-05-01 18:00:02 +04:00
}
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
2009-09-23 03:45:29 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
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 " ) ;