2023-05-04 19:36:12 +02:00
// SPDX-License-Identifier: GPL-2.0
/*
* Rockchip RK806 Core ( SPI ) driver
*
* Copyright ( c ) 2021 Rockchip Electronics Co . , Ltd .
* Copyright ( c ) 2023 Collabora Ltd .
*
* Author : Xu Shengfei < xsf @ rock - chips . com >
* Author : Sebastian Reichel < sebastian . reichel @ collabora . com >
*/
# include <linux/interrupt.h>
# include <linux/mfd/core.h>
# include <linux/mfd/rk808.h>
# include <linux/module.h>
# include <linux/regmap.h>
# include <linux/spi/spi.h>
# define RK806_ADDR_SIZE 2
# define RK806_CMD_WITH_SIZE(CMD, VALUE_BYTES) \
( RK806_CMD_ # # CMD | RK806_CMD_CRC_DIS | ( VALUE_BYTES - 1 ) )
static const struct regmap_range rk806_volatile_ranges [ ] = {
regmap_reg_range ( RK806_POWER_EN0 , RK806_POWER_EN5 ) ,
regmap_reg_range ( RK806_DVS_START_CTRL , RK806_INT_MSK1 ) ,
} ;
static const struct regmap_access_table rk806_volatile_table = {
. yes_ranges = rk806_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( rk806_volatile_ranges ) ,
} ;
static const struct regmap_config rk806_regmap_config_spi = {
. reg_bits = 16 ,
. val_bits = 8 ,
. max_register = RK806_BUCK_RSERVE_REG5 ,
2024-02-06 02:13:08 -05:00
. cache_type = REGCACHE_MAPLE ,
2023-05-04 19:36:12 +02:00
. volatile_table = & rk806_volatile_table ,
} ;
static int rk806_spi_bus_write ( void * context , const void * vdata , size_t count )
{
struct device * dev = context ;
struct spi_device * spi = to_spi_device ( dev ) ;
struct spi_transfer xfer [ 2 ] = { 0 } ;
/* data and thus count includes the register address */
size_t val_size = count - RK806_ADDR_SIZE ;
char cmd ;
if ( val_size < 1 | | val_size > ( RK806_CMD_LEN_MSK + 1 ) )
return - EINVAL ;
cmd = RK806_CMD_WITH_SIZE ( WRITE , val_size ) ;
xfer [ 0 ] . tx_buf = & cmd ;
xfer [ 0 ] . len = sizeof ( cmd ) ;
xfer [ 1 ] . tx_buf = vdata ;
xfer [ 1 ] . len = count ;
return spi_sync_transfer ( spi , xfer , ARRAY_SIZE ( xfer ) ) ;
}
static int rk806_spi_bus_read ( void * context , const void * vreg , size_t reg_size ,
void * val , size_t val_size )
{
struct device * dev = context ;
struct spi_device * spi = to_spi_device ( dev ) ;
char txbuf [ 3 ] = { 0 } ;
if ( reg_size ! = RK806_ADDR_SIZE | |
val_size < 1 | | val_size > ( RK806_CMD_LEN_MSK + 1 ) )
return - EINVAL ;
/* TX buffer contains command byte followed by two address bytes */
txbuf [ 0 ] = RK806_CMD_WITH_SIZE ( READ , val_size ) ;
memcpy ( txbuf + 1 , vreg , reg_size ) ;
return spi_write_then_read ( spi , txbuf , sizeof ( txbuf ) , val , val_size ) ;
}
static const struct regmap_bus rk806_regmap_bus_spi = {
. write = rk806_spi_bus_write ,
. read = rk806_spi_bus_read ,
. reg_format_endian_default = REGMAP_ENDIAN_LITTLE ,
} ;
static int rk8xx_spi_probe ( struct spi_device * spi )
{
struct regmap * regmap ;
regmap = devm_regmap_init ( & spi - > dev , & rk806_regmap_bus_spi ,
& spi - > dev , & rk806_regmap_config_spi ) ;
if ( IS_ERR ( regmap ) )
return dev_err_probe ( & spi - > dev , PTR_ERR ( regmap ) ,
" Failed to init regmap \n " ) ;
return rk8xx_probe ( & spi - > dev , RK806_ID , spi - > irq , regmap ) ;
}
static const struct of_device_id rk8xx_spi_of_match [ ] = {
{ . compatible = " rockchip,rk806 " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , rk8xx_spi_of_match ) ;
static const struct spi_device_id rk8xx_spi_id_table [ ] = {
{ " rk806 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( spi , rk8xx_spi_id_table ) ;
static struct spi_driver rk8xx_spi_driver = {
. driver = {
. name = " rk8xx-spi " ,
. of_match_table = rk8xx_spi_of_match ,
} ,
. probe = rk8xx_spi_probe ,
. id_table = rk8xx_spi_id_table ,
} ;
module_spi_driver ( rk8xx_spi_driver ) ;
MODULE_AUTHOR ( " Xu Shengfei <xsf@rock-chips.com> " ) ;
MODULE_DESCRIPTION ( " RK8xx SPI PMIC driver " ) ;
MODULE_LICENSE ( " GPL " ) ;