1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Industrial I/O driver for Microchip digital potentiometers 4 * 5 * Copyright (c) 2016 Slawomir Stepien 6 * Based on: Peter Rosin's code from mcp4531.c 7 * 8 * Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/22060b.pdf 9 * 10 * DEVID #Wipers #Positions Resistor Opts (kOhm) 11 * mcp4131 1 129 5, 10, 50, 100 12 * mcp4132 1 129 5, 10, 50, 100 13 * mcp4141 1 129 5, 10, 50, 100 14 * mcp4142 1 129 5, 10, 50, 100 15 * mcp4151 1 257 5, 10, 50, 100 16 * mcp4152 1 257 5, 10, 50, 100 17 * mcp4161 1 257 5, 10, 50, 100 18 * mcp4162 1 257 5, 10, 50, 100 19 * mcp4231 2 129 5, 10, 50, 100 20 * mcp4232 2 129 5, 10, 50, 100 21 * mcp4241 2 129 5, 10, 50, 100 22 * mcp4242 2 129 5, 10, 50, 100 23 * mcp4251 2 257 5, 10, 50, 100 24 * mcp4252 2 257 5, 10, 50, 100 25 * mcp4261 2 257 5, 10, 50, 100 26 * mcp4262 2 257 5, 10, 50, 100 27 */ 28 29 /* 30 * TODO: 31 * 1. Write wiper setting to EEPROM for EEPROM capable models. 32 */ 33 34 #include <linux/cache.h> 35 #include <linux/err.h> 36 #include <linux/iio/iio.h> 37 #include <linux/iio/types.h> 38 #include <linux/module.h> 39 #include <linux/mutex.h> 40 #include <linux/property.h> 41 #include <linux/spi/spi.h> 42 43 #define MCP4131_WRITE (0x00 << 2) 44 #define MCP4131_READ (0x03 << 2) 45 46 #define MCP4131_WIPER_SHIFT 4 47 #define MCP4131_CMDERR(r) ((r[0]) & 0x02) 48 #define MCP4131_RAW(r) ((r[0]) == 0xff ? 0x100 : (r[1])) 49 50 struct mcp4131_cfg { 51 int wipers; 52 int max_pos; 53 int kohms; 54 }; 55 56 enum mcp4131_type { 57 MCP413x_502 = 0, 58 MCP413x_103, 59 MCP413x_503, 60 MCP413x_104, 61 MCP414x_502, 62 MCP414x_103, 63 MCP414x_503, 64 MCP414x_104, 65 MCP415x_502, 66 MCP415x_103, 67 MCP415x_503, 68 MCP415x_104, 69 MCP416x_502, 70 MCP416x_103, 71 MCP416x_503, 72 MCP416x_104, 73 MCP423x_502, 74 MCP423x_103, 75 MCP423x_503, 76 MCP423x_104, 77 MCP424x_502, 78 MCP424x_103, 79 MCP424x_503, 80 MCP424x_104, 81 MCP425x_502, 82 MCP425x_103, 83 MCP425x_503, 84 MCP425x_104, 85 MCP426x_502, 86 MCP426x_103, 87 MCP426x_503, 88 MCP426x_104, 89 }; 90 91 static const struct mcp4131_cfg mcp4131_cfg[] = { 92 [MCP413x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, }, 93 [MCP413x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, }, 94 [MCP413x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, }, 95 [MCP413x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, }, 96 [MCP414x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, }, 97 [MCP414x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, }, 98 [MCP414x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, }, 99 [MCP414x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, }, 100 [MCP415x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, }, 101 [MCP415x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, }, 102 [MCP415x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, }, 103 [MCP415x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, }, 104 [MCP416x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, }, 105 [MCP416x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, }, 106 [MCP416x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, }, 107 [MCP416x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, }, 108 [MCP423x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, }, 109 [MCP423x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, }, 110 [MCP423x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, }, 111 [MCP423x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, }, 112 [MCP424x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, }, 113 [MCP424x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, }, 114 [MCP424x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, }, 115 [MCP424x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, }, 116 [MCP425x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, }, 117 [MCP425x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, }, 118 [MCP425x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, }, 119 [MCP425x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, }, 120 [MCP426x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, }, 121 [MCP426x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, }, 122 [MCP426x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, }, 123 [MCP426x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, }, 124 }; 125 126 struct mcp4131_data { 127 struct spi_device *spi; 128 const struct mcp4131_cfg *cfg; 129 struct mutex lock; 130 u8 buf[2] __aligned(IIO_DMA_MINALIGN); 131 }; 132 133 #define MCP4131_CHANNEL(ch) { \ 134 .type = IIO_RESISTANCE, \ 135 .indexed = 1, \ 136 .output = 1, \ 137 .channel = (ch), \ 138 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 139 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 140 } 141 142 static const struct iio_chan_spec mcp4131_channels[] = { 143 MCP4131_CHANNEL(0), 144 MCP4131_CHANNEL(1), 145 }; 146 147 static int mcp4131_read(struct spi_device *spi, void *buf, size_t len) 148 { 149 struct spi_transfer t = { 150 .tx_buf = buf, /* We need to send addr, cmd and 12 bits */ 151 .rx_buf = buf, 152 .len = len, 153 }; 154 struct spi_message m; 155 156 spi_message_init(&m); 157 spi_message_add_tail(&t, &m); 158 159 return spi_sync(spi, &m); 160 } 161 162 static int mcp4131_read_raw(struct iio_dev *indio_dev, 163 struct iio_chan_spec const *chan, 164 int *val, int *val2, long mask) 165 { 166 int err; 167 struct mcp4131_data *data = iio_priv(indio_dev); 168 int address = chan->channel; 169 170 switch (mask) { 171 case IIO_CHAN_INFO_RAW: 172 mutex_lock(&data->lock); 173 174 data->buf[0] = (address << MCP4131_WIPER_SHIFT) | MCP4131_READ; 175 data->buf[1] = 0; 176 177 err = mcp4131_read(data->spi, data->buf, 2); 178 if (err) { 179 mutex_unlock(&data->lock); 180 return err; 181 } 182 183 /* Error, bad address/command combination */ 184 if (!MCP4131_CMDERR(data->buf)) { 185 mutex_unlock(&data->lock); 186 return -EIO; 187 } 188 189 *val = MCP4131_RAW(data->buf); 190 mutex_unlock(&data->lock); 191 192 return IIO_VAL_INT; 193 194 case IIO_CHAN_INFO_SCALE: 195 *val = 1000 * data->cfg->kohms; 196 *val2 = data->cfg->max_pos; 197 return IIO_VAL_FRACTIONAL; 198 } 199 200 return -EINVAL; 201 } 202 203 static int mcp4131_write_raw(struct iio_dev *indio_dev, 204 struct iio_chan_spec const *chan, 205 int val, int val2, long mask) 206 { 207 int err; 208 struct mcp4131_data *data = iio_priv(indio_dev); 209 int address = chan->channel << MCP4131_WIPER_SHIFT; 210 211 switch (mask) { 212 case IIO_CHAN_INFO_RAW: 213 if (val > data->cfg->max_pos || val < 0) 214 return -EINVAL; 215 break; 216 217 default: 218 return -EINVAL; 219 } 220 221 mutex_lock(&data->lock); 222 223 data->buf[0] = address; 224 data->buf[0] |= MCP4131_WRITE | (val >> 8); 225 data->buf[1] = val & 0xFF; /* 8 bits here */ 226 227 err = spi_write(data->spi, data->buf, 2); 228 mutex_unlock(&data->lock); 229 230 return err; 231 } 232 233 static const struct iio_info mcp4131_info = { 234 .read_raw = mcp4131_read_raw, 235 .write_raw = mcp4131_write_raw, 236 }; 237 238 static int mcp4131_probe(struct spi_device *spi) 239 { 240 int err; 241 struct device *dev = &spi->dev; 242 unsigned long devid; 243 struct mcp4131_data *data; 244 struct iio_dev *indio_dev; 245 246 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 247 if (!indio_dev) 248 return -ENOMEM; 249 250 data = iio_priv(indio_dev); 251 spi_set_drvdata(spi, indio_dev); 252 data->spi = spi; 253 data->cfg = device_get_match_data(&spi->dev); 254 if (!data->cfg) { 255 devid = spi_get_device_id(spi)->driver_data; 256 data->cfg = &mcp4131_cfg[devid]; 257 } 258 259 mutex_init(&data->lock); 260 261 indio_dev->info = &mcp4131_info; 262 indio_dev->channels = mcp4131_channels; 263 indio_dev->num_channels = data->cfg->wipers; 264 indio_dev->name = spi_get_device_id(spi)->name; 265 266 err = devm_iio_device_register(dev, indio_dev); 267 if (err) { 268 dev_info(&spi->dev, "Unable to register %s\n", indio_dev->name); 269 return err; 270 } 271 272 return 0; 273 } 274 275 static const struct of_device_id mcp4131_dt_ids[] = { 276 { .compatible = "microchip,mcp4131-502", 277 .data = &mcp4131_cfg[MCP413x_502] }, 278 { .compatible = "microchip,mcp4131-103", 279 .data = &mcp4131_cfg[MCP413x_103] }, 280 { .compatible = "microchip,mcp4131-503", 281 .data = &mcp4131_cfg[MCP413x_503] }, 282 { .compatible = "microchip,mcp4131-104", 283 .data = &mcp4131_cfg[MCP413x_104] }, 284 { .compatible = "microchip,mcp4132-502", 285 .data = &mcp4131_cfg[MCP413x_502] }, 286 { .compatible = "microchip,mcp4132-103", 287 .data = &mcp4131_cfg[MCP413x_103] }, 288 { .compatible = "microchip,mcp4132-503", 289 .data = &mcp4131_cfg[MCP413x_503] }, 290 { .compatible = "microchip,mcp4132-104", 291 .data = &mcp4131_cfg[MCP413x_104] }, 292 { .compatible = "microchip,mcp4141-502", 293 .data = &mcp4131_cfg[MCP414x_502] }, 294 { .compatible = "microchip,mcp4141-103", 295 .data = &mcp4131_cfg[MCP414x_103] }, 296 { .compatible = "microchip,mcp4141-503", 297 .data = &mcp4131_cfg[MCP414x_503] }, 298 { .compatible = "microchip,mcp4141-104", 299 .data = &mcp4131_cfg[MCP414x_104] }, 300 { .compatible = "microchip,mcp4142-502", 301 .data = &mcp4131_cfg[MCP414x_502] }, 302 { .compatible = "microchip,mcp4142-103", 303 .data = &mcp4131_cfg[MCP414x_103] }, 304 { .compatible = "microchip,mcp4142-503", 305 .data = &mcp4131_cfg[MCP414x_503] }, 306 { .compatible = "microchip,mcp4142-104", 307 .data = &mcp4131_cfg[MCP414x_104] }, 308 { .compatible = "microchip,mcp4151-502", 309 .data = &mcp4131_cfg[MCP415x_502] }, 310 { .compatible = "microchip,mcp4151-103", 311 .data = &mcp4131_cfg[MCP415x_103] }, 312 { .compatible = "microchip,mcp4151-503", 313 .data = &mcp4131_cfg[MCP415x_503] }, 314 { .compatible = "microchip,mcp4151-104", 315 .data = &mcp4131_cfg[MCP415x_104] }, 316 { .compatible = "microchip,mcp4152-502", 317 .data = &mcp4131_cfg[MCP415x_502] }, 318 { .compatible = "microchip,mcp4152-103", 319 .data = &mcp4131_cfg[MCP415x_103] }, 320 { .compatible = "microchip,mcp4152-503", 321 .data = &mcp4131_cfg[MCP415x_503] }, 322 { .compatible = "microchip,mcp4152-104", 323 .data = &mcp4131_cfg[MCP415x_104] }, 324 { .compatible = "microchip,mcp4161-502", 325 .data = &mcp4131_cfg[MCP416x_502] }, 326 { .compatible = "microchip,mcp4161-103", 327 .data = &mcp4131_cfg[MCP416x_103] }, 328 { .compatible = "microchip,mcp4161-503", 329 .data = &mcp4131_cfg[MCP416x_503] }, 330 { .compatible = "microchip,mcp4161-104", 331 .data = &mcp4131_cfg[MCP416x_104] }, 332 { .compatible = "microchip,mcp4162-502", 333 .data = &mcp4131_cfg[MCP416x_502] }, 334 { .compatible = "microchip,mcp4162-103", 335 .data = &mcp4131_cfg[MCP416x_103] }, 336 { .compatible = "microchip,mcp4162-503", 337 .data = &mcp4131_cfg[MCP416x_503] }, 338 { .compatible = "microchip,mcp4162-104", 339 .data = &mcp4131_cfg[MCP416x_104] }, 340 { .compatible = "microchip,mcp4231-502", 341 .data = &mcp4131_cfg[MCP423x_502] }, 342 { .compatible = "microchip,mcp4231-103", 343 .data = &mcp4131_cfg[MCP423x_103] }, 344 { .compatible = "microchip,mcp4231-503", 345 .data = &mcp4131_cfg[MCP423x_503] }, 346 { .compatible = "microchip,mcp4231-104", 347 .data = &mcp4131_cfg[MCP423x_104] }, 348 { .compatible = "microchip,mcp4232-502", 349 .data = &mcp4131_cfg[MCP423x_502] }, 350 { .compatible = "microchip,mcp4232-103", 351 .data = &mcp4131_cfg[MCP423x_103] }, 352 { .compatible = "microchip,mcp4232-503", 353 .data = &mcp4131_cfg[MCP423x_503] }, 354 { .compatible = "microchip,mcp4232-104", 355 .data = &mcp4131_cfg[MCP423x_104] }, 356 { .compatible = "microchip,mcp4241-502", 357 .data = &mcp4131_cfg[MCP424x_502] }, 358 { .compatible = "microchip,mcp4241-103", 359 .data = &mcp4131_cfg[MCP424x_103] }, 360 { .compatible = "microchip,mcp4241-503", 361 .data = &mcp4131_cfg[MCP424x_503] }, 362 { .compatible = "microchip,mcp4241-104", 363 .data = &mcp4131_cfg[MCP424x_104] }, 364 { .compatible = "microchip,mcp4242-502", 365 .data = &mcp4131_cfg[MCP424x_502] }, 366 { .compatible = "microchip,mcp4242-103", 367 .data = &mcp4131_cfg[MCP424x_103] }, 368 { .compatible = "microchip,mcp4242-503", 369 .data = &mcp4131_cfg[MCP424x_503] }, 370 { .compatible = "microchip,mcp4242-104", 371 .data = &mcp4131_cfg[MCP424x_104] }, 372 { .compatible = "microchip,mcp4251-502", 373 .data = &mcp4131_cfg[MCP425x_502] }, 374 { .compatible = "microchip,mcp4251-103", 375 .data = &mcp4131_cfg[MCP425x_103] }, 376 { .compatible = "microchip,mcp4251-503", 377 .data = &mcp4131_cfg[MCP425x_503] }, 378 { .compatible = "microchip,mcp4251-104", 379 .data = &mcp4131_cfg[MCP425x_104] }, 380 { .compatible = "microchip,mcp4252-502", 381 .data = &mcp4131_cfg[MCP425x_502] }, 382 { .compatible = "microchip,mcp4252-103", 383 .data = &mcp4131_cfg[MCP425x_103] }, 384 { .compatible = "microchip,mcp4252-503", 385 .data = &mcp4131_cfg[MCP425x_503] }, 386 { .compatible = "microchip,mcp4252-104", 387 .data = &mcp4131_cfg[MCP425x_104] }, 388 { .compatible = "microchip,mcp4261-502", 389 .data = &mcp4131_cfg[MCP426x_502] }, 390 { .compatible = "microchip,mcp4261-103", 391 .data = &mcp4131_cfg[MCP426x_103] }, 392 { .compatible = "microchip,mcp4261-503", 393 .data = &mcp4131_cfg[MCP426x_503] }, 394 { .compatible = "microchip,mcp4261-104", 395 .data = &mcp4131_cfg[MCP426x_104] }, 396 { .compatible = "microchip,mcp4262-502", 397 .data = &mcp4131_cfg[MCP426x_502] }, 398 { .compatible = "microchip,mcp4262-103", 399 .data = &mcp4131_cfg[MCP426x_103] }, 400 { .compatible = "microchip,mcp4262-503", 401 .data = &mcp4131_cfg[MCP426x_503] }, 402 { .compatible = "microchip,mcp4262-104", 403 .data = &mcp4131_cfg[MCP426x_104] }, 404 { } 405 }; 406 MODULE_DEVICE_TABLE(of, mcp4131_dt_ids); 407 408 static const struct spi_device_id mcp4131_id[] = { 409 { .name = "mcp4131-502", .driver_data = MCP413x_502 }, 410 { .name = "mcp4131-103", .driver_data = MCP413x_103 }, 411 { .name = "mcp4131-503", .driver_data = MCP413x_503 }, 412 { .name = "mcp4131-104", .driver_data = MCP413x_104 }, 413 { .name = "mcp4132-502", .driver_data = MCP413x_502 }, 414 { .name = "mcp4132-103", .driver_data = MCP413x_103 }, 415 { .name = "mcp4132-503", .driver_data = MCP413x_503 }, 416 { .name = "mcp4132-104", .driver_data = MCP413x_104 }, 417 { .name = "mcp4141-502", .driver_data = MCP414x_502 }, 418 { .name = "mcp4141-103", .driver_data = MCP414x_103 }, 419 { .name = "mcp4141-503", .driver_data = MCP414x_503 }, 420 { .name = "mcp4141-104", .driver_data = MCP414x_104 }, 421 { .name = "mcp4142-502", .driver_data = MCP414x_502 }, 422 { .name = "mcp4142-103", .driver_data = MCP414x_103 }, 423 { .name = "mcp4142-503", .driver_data = MCP414x_503 }, 424 { .name = "mcp4142-104", .driver_data = MCP414x_104 }, 425 { .name = "mcp4151-502", .driver_data = MCP415x_502 }, 426 { .name = "mcp4151-103", .driver_data = MCP415x_103 }, 427 { .name = "mcp4151-503", .driver_data = MCP415x_503 }, 428 { .name = "mcp4151-104", .driver_data = MCP415x_104 }, 429 { .name = "mcp4152-502", .driver_data = MCP415x_502 }, 430 { .name = "mcp4152-103", .driver_data = MCP415x_103 }, 431 { .name = "mcp4152-503", .driver_data = MCP415x_503 }, 432 { .name = "mcp4152-104", .driver_data = MCP415x_104 }, 433 { .name = "mcp4161-502", .driver_data = MCP416x_502 }, 434 { .name = "mcp4161-103", .driver_data = MCP416x_103 }, 435 { .name = "mcp4161-503", .driver_data = MCP416x_503 }, 436 { .name = "mcp4161-104", .driver_data = MCP416x_104 }, 437 { .name = "mcp4162-502", .driver_data = MCP416x_502 }, 438 { .name = "mcp4162-103", .driver_data = MCP416x_103 }, 439 { .name = "mcp4162-503", .driver_data = MCP416x_503 }, 440 { .name = "mcp4162-104", .driver_data = MCP416x_104 }, 441 { .name = "mcp4231-502", .driver_data = MCP423x_502 }, 442 { .name = "mcp4231-103", .driver_data = MCP423x_103 }, 443 { .name = "mcp4231-503", .driver_data = MCP423x_503 }, 444 { .name = "mcp4231-104", .driver_data = MCP423x_104 }, 445 { .name = "mcp4232-502", .driver_data = MCP423x_502 }, 446 { .name = "mcp4232-103", .driver_data = MCP423x_103 }, 447 { .name = "mcp4232-503", .driver_data = MCP423x_503 }, 448 { .name = "mcp4232-104", .driver_data = MCP423x_104 }, 449 { .name = "mcp4241-502", .driver_data = MCP424x_502 }, 450 { .name = "mcp4241-103", .driver_data = MCP424x_103 }, 451 { .name = "mcp4241-503", .driver_data = MCP424x_503 }, 452 { .name = "mcp4241-104", .driver_data = MCP424x_104 }, 453 { .name = "mcp4242-502", .driver_data = MCP424x_502 }, 454 { .name = "mcp4242-103", .driver_data = MCP424x_103 }, 455 { .name = "mcp4242-503", .driver_data = MCP424x_503 }, 456 { .name = "mcp4242-104", .driver_data = MCP424x_104 }, 457 { .name = "mcp4251-502", .driver_data = MCP425x_502 }, 458 { .name = "mcp4251-103", .driver_data = MCP425x_103 }, 459 { .name = "mcp4251-503", .driver_data = MCP425x_503 }, 460 { .name = "mcp4251-104", .driver_data = MCP425x_104 }, 461 { .name = "mcp4252-502", .driver_data = MCP425x_502 }, 462 { .name = "mcp4252-103", .driver_data = MCP425x_103 }, 463 { .name = "mcp4252-503", .driver_data = MCP425x_503 }, 464 { .name = "mcp4252-104", .driver_data = MCP425x_104 }, 465 { .name = "mcp4261-502", .driver_data = MCP426x_502 }, 466 { .name = "mcp4261-103", .driver_data = MCP426x_103 }, 467 { .name = "mcp4261-503", .driver_data = MCP426x_503 }, 468 { .name = "mcp4261-104", .driver_data = MCP426x_104 }, 469 { .name = "mcp4262-502", .driver_data = MCP426x_502 }, 470 { .name = "mcp4262-103", .driver_data = MCP426x_103 }, 471 { .name = "mcp4262-503", .driver_data = MCP426x_503 }, 472 { .name = "mcp4262-104", .driver_data = MCP426x_104 }, 473 { } 474 }; 475 MODULE_DEVICE_TABLE(spi, mcp4131_id); 476 477 static struct spi_driver mcp4131_driver = { 478 .driver = { 479 .name = "mcp4131", 480 .of_match_table = mcp4131_dt_ids, 481 }, 482 .probe = mcp4131_probe, 483 .id_table = mcp4131_id, 484 }; 485 486 module_spi_driver(mcp4131_driver); 487 488 MODULE_AUTHOR("Slawomir Stepien <sst@poczta.fm>"); 489 MODULE_DESCRIPTION("MCP4131 digital potentiometer"); 490 MODULE_LICENSE("GPL v2"); 491