2007-05-27 12:57:15 +02:00
/*
* linux / drivers / mmc / core / sdio_io . c
*
* Copyright 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/mmc/host.h>
# include <linux/mmc/card.h>
2007-05-27 14:22:37 +02:00
# include <linux/mmc/sdio.h>
2007-05-27 12:57:15 +02:00
# include <linux/mmc/sdio_func.h>
# include "sdio_ops.h"
/**
* sdio_claim_host - exclusively claim a bus for a certain SDIO function
* @ func : SDIO function that will be accessed
*
* Claim a bus for a set of operations . The SDIO function given
* is used to figure out which bus is relevant .
*/
void sdio_claim_host ( struct sdio_func * func )
{
BUG_ON ( ! func ) ;
BUG_ON ( ! func - > card ) ;
mmc_claim_host ( func - > card - > host ) ;
}
EXPORT_SYMBOL_GPL ( sdio_claim_host ) ;
/**
* sdio_release_host - release a bus for a certain SDIO function
* @ func : SDIO function that was accessed
*
* Release a bus , allowing others to claim the bus for their
* operations .
*/
void sdio_release_host ( struct sdio_func * func )
{
BUG_ON ( ! func ) ;
BUG_ON ( ! func - > card ) ;
mmc_release_host ( func - > card - > host ) ;
}
EXPORT_SYMBOL_GPL ( sdio_release_host ) ;
2007-05-27 14:22:37 +02:00
/**
* sdio_enable_func - enables a SDIO function for usage
* @ func : SDIO function to enable
*
* Powers up and activates a SDIO function so that register
* access is possible .
*/
int sdio_enable_func ( struct sdio_func * func )
{
int ret ;
unsigned char reg ;
unsigned long timeout ;
BUG_ON ( ! func ) ;
BUG_ON ( ! func - > card ) ;
pr_debug ( " SDIO: Enabling device %s... \n " , sdio_func_id ( func ) ) ;
ret = mmc_io_rw_direct ( func - > card , 0 , 0 , SDIO_CCCR_IOEx , 0 , & reg ) ;
if ( ret )
goto err ;
reg | = 1 < < func - > num ;
ret = mmc_io_rw_direct ( func - > card , 1 , 0 , SDIO_CCCR_IOEx , reg , NULL ) ;
if ( ret )
goto err ;
/*
* FIXME : This should timeout based on information in the CIS ,
* but we don ' t have card to parse that yet .
*/
timeout = jiffies + HZ ;
while ( 1 ) {
ret = mmc_io_rw_direct ( func - > card , 0 , 0 , SDIO_CCCR_IORx , 0 , & reg ) ;
if ( ret )
goto err ;
if ( reg & ( 1 < < func - > num ) )
break ;
ret = - ETIME ;
if ( time_after ( jiffies , timeout ) )
goto err ;
}
pr_debug ( " SDIO: Enabled device %s \n " , sdio_func_id ( func ) ) ;
return 0 ;
err :
pr_debug ( " SDIO: Failed to enable device %s \n " , sdio_func_id ( func ) ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( sdio_enable_func ) ;
/**
* sdio_disable_func - disable a SDIO function
* @ func : SDIO function to disable
*
* Powers down and deactivates a SDIO function . Register access
* to this function will fail until the function is reenabled .
*/
int sdio_disable_func ( struct sdio_func * func )
{
int ret ;
unsigned char reg ;
BUG_ON ( ! func ) ;
BUG_ON ( ! func - > card ) ;
pr_debug ( " SDIO: Disabling device %s... \n " , sdio_func_id ( func ) ) ;
ret = mmc_io_rw_direct ( func - > card , 0 , 0 , SDIO_CCCR_IOEx , 0 , & reg ) ;
if ( ret )
goto err ;
reg & = ~ ( 1 < < func - > num ) ;
ret = mmc_io_rw_direct ( func - > card , 1 , 0 , SDIO_CCCR_IOEx , reg , NULL ) ;
if ( ret )
goto err ;
pr_debug ( " SDIO: Disabled device %s \n " , sdio_func_id ( func ) ) ;
return 0 ;
err :
pr_debug ( " SDIO: Failed to disable device %s \n " , sdio_func_id ( func ) ) ;
return - EIO ;
}
EXPORT_SYMBOL_GPL ( sdio_disable_func ) ;
2007-08-08 14:23:48 +01:00
/**
* sdio_set_block_size - set the block size of an SDIO function
* @ func : SDIO function to change
* @ blksz : new block size or 0 to use the default .
*
* The default block size is the largest supported by both the function
* and the host , with a maximum of 512 to ensure that arbitrarily sized
* data transfer use the optimal ( least ) number of commands .
*
* A driver may call this to override the default block size set by the
* core . This can be used to set a block size greater than the maximum
* that reported by the card ; it is the driver ' s responsibility to ensure
* it uses a value that the card supports .
*
* Returns 0 on success , - EINVAL if the host does not support the
* requested block size , or - EIO ( etc . ) if one of the resultant FBR block
* size register writes failed .
*
*/
int sdio_set_block_size ( struct sdio_func * func , unsigned blksz )
{
int ret ;
if ( blksz > func - > card - > host - > max_blk_size )
return - EINVAL ;
if ( blksz = = 0 ) {
blksz = min ( min (
func - > max_blksize ,
func - > card - > host - > max_blk_size ) ,
512u ) ;
}
ret = mmc_io_rw_direct ( func - > card , 1 , 0 ,
SDIO_FBR_BASE ( func - > num ) + SDIO_FBR_BLKSIZE ,
blksz & 0xff , NULL ) ;
if ( ret )
return ret ;
ret = mmc_io_rw_direct ( func - > card , 1 , 0 ,
SDIO_FBR_BASE ( func - > num ) + SDIO_FBR_BLKSIZE + 1 ,
( blksz > > 8 ) & 0xff , NULL ) ;
if ( ret )
return ret ;
func - > cur_blksize = blksz ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( sdio_set_block_size ) ;
2007-05-27 12:57:15 +02:00
/**
* sdio_readb - read a single byte from a SDIO function
* @ func : SDIO function to access
* @ addr : address to read
* @ err_ret : optional status value from transfer
*
* Reads a single byte from the address space of a given SDIO
* function . If there is a problem reading the address , 0xff
* is returned and @ err_ret will contain the error code .
*/
unsigned char sdio_readb ( struct sdio_func * func , unsigned int addr ,
int * err_ret )
{
int ret ;
unsigned char val ;
BUG_ON ( ! func ) ;
if ( err_ret )
* err_ret = 0 ;
ret = mmc_io_rw_direct ( func - > card , 0 , func - > num , addr , 0 , & val ) ;
if ( ret ) {
if ( err_ret )
* err_ret = ret ;
return 0xFF ;
}
return val ;
}
EXPORT_SYMBOL_GPL ( sdio_readb ) ;
/**
* sdio_writeb - write a single byte to a SDIO function
* @ func : SDIO function to access
* @ b : byte to write
* @ addr : address to write to
* @ err_ret : optional status value from transfer
*
* Writes a single byte to the address space of a given SDIO
* function . @ err_ret will contain the status of the actual
* transfer .
*/
void sdio_writeb ( struct sdio_func * func , unsigned char b , unsigned int addr ,
int * err_ret )
{
int ret ;
BUG_ON ( ! func ) ;
ret = mmc_io_rw_direct ( func - > card , 1 , func - > num , addr , b , NULL ) ;
if ( err_ret )
* err_ret = ret ;
}
EXPORT_SYMBOL_GPL ( sdio_writeb ) ;
2007-07-06 13:35:01 +02:00
/**
* sdio_memcpy_fromio - read a chunk of memory from a SDIO function
* @ func : SDIO function to access
* @ dst : buffer to store the data
* @ addr : address to begin reading from
* @ count : number of bytes to read
*
* Reads up to 512 bytes from the address space of a given SDIO
* function . Return value indicates if the transfer succeeded or
* not .
*/
int sdio_memcpy_fromio ( struct sdio_func * func , void * dst ,
unsigned int addr , int count )
{
return mmc_io_rw_extended ( func - > card , 0 , func - > num , addr , 0 , dst ,
count ) ;
}
EXPORT_SYMBOL_GPL ( sdio_memcpy_fromio ) ;
/**
* sdio_memcpy_toio - write a chunk of memory to a SDIO function
* @ func : SDIO function to access
* @ addr : address to start writing to
* @ src : buffer that contains the data to write
* @ count : number of bytes to write
*
* Writes up to 512 bytes to the address space of a given SDIO
* function . Return value indicates if the transfer succeeded or
* not .
*/
int sdio_memcpy_toio ( struct sdio_func * func , unsigned int addr ,
void * src , int count )
{
return mmc_io_rw_extended ( func - > card , 1 , func - > num , addr , 0 , src ,
count ) ;
}
EXPORT_SYMBOL_GPL ( sdio_memcpy_toio ) ;
/**
* sdio_readsb - read from a FIFO on a SDIO function
* @ func : SDIO function to access
* @ dst : buffer to store the data
* @ addr : address of ( single byte ) FIFO
* @ count : number of bytes to read
*
* Reads up to 512 bytes from the specified FIFO of a given SDIO
* function . Return value indicates if the transfer succeeded or
* not .
*/
int sdio_readsb ( struct sdio_func * func , void * dst , unsigned int addr ,
int count )
{
return mmc_io_rw_extended ( func - > card , 0 , func - > num , addr , 1 , dst ,
count ) ;
}
EXPORT_SYMBOL_GPL ( sdio_readsb ) ;
/**
* sdio_writesb - write to a FIFO of a SDIO function
* @ func : SDIO function to access
* @ addr : address of ( single byte ) FIFO
* @ src : buffer that contains the data to write
* @ count : number of bytes to write
*
* Writes up to 512 bytes to the specified FIFO of a given SDIO
* function . Return value indicates if the transfer succeeded or
* not .
*/
int sdio_writesb ( struct sdio_func * func , unsigned int addr , void * src ,
int count )
{
return mmc_io_rw_extended ( func - > card , 1 , func - > num , addr , 1 , src ,
count ) ;
}
EXPORT_SYMBOL_GPL ( sdio_writesb ) ;
/**
* sdio_readw - read a 16 bit integer from a SDIO function
* @ func : SDIO function to access
* @ addr : address to read
* @ err_ret : optional status value from transfer
*
* Reads a 16 bit integer from the address space of a given SDIO
* function . If there is a problem reading the address , 0xffff
* is returned and @ err_ret will contain the error code .
*/
unsigned short sdio_readw ( struct sdio_func * func , unsigned int addr ,
int * err_ret )
{
int ret ;
if ( err_ret )
* err_ret = 0 ;
ret = sdio_memcpy_fromio ( func , func - > tmpbuf , addr , 2 ) ;
if ( ret ) {
if ( err_ret )
* err_ret = ret ;
return 0xFFFF ;
}
return le16_to_cpu ( * ( u16 * ) func - > tmpbuf ) ;
}
EXPORT_SYMBOL_GPL ( sdio_readw ) ;
/**
* sdio_writew - write a 16 bit integer to a SDIO function
* @ func : SDIO function to access
* @ b : integer to write
* @ addr : address to write to
* @ err_ret : optional status value from transfer
*
* Writes a 16 bit integer to the address space of a given SDIO
* function . @ err_ret will contain the status of the actual
* transfer .
*/
void sdio_writew ( struct sdio_func * func , unsigned short b , unsigned int addr ,
int * err_ret )
{
int ret ;
* ( u16 * ) func - > tmpbuf = cpu_to_le16 ( b ) ;
ret = sdio_memcpy_toio ( func , addr , func - > tmpbuf , 2 ) ;
if ( err_ret )
* err_ret = ret ;
}
EXPORT_SYMBOL_GPL ( sdio_writew ) ;
/**
* sdio_readl - read a 32 bit integer from a SDIO function
* @ func : SDIO function to access
* @ addr : address to read
* @ err_ret : optional status value from transfer
*
* Reads a 32 bit integer from the address space of a given SDIO
* function . If there is a problem reading the address ,
* 0xffffffff is returned and @ err_ret will contain the error
* code .
*/
unsigned long sdio_readl ( struct sdio_func * func , unsigned int addr ,
int * err_ret )
{
int ret ;
if ( err_ret )
* err_ret = 0 ;
ret = sdio_memcpy_fromio ( func , func - > tmpbuf , addr , 4 ) ;
if ( ret ) {
if ( err_ret )
* err_ret = ret ;
return 0xFFFFFFFF ;
}
return le32_to_cpu ( * ( u32 * ) func - > tmpbuf ) ;
}
EXPORT_SYMBOL_GPL ( sdio_readl ) ;
/**
* sdio_writel - write a 32 bit integer to a SDIO function
* @ func : SDIO function to access
* @ b : integer to write
* @ addr : address to write to
* @ err_ret : optional status value from transfer
*
* Writes a 32 bit integer to the address space of a given SDIO
* function . @ err_ret will contain the status of the actual
* transfer .
*/
void sdio_writel ( struct sdio_func * func , unsigned long b , unsigned int addr ,
int * err_ret )
{
int ret ;
* ( u32 * ) func - > tmpbuf = cpu_to_le32 ( b ) ;
ret = sdio_memcpy_toio ( func , addr , func - > tmpbuf , 4 ) ;
if ( err_ret )
* err_ret = ret ;
}
EXPORT_SYMBOL_GPL ( sdio_writel ) ;