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