2018-10-25 18:35:42 +03:00
// SPDX-License-Identifier: GPL-2.0
2014-03-08 22:38:00 +04:00
/*
* Copyright ( C ) 2014 Angelo Compagnucci < angelo . compagnucci @ gmail . com >
*
2015-12-09 12:24:04 +03:00
* Driver for Texas Instruments ' ADC128S052 , ADC122S021 and ADC124S021 ADC chip .
2015-05-18 16:22:44 +03:00
* Datasheets can be found here :
2020-07-04 22:27:43 +03:00
* https : //www.ti.com/lit/ds/symlink/adc128s052.pdf
* https : //www.ti.com/lit/ds/symlink/adc122s021.pdf
* https : //www.ti.com/lit/ds/symlink/adc124s021.pdf
2014-03-08 22:38:00 +04:00
*/
# include <linux/err.h>
# include <linux/iio/iio.h>
2023-01-02 20:34:50 +03:00
# include <linux/mod_devicetable.h>
# include <linux/module.h>
2018-10-25 18:35:41 +03:00
# include <linux/property.h>
2014-03-08 22:38:00 +04:00
# include <linux/regulator/consumer.h>
2023-01-02 20:34:50 +03:00
# include <linux/spi/spi.h>
2014-03-08 22:38:00 +04:00
2015-05-18 16:22:44 +03:00
struct adc128_configuration {
const struct iio_chan_spec * channels ;
u8 num_channels ;
} ;
2014-03-08 22:38:00 +04:00
struct adc128 {
struct spi_device * spi ;
struct regulator * reg ;
struct mutex lock ;
2022-05-08 20:56:12 +03:00
u8 buffer [ 2 ] __aligned ( IIO_DMA_MINALIGN ) ;
2014-03-08 22:38:00 +04:00
} ;
static int adc128_adc_conversion ( struct adc128 * adc , u8 channel )
{
int ret ;
mutex_lock ( & adc - > lock ) ;
adc - > buffer [ 0 ] = channel < < 3 ;
adc - > buffer [ 1 ] = 0 ;
ret = spi_write ( adc - > spi , & adc - > buffer , 2 ) ;
if ( ret < 0 ) {
mutex_unlock ( & adc - > lock ) ;
return ret ;
}
ret = spi_read ( adc - > spi , & adc - > buffer , 2 ) ;
mutex_unlock ( & adc - > lock ) ;
if ( ret < 0 )
return ret ;
return ( ( adc - > buffer [ 0 ] < < 8 | adc - > buffer [ 1 ] ) & 0xFFF ) ;
}
static int adc128_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * channel , int * val ,
int * val2 , long mask )
{
struct adc128 * adc = iio_priv ( indio_dev ) ;
int ret ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
ret = adc128_adc_conversion ( adc , channel - > channel ) ;
if ( ret < 0 )
return ret ;
* val = ret ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
ret = regulator_get_voltage ( adc - > reg ) ;
if ( ret < 0 )
return ret ;
* val = ret / 1000 ;
* val2 = 12 ;
return IIO_VAL_FRACTIONAL_LOG2 ;
default :
return - EINVAL ;
}
}
# define ADC128_VOLTAGE_CHANNEL(num) \
{ \
. type = IIO_VOLTAGE , \
. indexed = 1 , \
. channel = ( num ) , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) \
}
2015-05-18 16:22:44 +03:00
static const struct iio_chan_spec adc128s052_channels [ ] = {
2014-03-08 22:38:00 +04:00
ADC128_VOLTAGE_CHANNEL ( 0 ) ,
ADC128_VOLTAGE_CHANNEL ( 1 ) ,
ADC128_VOLTAGE_CHANNEL ( 2 ) ,
ADC128_VOLTAGE_CHANNEL ( 3 ) ,
ADC128_VOLTAGE_CHANNEL ( 4 ) ,
ADC128_VOLTAGE_CHANNEL ( 5 ) ,
ADC128_VOLTAGE_CHANNEL ( 6 ) ,
ADC128_VOLTAGE_CHANNEL ( 7 ) ,
} ;
2015-05-18 16:22:44 +03:00
static const struct iio_chan_spec adc122s021_channels [ ] = {
ADC128_VOLTAGE_CHANNEL ( 0 ) ,
ADC128_VOLTAGE_CHANNEL ( 1 ) ,
} ;
2015-12-09 12:24:04 +03:00
static const struct iio_chan_spec adc124s021_channels [ ] = {
ADC128_VOLTAGE_CHANNEL ( 0 ) ,
ADC128_VOLTAGE_CHANNEL ( 1 ) ,
ADC128_VOLTAGE_CHANNEL ( 2 ) ,
ADC128_VOLTAGE_CHANNEL ( 3 ) ,
} ;
2015-05-18 16:22:44 +03:00
static const struct adc128_configuration adc128_config [ ] = {
{ adc128s052_channels , ARRAY_SIZE ( adc128s052_channels ) } ,
{ adc122s021_channels , ARRAY_SIZE ( adc122s021_channels ) } ,
2015-12-09 12:24:04 +03:00
{ adc124s021_channels , ARRAY_SIZE ( adc124s021_channels ) } ,
2015-05-18 16:22:44 +03:00
} ;
2014-03-08 22:38:00 +04:00
static const struct iio_info adc128_info = {
. read_raw = adc128_read_raw ,
} ;
2021-08-26 21:36:22 +03:00
static void adc128_disable_regulator ( void * reg )
{
regulator_disable ( reg ) ;
}
2014-03-08 22:38:00 +04:00
static int adc128_probe ( struct spi_device * spi )
{
2023-01-02 20:34:48 +03:00
const struct adc128_configuration * config ;
2014-03-08 22:38:00 +04:00
struct iio_dev * indio_dev ;
struct adc128 * adc ;
int ret ;
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * adc ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
adc = iio_priv ( indio_dev ) ;
adc - > spi = spi ;
indio_dev - > name = spi_get_device_id ( spi ) - > name ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > info = & adc128_info ;
2023-01-02 20:34:48 +03:00
config = spi_get_device_match_data ( spi ) ;
indio_dev - > channels = config - > channels ;
indio_dev - > num_channels = config - > num_channels ;
2014-03-08 22:38:00 +04:00
adc - > reg = devm_regulator_get ( & spi - > dev , " vref " ) ;
if ( IS_ERR ( adc - > reg ) )
return PTR_ERR ( adc - > reg ) ;
ret = regulator_enable ( adc - > reg ) ;
if ( ret < 0 )
return ret ;
2021-08-26 21:36:22 +03:00
ret = devm_add_action_or_reset ( & spi - > dev , adc128_disable_regulator ,
adc - > reg ) ;
2021-08-21 13:37:24 +03:00
if ( ret )
2021-08-26 21:36:22 +03:00
return ret ;
2014-03-08 22:38:00 +04:00
2021-08-26 21:36:22 +03:00
mutex_init ( & adc - > lock ) ;
2014-03-08 22:38:00 +04:00
2021-08-26 21:36:22 +03:00
return devm_iio_device_register ( & spi - > dev , indio_dev ) ;
2014-03-08 22:38:00 +04:00
}
2015-08-20 10:07:28 +03:00
static const struct of_device_id adc128_of_match [ ] = {
2023-01-02 20:34:48 +03:00
{ . compatible = " ti,adc128s052 " , . data = & adc128_config [ 0 ] } ,
{ . compatible = " ti,adc122s021 " , . data = & adc128_config [ 1 ] } ,
{ . compatible = " ti,adc122s051 " , . data = & adc128_config [ 1 ] } ,
{ . compatible = " ti,adc122s101 " , . data = & adc128_config [ 1 ] } ,
{ . compatible = " ti,adc124s021 " , . data = & adc128_config [ 2 ] } ,
{ . compatible = " ti,adc124s051 " , . data = & adc128_config [ 2 ] } ,
{ . compatible = " ti,adc124s101 " , . data = & adc128_config [ 2 ] } ,
2015-08-20 10:07:28 +03:00
{ /* sentinel */ } ,
} ;
MODULE_DEVICE_TABLE ( of , adc128_of_match ) ;
2014-03-08 22:38:00 +04:00
static const struct spi_device_id adc128_id [ ] = {
2023-01-02 20:34:48 +03:00
{ " adc128s052 " , ( kernel_ulong_t ) & adc128_config [ 0 ] } ,
{ " adc122s021 " , ( kernel_ulong_t ) & adc128_config [ 1 ] } ,
{ " adc122s051 " , ( kernel_ulong_t ) & adc128_config [ 1 ] } ,
{ " adc122s101 " , ( kernel_ulong_t ) & adc128_config [ 1 ] } ,
{ " adc124s021 " , ( kernel_ulong_t ) & adc128_config [ 2 ] } ,
{ " adc124s051 " , ( kernel_ulong_t ) & adc128_config [ 2 ] } ,
{ " adc124s101 " , ( kernel_ulong_t ) & adc128_config [ 2 ] } ,
2014-03-08 22:38:00 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( spi , adc128_id ) ;
2018-10-25 18:35:41 +03:00
static const struct acpi_device_id adc128_acpi_match [ ] = {
2023-01-02 20:34:48 +03:00
{ " AANT1280 " , ( kernel_ulong_t ) & adc128_config [ 2 ] } ,
2018-10-25 18:35:41 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( acpi , adc128_acpi_match ) ;
2014-03-08 22:38:00 +04:00
static struct spi_driver adc128_driver = {
. driver = {
. name = " adc128s052 " ,
2020-07-21 20:14:43 +03:00
. of_match_table = adc128_of_match ,
2023-01-02 20:34:49 +03:00
. acpi_match_table = adc128_acpi_match ,
2014-03-08 22:38:00 +04:00
} ,
. probe = adc128_probe ,
. id_table = adc128_id ,
} ;
module_spi_driver ( adc128_driver ) ;
MODULE_AUTHOR ( " Angelo Compagnucci <angelo.compagnucci@gmail.com> " ) ;
MODULE_DESCRIPTION ( " Texas Instruments ADC128S052 " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;