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>
# include <trace/events/asoc.h>
2011-08-13 06:50:48 +04:00
# ifdef CONFIG_REGMAP
2011-06-13 22:35:29 +04:00
static int hw_write ( struct snd_soc_codec * codec , unsigned int reg ,
unsigned int value )
2011-06-13 20:49:55 +04:00
{
int ret ;
if ( ! snd_soc_codec_volatile_register ( codec , reg ) & &
reg < codec - > driver - > reg_cache_size & &
! codec - > cache_bypass ) {
ret = snd_soc_cache_write ( codec , reg , value ) ;
if ( ret < 0 )
return - 1 ;
}
if ( codec - > cache_only ) {
codec - > cache_sync = 1 ;
return 0 ;
}
2011-06-13 22:35:29 +04:00
return regmap_write ( codec - > control_data , reg , value ) ;
2011-06-13 20:49:55 +04:00
}
static unsigned int hw_read ( struct snd_soc_codec * codec , unsigned int reg )
{
int ret ;
unsigned int val ;
if ( reg > = codec - > driver - > reg_cache_size | |
snd_soc_codec_volatile_register ( codec , reg ) | |
codec - > cache_bypass ) {
if ( codec - > cache_only )
return - 1 ;
2011-06-13 22:35:29 +04:00
ret = regmap_read ( codec - > control_data , reg , & val ) ;
if ( ret = = 0 )
return val ;
else
2011-10-09 17:06:13 +04:00
return - 1 ;
2011-06-13 20:49:55 +04:00
}
ret = snd_soc_cache_read ( codec , reg , & val ) ;
if ( ret < 0 )
return - 1 ;
return val ;
}
/* Primitive bulk write support for soc-cache. The data pointed to by
2011-06-13 22:35:29 +04:00
* ` data ' needs to already be in the form the hardware expects . Any
* data written through this function will not go through the cache as
* it only handles writing to volatile or out of bounds registers .
*
* This is currently only supported for devices using the regmap API
* wrappers .
2011-06-13 20:49:55 +04:00
*/
2011-06-13 22:35:29 +04:00
static int snd_soc_hw_bulk_write_raw ( struct snd_soc_codec * codec ,
unsigned int reg ,
2011-06-13 20:49:55 +04:00
const void * data , size_t len )
{
/* To ensure that we don't get out of sync with the cache, check
* whether the base register is volatile or if we ' ve directly asked
* to bypass the cache . Out of bounds registers are considered
* volatile .
*/
if ( ! codec - > cache_bypass
& & ! snd_soc_codec_volatile_register ( codec , reg )
& & reg < codec - > driver - > reg_cache_size )
return - EINVAL ;
2011-06-13 22:35:29 +04:00
return regmap_raw_write ( codec - > control_data , reg , data , len ) ;
2011-06-13 20:49:55 +04:00
}
/**
* snd_soc_codec_set_cache_io : Set up standard I / O functions .
*
* @ codec : CODEC to configure .
* @ addr_bits : Number of bits of register address data .
* @ data_bits : Number of bits of data per register .
* @ control : Control bus used .
*
* Register formats are frequently shared between many I2C and SPI
* devices . In order to promote code reuse the ASoC core provides
* some standard implementations of CODEC read and write operations
* which can be set up using this function .
*
* The caller is responsible for allocating and initialising the
* actual cache .
*
* Note that at present this code cannot be used by CODECs with
* volatile registers .
*/
int snd_soc_codec_set_cache_io ( struct snd_soc_codec * codec ,
int addr_bits , int data_bits ,
enum snd_soc_control_type control )
{
2011-06-13 22:35:29 +04:00
struct regmap_config config ;
2012-02-18 02:33:29 +04:00
int ret ;
2011-06-13 20:49:55 +04:00
2011-06-13 22:35:29 +04:00
memset ( & config , 0 , sizeof ( config ) ) ;
codec - > write = hw_write ;
2011-06-13 20:49:55 +04:00
codec - > read = hw_read ;
codec - > bulk_write_raw = snd_soc_hw_bulk_write_raw ;
2011-06-13 22:35:29 +04:00
config . reg_bits = addr_bits ;
config . val_bits = data_bits ;
2011-06-13 20:49:55 +04:00
switch ( control ) {
2011-08-11 21:59:11 +04:00
# if defined(CONFIG_REGMAP_I2C) || defined(CONFIG_REGMAP_I2C_MODULE)
2011-06-13 20:49:55 +04:00
case SND_SOC_I2C :
2011-06-13 22:35:29 +04:00
codec - > control_data = regmap_init_i2c ( to_i2c_client ( codec - > dev ) ,
& config ) ;
2011-06-13 20:49:55 +04:00
break ;
2011-08-10 12:24:12 +04:00
# endif
2011-06-13 20:49:55 +04:00
2011-08-11 21:59:11 +04:00
# if defined(CONFIG_REGMAP_SPI) || defined(CONFIG_REGMAP_SPI_MODULE)
2011-06-13 20:49:55 +04:00
case SND_SOC_SPI :
2011-06-13 22:35:29 +04:00
codec - > control_data = regmap_init_spi ( to_spi_device ( codec - > dev ) ,
& config ) ;
2011-06-13 20:49:55 +04:00
break ;
2011-08-10 12:24:12 +04:00
# endif
2011-06-13 22:35:29 +04:00
2011-07-24 15:23:37 +04:00
case SND_SOC_REGMAP :
/* Device has made its own regmap arrangements */
2011-12-03 16:33:55 +04:00
codec - > using_regmap = true ;
2012-05-08 20:46:36 +04:00
if ( ! codec - > control_data )
codec - > control_data = dev_get_regmap ( codec - > dev , NULL ) ;
2012-02-18 02:33:29 +04:00
2012-06-22 15:40:52 +04:00
if ( codec - > control_data ) {
ret = regmap_get_val_bytes ( codec - > control_data ) ;
/* Errors are legitimate for non-integer byte
* multiples */
if ( ret > 0 )
codec - > val_bytes = ret ;
}
2011-07-24 15:23:37 +04:00
break ;
2011-06-13 22:35:29 +04:00
default :
return - EINVAL ;
2011-06-13 20:49:55 +04:00
}
2011-06-13 22:35:29 +04:00
if ( IS_ERR ( codec - > control_data ) )
return PTR_ERR ( codec - > control_data ) ;
2011-06-13 20:49:55 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( snd_soc_codec_set_cache_io ) ;
2011-08-13 06:50:48 +04:00
# else
int snd_soc_codec_set_cache_io ( struct snd_soc_codec * codec ,
int addr_bits , int data_bits ,
enum snd_soc_control_type control )
{
return - ENOTSUPP ;
}
EXPORT_SYMBOL_GPL ( snd_soc_codec_set_cache_io ) ;
# endif