2006-12-31 02:11:32 +03:00
/*
2007-07-11 22:04:50 +04:00
* linux / drivers / mmc / core / sd . c
2006-12-31 02:11:32 +03:00
*
* Copyright ( C ) 2003 - 2004 Russell King , All Rights Reserved .
* SD support Copyright ( C ) 2004 Ian Molton , All Rights Reserved .
* Copyright ( C ) 2005 - 2007 Pierre Ossman , All Rights Reserved .
*
* 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/err.h>
# include <linux/mmc/host.h>
# include <linux/mmc/card.h>
# include <linux/mmc/mmc.h>
2007-06-01 00:25:11 +04:00
# include <linux/mmc/sd.h>
2006-12-31 02:11:32 +03:00
# include "core.h"
# include "sysfs.h"
2007-05-19 15:39:01 +04:00
# include "bus.h"
2006-12-31 02:11:32 +03:00
# include "mmc_ops.h"
# include "sd_ops.h"
static const unsigned int tran_exp [ ] = {
10000 , 100000 , 1000000 , 10000000 ,
0 , 0 , 0 , 0
} ;
static const unsigned char tran_mant [ ] = {
0 , 10 , 12 , 13 , 15 , 20 , 25 , 30 ,
35 , 40 , 45 , 50 , 55 , 60 , 70 , 80 ,
} ;
static const unsigned int tacc_exp [ ] = {
1 , 10 , 100 , 1000 , 10000 , 100000 , 1000000 , 10000000 ,
} ;
static const unsigned int tacc_mant [ ] = {
0 , 10 , 12 , 13 , 15 , 20 , 25 , 30 ,
35 , 40 , 45 , 50 , 55 , 60 , 70 , 80 ,
} ;
# define UNSTUFF_BITS(resp,start,size) \
( { \
const int __size = size ; \
const u32 __mask = ( __size < 32 ? 1 < < __size : 0 ) - 1 ; \
const int __off = 3 - ( ( start ) / 32 ) ; \
const int __shft = ( start ) & 31 ; \
u32 __res ; \
\
__res = resp [ __off ] > > __shft ; \
if ( __size + __shft > 32 ) \
__res | = resp [ __off - 1 ] < < ( ( 32 - __shft ) % 32 ) ; \
__res & __mask ; \
} )
/*
* Given the decoded CSD structure , decode the raw CID to our CID structure .
*/
static void mmc_decode_cid ( struct mmc_card * card )
{
u32 * resp = card - > raw_cid ;
memset ( & card - > cid , 0 , sizeof ( struct mmc_cid ) ) ;
/*
* SD doesn ' t currently have a version field so we will
* have to assume we can parse this .
*/
card - > cid . manfid = UNSTUFF_BITS ( resp , 120 , 8 ) ;
card - > cid . oemid = UNSTUFF_BITS ( resp , 104 , 16 ) ;
card - > cid . prod_name [ 0 ] = UNSTUFF_BITS ( resp , 96 , 8 ) ;
card - > cid . prod_name [ 1 ] = UNSTUFF_BITS ( resp , 88 , 8 ) ;
card - > cid . prod_name [ 2 ] = UNSTUFF_BITS ( resp , 80 , 8 ) ;
card - > cid . prod_name [ 3 ] = UNSTUFF_BITS ( resp , 72 , 8 ) ;
card - > cid . prod_name [ 4 ] = UNSTUFF_BITS ( resp , 64 , 8 ) ;
card - > cid . hwrev = UNSTUFF_BITS ( resp , 60 , 4 ) ;
card - > cid . fwrev = UNSTUFF_BITS ( resp , 56 , 4 ) ;
card - > cid . serial = UNSTUFF_BITS ( resp , 24 , 32 ) ;
card - > cid . year = UNSTUFF_BITS ( resp , 12 , 8 ) ;
card - > cid . month = UNSTUFF_BITS ( resp , 8 , 4 ) ;
card - > cid . year + = 2000 ; /* SD cards year offset */
}
/*
* Given a 128 - bit response , decode to our card CSD structure .
*/
2007-05-01 18:11:57 +04:00
static int mmc_decode_csd ( struct mmc_card * card )
2006-12-31 02:11:32 +03:00
{
struct mmc_csd * csd = & card - > csd ;
unsigned int e , m , csd_struct ;
u32 * resp = card - > raw_csd ;
csd_struct = UNSTUFF_BITS ( resp , 126 , 2 ) ;
switch ( csd_struct ) {
case 0 :
m = UNSTUFF_BITS ( resp , 115 , 4 ) ;
e = UNSTUFF_BITS ( resp , 112 , 3 ) ;
csd - > tacc_ns = ( tacc_exp [ e ] * tacc_mant [ m ] + 9 ) / 10 ;
csd - > tacc_clks = UNSTUFF_BITS ( resp , 104 , 8 ) * 100 ;
m = UNSTUFF_BITS ( resp , 99 , 4 ) ;
e = UNSTUFF_BITS ( resp , 96 , 3 ) ;
csd - > max_dtr = tran_exp [ e ] * tran_mant [ m ] ;
csd - > cmdclass = UNSTUFF_BITS ( resp , 84 , 12 ) ;
e = UNSTUFF_BITS ( resp , 47 , 3 ) ;
m = UNSTUFF_BITS ( resp , 62 , 12 ) ;
csd - > capacity = ( 1 + m ) < < ( e + 2 ) ;
csd - > read_blkbits = UNSTUFF_BITS ( resp , 80 , 4 ) ;
csd - > read_partial = UNSTUFF_BITS ( resp , 79 , 1 ) ;
csd - > write_misalign = UNSTUFF_BITS ( resp , 78 , 1 ) ;
csd - > read_misalign = UNSTUFF_BITS ( resp , 77 , 1 ) ;
csd - > r2w_factor = UNSTUFF_BITS ( resp , 26 , 3 ) ;
csd - > write_blkbits = UNSTUFF_BITS ( resp , 22 , 4 ) ;
csd - > write_partial = UNSTUFF_BITS ( resp , 21 , 1 ) ;
break ;
case 1 :
/*
* This is a block - addressed SDHC card . Most
* interesting fields are unused and have fixed
* values . To avoid getting tripped by buggy cards ,
* we assume those fixed values ourselves .
*/
mmc_card_set_blockaddr ( card ) ;
csd - > tacc_ns = 0 ; /* Unused */
csd - > tacc_clks = 0 ; /* Unused */
m = UNSTUFF_BITS ( resp , 99 , 4 ) ;
e = UNSTUFF_BITS ( resp , 96 , 3 ) ;
csd - > max_dtr = tran_exp [ e ] * tran_mant [ m ] ;
csd - > cmdclass = UNSTUFF_BITS ( resp , 84 , 12 ) ;
m = UNSTUFF_BITS ( resp , 48 , 22 ) ;
csd - > capacity = ( 1 + m ) < < 10 ;
csd - > read_blkbits = 9 ;
csd - > read_partial = 0 ;
csd - > write_misalign = 0 ;
csd - > read_misalign = 0 ;
csd - > r2w_factor = 4 ; /* Unused */
csd - > write_blkbits = 9 ;
csd - > write_partial = 0 ;
break ;
default :
2007-07-24 23:53:43 +04:00
printk ( KERN_ERR " %s: unrecognised CSD structure version %d \n " ,
2006-12-31 02:11:32 +03:00
mmc_hostname ( card - > host ) , csd_struct ) ;
2007-05-01 18:11:57 +04:00
return - EINVAL ;
2006-12-31 02:11:32 +03:00
}
2007-05-01 18:11:57 +04:00
return 0 ;
2006-12-31 02:11:32 +03:00
}
/*
* Given a 64 - bit response , decode to our card SCR structure .
*/
2007-05-01 18:11:57 +04:00
static int mmc_decode_scr ( struct mmc_card * card )
2006-12-31 02:11:32 +03:00
{
struct sd_scr * scr = & card - > scr ;
unsigned int scr_struct ;
u32 resp [ 4 ] ;
BUG_ON ( ! mmc_card_sd ( card ) ) ;
resp [ 3 ] = card - > raw_scr [ 1 ] ;
resp [ 2 ] = card - > raw_scr [ 0 ] ;
scr_struct = UNSTUFF_BITS ( resp , 60 , 4 ) ;
if ( scr_struct ! = 0 ) {
2007-07-24 23:53:43 +04:00
printk ( KERN_ERR " %s: unrecognised SCR structure version %d \n " ,
2006-12-31 02:11:32 +03:00
mmc_hostname ( card - > host ) , scr_struct ) ;
2007-05-01 18:11:57 +04:00
return - EINVAL ;
2006-12-31 02:11:32 +03:00
}
scr - > sda_vsn = UNSTUFF_BITS ( resp , 56 , 4 ) ;
scr - > bus_widths = UNSTUFF_BITS ( resp , 48 , 4 ) ;
2007-05-01 18:11:57 +04:00
return 0 ;
2006-12-31 02:11:32 +03:00
}
/*
2007-05-01 16:46:08 +04:00
* Fetches and decodes switch information
2006-12-31 02:11:32 +03:00
*/
2007-05-01 16:46:08 +04:00
static int mmc_read_switch ( struct mmc_card * card )
2006-12-31 02:11:32 +03:00
{
int err ;
u8 * status ;
2007-06-01 00:25:11 +04:00
if ( card - > scr . sda_vsn < SCR_SPEC_VER_1 )
2007-07-23 00:18:46 +04:00
return 0 ;
2007-06-01 00:25:11 +04:00
if ( ! ( card - > csd . cmdclass & CCC_SWITCH ) ) {
printk ( KERN_WARNING " %s: card lacks mandatory switch "
" function, performance might suffer. \n " ,
mmc_hostname ( card - > host ) ) ;
2007-07-23 00:18:46 +04:00
return 0 ;
2007-06-01 00:25:11 +04:00
}
2007-07-23 00:18:46 +04:00
err = - EIO ;
2006-12-31 02:11:32 +03:00
status = kmalloc ( 64 , GFP_KERNEL ) ;
if ( ! status ) {
2007-07-24 23:53:43 +04:00
printk ( KERN_ERR " %s: could not allocate a buffer for "
" switch capabilities. \n " , mmc_hostname ( card - > host ) ) ;
2007-07-23 00:18:46 +04:00
return - ENOMEM ;
2006-12-31 02:11:32 +03:00
}
err = mmc_sd_switch ( card , 0 , 0 , 1 , status ) ;
2007-07-23 00:18:46 +04:00
if ( err ) {
2007-07-23 01:08:30 +04:00
/*
* We all hosts that cannot perform the command
* to fail more gracefully
*/
if ( err ! = - EINVAL )
goto out ;
2007-06-01 00:25:11 +04:00
printk ( KERN_WARNING " %s: problem reading switch "
" capabilities, performance might suffer. \n " ,
mmc_hostname ( card - > host ) ) ;
2007-07-23 00:18:46 +04:00
err = 0 ;
2007-07-23 01:08:30 +04:00
2006-12-31 02:11:32 +03:00
goto out ;
}
if ( status [ 13 ] & 0x02 )
card - > sw_caps . hs_max_dtr = 50000000 ;
2007-05-01 16:46:08 +04:00
out :
kfree ( status ) ;
return err ;
}
/*
* Test if the card supports high - speed mode and , if so , switch to it .
*/
static int mmc_switch_hs ( struct mmc_card * card )
{
int err ;
u8 * status ;
2007-06-01 00:25:11 +04:00
if ( card - > scr . sda_vsn < SCR_SPEC_VER_1 )
2007-07-23 00:18:46 +04:00
return 0 ;
2007-06-01 00:25:11 +04:00
if ( ! ( card - > csd . cmdclass & CCC_SWITCH ) )
2007-07-23 00:18:46 +04:00
return 0 ;
2007-06-01 00:25:11 +04:00
2007-05-01 16:46:08 +04:00
if ( ! ( card - > host - > caps & MMC_CAP_SD_HIGHSPEED ) )
2007-07-23 00:18:46 +04:00
return 0 ;
2007-05-01 16:46:08 +04:00
if ( card - > sw_caps . hs_max_dtr = = 0 )
2007-07-23 00:18:46 +04:00
return 0 ;
2007-05-01 16:46:08 +04:00
2007-07-23 00:18:46 +04:00
err = - EIO ;
2007-05-01 16:46:08 +04:00
status = kmalloc ( 64 , GFP_KERNEL ) ;
if ( ! status ) {
2007-07-24 23:53:43 +04:00
printk ( KERN_ERR " %s: could not allocate a buffer for "
" switch capabilities. \n " , mmc_hostname ( card - > host ) ) ;
2007-07-23 00:18:46 +04:00
return - ENOMEM ;
2007-05-01 16:46:08 +04:00
}
2006-12-31 02:11:32 +03:00
err = mmc_sd_switch ( card , 1 , 0 , 1 , status ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2006-12-31 02:11:32 +03:00
goto out ;
if ( ( status [ 16 ] & 0xF ) ! = 1 ) {
printk ( KERN_WARNING " %s: Problem switching card "
" into high-speed mode! \n " ,
mmc_hostname ( card - > host ) ) ;
} else {
mmc_card_set_highspeed ( card ) ;
mmc_set_timing ( card - > host , MMC_TIMING_SD_HS ) ;
}
out :
kfree ( status ) ;
return err ;
}
/*
2007-05-01 18:00:02 +04:00
* Handle the detection and initialisation of a card .
*
* In the case of a resume , " curcard " will contain the card
* we ' re trying to reinitialise .
2006-12-31 02:11:32 +03:00
*/
2007-05-01 18:00:02 +04:00
static int mmc_sd_init_card ( struct mmc_host * host , u32 ocr ,
struct mmc_card * oldcard )
2006-12-31 02:11:32 +03:00
{
struct mmc_card * card ;
int err ;
u32 cid [ 4 ] ;
unsigned int max_dtr ;
BUG_ON ( ! host ) ;
BUG_ON ( ! host - > claimed ) ;
/*
* Since we ' re changing the OCR value , we seem to
* need to tell some cards to go back to the idle
* state . We wait 1 ms to give cards time to
* respond .
*/
mmc_go_idle ( host ) ;
/*
* If SD_SEND_IF_COND indicates an SD 2.0
* compliant card and we should set bit 30
* of the ocr to indicate that we can handle
* block - addressed SDHC cards .
*/
2007-05-01 18:00:02 +04:00
err = mmc_send_if_cond ( host , ocr ) ;
2007-07-23 00:18:46 +04:00
if ( ! err )
2007-05-01 18:00:02 +04:00
ocr | = 1 < < 30 ;
2006-12-31 02:11:32 +03:00
2007-05-01 18:00:02 +04:00
err = mmc_send_app_op_cond ( host , ocr , NULL ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2007-05-01 18:00:02 +04:00
goto err ;
2006-12-31 02:11:32 +03:00
/*
* Fetch CID from card .
*/
err = mmc_all_send_cid ( host , cid ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2006-12-31 02:11:32 +03:00
goto err ;
2007-05-01 18:00:02 +04:00
if ( oldcard ) {
2007-07-23 01:08:30 +04:00
if ( memcmp ( cid , oldcard - > raw_cid , sizeof ( cid ) ) ! = 0 ) {
err = - ENOENT ;
2007-05-01 18:00:02 +04:00
goto err ;
2007-07-23 01:08:30 +04:00
}
2006-12-31 02:11:32 +03:00
2007-05-01 18:00:02 +04:00
card = oldcard ;
} else {
/*
* Allocate card structure .
*/
card = mmc_alloc_card ( host ) ;
2007-07-23 01:08:30 +04:00
if ( IS_ERR ( card ) ) {
err = PTR_ERR ( card ) ;
2007-05-01 18:00:02 +04:00
goto err ;
2007-07-23 01:08:30 +04:00
}
2007-05-01 18:00:02 +04:00
card - > type = MMC_TYPE_SD ;
memcpy ( card - > raw_cid , cid , sizeof ( card - > raw_cid ) ) ;
}
2006-12-31 02:11:32 +03:00
/*
* Set card RCA .
*/
err = mmc_send_relative_addr ( host , & card - > rca ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2006-12-31 02:11:32 +03:00
goto free_card ;
mmc_set_bus_mode ( host , MMC_BUSMODE_PUSHPULL ) ;
2007-05-01 18:00:02 +04:00
if ( ! oldcard ) {
/*
* Fetch CSD from card .
*/
err = mmc_send_csd ( card , card - > raw_csd ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2007-05-01 18:00:02 +04:00
goto free_card ;
2006-12-31 02:11:32 +03:00
2007-05-01 18:11:57 +04:00
err = mmc_decode_csd ( card ) ;
2007-07-23 01:08:30 +04:00
if ( err )
2007-05-01 18:11:57 +04:00
goto free_card ;
2007-05-01 18:00:02 +04:00
mmc_decode_cid ( card ) ;
}
2006-12-31 02:11:32 +03:00
/*
2007-05-01 18:00:02 +04:00
* Select card , as all following commands rely on that .
2006-12-31 02:11:32 +03:00
*/
err = mmc_select_card ( card ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2006-12-31 02:11:32 +03:00
goto free_card ;
2007-05-01 18:00:02 +04:00
if ( ! oldcard ) {
/*
* Fetch SCR from card .
*/
err = mmc_app_send_scr ( card , card - > raw_scr ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2007-05-01 18:00:02 +04:00
goto free_card ;
2006-12-31 02:11:32 +03:00
2007-05-01 18:11:57 +04:00
err = mmc_decode_scr ( card ) ;
if ( err < 0 )
goto free_card ;
2006-12-31 02:11:32 +03:00
2007-05-01 18:00:02 +04:00
/*
* Fetch switch information from card .
*/
err = mmc_read_switch ( card ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2007-05-01 18:00:02 +04:00
goto free_card ;
}
2007-05-01 16:46:08 +04:00
/*
* Attempt to change to high - speed ( if supported )
2006-12-31 02:11:32 +03:00
*/
err = mmc_switch_hs ( card ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2006-12-31 02:11:32 +03:00
goto free_card ;
/*
* Compute bus speed .
*/
max_dtr = ( unsigned int ) - 1 ;
if ( mmc_card_highspeed ( card ) ) {
if ( max_dtr > card - > sw_caps . hs_max_dtr )
max_dtr = card - > sw_caps . hs_max_dtr ;
} else if ( max_dtr > card - > csd . max_dtr ) {
max_dtr = card - > csd . max_dtr ;
}
mmc_set_clock ( host , max_dtr ) ;
/*
* Switch to wider bus ( if supported ) .
*/
2007-06-06 22:23:25 +04:00
if ( ( host - > caps & MMC_CAP_4_BIT_DATA ) & &
2006-12-31 02:11:32 +03:00
( card - > scr . bus_widths & SD_SCR_BUS_WIDTH_4 ) ) {
err = mmc_app_set_bus_width ( card , MMC_BUS_WIDTH_4 ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2006-12-31 02:11:32 +03:00
goto free_card ;
mmc_set_bus_width ( host , MMC_BUS_WIDTH_4 ) ;
}
2007-06-13 21:06:03 +04:00
/*
* Check if read - only switch is active .
*/
if ( ! oldcard ) {
if ( ! host - > ops - > get_ro ) {
printk ( KERN_WARNING " %s: host does not "
" support reading read-only "
" switch. assuming write-enable. \n " ,
mmc_hostname ( host ) ) ;
} else {
if ( host - > ops - > get_ro ( host ) )
mmc_card_set_readonly ( card ) ;
}
}
2007-05-01 18:00:02 +04:00
if ( ! oldcard )
host - > card = card ;
2007-07-23 00:18:46 +04:00
return 0 ;
2007-05-01 18:00:02 +04:00
free_card :
if ( ! oldcard )
mmc_remove_card ( card ) ;
err :
2007-07-23 01:08:30 +04:00
return err ;
2007-05-01 18:00:02 +04:00
}
/*
* Host is being removed . Free up the current card .
*/
static void mmc_sd_remove ( struct mmc_host * host )
{
BUG_ON ( ! host ) ;
BUG_ON ( ! host - > card ) ;
mmc_remove_card ( host - > card ) ;
host - > card = NULL ;
}
/*
* Card detection callback from host .
*/
static void mmc_sd_detect ( struct mmc_host * host )
{
int err ;
BUG_ON ( ! host ) ;
BUG_ON ( ! host - > card ) ;
mmc_claim_host ( host ) ;
/*
* Just check if our card has been removed .
*/
err = mmc_send_status ( host - > card , NULL ) ;
2006-12-31 02:11:32 +03:00
mmc_release_host ( host ) ;
2007-07-23 00:18:46 +04:00
if ( err ) {
2007-05-19 15:39:01 +04:00
mmc_sd_remove ( host ) ;
2007-05-01 18:00:02 +04:00
mmc_claim_host ( host ) ;
mmc_detach_bus ( host ) ;
mmc_release_host ( host ) ;
}
}
2007-05-19 15:39:01 +04:00
MMC_ATTR_FN ( cid , " %08x%08x%08x%08x \n " , card - > raw_cid [ 0 ] , card - > raw_cid [ 1 ] ,
card - > raw_cid [ 2 ] , card - > raw_cid [ 3 ] ) ;
MMC_ATTR_FN ( csd , " %08x%08x%08x%08x \n " , card - > raw_csd [ 0 ] , card - > raw_csd [ 1 ] ,
card - > raw_csd [ 2 ] , card - > raw_csd [ 3 ] ) ;
MMC_ATTR_FN ( scr , " %08x%08x \n " , card - > raw_scr [ 0 ] , card - > raw_scr [ 1 ] ) ;
MMC_ATTR_FN ( date , " %02d/%04d \n " , card - > cid . month , card - > cid . year ) ;
MMC_ATTR_FN ( fwrev , " 0x%x \n " , card - > cid . fwrev ) ;
MMC_ATTR_FN ( hwrev , " 0x%x \n " , card - > cid . hwrev ) ;
MMC_ATTR_FN ( manfid , " 0x%06x \n " , card - > cid . manfid ) ;
MMC_ATTR_FN ( name , " %s \n " , card - > cid . prod_name ) ;
MMC_ATTR_FN ( oemid , " 0x%04x \n " , card - > cid . oemid ) ;
MMC_ATTR_FN ( serial , " 0x%08x \n " , card - > cid . serial ) ;
static struct device_attribute mmc_sd_dev_attrs [ ] = {
MMC_ATTR_RO ( cid ) ,
MMC_ATTR_RO ( csd ) ,
MMC_ATTR_RO ( scr ) ,
MMC_ATTR_RO ( date ) ,
MMC_ATTR_RO ( fwrev ) ,
MMC_ATTR_RO ( hwrev ) ,
MMC_ATTR_RO ( manfid ) ,
MMC_ATTR_RO ( name ) ,
MMC_ATTR_RO ( oemid ) ,
MMC_ATTR_RO ( serial ) ,
__ATTR_NULL ,
} ;
/*
* Adds sysfs entries as relevant .
*/
static int mmc_sd_sysfs_add ( struct mmc_host * host , struct mmc_card * card )
{
int ret ;
ret = mmc_add_attrs ( card , mmc_sd_dev_attrs ) ;
if ( ret < 0 )
return ret ;
return 0 ;
}
/*
* Removes the sysfs entries added by mmc_sysfs_add ( ) .
*/
static void mmc_sd_sysfs_remove ( struct mmc_host * host , struct mmc_card * card )
{
mmc_remove_attrs ( card , mmc_sd_dev_attrs ) ;
}
2007-05-01 18:00:02 +04:00
# ifdef CONFIG_MMC_UNSAFE_RESUME
/*
* Suspend callback from host .
*/
static void mmc_sd_suspend ( struct mmc_host * host )
{
BUG_ON ( ! host ) ;
BUG_ON ( ! host - > card ) ;
mmc_claim_host ( host ) ;
mmc_deselect_cards ( host ) ;
host - > card - > state & = ~ MMC_STATE_HIGHSPEED ;
mmc_release_host ( host ) ;
}
/*
* Resume callback from host .
*
* This function tries to determine if the same card is still present
* and , if so , restore all state to it .
*/
static void mmc_sd_resume ( struct mmc_host * host )
{
int err ;
BUG_ON ( ! host ) ;
BUG_ON ( ! host - > card ) ;
mmc_claim_host ( host ) ;
err = mmc_sd_init_card ( host , host - > ocr , host - > card ) ;
2007-07-22 19:52:06 +04:00
mmc_release_host ( host ) ;
2007-07-23 00:18:46 +04:00
if ( err ) {
2007-05-19 15:39:01 +04:00
mmc_sd_remove ( host ) ;
2007-07-22 19:52:06 +04:00
mmc_claim_host ( host ) ;
2007-05-01 18:00:02 +04:00
mmc_detach_bus ( host ) ;
2007-07-22 19:52:06 +04:00
mmc_release_host ( host ) ;
2007-05-01 18:00:02 +04:00
}
}
# else
# define mmc_sd_suspend NULL
# define mmc_sd_resume NULL
# endif
static const struct mmc_bus_ops mmc_sd_ops = {
. remove = mmc_sd_remove ,
. detect = mmc_sd_detect ,
2007-05-19 15:39:01 +04:00
. sysfs_add = mmc_sd_sysfs_add ,
. sysfs_remove = mmc_sd_sysfs_remove ,
2007-05-01 18:00:02 +04:00
. suspend = mmc_sd_suspend ,
. resume = mmc_sd_resume ,
} ;
/*
* Starting point for SD card init .
*/
int mmc_attach_sd ( struct mmc_host * host , u32 ocr )
{
int err ;
BUG_ON ( ! host ) ;
BUG_ON ( ! host - > claimed ) ;
mmc_attach_bus ( host , & mmc_sd_ops ) ;
/*
* Sanity check the voltages that the card claims to
* support .
*/
if ( ocr & 0x7F ) {
printk ( KERN_WARNING " %s: card claims to support voltages "
" below the defined range. These will be ignored. \n " ,
mmc_hostname ( host ) ) ;
ocr & = ~ 0x7F ;
}
if ( ocr & MMC_VDD_165_195 ) {
printk ( KERN_WARNING " %s: SD card claims to support the "
" incompletely defined 'low voltage range'. This "
" will be ignored. \n " , mmc_hostname ( host ) ) ;
ocr & = ~ MMC_VDD_165_195 ;
}
host - > ocr = mmc_select_voltage ( host , ocr ) ;
/*
* Can we support the voltage ( s ) of the card ( s ) ?
*/
2007-07-23 02:12:10 +04:00
if ( ! host - > ocr ) {
err = - EINVAL ;
2007-05-01 18:00:02 +04:00
goto err ;
2007-07-23 02:12:10 +04:00
}
2007-05-01 18:00:02 +04:00
/*
* Detect and init the card .
*/
err = mmc_sd_init_card ( host , host - > ocr , NULL ) ;
2007-07-23 00:18:46 +04:00
if ( err )
2007-05-01 18:00:02 +04:00
goto err ;
mmc_release_host ( host ) ;
2007-05-19 15:39:01 +04:00
err = mmc_add_card ( host - > card ) ;
2006-12-31 02:11:32 +03:00
if ( err )
2007-07-22 19:52:06 +04:00
goto remove_card ;
2006-12-31 02:11:32 +03:00
return 0 ;
2007-07-22 19:52:06 +04:00
remove_card :
2007-05-01 18:00:02 +04:00
mmc_remove_card ( host - > card ) ;
2006-12-31 02:11:32 +03:00
host - > card = NULL ;
2007-07-22 19:52:06 +04:00
mmc_claim_host ( host ) ;
2006-12-31 02:11:32 +03:00
err :
mmc_detach_bus ( host ) ;
mmc_release_host ( host ) ;
2007-07-23 02:12:10 +04:00
printk ( KERN_ERR " %s: error %d whilst initialising SD card \n " ,
mmc_hostname ( host ) , err ) ;
2007-07-23 01:08:30 +04:00
return err ;
2006-12-31 02:11:32 +03:00
}