2011-05-11 21:59:58 +04:00
/*
* Register map access API
*
* Copyright 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 version 2 as
* published by the Free Software Foundation .
*/
# include <linux/slab.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/err.h>
2011-07-25 00:30:55 +04:00
# define CREATE_TRACE_POINTS
# include <trace/events/regmap.h>
2011-07-21 01:35:37 +04:00
# include "internal.h"
2011-05-11 21:59:58 +04:00
2011-08-10 12:14:41 +04:00
bool regmap_writeable ( struct regmap * map , unsigned int reg )
{
if ( map - > max_register & & reg > map - > max_register )
return false ;
if ( map - > writeable_reg )
return map - > writeable_reg ( map - > dev , reg ) ;
return true ;
}
bool regmap_readable ( struct regmap * map , unsigned int reg )
{
if ( map - > max_register & & reg > map - > max_register )
return false ;
if ( map - > readable_reg )
return map - > readable_reg ( map - > dev , reg ) ;
return true ;
}
bool regmap_volatile ( struct regmap * map , unsigned int reg )
{
if ( map - > max_register & & reg > map - > max_register )
return false ;
if ( map - > volatile_reg )
return map - > volatile_reg ( map - > dev , reg ) ;
return true ;
}
bool regmap_precious ( struct regmap * map , unsigned int reg )
{
if ( map - > max_register & & reg > map - > max_register )
return false ;
if ( map - > precious_reg )
return map - > precious_reg ( map - > dev , reg ) ;
return false ;
}
2011-11-08 21:37:25 +04:00
static bool regmap_volatile_range ( struct regmap * map , unsigned int reg ,
unsigned int num )
{
unsigned int i ;
for ( i = 0 ; i < num ; i + + )
if ( ! regmap_volatile ( map , reg + i ) )
return false ;
return true ;
}
2011-05-11 21:59:58 +04:00
static void regmap_format_4_12_write ( struct regmap * map ,
unsigned int reg , unsigned int val )
{
__be16 * out = map - > work_buf ;
* out = cpu_to_be16 ( ( reg < < 12 ) | val ) ;
}
static void regmap_format_7_9_write ( struct regmap * map ,
unsigned int reg , unsigned int val )
{
__be16 * out = map - > work_buf ;
* out = cpu_to_be16 ( ( reg < < 9 ) | val ) ;
}
2011-11-16 19:28:21 +04:00
static void regmap_format_10_14_write ( struct regmap * map ,
unsigned int reg , unsigned int val )
{
u8 * out = map - > work_buf ;
out [ 2 ] = val ;
out [ 1 ] = ( val > > 8 ) | ( reg < < 6 ) ;
out [ 0 ] = reg > > 2 ;
}
2011-05-11 21:59:58 +04:00
static void regmap_format_8 ( void * buf , unsigned int val )
{
u8 * b = buf ;
b [ 0 ] = val ;
}
static void regmap_format_16 ( void * buf , unsigned int val )
{
__be16 * b = buf ;
b [ 0 ] = cpu_to_be16 ( val ) ;
}
static unsigned int regmap_parse_8 ( void * buf )
{
u8 * b = buf ;
return b [ 0 ] ;
}
static unsigned int regmap_parse_16 ( void * buf )
{
__be16 * b = buf ;
b [ 0 ] = be16_to_cpu ( b [ 0 ] ) ;
return b [ 0 ] ;
}
/**
* regmap_init ( ) : Initialise register map
*
* @ dev : Device that will be interacted with
* @ bus : Bus - specific callbacks to use with device
* @ config : Configuration for register map
*
* The return value will be an ERR_PTR ( ) on error or a valid pointer to
* a struct regmap . This function should generally not be called
* directly , it should be called by bus - specific init functions .
*/
struct regmap * regmap_init ( struct device * dev ,
const struct regmap_bus * bus ,
const struct regmap_config * config )
{
struct regmap * map ;
int ret = - EINVAL ;
if ( ! bus | | ! config )
2011-11-14 13:40:15 +04:00
goto err ;
2011-05-11 21:59:58 +04:00
map = kzalloc ( sizeof ( * map ) , GFP_KERNEL ) ;
if ( map = = NULL ) {
ret = - ENOMEM ;
goto err ;
}
mutex_init ( & map - > lock ) ;
map - > format . buf_size = ( config - > reg_bits + config - > val_bits ) / 8 ;
map - > format . reg_bytes = config - > reg_bits / 8 ;
2012-01-18 14:52:25 +04:00
map - > format . pad_bytes = config - > pad_bits / 8 ;
2011-05-11 21:59:58 +04:00
map - > format . val_bytes = config - > val_bits / 8 ;
2012-01-18 14:52:25 +04:00
map - > format . buf_size + = map - > format . pad_bytes ;
2011-05-11 21:59:58 +04:00
map - > dev = dev ;
map - > bus = bus ;
2011-07-21 01:33:39 +04:00
map - > max_register = config - > max_register ;
map - > writeable_reg = config - > writeable_reg ;
map - > readable_reg = config - > readable_reg ;
map - > volatile_reg = config - > volatile_reg ;
2011-08-08 10:41:46 +04:00
map - > precious_reg = config - > precious_reg ;
2011-09-19 17:34:05 +04:00
map - > cache_type = config - > cache_type ;
2011-05-11 21:59:58 +04:00
2011-09-05 22:46:32 +04:00
if ( config - > read_flag_mask | | config - > write_flag_mask ) {
map - > read_flag_mask = config - > read_flag_mask ;
map - > write_flag_mask = config - > write_flag_mask ;
} else {
map - > read_flag_mask = bus - > read_flag_mask ;
}
2011-05-11 21:59:58 +04:00
switch ( config - > reg_bits ) {
case 4 :
switch ( config - > val_bits ) {
case 12 :
map - > format . format_write = regmap_format_4_12_write ;
break ;
default :
goto err_map ;
}
break ;
case 7 :
switch ( config - > val_bits ) {
case 9 :
map - > format . format_write = regmap_format_7_9_write ;
break ;
default :
goto err_map ;
}
break ;
2011-11-16 19:28:21 +04:00
case 10 :
switch ( config - > val_bits ) {
case 14 :
map - > format . format_write = regmap_format_10_14_write ;
break ;
default :
goto err_map ;
}
break ;
2011-05-11 21:59:58 +04:00
case 8 :
map - > format . format_reg = regmap_format_8 ;
break ;
case 16 :
map - > format . format_reg = regmap_format_16 ;
break ;
default :
goto err_map ;
}
switch ( config - > val_bits ) {
case 8 :
map - > format . format_val = regmap_format_8 ;
map - > format . parse_val = regmap_parse_8 ;
break ;
case 16 :
map - > format . format_val = regmap_format_16 ;
map - > format . parse_val = regmap_parse_16 ;
break ;
}
if ( ! map - > format . format_write & &
! ( map - > format . format_reg & & map - > format . format_val ) )
goto err_map ;
2012-01-18 14:52:25 +04:00
map - > work_buf = kzalloc ( map - > format . buf_size , GFP_KERNEL ) ;
2011-05-11 21:59:58 +04:00
if ( map - > work_buf = = NULL ) {
ret = - ENOMEM ;
2011-09-05 19:07:47 +04:00
goto err_map ;
2011-05-11 21:59:58 +04:00
}
2011-11-21 23:05:13 +04:00
regmap_debugfs_init ( map ) ;
2011-11-16 19:28:16 +04:00
ret = regcache_init ( map , config ) ;
2011-09-19 17:34:05 +04:00
if ( ret < 0 )
2011-11-10 21:15:15 +04:00
goto err_free_workbuf ;
2011-09-19 17:34:05 +04:00
2011-05-11 21:59:58 +04:00
return map ;
2011-11-10 21:15:15 +04:00
err_free_workbuf :
kfree ( map - > work_buf ) ;
2011-05-11 21:59:58 +04:00
err_map :
kfree ( map ) ;
err :
return ERR_PTR ( ret ) ;
}
EXPORT_SYMBOL_GPL ( regmap_init ) ;
2011-12-03 21:06:20 +04:00
/**
* regmap_reinit_cache ( ) : Reinitialise the current register cache
*
* @ map : Register map to operate on .
* @ config : New configuration . Only the cache data will be used .
*
* Discard any existing register cache for the map and initialize a
* new cache . This can be used to restore the cache to defaults or to
* update the cache configuration to reflect runtime discovery of the
* hardware .
*/
int regmap_reinit_cache ( struct regmap * map , const struct regmap_config * config )
{
int ret ;
mutex_lock ( & map - > lock ) ;
regcache_exit ( map ) ;
2012-01-26 22:30:16 +04:00
regmap_debugfs_exit ( map ) ;
2011-12-03 21:06:20 +04:00
map - > max_register = config - > max_register ;
map - > writeable_reg = config - > writeable_reg ;
map - > readable_reg = config - > readable_reg ;
map - > volatile_reg = config - > volatile_reg ;
map - > precious_reg = config - > precious_reg ;
map - > cache_type = config - > cache_type ;
2012-01-26 22:30:16 +04:00
regmap_debugfs_init ( map ) ;
2011-12-03 21:06:20 +04:00
ret = regcache_init ( map , config ) ;
mutex_unlock ( & map - > lock ) ;
return ret ;
}
2011-05-11 21:59:58 +04:00
/**
* regmap_exit ( ) : Free a previously allocated register map
*/
void regmap_exit ( struct regmap * map )
{
2011-09-19 17:34:05 +04:00
regcache_exit ( map ) ;
2011-07-21 01:56:53 +04:00
regmap_debugfs_exit ( map ) ;
2011-05-11 21:59:58 +04:00
kfree ( map - > work_buf ) ;
kfree ( map ) ;
}
EXPORT_SYMBOL_GPL ( regmap_exit ) ;
static int _regmap_raw_write ( struct regmap * map , unsigned int reg ,
const void * val , size_t val_len )
{
2011-09-05 22:46:32 +04:00
u8 * u8 = map - > work_buf ;
2011-05-11 21:59:58 +04:00
void * buf ;
int ret = - ENOTSUPP ;
size_t len ;
2011-07-24 14:46:20 +04:00
int i ;
/* Check for unwritable registers before we start */
if ( map - > writeable_reg )
for ( i = 0 ; i < val_len / map - > format . val_bytes ; i + + )
if ( ! map - > writeable_reg ( map - > dev , reg + i ) )
return - EINVAL ;
2011-05-11 21:59:58 +04:00
map - > format . format_reg ( map - > work_buf , reg ) ;
2011-09-05 22:46:32 +04:00
u8 [ 0 ] | = map - > write_flag_mask ;
2011-07-25 00:30:55 +04:00
trace_regmap_hw_write_start ( map - > dev , reg ,
val_len / map - > format . val_bytes ) ;
2011-07-21 00:47:22 +04:00
/* If we're doing a single register write we can probably just
* send the work_buf directly , otherwise try to do a gather
* write .
*/
2012-01-18 14:52:25 +04:00
if ( val = = ( map - > work_buf + map - > format . pad_bytes +
map - > format . reg_bytes ) )
2011-07-21 00:47:22 +04:00
ret = map - > bus - > write ( map - > dev , map - > work_buf ,
2012-01-18 14:52:25 +04:00
map - > format . reg_bytes +
map - > format . pad_bytes +
val_len ) ;
2011-07-21 00:47:22 +04:00
else if ( map - > bus - > gather_write )
2011-05-11 21:59:58 +04:00
ret = map - > bus - > gather_write ( map - > dev , map - > work_buf ,
2012-01-18 14:52:25 +04:00
map - > format . reg_bytes +
map - > format . pad_bytes ,
2011-05-11 21:59:58 +04:00
val , val_len ) ;
2011-07-21 00:47:22 +04:00
/* If that didn't work fall back on linearising by hand. */
2011-05-11 21:59:58 +04:00
if ( ret = = - ENOTSUPP ) {
2012-01-18 14:52:25 +04:00
len = map - > format . reg_bytes + map - > format . pad_bytes + val_len ;
buf = kzalloc ( len , GFP_KERNEL ) ;
2011-05-11 21:59:58 +04:00
if ( ! buf )
return - ENOMEM ;
memcpy ( buf , map - > work_buf , map - > format . reg_bytes ) ;
2012-01-18 14:52:25 +04:00
memcpy ( buf + map - > format . reg_bytes + map - > format . pad_bytes ,
val , val_len ) ;
2011-05-11 21:59:58 +04:00
ret = map - > bus - > write ( map - > dev , buf , len ) ;
kfree ( buf ) ;
}
2011-07-25 00:30:55 +04:00
trace_regmap_hw_write_done ( map - > dev , reg ,
val_len / map - > format . val_bytes ) ;
2011-05-11 21:59:58 +04:00
return ret ;
}
2011-09-29 13:39:07 +04:00
int _regmap_write ( struct regmap * map , unsigned int reg ,
unsigned int val )
2011-05-11 21:59:58 +04:00
{
2011-07-25 00:30:55 +04:00
int ret ;
2011-05-11 21:59:58 +04:00
BUG_ON ( ! map - > format . format_write & & ! map - > format . format_val ) ;
2011-09-19 17:34:05 +04:00
if ( ! map - > cache_bypass ) {
ret = regcache_write ( map , reg , val ) ;
if ( ret ! = 0 )
return ret ;
2011-10-26 12:34:22 +04:00
if ( map - > cache_only ) {
map - > cache_dirty = true ;
2011-09-19 17:34:05 +04:00
return 0 ;
2011-10-26 12:34:22 +04:00
}
2011-09-19 17:34:05 +04:00
}
2011-07-25 00:30:55 +04:00
trace_regmap_reg_write ( map - > dev , reg , val ) ;
2011-05-11 21:59:58 +04:00
if ( map - > format . format_write ) {
map - > format . format_write ( map , reg , val ) ;
2011-07-25 00:30:55 +04:00
trace_regmap_hw_write_start ( map - > dev , reg , 1 ) ;
ret = map - > bus - > write ( map - > dev , map - > work_buf ,
map - > format . buf_size ) ;
trace_regmap_hw_write_done ( map - > dev , reg , 1 ) ;
return ret ;
2011-05-11 21:59:58 +04:00
} else {
2012-01-18 14:52:25 +04:00
map - > format . format_val ( map - > work_buf + map - > format . reg_bytes
+ map - > format . pad_bytes , val ) ;
2011-05-11 21:59:58 +04:00
return _regmap_raw_write ( map , reg ,
2012-01-18 14:52:25 +04:00
map - > work_buf +
map - > format . reg_bytes +
map - > format . pad_bytes ,
2011-05-11 21:59:58 +04:00
map - > format . val_bytes ) ;
}
}
/**
* regmap_write ( ) : Write a value to a single register
*
* @ map : Register map to write to
* @ reg : Register to write to
* @ val : Value to be written
*
* A value of zero will be returned on success , a negative errno will
* be returned in error cases .
*/
int regmap_write ( struct regmap * map , unsigned int reg , unsigned int val )
{
int ret ;
mutex_lock ( & map - > lock ) ;
ret = _regmap_write ( map , reg , val ) ;
mutex_unlock ( & map - > lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( regmap_write ) ;
/**
* regmap_raw_write ( ) : Write raw values to one or more registers
*
* @ map : Register map to write to
* @ reg : Initial register to write to
* @ val : Block of data to be written , laid out for direct transmission to the
* device
* @ val_len : Length of data pointed to by val .
*
* This function is intended to be used for things like firmware
* download where a large block of data needs to be transferred to the
* device . No formatting will be done on the data provided .
*
* A value of zero will be returned on success , a negative errno will
* be returned in error cases .
*/
int regmap_raw_write ( struct regmap * map , unsigned int reg ,
const void * val , size_t val_len )
{
2011-11-08 21:37:26 +04:00
size_t val_count = val_len / map - > format . val_bytes ;
2011-05-11 21:59:58 +04:00
int ret ;
2011-11-08 21:37:26 +04:00
WARN_ON ( ! regmap_volatile_range ( map , reg , val_count ) & &
map - > cache_type ! = REGCACHE_NONE ) ;
2011-10-09 16:35:43 +04:00
2011-05-11 21:59:58 +04:00
mutex_lock ( & map - > lock ) ;
ret = _regmap_raw_write ( map , reg , val , val_len ) ;
mutex_unlock ( & map - > lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( regmap_raw_write ) ;
static int _regmap_raw_read ( struct regmap * map , unsigned int reg , void * val ,
unsigned int val_len )
{
u8 * u8 = map - > work_buf ;
int ret ;
map - > format . format_reg ( map - > work_buf , reg ) ;
/*
2011-09-05 22:46:32 +04:00
* Some buses or devices flag reads by setting the high bits in the
2011-05-11 21:59:58 +04:00
* register addresss ; since it ' s always the high bits for all
* current formats we can do this here rather than in
* formatting . This may break if we get interesting formats .
*/
2011-09-05 22:46:32 +04:00
u8 [ 0 ] | = map - > read_flag_mask ;
2011-05-11 21:59:58 +04:00
2011-07-25 00:30:55 +04:00
trace_regmap_hw_read_start ( map - > dev , reg ,
val_len / map - > format . val_bytes ) ;
2012-01-18 14:52:25 +04:00
ret = map - > bus - > read ( map - > dev , map - > work_buf ,
map - > format . reg_bytes + map - > format . pad_bytes ,
2011-07-25 01:39:12 +04:00
val , val_len ) ;
2011-05-11 21:59:58 +04:00
2011-07-25 00:30:55 +04:00
trace_regmap_hw_read_done ( map - > dev , reg ,
val_len / map - > format . val_bytes ) ;
return ret ;
2011-05-11 21:59:58 +04:00
}
static int _regmap_read ( struct regmap * map , unsigned int reg ,
unsigned int * val )
{
int ret ;
2011-09-19 17:34:05 +04:00
if ( ! map - > cache_bypass ) {
ret = regcache_read ( map , reg , val ) ;
if ( ret = = 0 )
return 0 ;
}
2011-11-16 19:28:19 +04:00
if ( ! map - > format . parse_val )
return - EINVAL ;
2011-09-19 17:34:05 +04:00
if ( map - > cache_only )
return - EBUSY ;
2011-05-11 21:59:58 +04:00
ret = _regmap_raw_read ( map , reg , map - > work_buf , map - > format . val_bytes ) ;
2011-07-25 00:30:55 +04:00
if ( ret = = 0 ) {
2011-05-11 21:59:58 +04:00
* val = map - > format . parse_val ( map - > work_buf ) ;
2011-07-25 00:30:55 +04:00
trace_regmap_reg_read ( map - > dev , reg , * val ) ;
}
2011-05-11 21:59:58 +04:00
return ret ;
}
/**
* regmap_read ( ) : Read a value from a single register
*
* @ map : Register map to write to
* @ reg : Register to be read from
* @ val : Pointer to store read value
*
* A value of zero will be returned on success , a negative errno will
* be returned in error cases .
*/
int regmap_read ( struct regmap * map , unsigned int reg , unsigned int * val )
{
int ret ;
mutex_lock ( & map - > lock ) ;
ret = _regmap_read ( map , reg , val ) ;
mutex_unlock ( & map - > lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( regmap_read ) ;
/**
* regmap_raw_read ( ) : Read raw data from the device
*
* @ map : Register map to write to
* @ reg : First register to be read from
* @ val : Pointer to store read value
* @ val_len : Size of data to read
*
* A value of zero will be returned on success , a negative errno will
* be returned in error cases .
*/
int regmap_raw_read ( struct regmap * map , unsigned int reg , void * val ,
size_t val_len )
{
2011-11-08 21:37:25 +04:00
size_t val_count = val_len / map - > format . val_bytes ;
2011-05-11 21:59:58 +04:00
int ret ;
2011-10-10 16:24:52 +04:00
2011-11-08 21:37:25 +04:00
WARN_ON ( ! regmap_volatile_range ( map , reg , val_count ) & &
map - > cache_type ! = REGCACHE_NONE ) ;
2011-10-09 16:35:43 +04:00
2011-05-11 21:59:58 +04:00
mutex_lock ( & map - > lock ) ;
ret = _regmap_raw_read ( map , reg , val , val_len ) ;
mutex_unlock ( & map - > lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( regmap_raw_read ) ;
/**
* regmap_bulk_read ( ) : Read multiple registers from the device
*
* @ map : Register map to write to
* @ reg : First register to be read from
* @ val : Pointer to store read value , in native register size for device
* @ val_count : Number of registers to read
*
* A value of zero will be returned on success , a negative errno will
* be returned in error cases .
*/
int regmap_bulk_read ( struct regmap * map , unsigned int reg , void * val ,
size_t val_count )
{
int ret , i ;
size_t val_bytes = map - > format . val_bytes ;
2011-11-08 21:37:25 +04:00
bool vol = regmap_volatile_range ( map , reg , val_count ) ;
2011-09-19 17:34:05 +04:00
2011-05-11 21:59:58 +04:00
if ( ! map - > format . parse_val )
return - EINVAL ;
2011-10-10 16:24:52 +04:00
if ( vol | | map - > cache_type = = REGCACHE_NONE ) {
ret = regmap_raw_read ( map , reg , val , val_bytes * val_count ) ;
if ( ret ! = 0 )
return ret ;
for ( i = 0 ; i < val_count * val_bytes ; i + = val_bytes )
map - > format . parse_val ( val + i ) ;
} else {
for ( i = 0 ; i < val_count ; i + + ) {
ret = regmap_read ( map , reg + i , val + ( i * val_bytes ) ) ;
if ( ret ! = 0 )
return ret ;
}
}
2011-05-11 21:59:58 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( regmap_bulk_read ) ;
2011-11-30 00:10:36 +04:00
static int _regmap_update_bits ( struct regmap * map , unsigned int reg ,
unsigned int mask , unsigned int val ,
bool * change )
2011-05-11 21:59:58 +04:00
{
int ret ;
2011-11-18 20:03:50 +04:00
unsigned int tmp , orig ;
2011-05-11 21:59:58 +04:00
mutex_lock ( & map - > lock ) ;
2011-11-18 20:03:50 +04:00
ret = _regmap_read ( map , reg , & orig ) ;
2011-05-11 21:59:58 +04:00
if ( ret ! = 0 )
goto out ;
2011-11-18 20:03:50 +04:00
tmp = orig & ~ mask ;
2011-05-11 21:59:58 +04:00
tmp | = val & mask ;
2011-11-30 00:10:36 +04:00
if ( tmp ! = orig ) {
2011-11-18 20:03:50 +04:00
ret = _regmap_write ( map , reg , tmp ) ;
2011-11-30 00:10:36 +04:00
* change = true ;
} else {
* change = false ;
}
2011-05-11 21:59:58 +04:00
out :
mutex_unlock ( & map - > lock ) ;
return ret ;
}
2011-11-30 00:10:36 +04:00
/**
* regmap_update_bits : Perform a read / modify / write cycle on the register map
*
* @ map : Register map to update
* @ reg : Register to update
* @ mask : Bitmask to change
* @ val : New value for bitmask
*
* Returns zero for success , a negative number on error .
*/
int regmap_update_bits ( struct regmap * map , unsigned int reg ,
unsigned int mask , unsigned int val )
{
bool change ;
return _regmap_update_bits ( map , reg , mask , val , & change ) ;
}
2011-05-11 21:59:58 +04:00
EXPORT_SYMBOL_GPL ( regmap_update_bits ) ;
2011-07-21 01:56:53 +04:00
2011-11-30 00:10:36 +04:00
/**
* regmap_update_bits_check : Perform a read / modify / write cycle on the
* register map and report if updated
*
* @ map : Register map to update
* @ reg : Register to update
* @ mask : Bitmask to change
* @ val : New value for bitmask
* @ change : Boolean indicating if a write was done
*
* Returns zero for success , a negative number on error .
*/
int regmap_update_bits_check ( struct regmap * map , unsigned int reg ,
unsigned int mask , unsigned int val ,
bool * change )
{
return _regmap_update_bits ( map , reg , mask , val , change ) ;
}
EXPORT_SYMBOL_GPL ( regmap_update_bits_check ) ;
2011-07-21 01:56:53 +04:00
static int __init regmap_initcall ( void )
{
regmap_debugfs_initcall ( ) ;
return 0 ;
}
postcore_initcall ( regmap_initcall ) ;