linux/drivers/iio/potentiometer/mcp4131.c
<<
>>
Prefs
   1/*
   2 * Industrial I/O driver for Microchip digital potentiometers
   3 *
   4 * Copyright (c) 2016 Slawomir Stepien
   5 * Based on: Peter Rosin's code from mcp4531.c
   6 *
   7 * Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22060b.pdf
   8 *
   9 * DEVID        #Wipers #Positions      Resistor Opts (kOhm)
  10 * mcp4131      1       129             5, 10, 50, 100
  11 * mcp4132      1       129             5, 10, 50, 100
  12 * mcp4141      1       129             5, 10, 50, 100
  13 * mcp4142      1       129             5, 10, 50, 100
  14 * mcp4151      1       257             5, 10, 50, 100
  15 * mcp4152      1       257             5, 10, 50, 100
  16 * mcp4161      1       257             5, 10, 50, 100
  17 * mcp4162      1       257             5, 10, 50, 100
  18 * mcp4231      2       129             5, 10, 50, 100
  19 * mcp4232      2       129             5, 10, 50, 100
  20 * mcp4241      2       129             5, 10, 50, 100
  21 * mcp4242      2       129             5, 10, 50, 100
  22 * mcp4251      2       257             5, 10, 50, 100
  23 * mcp4252      2       257             5, 10, 50, 100
  24 * mcp4261      2       257             5, 10, 50, 100
  25 * mcp4262      2       257             5, 10, 50, 100
  26 *
  27 * This program is free software; you can redistribute it and/or modify it
  28 * under the terms of the GNU General Public License version 2 as published by
  29 * the Free Software Foundation.
  30 */
  31
  32/*
  33 * TODO:
  34 * 1. Write wiper setting to EEPROM for EEPROM capable models.
  35 */
  36
  37#include <linux/cache.h>
  38#include <linux/err.h>
  39#include <linux/export.h>
  40#include <linux/iio/iio.h>
  41#include <linux/iio/types.h>
  42#include <linux/module.h>
  43#include <linux/mutex.h>
  44#include <linux/of.h>
  45#include <linux/spi/spi.h>
  46
  47#define MCP4131_WRITE           (0x00 << 2)
  48#define MCP4131_READ            (0x03 << 2)
  49
  50#define MCP4131_WIPER_SHIFT     4
  51#define MCP4131_CMDERR(r)       ((r[0]) & 0x02)
  52#define MCP4131_RAW(r)          ((r[0]) == 0xff ? 0x100 : (r[1]))
  53
  54struct mcp4131_cfg {
  55        int wipers;
  56        int max_pos;
  57        int kohms;
  58};
  59
  60enum mcp4131_type {
  61        MCP413x_502 = 0,
  62        MCP413x_103,
  63        MCP413x_503,
  64        MCP413x_104,
  65        MCP414x_502,
  66        MCP414x_103,
  67        MCP414x_503,
  68        MCP414x_104,
  69        MCP415x_502,
  70        MCP415x_103,
  71        MCP415x_503,
  72        MCP415x_104,
  73        MCP416x_502,
  74        MCP416x_103,
  75        MCP416x_503,
  76        MCP416x_104,
  77        MCP423x_502,
  78        MCP423x_103,
  79        MCP423x_503,
  80        MCP423x_104,
  81        MCP424x_502,
  82        MCP424x_103,
  83        MCP424x_503,
  84        MCP424x_104,
  85        MCP425x_502,
  86        MCP425x_103,
  87        MCP425x_503,
  88        MCP425x_104,
  89        MCP426x_502,
  90        MCP426x_103,
  91        MCP426x_503,
  92        MCP426x_104,
  93};
  94
  95static const struct mcp4131_cfg mcp4131_cfg[] = {
  96        [MCP413x_502] = { .wipers = 1, .max_pos = 128, .kohms =   5, },
  97        [MCP413x_103] = { .wipers = 1, .max_pos = 128, .kohms =  10, },
  98        [MCP413x_503] = { .wipers = 1, .max_pos = 128, .kohms =  50, },
  99        [MCP413x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
 100        [MCP414x_502] = { .wipers = 1, .max_pos = 128, .kohms =   5, },
 101        [MCP414x_103] = { .wipers = 1, .max_pos = 128, .kohms =  10, },
 102        [MCP414x_503] = { .wipers = 1, .max_pos = 128, .kohms =  50, },
 103        [MCP414x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
 104        [MCP415x_502] = { .wipers = 1, .max_pos = 256, .kohms =   5, },
 105        [MCP415x_103] = { .wipers = 1, .max_pos = 256, .kohms =  10, },
 106        [MCP415x_503] = { .wipers = 1, .max_pos = 256, .kohms =  50, },
 107        [MCP415x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
 108        [MCP416x_502] = { .wipers = 1, .max_pos = 256, .kohms =   5, },
 109        [MCP416x_103] = { .wipers = 1, .max_pos = 256, .kohms =  10, },
 110        [MCP416x_503] = { .wipers = 1, .max_pos = 256, .kohms =  50, },
 111        [MCP416x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
 112        [MCP423x_502] = { .wipers = 2, .max_pos = 128, .kohms =   5, },
 113        [MCP423x_103] = { .wipers = 2, .max_pos = 128, .kohms =  10, },
 114        [MCP423x_503] = { .wipers = 2, .max_pos = 128, .kohms =  50, },
 115        [MCP423x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
 116        [MCP424x_502] = { .wipers = 2, .max_pos = 128, .kohms =   5, },
 117        [MCP424x_103] = { .wipers = 2, .max_pos = 128, .kohms =  10, },
 118        [MCP424x_503] = { .wipers = 2, .max_pos = 128, .kohms =  50, },
 119        [MCP424x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
 120        [MCP425x_502] = { .wipers = 2, .max_pos = 256, .kohms =   5, },
 121        [MCP425x_103] = { .wipers = 2, .max_pos = 256, .kohms =  10, },
 122        [MCP425x_503] = { .wipers = 2, .max_pos = 256, .kohms =  50, },
 123        [MCP425x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
 124        [MCP426x_502] = { .wipers = 2, .max_pos = 256, .kohms =   5, },
 125        [MCP426x_103] = { .wipers = 2, .max_pos = 256, .kohms =  10, },
 126        [MCP426x_503] = { .wipers = 2, .max_pos = 256, .kohms =  50, },
 127        [MCP426x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
 128};
 129
 130struct mcp4131_data {
 131        struct spi_device *spi;
 132        const struct mcp4131_cfg *cfg;
 133        struct mutex lock;
 134        u8 buf[2] ____cacheline_aligned;
 135};
 136
 137#define MCP4131_CHANNEL(ch) {                                   \
 138        .type = IIO_RESISTANCE,                                 \
 139        .indexed = 1,                                           \
 140        .output = 1,                                            \
 141        .channel = (ch),                                        \
 142        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
 143        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
 144}
 145
 146static const struct iio_chan_spec mcp4131_channels[] = {
 147        MCP4131_CHANNEL(0),
 148        MCP4131_CHANNEL(1),
 149};
 150
 151static int mcp4131_read(struct spi_device *spi, void *buf, size_t len)
 152{
 153        struct spi_transfer t = {
 154                .tx_buf = buf, /* We need to send addr, cmd and 12 bits */
 155                .rx_buf = buf,
 156                .len = len,
 157        };
 158        struct spi_message m;
 159
 160        spi_message_init(&m);
 161        spi_message_add_tail(&t, &m);
 162
 163        return spi_sync(spi, &m);
 164}
 165
 166static int mcp4131_read_raw(struct iio_dev *indio_dev,
 167                            struct iio_chan_spec const *chan,
 168                            int *val, int *val2, long mask)
 169{
 170        int err;
 171        struct mcp4131_data *data = iio_priv(indio_dev);
 172        int address = chan->channel;
 173
 174        switch (mask) {
 175        case IIO_CHAN_INFO_RAW:
 176                mutex_lock(&data->lock);
 177
 178                data->buf[0] = (address << MCP4131_WIPER_SHIFT) | MCP4131_READ;
 179                data->buf[1] = 0;
 180
 181                err = mcp4131_read(data->spi, data->buf, 2);
 182                if (err) {
 183                        mutex_unlock(&data->lock);
 184                        return err;
 185                }
 186
 187                /* Error, bad address/command combination */
 188                if (!MCP4131_CMDERR(data->buf)) {
 189                        mutex_unlock(&data->lock);
 190                        return -EIO;
 191                }
 192
 193                *val = MCP4131_RAW(data->buf);
 194                mutex_unlock(&data->lock);
 195
 196                return IIO_VAL_INT;
 197
 198        case IIO_CHAN_INFO_SCALE:
 199                *val = 1000 * data->cfg->kohms;
 200                *val2 = data->cfg->max_pos;
 201                return IIO_VAL_FRACTIONAL;
 202        }
 203
 204        return -EINVAL;
 205}
 206
 207static int mcp4131_write_raw(struct iio_dev *indio_dev,
 208                             struct iio_chan_spec const *chan,
 209                             int val, int val2, long mask)
 210{
 211        int err;
 212        struct mcp4131_data *data = iio_priv(indio_dev);
 213        int address = chan->channel << MCP4131_WIPER_SHIFT;
 214
 215        switch (mask) {
 216        case IIO_CHAN_INFO_RAW:
 217                if (val > data->cfg->max_pos || val < 0)
 218                        return -EINVAL;
 219                break;
 220
 221        default:
 222                return -EINVAL;
 223        }
 224
 225        mutex_lock(&data->lock);
 226
 227        data->buf[0] = address << MCP4131_WIPER_SHIFT;
 228        data->buf[0] |= MCP4131_WRITE | (val >> 8);
 229        data->buf[1] = val & 0xFF; /* 8 bits here */
 230
 231        err = spi_write(data->spi, data->buf, 2);
 232        mutex_unlock(&data->lock);
 233
 234        return err;
 235}
 236
 237static const struct iio_info mcp4131_info = {
 238        .read_raw = mcp4131_read_raw,
 239        .write_raw = mcp4131_write_raw,
 240};
 241
 242static int mcp4131_probe(struct spi_device *spi)
 243{
 244        int err;
 245        struct device *dev = &spi->dev;
 246        unsigned long devid = spi_get_device_id(spi)->driver_data;
 247        struct mcp4131_data *data;
 248        struct iio_dev *indio_dev;
 249
 250        indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
 251        if (!indio_dev)
 252                return -ENOMEM;
 253
 254        data = iio_priv(indio_dev);
 255        spi_set_drvdata(spi, indio_dev);
 256        data->spi = spi;
 257        data->cfg = &mcp4131_cfg[devid];
 258
 259        mutex_init(&data->lock);
 260
 261        indio_dev->dev.parent = dev;
 262        indio_dev->info = &mcp4131_info;
 263        indio_dev->channels = mcp4131_channels;
 264        indio_dev->num_channels = data->cfg->wipers;
 265        indio_dev->name = spi_get_device_id(spi)->name;
 266
 267        err = devm_iio_device_register(dev, indio_dev);
 268        if (err) {
 269                dev_info(&spi->dev, "Unable to register %s\n", indio_dev->name);
 270                return err;
 271        }
 272
 273        return 0;
 274}
 275
 276#if defined(CONFIG_OF)
 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#endif /* CONFIG_OF */
 410
 411static const struct spi_device_id mcp4131_id[] = {
 412        { "mcp4131-502", MCP413x_502 },
 413        { "mcp4131-103", MCP413x_103 },
 414        { "mcp4131-503", MCP413x_503 },
 415        { "mcp4131-104", MCP413x_104 },
 416        { "mcp4132-502", MCP413x_502 },
 417        { "mcp4132-103", MCP413x_103 },
 418        { "mcp4132-503", MCP413x_503 },
 419        { "mcp4132-104", MCP413x_104 },
 420        { "mcp4141-502", MCP414x_502 },
 421        { "mcp4141-103", MCP414x_103 },
 422        { "mcp4141-503", MCP414x_503 },
 423        { "mcp4141-104", MCP414x_104 },
 424        { "mcp4142-502", MCP414x_502 },
 425        { "mcp4142-103", MCP414x_103 },
 426        { "mcp4142-503", MCP414x_503 },
 427        { "mcp4142-104", MCP414x_104 },
 428        { "mcp4151-502", MCP415x_502 },
 429        { "mcp4151-103", MCP415x_103 },
 430        { "mcp4151-503", MCP415x_503 },
 431        { "mcp4151-104", MCP415x_104 },
 432        { "mcp4152-502", MCP415x_502 },
 433        { "mcp4152-103", MCP415x_103 },
 434        { "mcp4152-503", MCP415x_503 },
 435        { "mcp4152-104", MCP415x_104 },
 436        { "mcp4161-502", MCP416x_502 },
 437        { "mcp4161-103", MCP416x_103 },
 438        { "mcp4161-503", MCP416x_503 },
 439        { "mcp4161-104", MCP416x_104 },
 440        { "mcp4162-502", MCP416x_502 },
 441        { "mcp4162-103", MCP416x_103 },
 442        { "mcp4162-503", MCP416x_503 },
 443        { "mcp4162-104", MCP416x_104 },
 444        { "mcp4231-502", MCP423x_502 },
 445        { "mcp4231-103", MCP423x_103 },
 446        { "mcp4231-503", MCP423x_503 },
 447        { "mcp4231-104", MCP423x_104 },
 448        { "mcp4232-502", MCP423x_502 },
 449        { "mcp4232-103", MCP423x_103 },
 450        { "mcp4232-503", MCP423x_503 },
 451        { "mcp4232-104", MCP423x_104 },
 452        { "mcp4241-502", MCP424x_502 },
 453        { "mcp4241-103", MCP424x_103 },
 454        { "mcp4241-503", MCP424x_503 },
 455        { "mcp4241-104", MCP424x_104 },
 456        { "mcp4242-502", MCP424x_502 },
 457        { "mcp4242-103", MCP424x_103 },
 458        { "mcp4242-503", MCP424x_503 },
 459        { "mcp4242-104", MCP424x_104 },
 460        { "mcp4251-502", MCP425x_502 },
 461        { "mcp4251-103", MCP425x_103 },
 462        { "mcp4251-503", MCP425x_503 },
 463        { "mcp4251-104", MCP425x_104 },
 464        { "mcp4252-502", MCP425x_502 },
 465        { "mcp4252-103", MCP425x_103 },
 466        { "mcp4252-503", MCP425x_503 },
 467        { "mcp4252-104", MCP425x_104 },
 468        { "mcp4261-502", MCP426x_502 },
 469        { "mcp4261-103", MCP426x_103 },
 470        { "mcp4261-503", MCP426x_503 },
 471        { "mcp4261-104", MCP426x_104 },
 472        { "mcp4262-502", MCP426x_502 },
 473        { "mcp4262-103", MCP426x_103 },
 474        { "mcp4262-503", MCP426x_503 },
 475        { "mcp4262-104", MCP426x_104 },
 476        {}
 477};
 478MODULE_DEVICE_TABLE(spi, mcp4131_id);
 479
 480static struct spi_driver mcp4131_driver = {
 481        .driver = {
 482                .name   = "mcp4131",
 483                .of_match_table = of_match_ptr(mcp4131_dt_ids),
 484        },
 485        .probe          = mcp4131_probe,
 486        .id_table       = mcp4131_id,
 487};
 488
 489module_spi_driver(mcp4131_driver);
 490
 491MODULE_AUTHOR("Slawomir Stepien <sst@poczta.fm>");
 492MODULE_DESCRIPTION("MCP4131 digital potentiometer");
 493MODULE_LICENSE("GPL v2");
 494