2011-06-13 20:49:55 +04:00
/*
* soc - io . c - - ASoC register I / O helpers
*
* Copyright 2009 - 2011 Wolfson Microelectronics PLC .
*
* Author : Mark Brown < broonie @ opensource . wolfsonmicro . com >
*
* 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/i2c.h>
# include <linux/spi/spi.h>
2011-06-13 22:35:29 +04:00
# include <linux/regmap.h>
2011-09-22 17:34:58 +04:00
# include <linux/export.h>
2011-06-13 20:49:55 +04:00
# include <sound/soc.h>
2014-04-22 15:23:13 +04:00
/**
* snd_soc_component_read ( ) - Read register value
* @ component : Component to read from
* @ reg : Register to read
* @ val : Pointer to where the read value is stored
*
* Return : 0 on success , a negative error code otherwise .
*/
int snd_soc_component_read ( struct snd_soc_component * component ,
unsigned int reg , unsigned int * val )
{
int ret ;
if ( component - > regmap )
ret = regmap_read ( component - > regmap , reg , val ) ;
2018-01-16 05:00:59 +03:00
else if ( component - > driver - > read ) {
* val = component - > driver - > read ( component , reg ) ;
ret = 0 ;
}
2014-04-22 15:23:13 +04:00
else
ret = - EIO ;
return ret ;
}
EXPORT_SYMBOL_GPL ( snd_soc_component_read ) ;
2017-11-06 04:48:19 +03:00
unsigned int snd_soc_component_read32 ( struct snd_soc_component * component ,
unsigned int reg )
{
unsigned int val ;
int ret ;
ret = snd_soc_component_read ( component , reg , & val ) ;
if ( ret < 0 )
return - 1 ;
return val ;
}
EXPORT_SYMBOL_GPL ( snd_soc_component_read32 ) ;
2014-04-22 15:23:13 +04:00
/**
* snd_soc_component_write ( ) - Write register value
* @ component : Component to write to
* @ reg : Register to write
* @ val : Value to write to the register
*
* Return : 0 on success , a negative error code otherwise .
*/
int snd_soc_component_write ( struct snd_soc_component * component ,
unsigned int reg , unsigned int val )
2014-03-18 12:02:07 +04:00
{
2014-04-22 15:23:13 +04:00
if ( component - > regmap )
return regmap_write ( component - > regmap , reg , val ) ;
2018-01-16 05:00:59 +03:00
else if ( component - > driver - > write )
return component - > driver - > write ( component , reg , val ) ;
2014-04-22 15:23:13 +04:00
else
return - EIO ;
}
EXPORT_SYMBOL_GPL ( snd_soc_component_write ) ;
static int snd_soc_component_update_bits_legacy (
struct snd_soc_component * component , unsigned int reg ,
unsigned int mask , unsigned int val , bool * change )
{
unsigned int old , new ;
int ret ;
mutex_lock ( & component - > io_mutex ) ;
2018-03-12 17:24:23 +03:00
ret = snd_soc_component_read ( component , reg , & old ) ;
2014-04-22 15:23:13 +04:00
if ( ret < 0 )
goto out_unlock ;
new = ( old & ~ mask ) | ( val & mask ) ;
* change = old ! = new ;
if ( * change )
2018-03-12 17:24:23 +03:00
ret = snd_soc_component_write ( component , reg , new ) ;
2014-04-22 15:23:13 +04:00
out_unlock :
mutex_unlock ( & component - > io_mutex ) ;
2014-03-18 12:02:07 +04:00
return ret ;
}
2014-04-22 15:23:13 +04:00
/**
* snd_soc_component_update_bits ( ) - Perform read / modify / write cycle
* @ component : Component to update
* @ reg : Register to update
* @ mask : Mask that specifies which bits to update
* @ val : New value for the bits specified by mask
*
* Return : 1 if the operation was successful and the value of the register
* changed , 0 if the operation was successful , but the value did not change .
* Returns a negative error code otherwise .
*/
int snd_soc_component_update_bits ( struct snd_soc_component * component ,
unsigned int reg , unsigned int mask , unsigned int val )
{
bool change ;
int ret ;
if ( component - > regmap )
ret = regmap_update_bits_check ( component - > regmap , reg , mask ,
val , & change ) ;
else
ret = snd_soc_component_update_bits_legacy ( component , reg ,
mask , val , & change ) ;
if ( ret < 0 )
return ret ;
return change ;
}
EXPORT_SYMBOL_GPL ( snd_soc_component_update_bits ) ;
/**
* snd_soc_component_update_bits_async ( ) - Perform asynchronous
* read / modify / write cycle
* @ component : Component to update
* @ reg : Register to update
* @ mask : Mask that specifies which bits to update
* @ val : New value for the bits specified by mask
*
* This function is similar to snd_soc_component_update_bits ( ) , but the update
* operation is scheduled asynchronously . This means it may not be completed
* when the function returns . To make sure that all scheduled updates have been
* completed snd_soc_component_async_complete ( ) must be called .
*
* Return : 1 if the operation was successful and the value of the register
* changed , 0 if the operation was successful , but the value did not change .
* Returns a negative error code otherwise .
*/
int snd_soc_component_update_bits_async ( struct snd_soc_component * component ,
unsigned int reg , unsigned int mask , unsigned int val )
{
bool change ;
int ret ;
if ( component - > regmap )
ret = regmap_update_bits_check_async ( component - > regmap , reg ,
mask , val , & change ) ;
else
ret = snd_soc_component_update_bits_legacy ( component , reg ,
mask , val , & change ) ;
if ( ret < 0 )
return ret ;
return change ;
}
EXPORT_SYMBOL_GPL ( snd_soc_component_update_bits_async ) ;
/**
* snd_soc_component_async_complete ( ) - Ensure asynchronous I / O has completed
* @ component : Component for which to wait
*
* This function blocks until all asynchronous I / O which has previously been
* scheduled using snd_soc_component_update_bits_async ( ) has completed .
*/
void snd_soc_component_async_complete ( struct snd_soc_component * component )
{
if ( component - > regmap )
regmap_async_complete ( component - > regmap ) ;
}
EXPORT_SYMBOL_GPL ( snd_soc_component_async_complete ) ;
/**
* snd_soc_component_test_bits - Test register for change
* @ component : component
* @ reg : Register to test
* @ mask : Mask that specifies which bits to test
* @ value : Value to test against
*
* Tests a register with a new value and checks if the new value is
* different from the old value .
*
* Return : 1 for change , otherwise 0.
*/
int snd_soc_component_test_bits ( struct snd_soc_component * component ,
unsigned int reg , unsigned int mask , unsigned int value )
{
unsigned int old , new ;
int ret ;
ret = snd_soc_component_read ( component , reg , & old ) ;
if ( ret < 0 )
return ret ;
new = ( old & ~ mask ) | value ;
return old ! = new ;
}
EXPORT_SYMBOL_GPL ( snd_soc_component_test_bits ) ;