1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Maxim Integrated DS1803 digital potentiometer driver 4 * Copyright (c) 2016 Slawomir Stepien 5 * 6 * Datasheet: https://datasheets.maximintegrated.com/en/ds/DS1803.pdf 7 * 8 * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address 9 * ds1803 2 256 10, 50, 100 0101xxx 10 */ 11 12 #include <linux/err.h> 13 #include <linux/export.h> 14 #include <linux/i2c.h> 15 #include <linux/iio/iio.h> 16 #include <linux/module.h> 17 #include <linux/mod_devicetable.h> 18 19 #define DS1803_MAX_POS 255 20 #define DS1803_WRITE(chan) (0xa8 | ((chan) + 1)) 21 22 enum ds1803_type { 23 DS1803_010, 24 DS1803_050, 25 DS1803_100, 26 }; 27 28 struct ds1803_cfg { 29 int kohms; 30 }; 31 32 static const struct ds1803_cfg ds1803_cfg[] = { 33 [DS1803_010] = { .kohms = 10, }, 34 [DS1803_050] = { .kohms = 50, }, 35 [DS1803_100] = { .kohms = 100, }, 36 }; 37 38 struct ds1803_data { 39 struct i2c_client *client; 40 const struct ds1803_cfg *cfg; 41 }; 42 43 #define DS1803_CHANNEL(ch) { \ 44 .type = IIO_RESISTANCE, \ 45 .indexed = 1, \ 46 .output = 1, \ 47 .channel = (ch), \ 48 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 49 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 50 } 51 52 static const struct iio_chan_spec ds1803_channels[] = { 53 DS1803_CHANNEL(0), 54 DS1803_CHANNEL(1), 55 }; 56 57 static int ds1803_read_raw(struct iio_dev *indio_dev, 58 struct iio_chan_spec const *chan, 59 int *val, int *val2, long mask) 60 { 61 struct ds1803_data *data = iio_priv(indio_dev); 62 int pot = chan->channel; 63 int ret; 64 u8 result[ARRAY_SIZE(ds1803_channels)]; 65 66 switch (mask) { 67 case IIO_CHAN_INFO_RAW: 68 ret = i2c_master_recv(data->client, result, 69 indio_dev->num_channels); 70 if (ret < 0) 71 return ret; 72 73 *val = result[pot]; 74 return IIO_VAL_INT; 75 76 case IIO_CHAN_INFO_SCALE: 77 *val = 1000 * data->cfg->kohms; 78 *val2 = DS1803_MAX_POS; 79 return IIO_VAL_FRACTIONAL; 80 } 81 82 return -EINVAL; 83 } 84 85 static int ds1803_write_raw(struct iio_dev *indio_dev, 86 struct iio_chan_spec const *chan, 87 int val, int val2, long mask) 88 { 89 struct ds1803_data *data = iio_priv(indio_dev); 90 int pot = chan->channel; 91 92 if (val2 != 0) 93 return -EINVAL; 94 95 switch (mask) { 96 case IIO_CHAN_INFO_RAW: 97 if (val > DS1803_MAX_POS || val < 0) 98 return -EINVAL; 99 break; 100 default: 101 return -EINVAL; 102 } 103 104 return i2c_smbus_write_byte_data(data->client, DS1803_WRITE(pot), val); 105 } 106 107 static const struct iio_info ds1803_info = { 108 .read_raw = ds1803_read_raw, 109 .write_raw = ds1803_write_raw, 110 }; 111 112 static int ds1803_probe(struct i2c_client *client, 113 const struct i2c_device_id *id) 114 { 115 struct device *dev = &client->dev; 116 struct ds1803_data *data; 117 struct iio_dev *indio_dev; 118 119 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 120 if (!indio_dev) 121 return -ENOMEM; 122 123 i2c_set_clientdata(client, indio_dev); 124 125 data = iio_priv(indio_dev); 126 data->client = client; 127 data->cfg = &ds1803_cfg[id->driver_data]; 128 129 indio_dev->info = &ds1803_info; 130 indio_dev->channels = ds1803_channels; 131 indio_dev->num_channels = ARRAY_SIZE(ds1803_channels); 132 indio_dev->name = client->name; 133 134 return devm_iio_device_register(dev, indio_dev); 135 } 136 137 static const struct of_device_id ds1803_dt_ids[] = { 138 { .compatible = "maxim,ds1803-010", .data = &ds1803_cfg[DS1803_010] }, 139 { .compatible = "maxim,ds1803-050", .data = &ds1803_cfg[DS1803_050] }, 140 { .compatible = "maxim,ds1803-100", .data = &ds1803_cfg[DS1803_100] }, 141 {} 142 }; 143 MODULE_DEVICE_TABLE(of, ds1803_dt_ids); 144 145 static const struct i2c_device_id ds1803_id[] = { 146 { "ds1803-010", DS1803_010 }, 147 { "ds1803-050", DS1803_050 }, 148 { "ds1803-100", DS1803_100 }, 149 {} 150 }; 151 MODULE_DEVICE_TABLE(i2c, ds1803_id); 152 153 static struct i2c_driver ds1803_driver = { 154 .driver = { 155 .name = "ds1803", 156 .of_match_table = ds1803_dt_ids, 157 }, 158 .probe = ds1803_probe, 159 .id_table = ds1803_id, 160 }; 161 162 module_i2c_driver(ds1803_driver); 163 164 MODULE_AUTHOR("Slawomir Stepien <sst@poczta.fm>"); 165 MODULE_DESCRIPTION("DS1803 digital potentiometer"); 166 MODULE_LICENSE("GPL v2"); 167