linux/drivers/iio/potentiometer/mcp4531.c
<<
>>
Prefs
   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");
 397