2019-04-25 20:06:18 +02:00
// SPDX-License-Identifier: GPL-2.0
//
// Register map access API - SPI support
//
// Copyright 2011 Wolfson Microelectronics plc
//
// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
2011-05-12 11:42:10 +02:00
# include <linux/regmap.h>
# include <linux/spi/spi.h>
2011-08-16 09:36:06 +10:00
# include <linux/module.h>
2011-05-12 11:42:10 +02:00
2013-01-29 12:14:12 +08:00
# include "internal.h"
struct regmap_async_spi {
struct regmap_async core ;
struct spi_message m ;
struct spi_transfer t [ 2 ] ;
} ;
static void regmap_spi_complete ( void * data )
{
struct regmap_async_spi * async = data ;
regmap_async_complete_cb ( & async - > core , async - > m . status ) ;
}
2012-04-04 15:48:30 -06:00
static int regmap_spi_write ( void * context , const void * data , size_t count )
2011-05-12 11:42:10 +02:00
{
2012-04-04 15:48:30 -06:00
struct device * dev = context ;
2011-05-12 11:42:10 +02:00
struct spi_device * spi = to_spi_device ( dev ) ;
return spi_write ( spi , data , count ) ;
}
2012-04-04 15:48:30 -06:00
static int regmap_spi_gather_write ( void * context ,
2011-05-12 11:42:10 +02:00
const void * reg , size_t reg_len ,
const void * val , size_t val_len )
{
2012-04-04 15:48:30 -06:00
struct device * dev = context ;
2011-05-12 11:42:10 +02:00
struct spi_device * spi = to_spi_device ( dev ) ;
struct spi_message m ;
struct spi_transfer t [ 2 ] = { { . tx_buf = reg , . len = reg_len , } ,
{ . tx_buf = val , . len = val_len , } , } ;
spi_message_init ( & m ) ;
spi_message_add_tail ( & t [ 0 ] , & m ) ;
spi_message_add_tail ( & t [ 1 ] , & m ) ;
return spi_sync ( spi , & m ) ;
}
2013-01-29 12:14:12 +08:00
static int regmap_spi_async_write ( void * context ,
const void * reg , size_t reg_len ,
const void * val , size_t val_len ,
struct regmap_async * a )
{
struct regmap_async_spi * async = container_of ( a ,
struct regmap_async_spi ,
core ) ;
struct device * dev = context ;
struct spi_device * spi = to_spi_device ( dev ) ;
async - > t [ 0 ] . tx_buf = reg ;
async - > t [ 0 ] . len = reg_len ;
async - > t [ 1 ] . tx_buf = val ;
async - > t [ 1 ] . len = val_len ;
spi_message_init ( & async - > m ) ;
spi_message_add_tail ( & async - > t [ 0 ] , & async - > m ) ;
2013-10-10 22:25:23 +01:00
if ( val )
spi_message_add_tail ( & async - > t [ 1 ] , & async - > m ) ;
2013-01-29 12:14:12 +08:00
async - > m . complete = regmap_spi_complete ;
async - > m . context = async ;
return spi_async ( spi , & async - > m ) ;
}
static struct regmap_async * regmap_spi_async_alloc ( void )
{
struct regmap_async_spi * async_spi ;
async_spi = kzalloc ( sizeof ( * async_spi ) , GFP_KERNEL ) ;
2013-02-05 14:14:32 +00:00
if ( ! async_spi )
return NULL ;
2013-01-29 12:14:12 +08:00
return & async_spi - > core ;
}
2012-04-04 15:48:30 -06:00
static int regmap_spi_read ( void * context ,
2011-05-12 11:42:10 +02:00
const void * reg , size_t reg_size ,
void * val , size_t val_size )
{
2012-04-04 15:48:30 -06:00
struct device * dev = context ;
2011-05-12 11:42:10 +02:00
struct spi_device * spi = to_spi_device ( dev ) ;
return spi_write_then_read ( spi , reg , reg_size , val , val_size ) ;
}
2017-08-11 08:57:36 +02:00
static const struct regmap_bus regmap_spi = {
2011-05-12 11:42:10 +02:00
. write = regmap_spi_write ,
. gather_write = regmap_spi_gather_write ,
2013-01-29 12:14:12 +08:00
. async_write = regmap_spi_async_write ,
. async_alloc = regmap_spi_async_alloc ,
2011-05-12 11:42:10 +02:00
. read = regmap_spi_read ,
. read_flag_mask = 0x80 ,
2014-07-15 12:23:02 +08:00
. reg_format_endian_default = REGMAP_ENDIAN_BIG ,
. val_format_endian_default = REGMAP_ENDIAN_BIG ,
2011-05-12 11:42:10 +02:00
} ;
2021-10-21 10:27:21 -03:00
static const struct regmap_bus * regmap_get_spi_bus ( struct spi_device * spi ,
const struct regmap_config * config )
{
size_t max_size = spi_max_transfer_size ( spi ) ;
2022-08-18 13:48:51 +03:00
size_t max_msg_size , reg_reserve_size ;
2021-10-21 10:27:21 -03:00
struct regmap_bus * bus ;
if ( max_size ! = SIZE_MAX ) {
bus = kmemdup ( & regmap_spi , sizeof ( * bus ) , GFP_KERNEL ) ;
if ( ! bus )
return ERR_PTR ( - ENOMEM ) ;
2022-08-18 13:48:51 +03:00
max_msg_size = spi_max_message_size ( spi ) ;
reg_reserve_size = config - > reg_bits / BITS_PER_BYTE
+ config - > pad_bits / BITS_PER_BYTE ;
if ( max_size + reg_reserve_size > max_msg_size )
max_size - = reg_reserve_size ;
2021-10-21 10:27:21 -03:00
bus - > free_on_exit = true ;
bus - > max_raw_read = max_size ;
bus - > max_raw_write = max_size ;
2022-08-18 13:48:51 +03:00
2021-10-21 10:27:21 -03:00
return bus ;
}
return & regmap_spi ;
}
2015-07-08 14:30:18 +08:00
struct regmap * __regmap_init_spi ( struct spi_device * spi ,
const struct regmap_config * config ,
struct lock_class_key * lock_key ,
const char * lock_name )
2011-05-12 11:42:10 +02:00
{
2021-10-21 10:27:21 -03:00
const struct regmap_bus * bus = regmap_get_spi_bus ( spi , config ) ;
if ( IS_ERR ( bus ) )
return ERR_CAST ( bus ) ;
return __regmap_init ( & spi - > dev , bus , & spi - > dev , config , lock_key , lock_name ) ;
2011-05-12 11:42:10 +02:00
}
2015-07-08 14:30:18 +08:00
EXPORT_SYMBOL_GPL ( __regmap_init_spi ) ;
2011-08-11 11:59:10 -06:00
2015-07-08 14:30:18 +08:00
struct regmap * __devm_regmap_init_spi ( struct spi_device * spi ,
const struct regmap_config * config ,
struct lock_class_key * lock_key ,
const char * lock_name )
2012-01-30 19:56:52 +00:00
{
2021-10-21 10:27:21 -03:00
const struct regmap_bus * bus = regmap_get_spi_bus ( spi , config ) ;
if ( IS_ERR ( bus ) )
return ERR_CAST ( bus ) ;
return __devm_regmap_init ( & spi - > dev , bus , & spi - > dev , config , lock_key , lock_name ) ;
2012-01-30 19:56:52 +00:00
}
2015-07-08 14:30:18 +08:00
EXPORT_SYMBOL_GPL ( __devm_regmap_init_spi ) ;
2012-01-30 19:56:52 +00:00
2011-08-11 11:59:10 -06:00
MODULE_LICENSE ( " GPL " ) ;