2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-04-10 13:23:09 +02:00
/*
2022-02-23 22:05:24 +05:30
* Maxim Integrated DS1803 and similar digital potentiometer driver
2016-04-10 13:23:09 +02:00
* Copyright ( c ) 2016 Slawomir Stepien
2022-02-23 22:05:24 +05:30
* Copyright ( c ) 2022 Jagath Jog J
2016-04-10 13:23:09 +02:00
*
* Datasheet : https : //datasheets.maximintegrated.com/en/ds/DS1803.pdf
2022-02-23 22:05:24 +05:30
* Datasheet : https : //datasheets.maximintegrated.com/en/ds/DS3502.pdf
2016-04-10 13:23:09 +02:00
*
* DEVID # Wipers # Positions Resistor Opts ( kOhm ) i2c address
* ds1803 2 256 10 , 50 , 100 0101 xxx
2022-02-23 22:05:24 +05:30
* ds3502 1 128 10 01010 xx
2016-04-10 13:23:09 +02:00
*/
# include <linux/err.h>
# include <linux/export.h>
# include <linux/i2c.h>
# include <linux/iio/iio.h>
# include <linux/module.h>
2020-09-10 18:32:06 +01:00
# include <linux/mod_devicetable.h>
2022-02-23 22:05:22 +05:30
# include <linux/property.h>
2016-04-10 13:23:09 +02:00
2022-02-23 22:05:21 +05:30
# define DS1803_WIPER_0 0xA9
# define DS1803_WIPER_1 0xAA
2022-02-23 22:05:24 +05:30
# define DS3502_WR_IVR 0x00
2016-04-10 13:23:09 +02:00
enum ds1803_type {
DS1803_010 ,
DS1803_050 ,
DS1803_100 ,
2022-02-23 22:05:24 +05:30
DS3502 ,
2016-04-10 13:23:09 +02:00
} ;
struct ds1803_cfg {
2022-02-23 22:05:21 +05:30
int wipers ;
2022-02-23 22:05:20 +05:30
int avail [ 3 ] ;
2016-04-10 13:23:09 +02:00
int kohms ;
2022-02-23 22:05:21 +05:30
const struct iio_chan_spec * channels ;
u8 num_channels ;
2022-02-23 22:05:23 +05:30
int ( * read ) ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int * val ) ;
2016-04-10 13:23:09 +02:00
} ;
struct ds1803_data {
struct i2c_client * client ;
const struct ds1803_cfg * cfg ;
} ;
2022-02-23 22:05:21 +05:30
# define DS1803_CHANNEL(ch, addr) { \
2022-02-23 22:05:20 +05:30
. type = IIO_RESISTANCE , \
. indexed = 1 , \
. output = 1 , \
. channel = ( ch ) , \
2022-02-23 22:05:21 +05:30
. address = ( addr ) , \
2022-02-23 22:05:20 +05:30
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) , \
. info_mask_shared_by_type_available = BIT ( IIO_CHAN_INFO_RAW ) , \
2016-04-10 13:23:09 +02:00
}
static const struct iio_chan_spec ds1803_channels [ ] = {
2022-02-23 22:05:21 +05:30
DS1803_CHANNEL ( 0 , DS1803_WIPER_0 ) ,
DS1803_CHANNEL ( 1 , DS1803_WIPER_1 ) ,
2016-04-10 13:23:09 +02:00
} ;
2022-02-23 22:05:24 +05:30
static const struct iio_chan_spec ds3502_channels [ ] = {
DS1803_CHANNEL ( 0 , DS3502_WR_IVR ) ,
} ;
2022-02-23 22:05:23 +05:30
static int ds1803_read ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val )
{
struct ds1803_data * data = iio_priv ( indio_dev ) ;
int ret ;
u8 result [ ARRAY_SIZE ( ds1803_channels ) ] ;
ret = i2c_master_recv ( data - > client , result , indio_dev - > num_channels ) ;
if ( ret < 0 )
return ret ;
* val = result [ chan - > channel ] ;
return ret ;
}
2022-02-23 22:05:24 +05:30
static int ds3502_read ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val )
{
struct ds1803_data * data = iio_priv ( indio_dev ) ;
int ret ;
ret = i2c_smbus_read_byte_data ( data - > client , chan - > address ) ;
if ( ret < 0 )
return ret ;
* val = ret ;
return ret ;
}
2022-02-23 22:05:20 +05:30
static const struct ds1803_cfg ds1803_cfg [ ] = {
[ DS1803_010 ] = {
2022-02-23 22:05:21 +05:30
. wipers = 2 ,
2022-02-23 22:05:20 +05:30
. avail = { 0 , 1 , 255 } ,
. kohms = 10 ,
2022-02-23 22:05:21 +05:30
. channels = ds1803_channels ,
. num_channels = ARRAY_SIZE ( ds1803_channels ) ,
2022-02-23 22:05:23 +05:30
. read = ds1803_read ,
2022-02-23 22:05:20 +05:30
} ,
[ DS1803_050 ] = {
2022-02-23 22:05:21 +05:30
. wipers = 2 ,
2022-02-23 22:05:20 +05:30
. avail = { 0 , 1 , 255 } ,
. kohms = 50 ,
2022-02-23 22:05:21 +05:30
. channels = ds1803_channels ,
. num_channels = ARRAY_SIZE ( ds1803_channels ) ,
2022-02-23 22:05:23 +05:30
. read = ds1803_read ,
2022-02-23 22:05:20 +05:30
} ,
[ DS1803_100 ] = {
2022-02-23 22:05:21 +05:30
. wipers = 2 ,
2022-02-23 22:05:20 +05:30
. avail = { 0 , 1 , 255 } ,
. kohms = 100 ,
2022-02-23 22:05:21 +05:30
. channels = ds1803_channels ,
. num_channels = ARRAY_SIZE ( ds1803_channels ) ,
2022-02-23 22:05:23 +05:30
. read = ds1803_read ,
2022-02-23 22:05:20 +05:30
} ,
2022-02-23 22:05:24 +05:30
[ DS3502 ] = {
. wipers = 1 ,
. avail = { 0 , 1 , 127 } ,
. kohms = 10 ,
. channels = ds3502_channels ,
. num_channels = ARRAY_SIZE ( ds3502_channels ) ,
. read = ds3502_read ,
} ,
2022-02-23 22:05:20 +05:30
} ;
2016-04-10 13:23:09 +02:00
static int ds1803_read_raw ( struct iio_dev * indio_dev ,
2022-02-23 22:05:19 +05:30
struct iio_chan_spec const * chan ,
int * val , int * val2 , long mask )
2016-04-10 13:23:09 +02:00
{
struct ds1803_data * data = iio_priv ( indio_dev ) ;
int ret ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
2022-02-23 22:05:23 +05:30
ret = data - > cfg - > read ( indio_dev , chan , val ) ;
2016-04-10 13:23:09 +02:00
if ( ret < 0 )
return ret ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
* val = 1000 * data - > cfg - > kohms ;
2022-02-23 22:05:20 +05:30
* val2 = data - > cfg - > avail [ 2 ] ; /* Max wiper position */
2016-04-10 13:23:09 +02:00
return IIO_VAL_FRACTIONAL ;
}
return - EINVAL ;
}
static int ds1803_write_raw ( struct iio_dev * indio_dev ,
2022-02-23 22:05:19 +05:30
struct iio_chan_spec const * chan ,
int val , int val2 , long mask )
2016-04-10 13:23:09 +02:00
{
struct ds1803_data * data = iio_priv ( indio_dev ) ;
2022-02-23 22:05:21 +05:30
u8 addr = chan - > address ;
2022-02-23 22:05:20 +05:30
int max_pos = data - > cfg - > avail [ 2 ] ;
2016-04-10 13:23:09 +02:00
if ( val2 ! = 0 )
return - EINVAL ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
2022-02-23 22:05:20 +05:30
if ( val > max_pos | | val < 0 )
2016-04-10 13:23:09 +02:00
return - EINVAL ;
break ;
default :
return - EINVAL ;
}
2022-02-23 22:05:21 +05:30
return i2c_smbus_write_byte_data ( data - > client , addr , val ) ;
2016-04-10 13:23:09 +02:00
}
2022-02-23 22:05:20 +05:30
static int ds1803_read_avail ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
const int * * vals , int * type ,
int * length , long mask )
{
struct ds1803_data * data = iio_priv ( indio_dev ) ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
* vals = data - > cfg - > avail ;
* length = ARRAY_SIZE ( data - > cfg - > avail ) ;
* type = IIO_VAL_INT ;
return IIO_AVAIL_RANGE ;
}
return - EINVAL ;
}
2016-04-10 13:23:09 +02:00
static const struct iio_info ds1803_info = {
. read_raw = ds1803_read_raw ,
. write_raw = ds1803_write_raw ,
2022-02-23 22:05:20 +05:30
. read_avail = ds1803_read_avail ,
2016-04-10 13:23:09 +02:00
} ;
2022-02-23 22:05:19 +05:30
static int ds1803_probe ( struct i2c_client * client , const struct i2c_device_id * id )
2016-04-10 13:23:09 +02:00
{
struct device * dev = & client - > dev ;
struct ds1803_data * data ;
struct iio_dev * indio_dev ;
indio_dev = devm_iio_device_alloc ( dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
i2c_set_clientdata ( client , indio_dev ) ;
data = iio_priv ( indio_dev ) ;
data - > client = client ;
2022-02-23 22:05:22 +05:30
data - > cfg = device_get_match_data ( dev ) ;
if ( ! data - > cfg )
data - > cfg = & ds1803_cfg [ id - > driver_data ] ;
2016-04-10 13:23:09 +02:00
indio_dev - > info = & ds1803_info ;
2022-02-23 22:05:21 +05:30
indio_dev - > channels = data - > cfg - > channels ;
indio_dev - > num_channels = data - > cfg - > num_channels ;
2016-04-10 13:23:09 +02:00
indio_dev - > name = client - > name ;
return devm_iio_device_register ( dev , indio_dev ) ;
}
static const struct of_device_id ds1803_dt_ids [ ] = {
{ . compatible = " maxim,ds1803-010 " , . data = & ds1803_cfg [ DS1803_010 ] } ,
{ . compatible = " maxim,ds1803-050 " , . data = & ds1803_cfg [ DS1803_050 ] } ,
{ . compatible = " maxim,ds1803-100 " , . data = & ds1803_cfg [ DS1803_100 ] } ,
2022-02-23 22:05:24 +05:30
{ . compatible = " maxim,ds3502 " , . data = & ds1803_cfg [ DS3502 ] } ,
2016-04-10 13:23:09 +02:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , ds1803_dt_ids ) ;
static const struct i2c_device_id ds1803_id [ ] = {
{ " ds1803-010 " , DS1803_010 } ,
{ " ds1803-050 " , DS1803_050 } ,
{ " ds1803-100 " , DS1803_100 } ,
2022-02-23 22:05:24 +05:30
{ " ds3502 " , DS3502 } ,
2016-04-10 13:23:09 +02:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ds1803_id ) ;
static struct i2c_driver ds1803_driver = {
. driver = {
. name = " ds1803 " ,
2020-09-10 18:32:06 +01:00
. of_match_table = ds1803_dt_ids ,
2016-04-10 13:23:09 +02:00
} ,
. probe = ds1803_probe ,
. id_table = ds1803_id ,
} ;
module_i2c_driver ( ds1803_driver ) ;
MODULE_AUTHOR ( " Slawomir Stepien <sst@poczta.fm> " ) ;
2022-02-23 22:05:24 +05:30
MODULE_AUTHOR ( " Jagath Jog J <jagathjog1996@gmail.com> " ) ;
2016-04-10 13:23:09 +02:00
MODULE_DESCRIPTION ( " DS1803 digital potentiometer " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;