0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #include <linux/cache.h>
0035 #include <linux/err.h>
0036 #include <linux/export.h>
0037 #include <linux/iio/iio.h>
0038 #include <linux/iio/types.h>
0039 #include <linux/module.h>
0040 #include <linux/mod_devicetable.h>
0041 #include <linux/mutex.h>
0042 #include <linux/property.h>
0043 #include <linux/spi/spi.h>
0044
0045 #define MCP4131_WRITE (0x00 << 2)
0046 #define MCP4131_READ (0x03 << 2)
0047
0048 #define MCP4131_WIPER_SHIFT 4
0049 #define MCP4131_CMDERR(r) ((r[0]) & 0x02)
0050 #define MCP4131_RAW(r) ((r[0]) == 0xff ? 0x100 : (r[1]))
0051
0052 struct mcp4131_cfg {
0053 int wipers;
0054 int max_pos;
0055 int kohms;
0056 };
0057
0058 enum mcp4131_type {
0059 MCP413x_502 = 0,
0060 MCP413x_103,
0061 MCP413x_503,
0062 MCP413x_104,
0063 MCP414x_502,
0064 MCP414x_103,
0065 MCP414x_503,
0066 MCP414x_104,
0067 MCP415x_502,
0068 MCP415x_103,
0069 MCP415x_503,
0070 MCP415x_104,
0071 MCP416x_502,
0072 MCP416x_103,
0073 MCP416x_503,
0074 MCP416x_104,
0075 MCP423x_502,
0076 MCP423x_103,
0077 MCP423x_503,
0078 MCP423x_104,
0079 MCP424x_502,
0080 MCP424x_103,
0081 MCP424x_503,
0082 MCP424x_104,
0083 MCP425x_502,
0084 MCP425x_103,
0085 MCP425x_503,
0086 MCP425x_104,
0087 MCP426x_502,
0088 MCP426x_103,
0089 MCP426x_503,
0090 MCP426x_104,
0091 };
0092
0093 static const struct mcp4131_cfg mcp4131_cfg[] = {
0094 [MCP413x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, },
0095 [MCP413x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
0096 [MCP413x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, },
0097 [MCP413x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
0098 [MCP414x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, },
0099 [MCP414x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
0100 [MCP414x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, },
0101 [MCP414x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
0102 [MCP415x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, },
0103 [MCP415x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, },
0104 [MCP415x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
0105 [MCP415x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
0106 [MCP416x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, },
0107 [MCP416x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, },
0108 [MCP416x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
0109 [MCP416x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
0110 [MCP423x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, },
0111 [MCP423x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, },
0112 [MCP423x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, },
0113 [MCP423x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
0114 [MCP424x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, },
0115 [MCP424x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, },
0116 [MCP424x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, },
0117 [MCP424x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
0118 [MCP425x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, },
0119 [MCP425x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, },
0120 [MCP425x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, },
0121 [MCP425x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
0122 [MCP426x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, },
0123 [MCP426x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, },
0124 [MCP426x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, },
0125 [MCP426x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
0126 };
0127
0128 struct mcp4131_data {
0129 struct spi_device *spi;
0130 const struct mcp4131_cfg *cfg;
0131 struct mutex lock;
0132 u8 buf[2] __aligned(IIO_DMA_MINALIGN);
0133 };
0134
0135 #define MCP4131_CHANNEL(ch) { \
0136 .type = IIO_RESISTANCE, \
0137 .indexed = 1, \
0138 .output = 1, \
0139 .channel = (ch), \
0140 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
0141 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
0142 }
0143
0144 static const struct iio_chan_spec mcp4131_channels[] = {
0145 MCP4131_CHANNEL(0),
0146 MCP4131_CHANNEL(1),
0147 };
0148
0149 static int mcp4131_read(struct spi_device *spi, void *buf, size_t len)
0150 {
0151 struct spi_transfer t = {
0152 .tx_buf = buf,
0153 .rx_buf = buf,
0154 .len = len,
0155 };
0156 struct spi_message m;
0157
0158 spi_message_init(&m);
0159 spi_message_add_tail(&t, &m);
0160
0161 return spi_sync(spi, &m);
0162 }
0163
0164 static int mcp4131_read_raw(struct iio_dev *indio_dev,
0165 struct iio_chan_spec const *chan,
0166 int *val, int *val2, long mask)
0167 {
0168 int err;
0169 struct mcp4131_data *data = iio_priv(indio_dev);
0170 int address = chan->channel;
0171
0172 switch (mask) {
0173 case IIO_CHAN_INFO_RAW:
0174 mutex_lock(&data->lock);
0175
0176 data->buf[0] = (address << MCP4131_WIPER_SHIFT) | MCP4131_READ;
0177 data->buf[1] = 0;
0178
0179 err = mcp4131_read(data->spi, data->buf, 2);
0180 if (err) {
0181 mutex_unlock(&data->lock);
0182 return err;
0183 }
0184
0185
0186 if (!MCP4131_CMDERR(data->buf)) {
0187 mutex_unlock(&data->lock);
0188 return -EIO;
0189 }
0190
0191 *val = MCP4131_RAW(data->buf);
0192 mutex_unlock(&data->lock);
0193
0194 return IIO_VAL_INT;
0195
0196 case IIO_CHAN_INFO_SCALE:
0197 *val = 1000 * data->cfg->kohms;
0198 *val2 = data->cfg->max_pos;
0199 return IIO_VAL_FRACTIONAL;
0200 }
0201
0202 return -EINVAL;
0203 }
0204
0205 static int mcp4131_write_raw(struct iio_dev *indio_dev,
0206 struct iio_chan_spec const *chan,
0207 int val, int val2, long mask)
0208 {
0209 int err;
0210 struct mcp4131_data *data = iio_priv(indio_dev);
0211 int address = chan->channel << MCP4131_WIPER_SHIFT;
0212
0213 switch (mask) {
0214 case IIO_CHAN_INFO_RAW:
0215 if (val > data->cfg->max_pos || val < 0)
0216 return -EINVAL;
0217 break;
0218
0219 default:
0220 return -EINVAL;
0221 }
0222
0223 mutex_lock(&data->lock);
0224
0225 data->buf[0] = address << MCP4131_WIPER_SHIFT;
0226 data->buf[0] |= MCP4131_WRITE | (val >> 8);
0227 data->buf[1] = val & 0xFF;
0228
0229 err = spi_write(data->spi, data->buf, 2);
0230 mutex_unlock(&data->lock);
0231
0232 return err;
0233 }
0234
0235 static const struct iio_info mcp4131_info = {
0236 .read_raw = mcp4131_read_raw,
0237 .write_raw = mcp4131_write_raw,
0238 };
0239
0240 static int mcp4131_probe(struct spi_device *spi)
0241 {
0242 int err;
0243 struct device *dev = &spi->dev;
0244 unsigned long devid;
0245 struct mcp4131_data *data;
0246 struct iio_dev *indio_dev;
0247
0248 indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
0249 if (!indio_dev)
0250 return -ENOMEM;
0251
0252 data = iio_priv(indio_dev);
0253 spi_set_drvdata(spi, indio_dev);
0254 data->spi = spi;
0255 data->cfg = device_get_match_data(&spi->dev);
0256 if (!data->cfg) {
0257 devid = spi_get_device_id(spi)->driver_data;
0258 data->cfg = &mcp4131_cfg[devid];
0259 }
0260
0261 mutex_init(&data->lock);
0262
0263 indio_dev->info = &mcp4131_info;
0264 indio_dev->channels = mcp4131_channels;
0265 indio_dev->num_channels = data->cfg->wipers;
0266 indio_dev->name = spi_get_device_id(spi)->name;
0267
0268 err = devm_iio_device_register(dev, indio_dev);
0269 if (err) {
0270 dev_info(&spi->dev, "Unable to register %s\n", indio_dev->name);
0271 return err;
0272 }
0273
0274 return 0;
0275 }
0276
0277 static const struct of_device_id mcp4131_dt_ids[] = {
0278 { .compatible = "microchip,mcp4131-502",
0279 .data = &mcp4131_cfg[MCP413x_502] },
0280 { .compatible = "microchip,mcp4131-103",
0281 .data = &mcp4131_cfg[MCP413x_103] },
0282 { .compatible = "microchip,mcp4131-503",
0283 .data = &mcp4131_cfg[MCP413x_503] },
0284 { .compatible = "microchip,mcp4131-104",
0285 .data = &mcp4131_cfg[MCP413x_104] },
0286 { .compatible = "microchip,mcp4132-502",
0287 .data = &mcp4131_cfg[MCP413x_502] },
0288 { .compatible = "microchip,mcp4132-103",
0289 .data = &mcp4131_cfg[MCP413x_103] },
0290 { .compatible = "microchip,mcp4132-503",
0291 .data = &mcp4131_cfg[MCP413x_503] },
0292 { .compatible = "microchip,mcp4132-104",
0293 .data = &mcp4131_cfg[MCP413x_104] },
0294 { .compatible = "microchip,mcp4141-502",
0295 .data = &mcp4131_cfg[MCP414x_502] },
0296 { .compatible = "microchip,mcp4141-103",
0297 .data = &mcp4131_cfg[MCP414x_103] },
0298 { .compatible = "microchip,mcp4141-503",
0299 .data = &mcp4131_cfg[MCP414x_503] },
0300 { .compatible = "microchip,mcp4141-104",
0301 .data = &mcp4131_cfg[MCP414x_104] },
0302 { .compatible = "microchip,mcp4142-502",
0303 .data = &mcp4131_cfg[MCP414x_502] },
0304 { .compatible = "microchip,mcp4142-103",
0305 .data = &mcp4131_cfg[MCP414x_103] },
0306 { .compatible = "microchip,mcp4142-503",
0307 .data = &mcp4131_cfg[MCP414x_503] },
0308 { .compatible = "microchip,mcp4142-104",
0309 .data = &mcp4131_cfg[MCP414x_104] },
0310 { .compatible = "microchip,mcp4151-502",
0311 .data = &mcp4131_cfg[MCP415x_502] },
0312 { .compatible = "microchip,mcp4151-103",
0313 .data = &mcp4131_cfg[MCP415x_103] },
0314 { .compatible = "microchip,mcp4151-503",
0315 .data = &mcp4131_cfg[MCP415x_503] },
0316 { .compatible = "microchip,mcp4151-104",
0317 .data = &mcp4131_cfg[MCP415x_104] },
0318 { .compatible = "microchip,mcp4152-502",
0319 .data = &mcp4131_cfg[MCP415x_502] },
0320 { .compatible = "microchip,mcp4152-103",
0321 .data = &mcp4131_cfg[MCP415x_103] },
0322 { .compatible = "microchip,mcp4152-503",
0323 .data = &mcp4131_cfg[MCP415x_503] },
0324 { .compatible = "microchip,mcp4152-104",
0325 .data = &mcp4131_cfg[MCP415x_104] },
0326 { .compatible = "microchip,mcp4161-502",
0327 .data = &mcp4131_cfg[MCP416x_502] },
0328 { .compatible = "microchip,mcp4161-103",
0329 .data = &mcp4131_cfg[MCP416x_103] },
0330 { .compatible = "microchip,mcp4161-503",
0331 .data = &mcp4131_cfg[MCP416x_503] },
0332 { .compatible = "microchip,mcp4161-104",
0333 .data = &mcp4131_cfg[MCP416x_104] },
0334 { .compatible = "microchip,mcp4162-502",
0335 .data = &mcp4131_cfg[MCP416x_502] },
0336 { .compatible = "microchip,mcp4162-103",
0337 .data = &mcp4131_cfg[MCP416x_103] },
0338 { .compatible = "microchip,mcp4162-503",
0339 .data = &mcp4131_cfg[MCP416x_503] },
0340 { .compatible = "microchip,mcp4162-104",
0341 .data = &mcp4131_cfg[MCP416x_104] },
0342 { .compatible = "microchip,mcp4231-502",
0343 .data = &mcp4131_cfg[MCP423x_502] },
0344 { .compatible = "microchip,mcp4231-103",
0345 .data = &mcp4131_cfg[MCP423x_103] },
0346 { .compatible = "microchip,mcp4231-503",
0347 .data = &mcp4131_cfg[MCP423x_503] },
0348 { .compatible = "microchip,mcp4231-104",
0349 .data = &mcp4131_cfg[MCP423x_104] },
0350 { .compatible = "microchip,mcp4232-502",
0351 .data = &mcp4131_cfg[MCP423x_502] },
0352 { .compatible = "microchip,mcp4232-103",
0353 .data = &mcp4131_cfg[MCP423x_103] },
0354 { .compatible = "microchip,mcp4232-503",
0355 .data = &mcp4131_cfg[MCP423x_503] },
0356 { .compatible = "microchip,mcp4232-104",
0357 .data = &mcp4131_cfg[MCP423x_104] },
0358 { .compatible = "microchip,mcp4241-502",
0359 .data = &mcp4131_cfg[MCP424x_502] },
0360 { .compatible = "microchip,mcp4241-103",
0361 .data = &mcp4131_cfg[MCP424x_103] },
0362 { .compatible = "microchip,mcp4241-503",
0363 .data = &mcp4131_cfg[MCP424x_503] },
0364 { .compatible = "microchip,mcp4241-104",
0365 .data = &mcp4131_cfg[MCP424x_104] },
0366 { .compatible = "microchip,mcp4242-502",
0367 .data = &mcp4131_cfg[MCP424x_502] },
0368 { .compatible = "microchip,mcp4242-103",
0369 .data = &mcp4131_cfg[MCP424x_103] },
0370 { .compatible = "microchip,mcp4242-503",
0371 .data = &mcp4131_cfg[MCP424x_503] },
0372 { .compatible = "microchip,mcp4242-104",
0373 .data = &mcp4131_cfg[MCP424x_104] },
0374 { .compatible = "microchip,mcp4251-502",
0375 .data = &mcp4131_cfg[MCP425x_502] },
0376 { .compatible = "microchip,mcp4251-103",
0377 .data = &mcp4131_cfg[MCP425x_103] },
0378 { .compatible = "microchip,mcp4251-503",
0379 .data = &mcp4131_cfg[MCP425x_503] },
0380 { .compatible = "microchip,mcp4251-104",
0381 .data = &mcp4131_cfg[MCP425x_104] },
0382 { .compatible = "microchip,mcp4252-502",
0383 .data = &mcp4131_cfg[MCP425x_502] },
0384 { .compatible = "microchip,mcp4252-103",
0385 .data = &mcp4131_cfg[MCP425x_103] },
0386 { .compatible = "microchip,mcp4252-503",
0387 .data = &mcp4131_cfg[MCP425x_503] },
0388 { .compatible = "microchip,mcp4252-104",
0389 .data = &mcp4131_cfg[MCP425x_104] },
0390 { .compatible = "microchip,mcp4261-502",
0391 .data = &mcp4131_cfg[MCP426x_502] },
0392 { .compatible = "microchip,mcp4261-103",
0393 .data = &mcp4131_cfg[MCP426x_103] },
0394 { .compatible = "microchip,mcp4261-503",
0395 .data = &mcp4131_cfg[MCP426x_503] },
0396 { .compatible = "microchip,mcp4261-104",
0397 .data = &mcp4131_cfg[MCP426x_104] },
0398 { .compatible = "microchip,mcp4262-502",
0399 .data = &mcp4131_cfg[MCP426x_502] },
0400 { .compatible = "microchip,mcp4262-103",
0401 .data = &mcp4131_cfg[MCP426x_103] },
0402 { .compatible = "microchip,mcp4262-503",
0403 .data = &mcp4131_cfg[MCP426x_503] },
0404 { .compatible = "microchip,mcp4262-104",
0405 .data = &mcp4131_cfg[MCP426x_104] },
0406 {}
0407 };
0408 MODULE_DEVICE_TABLE(of, mcp4131_dt_ids);
0409
0410 static const struct spi_device_id mcp4131_id[] = {
0411 { "mcp4131-502", MCP413x_502 },
0412 { "mcp4131-103", MCP413x_103 },
0413 { "mcp4131-503", MCP413x_503 },
0414 { "mcp4131-104", MCP413x_104 },
0415 { "mcp4132-502", MCP413x_502 },
0416 { "mcp4132-103", MCP413x_103 },
0417 { "mcp4132-503", MCP413x_503 },
0418 { "mcp4132-104", MCP413x_104 },
0419 { "mcp4141-502", MCP414x_502 },
0420 { "mcp4141-103", MCP414x_103 },
0421 { "mcp4141-503", MCP414x_503 },
0422 { "mcp4141-104", MCP414x_104 },
0423 { "mcp4142-502", MCP414x_502 },
0424 { "mcp4142-103", MCP414x_103 },
0425 { "mcp4142-503", MCP414x_503 },
0426 { "mcp4142-104", MCP414x_104 },
0427 { "mcp4151-502", MCP415x_502 },
0428 { "mcp4151-103", MCP415x_103 },
0429 { "mcp4151-503", MCP415x_503 },
0430 { "mcp4151-104", MCP415x_104 },
0431 { "mcp4152-502", MCP415x_502 },
0432 { "mcp4152-103", MCP415x_103 },
0433 { "mcp4152-503", MCP415x_503 },
0434 { "mcp4152-104", MCP415x_104 },
0435 { "mcp4161-502", MCP416x_502 },
0436 { "mcp4161-103", MCP416x_103 },
0437 { "mcp4161-503", MCP416x_503 },
0438 { "mcp4161-104", MCP416x_104 },
0439 { "mcp4162-502", MCP416x_502 },
0440 { "mcp4162-103", MCP416x_103 },
0441 { "mcp4162-503", MCP416x_503 },
0442 { "mcp4162-104", MCP416x_104 },
0443 { "mcp4231-502", MCP423x_502 },
0444 { "mcp4231-103", MCP423x_103 },
0445 { "mcp4231-503", MCP423x_503 },
0446 { "mcp4231-104", MCP423x_104 },
0447 { "mcp4232-502", MCP423x_502 },
0448 { "mcp4232-103", MCP423x_103 },
0449 { "mcp4232-503", MCP423x_503 },
0450 { "mcp4232-104", MCP423x_104 },
0451 { "mcp4241-502", MCP424x_502 },
0452 { "mcp4241-103", MCP424x_103 },
0453 { "mcp4241-503", MCP424x_503 },
0454 { "mcp4241-104", MCP424x_104 },
0455 { "mcp4242-502", MCP424x_502 },
0456 { "mcp4242-103", MCP424x_103 },
0457 { "mcp4242-503", MCP424x_503 },
0458 { "mcp4242-104", MCP424x_104 },
0459 { "mcp4251-502", MCP425x_502 },
0460 { "mcp4251-103", MCP425x_103 },
0461 { "mcp4251-503", MCP425x_503 },
0462 { "mcp4251-104", MCP425x_104 },
0463 { "mcp4252-502", MCP425x_502 },
0464 { "mcp4252-103", MCP425x_103 },
0465 { "mcp4252-503", MCP425x_503 },
0466 { "mcp4252-104", MCP425x_104 },
0467 { "mcp4261-502", MCP426x_502 },
0468 { "mcp4261-103", MCP426x_103 },
0469 { "mcp4261-503", MCP426x_503 },
0470 { "mcp4261-104", MCP426x_104 },
0471 { "mcp4262-502", MCP426x_502 },
0472 { "mcp4262-103", MCP426x_103 },
0473 { "mcp4262-503", MCP426x_503 },
0474 { "mcp4262-104", MCP426x_104 },
0475 {}
0476 };
0477 MODULE_DEVICE_TABLE(spi, mcp4131_id);
0478
0479 static struct spi_driver mcp4131_driver = {
0480 .driver = {
0481 .name = "mcp4131",
0482 .of_match_table = mcp4131_dt_ids,
0483 },
0484 .probe = mcp4131_probe,
0485 .id_table = mcp4131_id,
0486 };
0487
0488 module_spi_driver(mcp4131_driver);
0489
0490 MODULE_AUTHOR("Slawomir Stepien <sst@poczta.fm>");
0491 MODULE_DESCRIPTION("MCP4131 digital potentiometer");
0492 MODULE_LICENSE("GPL v2");