2018-07-02 06:21:54 +00:00
// SPDX-License-Identifier: GPL-2.0+
//
// soc-io.c -- ASoC register I/O helpers
//
// Copyright 2009-2011 Wolfson Microelectronics PLC.
//
// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
2011-06-13 17:49:55 +01:00
# include <linux/i2c.h>
# include <linux/spi/spi.h>
2011-06-13 19:35:29 +01:00
# include <linux/regmap.h>
2011-09-22 09:34:58 -04:00
# include <linux/export.h>
2011-06-13 17:49:55 +01:00
# include <sound/soc.h>
2014-04-22 13:23:13 +02: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 02:00:59 +00:00
else if ( component - > driver - > read ) {
* val = component - > driver - > read ( component , reg ) ;
ret = 0 ;
}
2014-04-22 13:23:13 +02:00
else
ret = - EIO ;
return ret ;
}
EXPORT_SYMBOL_GPL ( snd_soc_component_read ) ;
2017-11-06 01:48:19 +00: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 13:23:13 +02: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 09:02:07 +01:00
{
2014-04-22 13:23:13 +02:00
if ( component - > regmap )
return regmap_write ( component - > regmap , reg , val ) ;
2018-01-16 02:00:59 +00:00
else if ( component - > driver - > write )
return component - > driver - > write ( component , reg , val ) ;
2014-04-22 13:23:13 +02: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 16:24:23 +02:00
ret = snd_soc_component_read ( component , reg , & old ) ;
2014-04-22 13:23:13 +02:00
if ( ret < 0 )
goto out_unlock ;
new = ( old & ~ mask ) | ( val & mask ) ;
* change = old ! = new ;
if ( * change )
2018-03-12 16:24:23 +02:00
ret = snd_soc_component_write ( component , reg , new ) ;
2014-04-22 13:23:13 +02:00
out_unlock :
mutex_unlock ( & component - > io_mutex ) ;
2014-03-18 09:02:07 +01:00
return ret ;
}
2014-04-22 13:23:13 +02: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 ) ;