^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Industrial I/O driver for Microchip digital potentiometers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2018 Chris Coffey <cmc@babblebit.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Based on: Slawomir Stepien's code from mcp4131.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Datasheet: https://ww1.microchip.com/downloads/en/devicedoc/11195c.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * DEVID #Wipers #Positions Resistance (kOhm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * mcp41010 1 256 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * mcp41050 1 256 50
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * mcp41100 1 256 100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * mcp42010 2 256 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * mcp42050 2 256 50
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * mcp42100 2 256 100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/cache.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/iio/iio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/iio/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/spi/spi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define MCP41010_MAX_WIPERS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define MCP41010_WRITE BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define MCP41010_WIPER_MAX 255
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define MCP41010_WIPER_CHANNEL BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct mcp41010_cfg {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) char name[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) int wipers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) int kohms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) enum mcp41010_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) MCP41010,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) MCP41050,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) MCP41100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) MCP42010,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) MCP42050,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) MCP42100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static const struct mcp41010_cfg mcp41010_cfg[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) [MCP41010] = { .name = "mcp41010", .wipers = 1, .kohms = 10, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) [MCP41050] = { .name = "mcp41050", .wipers = 1, .kohms = 50, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) [MCP41100] = { .name = "mcp41100", .wipers = 1, .kohms = 100, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) [MCP42010] = { .name = "mcp42010", .wipers = 2, .kohms = 10, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) [MCP42050] = { .name = "mcp42050", .wipers = 2, .kohms = 50, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) [MCP42100] = { .name = "mcp42100", .wipers = 2, .kohms = 100, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct mcp41010_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct spi_device *spi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) const struct mcp41010_cfg *cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct mutex lock; /* Protect write sequences */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) unsigned int value[MCP41010_MAX_WIPERS]; /* Cache wiper values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) u8 buf[2] ____cacheline_aligned;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define MCP41010_CHANNEL(ch) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .type = IIO_RESISTANCE, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) .indexed = 1, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) .output = 1, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) .channel = (ch), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static const struct iio_chan_spec mcp41010_channels[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) MCP41010_CHANNEL(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) MCP41010_CHANNEL(1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int mcp41010_read_raw(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int *val, int *val2, long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct mcp41010_data *data = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) int channel = chan->channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) switch (mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) case IIO_CHAN_INFO_RAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) *val = data->value[channel];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return IIO_VAL_INT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) case IIO_CHAN_INFO_SCALE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) *val = 1000 * data->cfg->kohms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) *val2 = MCP41010_WIPER_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return IIO_VAL_FRACTIONAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static int mcp41010_write_raw(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) int val, int val2, long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct mcp41010_data *data = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) int channel = chan->channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (mask != IIO_CHAN_INFO_RAW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (val > MCP41010_WIPER_MAX || val < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) mutex_lock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) data->buf[0] = MCP41010_WIPER_CHANNEL << channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) data->buf[0] |= MCP41010_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) data->buf[1] = val & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) err = spi_write(data->spi, data->buf, sizeof(data->buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) data->value[channel] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) mutex_unlock(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static const struct iio_info mcp41010_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .read_raw = mcp41010_read_raw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .write_raw = mcp41010_write_raw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static int mcp41010_probe(struct spi_device *spi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) struct device *dev = &spi->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct mcp41010_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct iio_dev *indio_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (!indio_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) data = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) spi_set_drvdata(spi, indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) data->spi = spi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) data->cfg = of_device_get_match_data(&spi->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (!data->cfg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) data->cfg = &mcp41010_cfg[spi_get_device_id(spi)->driver_data];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) mutex_init(&data->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) indio_dev->info = &mcp41010_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) indio_dev->channels = mcp41010_channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) indio_dev->num_channels = data->cfg->wipers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) indio_dev->name = data->cfg->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) err = devm_iio_device_register(dev, indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) dev_info(&spi->dev, "Unable to register %s\n", indio_dev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static const struct of_device_id mcp41010_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) { .compatible = "microchip,mcp41010", .data = &mcp41010_cfg[MCP41010] },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) { .compatible = "microchip,mcp41050", .data = &mcp41010_cfg[MCP41050] },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) { .compatible = "microchip,mcp41100", .data = &mcp41010_cfg[MCP41100] },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) { .compatible = "microchip,mcp42010", .data = &mcp41010_cfg[MCP42010] },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) { .compatible = "microchip,mcp42050", .data = &mcp41010_cfg[MCP42050] },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) { .compatible = "microchip,mcp42100", .data = &mcp41010_cfg[MCP42100] },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) MODULE_DEVICE_TABLE(of, mcp41010_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static const struct spi_device_id mcp41010_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) { "mcp41010", MCP41010 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) { "mcp41050", MCP41050 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) { "mcp41100", MCP41100 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) { "mcp42010", MCP42010 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) { "mcp42050", MCP42050 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) { "mcp42100", MCP42100 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) MODULE_DEVICE_TABLE(spi, mcp41010_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) static struct spi_driver mcp41010_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .name = "mcp41010",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .of_match_table = mcp41010_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .probe = mcp41010_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .id_table = mcp41010_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) module_spi_driver(mcp41010_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) MODULE_AUTHOR("Chris Coffey <cmc@babblebit.net>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) MODULE_DESCRIPTION("MCP41010 digital potentiometer");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) MODULE_LICENSE("GPL v2");