2023-05-11 12:51:22 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* SPI access driver for TI TPS6594 / TPS6593 / LP8764 PMICs
*
* Copyright ( C ) 2023 BayLibre Incorporated - https : //www.baylibre.com/
*/
# include <linux/crc8.h>
# include <linux/module.h>
# include <linux/mod_devicetable.h>
# include <linux/of_device.h>
# include <linux/regmap.h>
# include <linux/spi/spi.h>
# include <linux/mfd/tps6594.h>
# define TPS6594_SPI_PAGE_SHIFT 5
# define TPS6594_SPI_READ_BIT BIT(4)
static bool enable_crc ;
module_param ( enable_crc , bool , 0444 ) ;
MODULE_PARM_DESC ( enable_crc , " Enable CRC feature for SPI interface " ) ;
DECLARE_CRC8_TABLE ( tps6594_spi_crc_table ) ;
static int tps6594_spi_reg_read ( void * context , unsigned int reg , unsigned int * val )
{
struct spi_device * spi = context ;
struct tps6594 * tps = spi_get_drvdata ( spi ) ;
u8 buf [ 4 ] = { 0 } ;
size_t count_rx = 1 ;
int ret ;
buf [ 0 ] = reg ;
buf [ 1 ] = TPS6594_REG_TO_PAGE ( reg ) < < TPS6594_SPI_PAGE_SHIFT | TPS6594_SPI_READ_BIT ;
if ( tps - > use_crc )
count_rx + + ;
ret = spi_write_then_read ( spi , buf , 2 , buf + 2 , count_rx ) ;
if ( ret < 0 )
return ret ;
if ( tps - > use_crc & & buf [ 3 ] ! = crc8 ( tps6594_spi_crc_table , buf , 3 , CRC8_INIT_VALUE ) )
return - EIO ;
* val = buf [ 2 ] ;
return 0 ;
}
static int tps6594_spi_reg_write ( void * context , unsigned int reg , unsigned int val )
{
struct spi_device * spi = context ;
struct tps6594 * tps = spi_get_drvdata ( spi ) ;
u8 buf [ 4 ] = { 0 } ;
size_t count = 3 ;
buf [ 0 ] = reg ;
buf [ 1 ] = TPS6594_REG_TO_PAGE ( reg ) < < TPS6594_SPI_PAGE_SHIFT ;
buf [ 2 ] = val ;
if ( tps - > use_crc )
buf [ 3 ] = crc8 ( tps6594_spi_crc_table , buf , count + + , CRC8_INIT_VALUE ) ;
return spi_write ( spi , buf , count ) ;
}
static const struct regmap_config tps6594_spi_regmap_config = {
. reg_bits = 16 ,
. val_bits = 8 ,
. max_register = TPS6594_REG_DWD_FAIL_CNT_REG ,
. volatile_reg = tps6594_is_volatile_reg ,
. reg_read = tps6594_spi_reg_read ,
. reg_write = tps6594_spi_reg_write ,
. use_single_read = true ,
. use_single_write = true ,
} ;
static const struct of_device_id tps6594_spi_of_match_table [ ] = {
{ . compatible = " ti,tps6594-q1 " , . data = ( void * ) TPS6594 , } ,
{ . compatible = " ti,tps6593-q1 " , . data = ( void * ) TPS6593 , } ,
{ . compatible = " ti,lp8764-q1 " , . data = ( void * ) LP8764 , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , tps6594_spi_of_match_table ) ;
static int tps6594_spi_probe ( struct spi_device * spi )
{
struct device * dev = & spi - > dev ;
struct tps6594 * tps ;
const struct of_device_id * match ;
tps = devm_kzalloc ( dev , sizeof ( * tps ) , GFP_KERNEL ) ;
if ( ! tps )
return - ENOMEM ;
spi_set_drvdata ( spi , tps ) ;
tps - > dev = dev ;
2023-11-25 12:21:28 +03:00
tps - > reg = spi_get_chipselect ( spi , 0 ) ;
2023-05-11 12:51:22 +03:00
tps - > irq = spi - > irq ;
tps - > regmap = devm_regmap_init ( dev , NULL , spi , & tps6594_spi_regmap_config ) ;
if ( IS_ERR ( tps - > regmap ) )
return dev_err_probe ( dev , PTR_ERR ( tps - > regmap ) , " Failed to init regmap \n " ) ;
match = of_match_device ( tps6594_spi_of_match_table , dev ) ;
if ( ! match )
2023-05-25 12:03:45 +03:00
return dev_err_probe ( dev , - EINVAL , " Failed to find matching chip ID \n " ) ;
2023-05-11 12:51:22 +03:00
tps - > chip_id = ( unsigned long ) match - > data ;
crc8_populate_msb ( tps6594_spi_crc_table , TPS6594_CRC8_POLYNOMIAL ) ;
return tps6594_device_init ( tps , enable_crc ) ;
}
static struct spi_driver tps6594_spi_driver = {
. driver = {
. name = " tps6594 " ,
. of_match_table = tps6594_spi_of_match_table ,
} ,
. probe = tps6594_spi_probe ,
} ;
module_spi_driver ( tps6594_spi_driver ) ;
MODULE_AUTHOR ( " Julien Panis <jpanis@baylibre.com> " ) ;
MODULE_DESCRIPTION ( " TPS6594 SPI Interface Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;