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"
2006-12-25 00:46:55 +03:00
# include "mmc_ops.h"
# include "sd_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 ) ;
2005-04-17 02:20:36 +04:00
2007-05-19 16:32:22 +04:00
static struct workqueue_struct * workqueue ;
/*
* 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 ;
pr_debug ( " %s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x \n " ,
mmc_hostname ( host ) , cmd - > opcode , err ,
mrq - > data ? mrq - > data - > error : 0 ,
mrq - > stop ? mrq - > stop - > error : 0 ,
cmd - > resp [ 0 ] , cmd - > resp [ 1 ] , cmd - > resp [ 2 ] , cmd - > resp [ 3 ] ) ;
2005-04-17 02:20:36 +04:00
if ( err & & cmd - > retries ) {
cmd - > retries - - ;
cmd - > error = 0 ;
host - > ops - > request ( host , mrq ) ;
} else if ( mrq - > done ) {
mrq - > done ( mrq ) ;
}
}
EXPORT_SYMBOL ( mmc_request_done ) ;
/**
* mmc_start_request - start a command on a host
* @ host : MMC host to start command on
* @ mrq : MMC request to start
*
* Queue a command on the specified host . We expect the
* caller to be holding the host lock with interrupts disabled .
*/
void
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
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 ) ;
}
EXPORT_SYMBOL ( mmc_start_request ) ;
static void mmc_wait_done ( struct mmc_request * mrq )
{
complete ( mrq - > done_data ) ;
}
int mmc_wait_for_req ( struct mmc_host * host , struct mmc_request * mrq )
{
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 ) ;
return 0 ;
}
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 ;
2006-12-26 17:11:23 +03:00
BUG_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
* @ write : flag to differentiate reads from writes
*/
void mmc_set_data_timeout ( struct mmc_data * data , const struct mmc_card * card ,
int write )
{
unsigned int mult ;
/*
* 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 .
*/
if ( write )
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 ) ;
if ( write )
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
/**
* __mmc_claim_host - exclusively claim a host
* @ host : mmc host to claim
* @ card : mmc card to claim host for
*
* Claim a host for a set of operations . If a valid card
* is passed and this wasn ' t the last card selected , select
* the card before returning .
*
* Note : you should use mmc_card_claim_host or mmc_claim_host .
*/
2007-01-03 21:47:29 +03:00
void mmc_claim_host ( struct mmc_host * host )
2005-04-17 02:20:36 +04:00
{
DECLARE_WAITQUEUE ( wait , current ) ;
unsigned long flags ;
add_wait_queue ( & host - > wq , & wait ) ;
spin_lock_irqsave ( & host - > lock , flags ) ;
while ( 1 ) {
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
2006-12-26 17:11:23 +03:00
if ( ! 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 ) ;
2006-12-26 17:11:23 +03:00
host - > claimed = 1 ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & host - > lock , flags ) ;
remove_wait_queue ( & host - > wq , & wait ) ;
}
2007-01-03 21:47:29 +03: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 ;
2006-12-26 17:11:23 +03:00
BUG_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 ;
host - > ios . bus_mode = MMC_BUSMODE_OPENDRAIN ;
2005-09-03 19:45:02 +04:00
host - > ios . chip_select = MMC_CS_DONTCARE ;
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
mmc_delay ( 1 ) ;
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
mmc_delay ( 2 ) ;
}
static void mmc_power_off ( struct mmc_host * host )
{
host - > ios . clock = 0 ;
host - > ios . vdd = 0 ;
host - > ios . bus_mode = MMC_BUSMODE_OPENDRAIN ;
2005-09-03 19:45:02 +04:00
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
}
/*
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
2006-12-31 02:11:32 +03:00
BUG_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
2006-12-31 02:11:32 +03:00
BUG_ON ( ! host - > claimed ) ;
BUG_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
}
/*
2006-12-31 02:11:32 +03:00
* Cleanup when the last reference to the bus operator is dropped .
2005-04-17 02:20:36 +04:00
*/
2006-12-31 02:11:32 +03:00
void __mmc_release_bus ( struct mmc_host * host )
2005-04-17 02:20:36 +04:00
{
2006-12-31 02:11:32 +03:00
BUG_ON ( ! host ) ;
BUG_ON ( host - > bus_refs ) ;
BUG_ON ( ! host - > bus_dead ) ;
2005-04-17 02:20:36 +04:00
2006-12-31 02:11:32 +03:00
host - > bus_ops = NULL ;
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
*
* All we know is that card ( s ) have been inserted or removed
* from the socket ( s ) . We don ' t know which socket or cards .
*/
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-02-11 22:43:19 +03:00
BUG_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
2006-12-31 02:11:32 +03:00
err = mmc_send_app_op_cond ( host , 0 , & ocr ) ;
if ( err = = MMC_ERR_NONE ) {
if ( mmc_attach_sd ( host , ocr ) )
mmc_power_off ( host ) ;
} else {
/*
* If we fail to detect any SD cards then try
* searching for MMC cards .
*/
err = mmc_send_op_cond ( host , 0 , & ocr ) ;
if ( err = = MMC_ERR_NONE ) {
if ( mmc_attach_mmc ( host , ocr ) )
mmc_power_off ( host ) ;
} else {
mmc_power_off ( host ) ;
mmc_release_host ( host ) ;
}
}
} 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 ( ) ;
if ( ret = = 0 ) {
ret = mmc_register_host_class ( ) ;
if ( ret )
mmc_unregister_bus ( ) ;
}
return ret ;
}
static void __exit mmc_exit ( void )
{
mmc_unregister_host_class ( ) ;
mmc_unregister_bus ( ) ;
destroy_workqueue ( workqueue ) ;
}
module_init ( mmc_init ) ;
module_exit ( mmc_exit ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;