xref: /linux/drivers/iio/potentiometer/tpl0102.c (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
1d6ad8058SMatt Ranostay // SPDX-License-Identifier: GPL-2.0+
22edbd295SMatt Ranostay /*
32edbd295SMatt Ranostay  * tpl0102.c - Support for Texas Instruments digital potentiometers
42edbd295SMatt Ranostay  *
5d6ad8058SMatt Ranostay  * Copyright (C) 2016, 2018
6d6ad8058SMatt Ranostay  * Author: Matt Ranostay <matt.ranostay@konsulko.com>
72edbd295SMatt Ranostay  *
82edbd295SMatt Ranostay  * TODO: enable/disable hi-z output control
92edbd295SMatt Ranostay  */
102edbd295SMatt Ranostay 
112edbd295SMatt Ranostay #include <linux/module.h>
122edbd295SMatt Ranostay #include <linux/i2c.h>
132edbd295SMatt Ranostay #include <linux/regmap.h>
142edbd295SMatt Ranostay #include <linux/iio/iio.h>
152edbd295SMatt Ranostay 
162edbd295SMatt Ranostay struct tpl0102_cfg {
172edbd295SMatt Ranostay 	int wipers;
1874cf7b86SMatt Ranostay 	int avail[3];
192edbd295SMatt Ranostay 	int kohms;
202edbd295SMatt Ranostay };
212edbd295SMatt Ranostay 
222edbd295SMatt Ranostay enum tpl0102_type {
232edbd295SMatt Ranostay 	CAT5140_503,
242edbd295SMatt Ranostay 	CAT5140_104,
252edbd295SMatt Ranostay 	TPL0102_104,
262edbd295SMatt Ranostay 	TPL0401_103,
272edbd295SMatt Ranostay };
282edbd295SMatt Ranostay 
292edbd295SMatt Ranostay static const struct tpl0102_cfg tpl0102_cfg[] = {
302edbd295SMatt Ranostay 	/* on-semiconductor parts */
3174cf7b86SMatt Ranostay 	[CAT5140_503] = { .wipers = 1, .avail = { 0, 1, 255 }, .kohms = 50, },
3274cf7b86SMatt Ranostay 	[CAT5140_104] = { .wipers = 1, .avail = { 0, 1, 255 }, .kohms = 100, },
332edbd295SMatt Ranostay 	/* ti parts */
3474cf7b86SMatt Ranostay 	[TPL0102_104] = { .wipers = 2, .avail = { 0, 1, 255 }, .kohms = 100 },
3574cf7b86SMatt Ranostay 	[TPL0401_103] = { .wipers = 1, .avail = { 0, 1, 127 }, .kohms = 10, },
362edbd295SMatt Ranostay };
372edbd295SMatt Ranostay 
382edbd295SMatt Ranostay struct tpl0102_data {
392edbd295SMatt Ranostay 	struct regmap *regmap;
40ee230351SMatt Ranostay 	const struct tpl0102_cfg *cfg;
412edbd295SMatt Ranostay };
422edbd295SMatt Ranostay 
432edbd295SMatt Ranostay static const struct regmap_config tpl0102_regmap_config = {
442edbd295SMatt Ranostay 	.reg_bits = 8,
452edbd295SMatt Ranostay 	.val_bits = 8,
462edbd295SMatt Ranostay };
472edbd295SMatt Ranostay 
482edbd295SMatt Ranostay #define TPL0102_CHANNEL(ch) {					\
492edbd295SMatt Ranostay 	.type = IIO_RESISTANCE,					\
502edbd295SMatt Ranostay 	.indexed = 1,						\
512edbd295SMatt Ranostay 	.output = 1,						\
522edbd295SMatt Ranostay 	.channel = (ch),					\
532edbd295SMatt Ranostay 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
542edbd295SMatt Ranostay 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
5574cf7b86SMatt Ranostay 	.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),	\
562edbd295SMatt Ranostay }
572edbd295SMatt Ranostay 
582edbd295SMatt Ranostay static const struct iio_chan_spec tpl0102_channels[] = {
592edbd295SMatt Ranostay 	TPL0102_CHANNEL(0),
602edbd295SMatt Ranostay 	TPL0102_CHANNEL(1),
612edbd295SMatt Ranostay };
622edbd295SMatt Ranostay 
tpl0102_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)632edbd295SMatt Ranostay static int tpl0102_read_raw(struct iio_dev *indio_dev,
642edbd295SMatt Ranostay 			    struct iio_chan_spec const *chan,
652edbd295SMatt Ranostay 			    int *val, int *val2, long mask)
662edbd295SMatt Ranostay {
672edbd295SMatt Ranostay 	struct tpl0102_data *data = iio_priv(indio_dev);
682edbd295SMatt Ranostay 
692edbd295SMatt Ranostay 	switch (mask) {
702edbd295SMatt Ranostay 	case IIO_CHAN_INFO_RAW: {
712edbd295SMatt Ranostay 		int ret = regmap_read(data->regmap, chan->channel, val);
722edbd295SMatt Ranostay 
732edbd295SMatt Ranostay 		return ret ? ret : IIO_VAL_INT;
742edbd295SMatt Ranostay 	}
752edbd295SMatt Ranostay 	case IIO_CHAN_INFO_SCALE:
76ee230351SMatt Ranostay 		*val = 1000 * data->cfg->kohms;
7774cf7b86SMatt Ranostay 		*val2 = data->cfg->avail[2] + 1;
782edbd295SMatt Ranostay 		return IIO_VAL_FRACTIONAL;
792edbd295SMatt Ranostay 	}
802edbd295SMatt Ranostay 
812edbd295SMatt Ranostay 	return -EINVAL;
822edbd295SMatt Ranostay }
832edbd295SMatt Ranostay 
tpl0102_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)8474cf7b86SMatt Ranostay static int tpl0102_read_avail(struct iio_dev *indio_dev,
8574cf7b86SMatt Ranostay 			      struct iio_chan_spec const *chan,
8674cf7b86SMatt Ranostay 			      const int **vals, int *type, int *length,
8774cf7b86SMatt Ranostay 			      long mask)
8874cf7b86SMatt Ranostay {
8974cf7b86SMatt Ranostay 	struct tpl0102_data *data = iio_priv(indio_dev);
9074cf7b86SMatt Ranostay 
9174cf7b86SMatt Ranostay 	switch (mask) {
9274cf7b86SMatt Ranostay 	case IIO_CHAN_INFO_RAW:
9374cf7b86SMatt Ranostay 		*length = ARRAY_SIZE(data->cfg->avail);
9474cf7b86SMatt Ranostay 		*vals = data->cfg->avail;
9574cf7b86SMatt Ranostay 		*type = IIO_VAL_INT;
9674cf7b86SMatt Ranostay 		return IIO_AVAIL_RANGE;
9774cf7b86SMatt Ranostay 	}
9874cf7b86SMatt Ranostay 
9974cf7b86SMatt Ranostay 	return -EINVAL;
10074cf7b86SMatt Ranostay }
10174cf7b86SMatt Ranostay 
tpl0102_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)1022edbd295SMatt Ranostay static int tpl0102_write_raw(struct iio_dev *indio_dev,
1032edbd295SMatt Ranostay 			     struct iio_chan_spec const *chan,
1042edbd295SMatt Ranostay 			     int val, int val2, long mask)
1052edbd295SMatt Ranostay {
1062edbd295SMatt Ranostay 	struct tpl0102_data *data = iio_priv(indio_dev);
1072edbd295SMatt Ranostay 
1082edbd295SMatt Ranostay 	if (mask != IIO_CHAN_INFO_RAW)
1092edbd295SMatt Ranostay 		return -EINVAL;
1102edbd295SMatt Ranostay 
11174cf7b86SMatt Ranostay 	if (val > data->cfg->avail[2] || val < 0)
1122edbd295SMatt Ranostay 		return -EINVAL;
1132edbd295SMatt Ranostay 
1142edbd295SMatt Ranostay 	return regmap_write(data->regmap, chan->channel, val);
1152edbd295SMatt Ranostay }
1162edbd295SMatt Ranostay 
1172edbd295SMatt Ranostay static const struct iio_info tpl0102_info = {
1182edbd295SMatt Ranostay 	.read_raw = tpl0102_read_raw,
11974cf7b86SMatt Ranostay 	.read_avail = tpl0102_read_avail,
1202edbd295SMatt Ranostay 	.write_raw = tpl0102_write_raw,
1212edbd295SMatt Ranostay };
1222edbd295SMatt Ranostay 
tpl0102_probe(struct i2c_client * client)1234c1142ccSUwe Kleine-König static int tpl0102_probe(struct i2c_client *client)
1242edbd295SMatt Ranostay {
1254c1142ccSUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
1262edbd295SMatt Ranostay 	struct device *dev = &client->dev;
1272edbd295SMatt Ranostay 	struct tpl0102_data *data;
1282edbd295SMatt Ranostay 	struct iio_dev *indio_dev;
1292edbd295SMatt Ranostay 
1302edbd295SMatt Ranostay 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
1312edbd295SMatt Ranostay 	if (!indio_dev)
1322edbd295SMatt Ranostay 		return -ENOMEM;
1332edbd295SMatt Ranostay 	data = iio_priv(indio_dev);
1342edbd295SMatt Ranostay 	i2c_set_clientdata(client, indio_dev);
1352edbd295SMatt Ranostay 
136ee230351SMatt Ranostay 	data->cfg = &tpl0102_cfg[id->driver_data];
1372edbd295SMatt Ranostay 	data->regmap = devm_regmap_init_i2c(client, &tpl0102_regmap_config);
1382edbd295SMatt Ranostay 	if (IS_ERR(data->regmap)) {
1392edbd295SMatt Ranostay 		dev_err(dev, "regmap initialization failed\n");
1402edbd295SMatt Ranostay 		return PTR_ERR(data->regmap);
1412edbd295SMatt Ranostay 	}
1422edbd295SMatt Ranostay 
1432edbd295SMatt Ranostay 	indio_dev->info = &tpl0102_info;
1442edbd295SMatt Ranostay 	indio_dev->channels = tpl0102_channels;
145ee230351SMatt Ranostay 	indio_dev->num_channels = data->cfg->wipers;
1462edbd295SMatt Ranostay 	indio_dev->name = client->name;
1472edbd295SMatt Ranostay 
1482edbd295SMatt Ranostay 	return devm_iio_device_register(dev, indio_dev);
1492edbd295SMatt Ranostay }
1502edbd295SMatt Ranostay 
1512edbd295SMatt Ranostay static const struct i2c_device_id tpl0102_id[] = {
1522edbd295SMatt Ranostay 	{ "cat5140-503", CAT5140_503 },
1532edbd295SMatt Ranostay 	{ "cat5140-104", CAT5140_104 },
1542edbd295SMatt Ranostay 	{ "tpl0102-104", TPL0102_104 },
1552edbd295SMatt Ranostay 	{ "tpl0401-103", TPL0401_103 },
1562edbd295SMatt Ranostay 	{}
1572edbd295SMatt Ranostay };
1582edbd295SMatt Ranostay MODULE_DEVICE_TABLE(i2c, tpl0102_id);
1592edbd295SMatt Ranostay 
1602edbd295SMatt Ranostay static struct i2c_driver tpl0102_driver = {
1612edbd295SMatt Ranostay 	.driver = {
1622edbd295SMatt Ranostay 		.name = "tpl0102",
1632edbd295SMatt Ranostay 	},
164*7cf15f42SUwe Kleine-König 	.probe = tpl0102_probe,
1652edbd295SMatt Ranostay 	.id_table = tpl0102_id,
1662edbd295SMatt Ranostay };
1672edbd295SMatt Ranostay 
1682edbd295SMatt Ranostay module_i2c_driver(tpl0102_driver);
1692edbd295SMatt Ranostay 
170d6ad8058SMatt Ranostay MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
1712edbd295SMatt Ranostay MODULE_DESCRIPTION("TPL0102 digital potentiometer");
1722edbd295SMatt Ranostay MODULE_LICENSE("GPL");
173