mcp4531.c (13940B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Industrial I/O driver for Microchip digital potentiometers 4 * Copyright (c) 2015 Axentia Technologies AB 5 * Author: Peter Rosin <peda@axentia.se> 6 * 7 * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf 8 * 9 * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address 10 * mcp4531 1 129 5, 10, 50, 100 010111x 11 * mcp4532 1 129 5, 10, 50, 100 01011xx 12 * mcp4541 1 129 5, 10, 50, 100 010111x 13 * mcp4542 1 129 5, 10, 50, 100 01011xx 14 * mcp4551 1 257 5, 10, 50, 100 010111x 15 * mcp4552 1 257 5, 10, 50, 100 01011xx 16 * mcp4561 1 257 5, 10, 50, 100 010111x 17 * mcp4562 1 257 5, 10, 50, 100 01011xx 18 * mcp4631 2 129 5, 10, 50, 100 0101xxx 19 * mcp4632 2 129 5, 10, 50, 100 01011xx 20 * mcp4641 2 129 5, 10, 50, 100 0101xxx 21 * mcp4642 2 129 5, 10, 50, 100 01011xx 22 * mcp4651 2 257 5, 10, 50, 100 0101xxx 23 * mcp4652 2 257 5, 10, 50, 100 01011xx 24 * mcp4661 2 257 5, 10, 50, 100 0101xxx 25 * mcp4662 2 257 5, 10, 50, 100 01011xx 26 */ 27 28#include <linux/module.h> 29#include <linux/i2c.h> 30#include <linux/err.h> 31#include <linux/mod_devicetable.h> 32#include <linux/property.h> 33 34#include <linux/iio/iio.h> 35 36struct mcp4531_cfg { 37 int wipers; 38 int avail[3]; 39 int kohms; 40}; 41 42enum mcp4531_type { 43 MCP453x_502, 44 MCP453x_103, 45 MCP453x_503, 46 MCP453x_104, 47 MCP454x_502, 48 MCP454x_103, 49 MCP454x_503, 50 MCP454x_104, 51 MCP455x_502, 52 MCP455x_103, 53 MCP455x_503, 54 MCP455x_104, 55 MCP456x_502, 56 MCP456x_103, 57 MCP456x_503, 58 MCP456x_104, 59 MCP463x_502, 60 MCP463x_103, 61 MCP463x_503, 62 MCP463x_104, 63 MCP464x_502, 64 MCP464x_103, 65 MCP464x_503, 66 MCP464x_104, 67 MCP465x_502, 68 MCP465x_103, 69 MCP465x_503, 70 MCP465x_104, 71 MCP466x_502, 72 MCP466x_103, 73 MCP466x_503, 74 MCP466x_104, 75}; 76 77static const struct mcp4531_cfg mcp4531_cfg[] = { 78 [MCP453x_502] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 5, }, 79 [MCP453x_103] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 10, }, 80 [MCP453x_503] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 50, }, 81 [MCP453x_104] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 100, }, 82 [MCP454x_502] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 5, }, 83 [MCP454x_103] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 10, }, 84 [MCP454x_503] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 50, }, 85 [MCP454x_104] = { .wipers = 1, .avail = { 0, 1, 128 }, .kohms = 100, }, 86 [MCP455x_502] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 5, }, 87 [MCP455x_103] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 10, }, 88 [MCP455x_503] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 50, }, 89 [MCP455x_104] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 100, }, 90 [MCP456x_502] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 5, }, 91 [MCP456x_103] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 10, }, 92 [MCP456x_503] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 50, }, 93 [MCP456x_104] = { .wipers = 1, .avail = { 0, 1, 256 }, .kohms = 100, }, 94 [MCP463x_502] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 5, }, 95 [MCP463x_103] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 10, }, 96 [MCP463x_503] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 50, }, 97 [MCP463x_104] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 100, }, 98 [MCP464x_502] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 5, }, 99 [MCP464x_103] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 10, }, 100 [MCP464x_503] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 50, }, 101 [MCP464x_104] = { .wipers = 2, .avail = { 0, 1, 128 }, .kohms = 100, }, 102 [MCP465x_502] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 5, }, 103 [MCP465x_103] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 10, }, 104 [MCP465x_503] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 50, }, 105 [MCP465x_104] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 100, }, 106 [MCP466x_502] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 5, }, 107 [MCP466x_103] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 10, }, 108 [MCP466x_503] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 50, }, 109 [MCP466x_104] = { .wipers = 2, .avail = { 0, 1, 256 }, .kohms = 100, }, 110}; 111 112#define MCP4531_WRITE (0 << 2) 113#define MCP4531_INCR (1 << 2) 114#define MCP4531_DECR (2 << 2) 115#define MCP4531_READ (3 << 2) 116 117#define MCP4531_WIPER_SHIFT (4) 118 119struct mcp4531_data { 120 struct i2c_client *client; 121 const struct mcp4531_cfg *cfg; 122}; 123 124#define MCP4531_CHANNEL(ch) { \ 125 .type = IIO_RESISTANCE, \ 126 .indexed = 1, \ 127 .output = 1, \ 128 .channel = (ch), \ 129 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 130 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 131 .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_RAW), \ 132} 133 134static const struct iio_chan_spec mcp4531_channels[] = { 135 MCP4531_CHANNEL(0), 136 MCP4531_CHANNEL(1), 137}; 138 139static int mcp4531_read_raw(struct iio_dev *indio_dev, 140 struct iio_chan_spec const *chan, 141 int *val, int *val2, long mask) 142{ 143 struct mcp4531_data *data = iio_priv(indio_dev); 144 int address = chan->channel << MCP4531_WIPER_SHIFT; 145 s32 ret; 146 147 switch (mask) { 148 case IIO_CHAN_INFO_RAW: 149 ret = i2c_smbus_read_word_swapped(data->client, 150 MCP4531_READ | address); 151 if (ret < 0) 152 return ret; 153 *val = ret; 154 return IIO_VAL_INT; 155 case IIO_CHAN_INFO_SCALE: 156 *val = 1000 * data->cfg->kohms; 157 *val2 = data->cfg->avail[2]; 158 return IIO_VAL_FRACTIONAL; 159 } 160 161 return -EINVAL; 162} 163 164static int mcp4531_read_avail(struct iio_dev *indio_dev, 165 struct iio_chan_spec const *chan, 166 const int **vals, int *type, int *length, 167 long mask) 168{ 169 struct mcp4531_data *data = iio_priv(indio_dev); 170 171 switch (mask) { 172 case IIO_CHAN_INFO_RAW: 173 *length = ARRAY_SIZE(data->cfg->avail); 174 *vals = data->cfg->avail; 175 *type = IIO_VAL_INT; 176 return IIO_AVAIL_RANGE; 177 } 178 179 return -EINVAL; 180} 181 182static int mcp4531_write_raw(struct iio_dev *indio_dev, 183 struct iio_chan_spec const *chan, 184 int val, int val2, long mask) 185{ 186 struct mcp4531_data *data = iio_priv(indio_dev); 187 int address = chan->channel << MCP4531_WIPER_SHIFT; 188 189 switch (mask) { 190 case IIO_CHAN_INFO_RAW: 191 if (val > data->cfg->avail[2] || val < 0) 192 return -EINVAL; 193 break; 194 default: 195 return -EINVAL; 196 } 197 198 return i2c_smbus_write_byte_data(data->client, 199 MCP4531_WRITE | address | (val >> 8), 200 val & 0xff); 201} 202 203static const struct iio_info mcp4531_info = { 204 .read_raw = mcp4531_read_raw, 205 .read_avail = mcp4531_read_avail, 206 .write_raw = mcp4531_write_raw, 207}; 208 209static const struct i2c_device_id mcp4531_id[] = { 210 { "mcp4531-502", MCP453x_502 }, 211 { "mcp4531-103", MCP453x_103 }, 212 { "mcp4531-503", MCP453x_503 }, 213 { "mcp4531-104", MCP453x_104 }, 214 { "mcp4532-502", MCP453x_502 }, 215 { "mcp4532-103", MCP453x_103 }, 216 { "mcp4532-503", MCP453x_503 }, 217 { "mcp4532-104", MCP453x_104 }, 218 { "mcp4541-502", MCP454x_502 }, 219 { "mcp4541-103", MCP454x_103 }, 220 { "mcp4541-503", MCP454x_503 }, 221 { "mcp4541-104", MCP454x_104 }, 222 { "mcp4542-502", MCP454x_502 }, 223 { "mcp4542-103", MCP454x_103 }, 224 { "mcp4542-503", MCP454x_503 }, 225 { "mcp4542-104", MCP454x_104 }, 226 { "mcp4551-502", MCP455x_502 }, 227 { "mcp4551-103", MCP455x_103 }, 228 { "mcp4551-503", MCP455x_503 }, 229 { "mcp4551-104", MCP455x_104 }, 230 { "mcp4552-502", MCP455x_502 }, 231 { "mcp4552-103", MCP455x_103 }, 232 { "mcp4552-503", MCP455x_503 }, 233 { "mcp4552-104", MCP455x_104 }, 234 { "mcp4561-502", MCP456x_502 }, 235 { "mcp4561-103", MCP456x_103 }, 236 { "mcp4561-503", MCP456x_503 }, 237 { "mcp4561-104", MCP456x_104 }, 238 { "mcp4562-502", MCP456x_502 }, 239 { "mcp4562-103", MCP456x_103 }, 240 { "mcp4562-503", MCP456x_503 }, 241 { "mcp4562-104", MCP456x_104 }, 242 { "mcp4631-502", MCP463x_502 }, 243 { "mcp4631-103", MCP463x_103 }, 244 { "mcp4631-503", MCP463x_503 }, 245 { "mcp4631-104", MCP463x_104 }, 246 { "mcp4632-502", MCP463x_502 }, 247 { "mcp4632-103", MCP463x_103 }, 248 { "mcp4632-503", MCP463x_503 }, 249 { "mcp4632-104", MCP463x_104 }, 250 { "mcp4641-502", MCP464x_502 }, 251 { "mcp4641-103", MCP464x_103 }, 252 { "mcp4641-503", MCP464x_503 }, 253 { "mcp4641-104", MCP464x_104 }, 254 { "mcp4642-502", MCP464x_502 }, 255 { "mcp4642-103", MCP464x_103 }, 256 { "mcp4642-503", MCP464x_503 }, 257 { "mcp4642-104", MCP464x_104 }, 258 { "mcp4651-502", MCP465x_502 }, 259 { "mcp4651-103", MCP465x_103 }, 260 { "mcp4651-503", MCP465x_503 }, 261 { "mcp4651-104", MCP465x_104 }, 262 { "mcp4652-502", MCP465x_502 }, 263 { "mcp4652-103", MCP465x_103 }, 264 { "mcp4652-503", MCP465x_503 }, 265 { "mcp4652-104", MCP465x_104 }, 266 { "mcp4661-502", MCP466x_502 }, 267 { "mcp4661-103", MCP466x_103 }, 268 { "mcp4661-503", MCP466x_503 }, 269 { "mcp4661-104", MCP466x_104 }, 270 { "mcp4662-502", MCP466x_502 }, 271 { "mcp4662-103", MCP466x_103 }, 272 { "mcp4662-503", MCP466x_503 }, 273 { "mcp4662-104", MCP466x_104 }, 274 {} 275}; 276MODULE_DEVICE_TABLE(i2c, mcp4531_id); 277 278#define MCP4531_COMPATIBLE(of_compatible, cfg) { \ 279 .compatible = of_compatible, \ 280 .data = &mcp4531_cfg[cfg], \ 281} 282 283static const struct of_device_id mcp4531_of_match[] = { 284 MCP4531_COMPATIBLE("microchip,mcp4531-502", MCP453x_502), 285 MCP4531_COMPATIBLE("microchip,mcp4531-103", MCP453x_103), 286 MCP4531_COMPATIBLE("microchip,mcp4531-503", MCP453x_503), 287 MCP4531_COMPATIBLE("microchip,mcp4531-104", MCP453x_104), 288 MCP4531_COMPATIBLE("microchip,mcp4532-502", MCP453x_502), 289 MCP4531_COMPATIBLE("microchip,mcp4532-103", MCP453x_103), 290 MCP4531_COMPATIBLE("microchip,mcp4532-503", MCP453x_503), 291 MCP4531_COMPATIBLE("microchip,mcp4532-104", MCP453x_104), 292 MCP4531_COMPATIBLE("microchip,mcp4541-502", MCP454x_502), 293 MCP4531_COMPATIBLE("microchip,mcp4541-103", MCP454x_103), 294 MCP4531_COMPATIBLE("microchip,mcp4541-503", MCP454x_503), 295 MCP4531_COMPATIBLE("microchip,mcp4541-104", MCP454x_104), 296 MCP4531_COMPATIBLE("microchip,mcp4542-502", MCP454x_502), 297 MCP4531_COMPATIBLE("microchip,mcp4542-103", MCP454x_103), 298 MCP4531_COMPATIBLE("microchip,mcp4542-503", MCP454x_503), 299 MCP4531_COMPATIBLE("microchip,mcp4542-104", MCP454x_104), 300 MCP4531_COMPATIBLE("microchip,mcp4551-502", MCP455x_502), 301 MCP4531_COMPATIBLE("microchip,mcp4551-103", MCP455x_103), 302 MCP4531_COMPATIBLE("microchip,mcp4551-503", MCP455x_503), 303 MCP4531_COMPATIBLE("microchip,mcp4551-104", MCP455x_104), 304 MCP4531_COMPATIBLE("microchip,mcp4552-502", MCP455x_502), 305 MCP4531_COMPATIBLE("microchip,mcp4552-103", MCP455x_103), 306 MCP4531_COMPATIBLE("microchip,mcp4552-503", MCP455x_503), 307 MCP4531_COMPATIBLE("microchip,mcp4552-104", MCP455x_104), 308 MCP4531_COMPATIBLE("microchip,mcp4561-502", MCP456x_502), 309 MCP4531_COMPATIBLE("microchip,mcp4561-103", MCP456x_103), 310 MCP4531_COMPATIBLE("microchip,mcp4561-503", MCP456x_503), 311 MCP4531_COMPATIBLE("microchip,mcp4561-104", MCP456x_104), 312 MCP4531_COMPATIBLE("microchip,mcp4562-502", MCP456x_502), 313 MCP4531_COMPATIBLE("microchip,mcp4562-103", MCP456x_103), 314 MCP4531_COMPATIBLE("microchip,mcp4562-503", MCP456x_503), 315 MCP4531_COMPATIBLE("microchip,mcp4562-104", MCP456x_104), 316 MCP4531_COMPATIBLE("microchip,mcp4631-502", MCP463x_502), 317 MCP4531_COMPATIBLE("microchip,mcp4631-103", MCP463x_103), 318 MCP4531_COMPATIBLE("microchip,mcp4631-503", MCP463x_503), 319 MCP4531_COMPATIBLE("microchip,mcp4631-104", MCP463x_104), 320 MCP4531_COMPATIBLE("microchip,mcp4632-502", MCP463x_502), 321 MCP4531_COMPATIBLE("microchip,mcp4632-103", MCP463x_103), 322 MCP4531_COMPATIBLE("microchip,mcp4632-503", MCP463x_503), 323 MCP4531_COMPATIBLE("microchip,mcp4632-104", MCP463x_104), 324 MCP4531_COMPATIBLE("microchip,mcp4641-502", MCP464x_502), 325 MCP4531_COMPATIBLE("microchip,mcp4641-103", MCP464x_103), 326 MCP4531_COMPATIBLE("microchip,mcp4641-503", MCP464x_503), 327 MCP4531_COMPATIBLE("microchip,mcp4641-104", MCP464x_104), 328 MCP4531_COMPATIBLE("microchip,mcp4642-502", MCP464x_502), 329 MCP4531_COMPATIBLE("microchip,mcp4642-103", MCP464x_103), 330 MCP4531_COMPATIBLE("microchip,mcp4642-503", MCP464x_503), 331 MCP4531_COMPATIBLE("microchip,mcp4642-104", MCP464x_104), 332 MCP4531_COMPATIBLE("microchip,mcp4651-502", MCP465x_502), 333 MCP4531_COMPATIBLE("microchip,mcp4651-103", MCP465x_103), 334 MCP4531_COMPATIBLE("microchip,mcp4651-503", MCP465x_503), 335 MCP4531_COMPATIBLE("microchip,mcp4651-104", MCP465x_104), 336 MCP4531_COMPATIBLE("microchip,mcp4652-502", MCP465x_502), 337 MCP4531_COMPATIBLE("microchip,mcp4652-103", MCP465x_103), 338 MCP4531_COMPATIBLE("microchip,mcp4652-503", MCP465x_503), 339 MCP4531_COMPATIBLE("microchip,mcp4652-104", MCP465x_104), 340 MCP4531_COMPATIBLE("microchip,mcp4661-502", MCP466x_502), 341 MCP4531_COMPATIBLE("microchip,mcp4661-103", MCP466x_103), 342 MCP4531_COMPATIBLE("microchip,mcp4661-503", MCP466x_503), 343 MCP4531_COMPATIBLE("microchip,mcp4661-104", MCP466x_104), 344 MCP4531_COMPATIBLE("microchip,mcp4662-502", MCP466x_502), 345 MCP4531_COMPATIBLE("microchip,mcp4662-103", MCP466x_103), 346 MCP4531_COMPATIBLE("microchip,mcp4662-503", MCP466x_503), 347 MCP4531_COMPATIBLE("microchip,mcp4662-104", MCP466x_104), 348 { /* sentinel */ } 349}; 350MODULE_DEVICE_TABLE(of, mcp4531_of_match); 351 352static int mcp4531_probe(struct i2c_client *client) 353{ 354 struct device *dev = &client->dev; 355 struct mcp4531_data *data; 356 struct iio_dev *indio_dev; 357 358 if (!i2c_check_functionality(client->adapter, 359 I2C_FUNC_SMBUS_WORD_DATA)) { 360 dev_err(dev, "SMBUS Word Data not supported\n"); 361 return -EOPNOTSUPP; 362 } 363 364 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 365 if (!indio_dev) 366 return -ENOMEM; 367 data = iio_priv(indio_dev); 368 i2c_set_clientdata(client, indio_dev); 369 data->client = client; 370 371 data->cfg = device_get_match_data(dev); 372 if (!data->cfg) 373 data->cfg = &mcp4531_cfg[i2c_match_id(mcp4531_id, client)->driver_data]; 374 375 indio_dev->info = &mcp4531_info; 376 indio_dev->channels = mcp4531_channels; 377 indio_dev->num_channels = data->cfg->wipers; 378 indio_dev->name = client->name; 379 380 return devm_iio_device_register(dev, indio_dev); 381} 382 383static struct i2c_driver mcp4531_driver = { 384 .driver = { 385 .name = "mcp4531", 386 .of_match_table = mcp4531_of_match, 387 }, 388 .probe_new = mcp4531_probe, 389 .id_table = mcp4531_id, 390}; 391 392module_i2c_driver(mcp4531_driver); 393 394MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); 395MODULE_DESCRIPTION("MCP4531 digital potentiometer"); 396MODULE_LICENSE("GPL v2");