2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-05-27 12:57:15 +02:00
/*
* linux / drivers / mmc / core / sdio_io . c
*
2008-06-28 12:52:45 +02:00
* Copyright 2007 - 2008 Pierre Ossman
2007-05-27 12:57:15 +02:00
*/
2011-07-10 12:42:00 -04:00
# include <linux/export.h>
2019-02-13 20:03:30 +01:00
# include <linux/kernel.h>
2007-05-27 12:57:15 +02:00
# 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"
2017-01-13 14:14:08 +01:00
# include "core.h"
2017-01-13 14:14:14 +01:00
# include "card.h"
2019-06-17 10:56:52 -07:00
# include "host.h"
2007-05-27 12:57:15 +02:00
/**
* 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 )
{
2016-08-26 08:49:56 +08:00
if ( WARN_ON ( ! func ) )
return ;
2007-05-27 12:57:15 +02:00
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 )
{
2016-08-26 08:49:56 +08:00
if ( WARN_ON ( ! func ) )
return ;
2007-05-27 12:57:15 +02:00
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 ;
2016-08-26 08:49:56 +08:00
if ( ! func )
return - EINVAL ;
2007-05-27 14:22:37 +02:00
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 ;
2008-07-10 02:41:43 +03:00
timeout = jiffies + msecs_to_jiffies ( func - > enable_timeout ) ;
2007-05-27 14:22:37 +02:00
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 ;
2016-08-26 08:49:56 +08:00
if ( ! func )
return - EINVAL ;
2007-05-27 14:22:37 +02:00
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 ) ) ;
2020-06-04 18:01:02 +08:00
return ret ;
2007-05-27 14:22:37 +02:00
}
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 ) {
2008-06-30 10:50:24 +03:00
blksz = min ( func - > max_blksize , func - > card - > host - > max_blk_size ) ;
blksz = min ( blksz , 512u ) ;
2007-08-08 14:23:48 +01:00
}
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 ) ;
2008-06-28 13:22:40 +02:00
/*
* Calculate the maximum byte mode transfer size
*/
static inline unsigned int sdio_max_byte_size ( struct sdio_func * func )
{
2012-10-22 20:01:00 +09:00
unsigned mval = func - > card - > host - > max_blk_size ;
2010-03-05 13:43:25 -08:00
if ( mmc_blksz_for_byte_mode ( func - > card ) )
mval = min ( mval , func - > cur_blksize ) ;
else
mval = min ( mval , func - > max_blksize ) ;
2011-10-26 10:52:17 +02:00
if ( mmc_card_broken_byte_mode_512 ( func - > card ) )
return min ( mval , 511u ) ;
2008-07-10 03:01:56 +03:00
return min ( mval , 512u ) ; /* maximum size for byte mode */
2008-06-28 13:22:40 +02:00
}
2019-02-13 20:03:30 +01:00
/*
* This is legacy code , which needs to be re - worked some day . Basically we need
* to take into account the properties of the host , as to enable the SDIO func
* driver layer to allocate optimal buffers .
*/
static inline unsigned int _sdio_align_size ( 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 .
*/
return ALIGN ( sz , 4 ) ;
}
2008-06-28 12:52:45 +02:00
/**
* sdio_align_size - pads a transfer size to a more optimal value
* @ func : SDIO function
* @ 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 ) .
*
* If possible , it will also adjust the size so that it can be
* handled in just a single request .
*
* Returns the improved size , which might be unmodified .
*/
unsigned int sdio_align_size ( struct sdio_func * func , unsigned int sz )
{
unsigned int orig_sz ;
unsigned int blk_sz , byte_sz ;
unsigned chunk_sz ;
orig_sz = sz ;
/*
* Do a first check with the controller , in case it
* wants to increase the size up to a point where it
* might need more than one block .
*/
2019-02-13 20:03:30 +01:00
sz = _sdio_align_size ( sz ) ;
2008-06-28 12:52:45 +02:00
/*
* If we can still do this with just a byte transfer , then
* we ' re done .
*/
2008-06-28 13:22:40 +02:00
if ( sz < = sdio_max_byte_size ( func ) )
2008-06-28 12:52:45 +02:00
return sz ;
if ( func - > card - > cccr . multi_block ) {
/*
* Check if the transfer is already block aligned
*/
if ( ( sz % func - > cur_blksize ) = = 0 )
return sz ;
/*
* Realign it so that it can be done with one request ,
* and recheck if the controller still likes it .
*/
blk_sz = ( ( sz + func - > cur_blksize - 1 ) /
func - > cur_blksize ) * func - > cur_blksize ;
2019-02-13 20:03:30 +01:00
blk_sz = _sdio_align_size ( blk_sz ) ;
2008-06-28 12:52:45 +02:00
/*
* This value is only good if it is still just
* one request .
*/
if ( ( blk_sz % func - > cur_blksize ) = = 0 )
return blk_sz ;
/*
* We failed to do one request , but at least try to
* pad the remainder properly .
*/
2019-02-13 20:03:30 +01:00
byte_sz = _sdio_align_size ( sz % func - > cur_blksize ) ;
2008-06-28 13:22:40 +02:00
if ( byte_sz < = sdio_max_byte_size ( func ) ) {
2008-06-28 12:52:45 +02:00
blk_sz = sz / func - > cur_blksize ;
return blk_sz * func - > cur_blksize + byte_sz ;
}
} else {
/*
* We need multiple requests , so first check that the
* controller can handle the chunk size ;
*/
2019-02-13 20:03:30 +01:00
chunk_sz = _sdio_align_size ( sdio_max_byte_size ( func ) ) ;
2008-06-28 13:22:40 +02:00
if ( chunk_sz = = sdio_max_byte_size ( func ) ) {
2008-06-28 12:52:45 +02:00
/*
* Fix up the size of the remainder ( if any )
*/
byte_sz = orig_sz % chunk_sz ;
if ( byte_sz ) {
2019-02-13 20:03:30 +01:00
byte_sz = _sdio_align_size ( byte_sz ) ;
2008-06-28 12:52:45 +02:00
}
return ( orig_sz / chunk_sz ) * chunk_sz + byte_sz ;
}
}
/*
* The controller is simply incapable of transferring the size
* we want in decent manner , so just return the original size .
*/
return orig_sz ;
}
EXPORT_SYMBOL_GPL ( sdio_align_size ) ;
2007-08-08 14:24:21 +01:00
/* Split an arbitrarily sized data transfer into several
* IO_RW_EXTENDED commands . */
static int sdio_io_rw_ext_helper ( struct sdio_func * func , int write ,
unsigned addr , int incr_addr , u8 * buf , unsigned size )
{
unsigned remainder = size ;
unsigned max_blocks ;
int ret ;
2016-08-26 08:49:56 +08:00
if ( ! func | | ( func - > num > 7 ) )
return - EINVAL ;
2007-08-08 14:24:21 +01:00
/* Do the bulk of the transfer using block mode (if supported). */
2008-06-28 13:22:40 +02:00
if ( func - > card - > cccr . multi_block & & ( size > sdio_max_byte_size ( func ) ) ) {
2007-08-08 14:24:21 +01:00
/* Blocks per command is limited by host count, host transfer
2012-10-22 20:01:00 +09:00
* size and the maximum for IO_RW_EXTENDED of 511 blocks . */
max_blocks = min ( func - > card - > host - > max_blk_count , 511u ) ;
2007-08-08 14:24:21 +01:00
2011-10-26 10:52:17 +02:00
while ( remainder > = func - > cur_blksize ) {
2007-08-08 14:24:21 +01:00
unsigned blocks ;
blocks = remainder / func - > cur_blksize ;
if ( blocks > max_blocks )
blocks = max_blocks ;
size = blocks * func - > cur_blksize ;
ret = mmc_io_rw_extended ( func - > card , write ,
func - > num , addr , incr_addr , buf ,
blocks , func - > cur_blksize ) ;
if ( ret )
return ret ;
remainder - = size ;
buf + = size ;
if ( incr_addr )
addr + = size ;
}
}
/* Write the remainder using byte mode. */
while ( remainder > 0 ) {
2008-06-28 13:22:40 +02:00
size = min ( remainder , sdio_max_byte_size ( func ) ) ;
2007-08-08 14:24:21 +01:00
2011-10-26 10:52:17 +02:00
/* Indicate byte mode by setting "blocks" = 0 */
2007-08-08 14:24:21 +01:00
ret = mmc_io_rw_extended ( func - > card , write , func - > num , addr ,
2011-10-26 10:52:17 +02:00
incr_addr , buf , 0 , size ) ;
2007-08-08 14:24:21 +01:00
if ( ret )
return ret ;
remainder - = size ;
buf + = size ;
if ( incr_addr )
addr + = size ;
}
return 0 ;
}
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 .
*/
2008-06-30 10:50:24 +03:00
u8 sdio_readb ( struct sdio_func * func , unsigned int addr , int * err_ret )
2007-05-27 12:57:15 +02:00
{
int ret ;
2008-06-30 10:50:24 +03:00
u8 val ;
2007-05-27 12:57:15 +02:00
2016-08-26 08:49:56 +08:00
if ( ! func ) {
2017-03-15 19:48:03 +11:00
if ( err_ret )
* err_ret = - EINVAL ;
2016-08-26 08:49:56 +08:00
return 0xFF ;
}
2007-05-27 12:57:15 +02:00
ret = mmc_io_rw_direct ( func - > card , 0 , func - > num , addr , 0 , & val ) ;
2017-03-15 19:48:04 +11:00
if ( err_ret )
* err_ret = ret ;
if ( ret )
2007-05-27 12:57:15 +02:00
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 .
*/
2008-06-30 10:50:24 +03:00
void sdio_writeb ( struct sdio_func * func , u8 b , unsigned int addr , int * err_ret )
2007-05-27 12:57:15 +02:00
{
int ret ;
2016-08-26 08:49:56 +08:00
if ( ! func ) {
2017-03-15 19:48:03 +11:00
if ( err_ret )
* err_ret = - EINVAL ;
2016-08-26 08:49:56 +08:00
return ;
}
2007-05-27 12:57:15 +02:00
ret = mmc_io_rw_direct ( func - > card , 1 , func - > num , addr , b , NULL ) ;
if ( err_ret )
* err_ret = ret ;
}
EXPORT_SYMBOL_GPL ( sdio_writeb ) ;
2010-05-26 14:42:09 -07:00
/**
* sdio_writeb_readb - write and read a byte from SDIO function
* @ func : SDIO function to access
* @ write_byte : byte to write
* @ addr : address to write to
* @ err_ret : optional status value from transfer
*
* Performs a RAW ( Read after Write ) operation as defined by SDIO spec -
* single byte is written to address space of a given SDIO function and
* response is read back from the same address , both using single request .
* If there is a problem with the operation , 0xff is returned and
* @ err_ret will contain the error code .
*/
u8 sdio_writeb_readb ( struct sdio_func * func , u8 write_byte ,
unsigned int addr , int * err_ret )
{
int ret ;
u8 val ;
ret = mmc_io_rw_direct ( func - > card , 1 , func - > num , addr ,
write_byte , & val ) ;
if ( err_ret )
* err_ret = ret ;
if ( ret )
2017-03-15 19:48:04 +11:00
return 0xff ;
2010-05-26 14:42:09 -07:00
return val ;
}
EXPORT_SYMBOL_GPL ( sdio_writeb_readb ) ;
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
*
2007-08-08 14:24:21 +01:00
* Reads from the address space of a given SDIO function . Return
* value indicates if the transfer succeeded or not .
2007-07-06 13:35:01 +02:00
*/
int sdio_memcpy_fromio ( struct sdio_func * func , void * dst ,
unsigned int addr , int count )
{
2007-08-08 14:24:21 +01:00
return sdio_io_rw_ext_helper ( func , 0 , addr , 1 , dst , count ) ;
2007-07-06 13:35:01 +02:00
}
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
*
2007-08-08 14:24:21 +01:00
* Writes to the address space of a given SDIO function . Return
* value indicates if the transfer succeeded or not .
2007-07-06 13:35:01 +02:00
*/
int sdio_memcpy_toio ( struct sdio_func * func , unsigned int addr ,
void * src , int count )
{
2007-08-08 14:24:21 +01:00
return sdio_io_rw_ext_helper ( func , 1 , addr , 1 , src , count ) ;
2007-07-06 13:35:01 +02:00
}
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
*
2007-08-08 14:24:21 +01:00
* Reads from the specified FIFO of a given SDIO function . Return
* value indicates if the transfer succeeded or not .
2007-07-06 13:35:01 +02:00
*/
int sdio_readsb ( struct sdio_func * func , void * dst , unsigned int addr ,
int count )
{
2007-08-08 14:24:21 +01:00
return sdio_io_rw_ext_helper ( func , 0 , addr , 0 , dst , count ) ;
2007-07-06 13:35:01 +02:00
}
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
*
2007-08-08 14:24:21 +01:00
* Writes to the specified FIFO of a given SDIO function . Return
* value indicates if the transfer succeeded or not .
2007-07-06 13:35:01 +02:00
*/
int sdio_writesb ( struct sdio_func * func , unsigned int addr , void * src ,
int count )
{
2007-08-08 14:24:21 +01:00
return sdio_io_rw_ext_helper ( func , 1 , addr , 0 , src , count ) ;
2007-07-06 13:35:01 +02:00
}
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 .
*/
2008-06-30 10:50:24 +03:00
u16 sdio_readw ( struct sdio_func * func , unsigned int addr , int * err_ret )
2007-07-06 13:35:01 +02:00
{
int ret ;
ret = sdio_memcpy_fromio ( func , func - > tmpbuf , addr , 2 ) ;
2017-03-15 19:48:04 +11:00
if ( err_ret )
* err_ret = ret ;
if ( ret )
2007-07-06 13:35:01 +02:00
return 0xFFFF ;
2008-06-30 10:50:24 +03:00
return le16_to_cpup ( ( __le16 * ) func - > tmpbuf ) ;
2007-07-06 13:35:01 +02:00
}
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 .
*/
2008-06-30 10:50:24 +03:00
void sdio_writew ( struct sdio_func * func , u16 b , unsigned int addr , int * err_ret )
2007-07-06 13:35:01 +02:00
{
int ret ;
2008-06-30 10:50:24 +03:00
* ( __le16 * ) func - > tmpbuf = cpu_to_le16 ( b ) ;
2007-07-06 13:35:01 +02:00
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 .
*/
2008-06-30 10:50:24 +03:00
u32 sdio_readl ( struct sdio_func * func , unsigned int addr , int * err_ret )
2007-07-06 13:35:01 +02:00
{
int ret ;
ret = sdio_memcpy_fromio ( func , func - > tmpbuf , addr , 4 ) ;
2017-03-15 19:48:04 +11:00
if ( err_ret )
* err_ret = ret ;
if ( ret )
2007-07-06 13:35:01 +02:00
return 0xFFFFFFFF ;
2008-06-30 10:50:24 +03:00
return le32_to_cpup ( ( __le32 * ) func - > tmpbuf ) ;
2007-07-06 13:35:01 +02:00
}
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 .
*/
2008-06-30 10:50:24 +03:00
void sdio_writel ( struct sdio_func * func , u32 b , unsigned int addr , int * err_ret )
2007-07-06 13:35:01 +02:00
{
int ret ;
2008-06-30 10:50:24 +03:00
* ( __le32 * ) func - > tmpbuf = cpu_to_le32 ( b ) ;
2007-07-06 13:35:01 +02:00
ret = sdio_memcpy_toio ( func , addr , func - > tmpbuf , 4 ) ;
if ( err_ret )
* err_ret = ret ;
}
EXPORT_SYMBOL_GPL ( sdio_writel ) ;
2007-08-10 13:29:46 +01:00
/**
* sdio_f0_readb - read a single byte from SDIO function 0
* @ func : an SDIO function of the card
* @ addr : address to read
* @ err_ret : optional status value from transfer
*
* Reads a single byte from the address space of SDIO function 0.
* If there is a problem reading the address , 0xff is returned
* and @ err_ret will contain the error code .
*/
unsigned char sdio_f0_readb ( struct sdio_func * func , unsigned int addr ,
int * err_ret )
{
int ret ;
unsigned char val ;
2016-08-26 08:49:56 +08:00
if ( ! func ) {
2017-03-15 19:48:03 +11:00
if ( err_ret )
* err_ret = - EINVAL ;
2016-08-26 08:49:56 +08:00
return 0xFF ;
}
2007-08-10 13:29:46 +01:00
ret = mmc_io_rw_direct ( func - > card , 0 , 0 , addr , 0 , & val ) ;
2017-03-15 19:48:04 +11:00
if ( err_ret )
* err_ret = ret ;
if ( ret )
2007-08-10 13:29:46 +01:00
return 0xFF ;
return val ;
}
EXPORT_SYMBOL_GPL ( sdio_f0_readb ) ;
/**
* sdio_f0_writeb - write a single byte to SDIO function 0
* @ func : an SDIO function of the card
* @ 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 SDIO function 0.
* @ err_ret will contain the status of the actual transfer .
*
* Only writes to the vendor specific CCCR registers ( 0xF0 -
* 0xFF ) are permiited ; @ err_ret will be set to - EINVAL for *
* writes outside this range .
*/
void sdio_f0_writeb ( struct sdio_func * func , unsigned char b , unsigned int addr ,
int * err_ret )
{
int ret ;
2016-08-26 08:49:56 +08:00
if ( ! func ) {
2017-03-15 19:48:03 +11:00
if ( err_ret )
* err_ret = - EINVAL ;
2016-08-26 08:49:56 +08:00
return ;
}
2007-08-10 13:29:46 +01:00
2009-09-22 16:45:18 -07:00
if ( ( addr < 0xF0 | | addr > 0xFF ) & & ( ! mmc_card_lenient_fn0 ( func - > card ) ) ) {
2007-08-10 13:29:46 +01:00
if ( err_ret )
* err_ret = - EINVAL ;
return ;
}
ret = mmc_io_rw_direct ( func - > card , 1 , 0 , addr , b , NULL ) ;
if ( err_ret )
* err_ret = ret ;
}
EXPORT_SYMBOL_GPL ( sdio_f0_writeb ) ;
2010-03-05 13:43:31 -08:00
/**
* sdio_get_host_pm_caps - get host power management capabilities
* @ func : SDIO function attached to host
*
* Returns a capability bitmask corresponding to power management
* features supported by the host controller that the card function
* might rely upon during a system suspend . The host doesn ' t need
* to be claimed , nor the function active , for this information to be
* obtained .
*/
mmc_pm_flag_t sdio_get_host_pm_caps ( struct sdio_func * func )
{
2016-08-26 08:49:56 +08:00
if ( ! func )
return 0 ;
2010-03-05 13:43:31 -08:00
return func - > card - > host - > pm_caps ;
}
EXPORT_SYMBOL_GPL ( sdio_get_host_pm_caps ) ;
/**
* sdio_set_host_pm_flags - set wanted host power management capabilities
* @ func : SDIO function attached to host
2020-07-01 13:46:49 +01:00
* @ flags : Power Management flags to set
2010-03-05 13:43:31 -08:00
*
* Set a capability bitmask corresponding to wanted host controller
* power management features for the upcoming suspend state .
* This must be called , if needed , each time the suspend method of
* the function driver is called , and must contain only bits that
* were returned by sdio_get_host_pm_caps ( ) .
* The host doesn ' t need to be claimed , nor the function active ,
* for this information to be set .
*/
int sdio_set_host_pm_flags ( struct sdio_func * func , mmc_pm_flag_t flags )
{
struct mmc_host * host ;
2016-08-26 08:49:56 +08:00
if ( ! func )
return - EINVAL ;
2010-03-05 13:43:31 -08:00
host = func - > card - > host ;
if ( flags & ~ host - > pm_caps )
return - EINVAL ;
/* function suspend methods are serialized, hence no lock needed */
host - > pm_flags | = flags ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( sdio_set_host_pm_flags ) ;
2019-06-17 10:56:50 -07:00
/**
* sdio_retune_crc_disable - temporarily disable retuning on CRC errors
* @ func : SDIO function attached to host
*
* If the SDIO card is known to be in a state where it might produce
* CRC errors on the bus in response to commands ( like if we know it is
* transitioning between power states ) , an SDIO function driver can
* call this function to temporarily disable the SD / MMC core behavior of
* triggering an automatic retuning .
*
* This function should be called while the host is claimed and the host
* should remain claimed until sdio_retune_crc_enable ( ) is called .
* Specifically , the expected sequence of calls is :
* - sdio_claim_host ( )
* - sdio_retune_crc_disable ( )
* - some number of calls like sdio_writeb ( ) and sdio_readb ( )
* - sdio_retune_crc_enable ( )
* - sdio_release_host ( )
*/
void sdio_retune_crc_disable ( struct sdio_func * func )
{
func - > card - > host - > retune_crc_disable = true ;
}
EXPORT_SYMBOL_GPL ( sdio_retune_crc_disable ) ;
/**
* sdio_retune_crc_enable - re - enable retuning on CRC errors
* @ func : SDIO function attached to host
*
* This is the compement to sdio_retune_crc_disable ( ) .
*/
void sdio_retune_crc_enable ( struct sdio_func * func )
{
func - > card - > host - > retune_crc_disable = false ;
}
EXPORT_SYMBOL_GPL ( sdio_retune_crc_enable ) ;
2019-06-17 10:56:52 -07:00
/**
* sdio_retune_hold_now - start deferring retuning requests till release
* @ func : SDIO function attached to host
*
* This function can be called if it ' s currently a bad time to do
* a retune of the SDIO card . Retune requests made during this time
* will be held and we ' ll actually do the retune sometime after the
* release .
*
* This function could be useful if an SDIO card is in a power state
* where it can respond to a small subset of commands that doesn ' t
* include the retuning command . Care should be taken when using
* this function since ( presumably ) the retuning request we might be
* deferring was made for a good reason .
*
* This function should be called while the host is claimed .
*/
void sdio_retune_hold_now ( struct sdio_func * func )
{
mmc_retune_hold_now ( func - > card - > host ) ;
}
EXPORT_SYMBOL_GPL ( sdio_retune_hold_now ) ;
/**
* sdio_retune_release - signal that it ' s OK to retune now
* @ func : SDIO function attached to host
*
* This is the complement to sdio_retune_hold_now ( ) . Calling this
* function won ' t make a retune happen right away but will allow
* them to be scheduled normally .
*
* This function should be called while the host is claimed .
*/
void sdio_retune_release ( struct sdio_func * func )
{
mmc_retune_release ( func - > card - > host ) ;
}
EXPORT_SYMBOL_GPL ( sdio_retune_release ) ;