2007-05-21 22:23:20 +04:00
/*
* linux / drivers / mmc / sdio . c
*
* Copyright 2006 - 2007 Pierre Ossman
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or ( at
* your option ) any later version .
*/
# include <linux/err.h>
# include <linux/mmc/host.h>
# include <linux/mmc/card.h>
2007-06-11 22:25:43 +04:00
# include <linux/mmc/sdio.h>
2007-05-26 15:48:18 +04:00
# include <linux/mmc/sdio_func.h>
2007-05-21 22:23:20 +04:00
# include "core.h"
# include "bus.h"
2007-05-26 15:48:18 +04:00
# include "sdio_bus.h"
2007-05-21 22:23:20 +04:00
# include "mmc_ops.h"
# include "sd_ops.h"
# include "sdio_ops.h"
2007-06-16 10:04:16 +04:00
# include "sdio_cis.h"
2007-05-21 22:23:20 +04:00
2007-06-11 23:01:00 +04:00
static int sdio_read_fbr ( struct sdio_func * func )
{
int ret ;
unsigned char data ;
ret = mmc_io_rw_direct ( func - > card , 0 , 0 ,
2007-08-08 17:23:05 +04:00
SDIO_FBR_BASE ( func - > num ) + SDIO_FBR_STD_IF , 0 , & data ) ;
2007-06-11 23:01:00 +04:00
if ( ret )
goto out ;
data & = 0x0f ;
if ( data = = 0x0f ) {
ret = mmc_io_rw_direct ( func - > card , 0 , 0 ,
2007-08-08 17:23:05 +04:00
SDIO_FBR_BASE ( func - > num ) + SDIO_FBR_STD_IF_EXT , 0 , & data ) ;
2007-06-11 23:01:00 +04:00
if ( ret )
goto out ;
}
func - > class = data ;
out :
return ret ;
}
2007-05-26 15:48:18 +04:00
static int sdio_init_func ( struct mmc_card * card , unsigned int fn )
{
2007-06-11 23:01:00 +04:00
int ret ;
2007-05-26 15:48:18 +04:00
struct sdio_func * func ;
BUG_ON ( fn > SDIO_MAX_FUNCS ) ;
func = sdio_alloc_func ( card ) ;
if ( IS_ERR ( func ) )
return PTR_ERR ( func ) ;
func - > num = fn ;
2007-06-11 23:01:00 +04:00
ret = sdio_read_fbr ( func ) ;
if ( ret )
goto fail ;
2007-07-30 17:15:30 +04:00
ret = sdio_read_func_cis ( func ) ;
2007-06-16 10:04:16 +04:00
if ( ret )
goto fail ;
2007-05-26 15:48:18 +04:00
card - > sdio_func [ fn - 1 ] = func ;
return 0 ;
2007-06-11 23:01:00 +04:00
fail :
/*
* It is okay to remove the function here even though we hold
* the host lock as we haven ' t registered the device yet .
*/
sdio_remove_func ( func ) ;
return ret ;
2007-05-26 15:48:18 +04:00
}
2007-06-11 22:25:43 +04:00
static int sdio_read_cccr ( struct mmc_card * card )
{
int ret ;
int cccr_vsn ;
unsigned char data ;
memset ( & card - > cccr , 0 , sizeof ( struct sdio_cccr ) ) ;
ret = mmc_io_rw_direct ( card , 0 , 0 , SDIO_CCCR_CCCR , 0 , & data ) ;
if ( ret )
goto out ;
cccr_vsn = data & 0x0f ;
if ( cccr_vsn > SDIO_CCCR_REV_1_20 ) {
printk ( KERN_ERR " %s: unrecognised CCCR structure version %d \n " ,
mmc_hostname ( card - > host ) , cccr_vsn ) ;
return - EINVAL ;
}
card - > cccr . sdio_vsn = ( data & 0xf0 ) > > 4 ;
ret = mmc_io_rw_direct ( card , 0 , 0 , SDIO_CCCR_CAPS , 0 , & data ) ;
if ( ret )
goto out ;
if ( data & SDIO_CCCR_CAP_SMB )
card - > cccr . multi_block = 1 ;
if ( data & SDIO_CCCR_CAP_LSC )
card - > cccr . low_speed = 1 ;
if ( data & SDIO_CCCR_CAP_4BLS )
card - > cccr . wide_bus = 1 ;
if ( cccr_vsn > = SDIO_CCCR_REV_1_10 ) {
ret = mmc_io_rw_direct ( card , 0 , 0 , SDIO_CCCR_POWER , 0 , & data ) ;
if ( ret )
goto out ;
if ( data & SDIO_POWER_SMPC )
card - > cccr . high_power = 1 ;
}
if ( cccr_vsn > = SDIO_CCCR_REV_1_20 ) {
ret = mmc_io_rw_direct ( card , 0 , 0 , SDIO_CCCR_SPEED , 0 , & data ) ;
if ( ret )
goto out ;
if ( data & SDIO_SPEED_SHS )
card - > cccr . high_speed = 1 ;
}
out :
return ret ;
}
2007-07-30 20:23:53 +04:00
static int sdio_enable_wide ( struct mmc_card * card )
{
int ret ;
u8 ctrl ;
if ( ! ( card - > host - > caps & MMC_CAP_4_BIT_DATA ) )
return 0 ;
if ( card - > cccr . low_speed & & ! card - > cccr . wide_bus )
return 0 ;
ret = mmc_io_rw_direct ( card , 0 , 0 , SDIO_CCCR_IF , 0 , & ctrl ) ;
if ( ret )
return ret ;
ctrl | = SDIO_BUS_WIDTH_4BIT ;
ret = mmc_io_rw_direct ( card , 1 , 0 , SDIO_CCCR_IF , ctrl , NULL ) ;
if ( ret )
return ret ;
mmc_set_bus_width ( card - > host , MMC_BUS_WIDTH_4 ) ;
return 0 ;
}
2008-08-31 19:22:46 +04:00
/*
* Test if the card supports high - speed mode and , if so , switch to it .
*/
static int sdio_enable_hs ( struct mmc_card * card )
{
int ret ;
u8 speed ;
if ( ! ( card - > host - > caps & MMC_CAP_SD_HIGHSPEED ) )
return 0 ;
if ( ! card - > cccr . high_speed )
return 0 ;
ret = mmc_io_rw_direct ( card , 0 , 0 , SDIO_CCCR_SPEED , 0 , & speed ) ;
if ( ret )
return ret ;
speed | = SDIO_SPEED_EHS ;
ret = mmc_io_rw_direct ( card , 1 , 0 , SDIO_CCCR_SPEED , speed , NULL ) ;
if ( ret )
return ret ;
mmc_card_set_highspeed ( card ) ;
mmc_set_timing ( card - > host , MMC_TIMING_SD_HS ) ;
return 0 ;
}
2007-05-21 22:23:20 +04:00
/*
* Host is being removed . Free up the current card .
*/
static void mmc_sdio_remove ( struct mmc_host * host )
{
2007-05-26 15:48:18 +04:00
int i ;
2007-05-21 22:23:20 +04:00
BUG_ON ( ! host ) ;
BUG_ON ( ! host - > card ) ;
2007-05-26 15:48:18 +04:00
for ( i = 0 ; i < host - > card - > sdio_funcs ; i + + ) {
if ( host - > card - > sdio_func [ i ] ) {
sdio_remove_func ( host - > card - > sdio_func [ i ] ) ;
host - > card - > sdio_func [ i ] = NULL ;
}
}
2007-05-21 22:23:20 +04:00
mmc_remove_card ( host - > card ) ;
host - > card = NULL ;
}
/*
* Card detection callback from host .
*/
static void mmc_sdio_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_select_card ( host - > card ) ;
mmc_release_host ( host ) ;
if ( err ) {
mmc_sdio_remove ( host ) ;
mmc_claim_host ( host ) ;
mmc_detach_bus ( host ) ;
mmc_release_host ( host ) ;
}
}
static const struct mmc_bus_ops mmc_sdio_ops = {
. remove = mmc_sdio_remove ,
. detect = mmc_sdio_detect ,
} ;
/*
* Starting point for SDIO card init .
*/
int mmc_attach_sdio ( struct mmc_host * host , u32 ocr )
{
int err ;
2007-05-26 15:48:18 +04:00
int i , funcs ;
2007-05-21 22:23:20 +04:00
struct mmc_card * card ;
BUG_ON ( ! host ) ;
2007-08-09 15:23:56 +04:00
WARN_ON ( ! host - > claimed ) ;
2007-05-21 22:23:20 +04:00
mmc_attach_bus ( host , & mmc_sdio_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 ;
}
host - > ocr = mmc_select_voltage ( host , ocr ) ;
/*
* Can we support the voltage ( s ) of the card ( s ) ?
*/
if ( ! host - > ocr ) {
err = - EINVAL ;
goto err ;
}
/*
* Inform the card of the voltage
*/
err = mmc_send_io_op_cond ( host , host - > ocr , & ocr ) ;
if ( err )
goto err ;
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
/*
* For SPI , enable CRC as appropriate .
*/
if ( mmc_host_is_spi ( host ) ) {
err = mmc_spi_set_crc ( host , use_spi_crc ) ;
if ( err )
goto err ;
}
2007-05-21 22:23:20 +04:00
/*
* The number of functions on the card is encoded inside
* the ocr .
*/
funcs = ( ocr & 0x70000000 ) > > 28 ;
/*
* Allocate card structure .
*/
2008-03-22 01:54:50 +03:00
card = mmc_alloc_card ( host , NULL ) ;
2007-05-21 22:23:20 +04:00
if ( IS_ERR ( card ) ) {
err = PTR_ERR ( card ) ;
goto err ;
}
card - > type = MMC_TYPE_SDIO ;
2007-05-26 15:48:18 +04:00
card - > sdio_funcs = funcs ;
host - > card = card ;
2007-05-21 22:23:20 +04:00
/*
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
* For native busses : set card RCA and quit open drain mode .
2007-05-21 22:23:20 +04:00
*/
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 ) ) {
err = mmc_send_relative_addr ( host , & card - > rca ) ;
if ( err )
goto remove ;
2007-05-21 22:23:20 +04:00
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
mmc_set_bus_mode ( host , MMC_BUSMODE_PUSHPULL ) ;
}
2007-05-21 22:23:20 +04:00
/*
* Select card , as all following commands rely on that .
*/
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 ) ) {
err = mmc_select_card ( card ) ;
if ( err )
goto remove ;
}
2007-05-21 22:23:20 +04:00
2007-06-11 22:25:43 +04:00
/*
* Read the common registers .
*/
err = sdio_read_cccr ( card ) ;
if ( err )
goto remove ;
2007-07-30 17:15:30 +04:00
/*
* Read the common CIS tuples .
*/
err = sdio_read_common_cis ( card ) ;
if ( err )
goto remove ;
2007-07-30 19:15:07 +04:00
/*
2008-08-31 19:22:46 +04:00
* Switch to high - speed ( if supported ) .
2007-07-30 19:15:07 +04:00
*/
2008-08-31 19:22:46 +04:00
err = sdio_enable_hs ( card ) ;
if ( err )
goto remove ;
/*
* Change to the card ' s maximum speed .
*/
if ( mmc_card_highspeed ( card ) ) {
/*
* The SDIO specification doesn ' t mention how
* the CIS transfer speed register relates to
* high - speed , but it seems that 50 MHz is
* mandatory .
*/
mmc_set_clock ( host , 50000000 ) ;
} else {
mmc_set_clock ( host , card - > cis . max_dtr ) ;
}
2007-07-30 19:15:07 +04:00
2007-07-30 20:23:53 +04:00
/*
* Switch to wider bus ( if supported ) .
*/
err = sdio_enable_wide ( card ) ;
if ( err )
goto remove ;
2007-05-26 15:48:18 +04:00
/*
* Initialize ( but don ' t add ) all present functions .
*/
for ( i = 0 ; i < funcs ; i + + ) {
err = sdio_init_func ( host - > card , i + 1 ) ;
if ( err )
goto remove ;
}
2007-05-21 22:23:20 +04:00
mmc_release_host ( host ) ;
2007-05-26 15:48:18 +04:00
/*
* First add the card to the driver model . . .
*/
2007-05-21 22:23:20 +04:00
err = mmc_add_card ( host - > card ) ;
if ( err )
2007-05-26 15:48:18 +04:00
goto remove_added ;
/*
* . . . then the SDIO functions .
*/
for ( i = 0 ; i < funcs ; i + + ) {
err = sdio_add_func ( host - > card - > sdio_func [ i ] ) ;
if ( err )
goto remove_added ;
}
2007-05-21 22:23:20 +04:00
return 0 ;
2007-05-26 15:48:18 +04:00
remove_added :
/* Remove without lock if the device has been added. */
mmc_sdio_remove ( host ) ;
2007-05-21 22:23:20 +04:00
mmc_claim_host ( host ) ;
2007-05-26 15:48:18 +04:00
remove :
/* And with lock if it hasn't been added. */
if ( host - > card )
mmc_sdio_remove ( host ) ;
2007-05-21 22:23:20 +04:00
err :
mmc_detach_bus ( host ) ;
mmc_release_host ( host ) ;
printk ( KERN_ERR " %s: error %d whilst initialising SDIO card \n " ,
mmc_hostname ( host ) , err ) ;
return err ;
}