2018-03-08 22:58:30 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Industrial I / O driver for Microchip digital potentiometers
* Copyright ( c ) 2018 Axentia Technologies AB
* Author : Peter Rosin < peda @ axentia . se >
*
* Datasheet : http : //www.microchip.com/downloads/en/DeviceDoc/22147a.pdf
*
* DEVID # Wipers # Positions Resistor Opts ( kOhm )
* mcp4017 1 128 5 , 10 , 50 , 100
* mcp4018 1 128 5 , 10 , 50 , 100
* mcp4019 1 128 5 , 10 , 50 , 100
*/
# include <linux/err.h>
# include <linux/i2c.h>
# include <linux/iio/iio.h>
# include <linux/module.h>
2020-09-10 20:32:10 +03:00
# include <linux/mod_devicetable.h>
# include <linux/property.h>
2018-03-08 22:58:30 +03:00
# define MCP4018_WIPER_MAX 127
struct mcp4018_cfg {
int kohms ;
} ;
enum mcp4018_type {
MCP4018_502 ,
MCP4018_103 ,
MCP4018_503 ,
MCP4018_104 ,
} ;
static const struct mcp4018_cfg mcp4018_cfg [ ] = {
[ MCP4018_502 ] = { . kohms = 5 , } ,
[ MCP4018_103 ] = { . kohms = 10 , } ,
[ MCP4018_503 ] = { . kohms = 50 , } ,
[ MCP4018_104 ] = { . kohms = 100 , } ,
} ;
struct mcp4018_data {
struct i2c_client * client ;
const struct mcp4018_cfg * cfg ;
} ;
static const struct iio_chan_spec mcp4018_channel = {
. type = IIO_RESISTANCE ,
. indexed = 1 ,
. output = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) ,
} ;
static int mcp4018_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 , long mask )
{
struct mcp4018_data * data = iio_priv ( indio_dev ) ;
s32 ret ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
ret = i2c_smbus_read_byte ( data - > client ) ;
if ( ret < 0 )
return ret ;
* val = ret ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
* val = 1000 * data - > cfg - > kohms ;
* val2 = MCP4018_WIPER_MAX ;
return IIO_VAL_FRACTIONAL ;
}
return - EINVAL ;
}
static int mcp4018_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val , int val2 , long mask )
{
struct mcp4018_data * data = iio_priv ( indio_dev ) ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
if ( val > MCP4018_WIPER_MAX | | val < 0 )
return - EINVAL ;
break ;
default :
return - EINVAL ;
}
return i2c_smbus_write_byte ( data - > client , val ) ;
}
static const struct iio_info mcp4018_info = {
. read_raw = mcp4018_read_raw ,
. write_raw = mcp4018_write_raw ,
} ;
2023-07-23 13:52:09 +03:00
# define MCP4018_ID_TABLE(_name, cfg) { \
. name = _name , \
. driver_data = ( kernel_ulong_t ) & mcp4018_cfg [ cfg ] , \
}
2018-04-11 15:49:14 +03:00
static const struct i2c_device_id mcp4018_id [ ] = {
2023-07-23 13:52:09 +03:00
MCP4018_ID_TABLE ( " mcp4017-502 " , MCP4018_502 ) ,
MCP4018_ID_TABLE ( " mcp4017-103 " , MCP4018_103 ) ,
MCP4018_ID_TABLE ( " mcp4017-503 " , MCP4018_503 ) ,
MCP4018_ID_TABLE ( " mcp4017-104 " , MCP4018_104 ) ,
MCP4018_ID_TABLE ( " mcp4018-502 " , MCP4018_502 ) ,
MCP4018_ID_TABLE ( " mcp4018-103 " , MCP4018_103 ) ,
MCP4018_ID_TABLE ( " mcp4018-503 " , MCP4018_503 ) ,
MCP4018_ID_TABLE ( " mcp4018-104 " , MCP4018_104 ) ,
MCP4018_ID_TABLE ( " mcp4019-502 " , MCP4018_502 ) ,
MCP4018_ID_TABLE ( " mcp4019-103 " , MCP4018_103 ) ,
MCP4018_ID_TABLE ( " mcp4019-503 " , MCP4018_503 ) ,
MCP4018_ID_TABLE ( " mcp4019-104 " , MCP4018_104 ) ,
{ /* sentinel */ }
2018-04-11 15:49:14 +03:00
} ;
MODULE_DEVICE_TABLE ( i2c , mcp4018_id ) ;
2018-03-08 22:58:30 +03:00
# define MCP4018_COMPATIBLE(of_compatible, cfg) { \
. compatible = of_compatible , \
. data = & mcp4018_cfg [ cfg ] , \
}
static const struct of_device_id mcp4018_of_match [ ] = {
MCP4018_COMPATIBLE ( " microchip,mcp4017-502 " , MCP4018_502 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4017-103 " , MCP4018_103 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4017-503 " , MCP4018_503 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4017-104 " , MCP4018_104 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4018-502 " , MCP4018_502 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4018-103 " , MCP4018_103 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4018-503 " , MCP4018_503 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4018-104 " , MCP4018_104 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4019-502 " , MCP4018_502 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4019-103 " , MCP4018_103 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4019-503 " , MCP4018_503 ) ,
MCP4018_COMPATIBLE ( " microchip,mcp4019-104 " , MCP4018_104 ) ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , mcp4018_of_match ) ;
2018-04-11 15:49:14 +03:00
static int mcp4018_probe ( struct i2c_client * client )
2018-03-08 22:58:30 +03:00
{
struct device * dev = & client - > dev ;
struct mcp4018_data * data ;
struct iio_dev * indio_dev ;
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_BYTE ) ) {
dev_err ( dev , " SMBUS Byte transfers not supported \n " ) ;
return - EOPNOTSUPP ;
}
indio_dev = devm_iio_device_alloc ( dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
data = iio_priv ( indio_dev ) ;
i2c_set_clientdata ( client , indio_dev ) ;
data - > client = client ;
2023-07-23 13:52:09 +03:00
data - > cfg = i2c_get_match_data ( client ) ;
2018-03-08 22:58:30 +03:00
indio_dev - > info = & mcp4018_info ;
indio_dev - > channels = & mcp4018_channel ;
indio_dev - > num_channels = 1 ;
indio_dev - > name = client - > name ;
return devm_iio_device_register ( dev , indio_dev ) ;
}
static struct i2c_driver mcp4018_driver = {
. driver = {
. name = " mcp4018 " ,
2020-09-10 20:32:10 +03:00
. of_match_table = mcp4018_of_match ,
2018-03-08 22:58:30 +03:00
} ,
2023-05-15 23:50:48 +03:00
. probe = mcp4018_probe ,
2018-03-08 22:58:30 +03:00
. id_table = mcp4018_id ,
} ;
module_i2c_driver ( mcp4018_driver ) ;
MODULE_AUTHOR ( " Peter Rosin <peda@axentia.se> " ) ;
MODULE_DESCRIPTION ( " MCP4018 digital potentiometer " ) ;
2018-08-20 13:01:10 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;