^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * max5487.c - Support for MAX5487, MAX5488, MAX5489 digital potentiometers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/spi/spi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/iio/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/iio/iio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define MAX5487_WRITE_WIPER_A (0x01 << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define MAX5487_WRITE_WIPER_B (0x02 << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /* copy both wiper regs to NV regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define MAX5487_COPY_AB_TO_NV (0x23 << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /* copy both NV regs to wiper regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define MAX5487_COPY_NV_TO_AB (0x33 << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define MAX5487_MAX_POS 255
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct max5487_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct spi_device *spi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) int kohms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define MAX5487_CHANNEL(ch, addr) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) .type = IIO_RESISTANCE, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) .indexed = 1, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) .output = 1, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) .channel = ch, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) .address = addr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static const struct iio_chan_spec max5487_channels[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) MAX5487_CHANNEL(0, MAX5487_WRITE_WIPER_A),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) MAX5487_CHANNEL(1, MAX5487_WRITE_WIPER_B),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static int max5487_write_cmd(struct spi_device *spi, u16 cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return spi_write(spi, (const void *) &cmd, sizeof(u16));
^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 int max5487_read_raw(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int *val, int *val2, long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct max5487_data *data = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (mask != IIO_CHAN_INFO_SCALE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) *val = 1000 * data->kohms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) *val2 = MAX5487_MAX_POS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return IIO_VAL_FRACTIONAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int max5487_write_raw(struct iio_dev *indio_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct iio_chan_spec const *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) int val, int val2, long mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct max5487_data *data = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (mask != IIO_CHAN_INFO_RAW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (val < 0 || val > MAX5487_MAX_POS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return max5487_write_cmd(data->spi, chan->address | val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static const struct iio_info max5487_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .read_raw = max5487_read_raw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .write_raw = max5487_write_raw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int max5487_spi_probe(struct spi_device *spi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct iio_dev *indio_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct max5487_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) const struct spi_device_id *id = spi_get_device_id(spi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (!indio_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) dev_set_drvdata(&spi->dev, indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) data = iio_priv(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) data->spi = spi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) data->kohms = id->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) indio_dev->info = &max5487_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) indio_dev->name = id->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) indio_dev->modes = INDIO_DIRECT_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) indio_dev->channels = max5487_channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) indio_dev->num_channels = ARRAY_SIZE(max5487_channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* restore both wiper regs from NV regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ret = max5487_write_cmd(data->spi, MAX5487_COPY_NV_TO_AB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return iio_device_register(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static int max5487_spi_remove(struct spi_device *spi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) iio_device_unregister(indio_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* save both wiper regs to NV regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return max5487_write_cmd(spi, MAX5487_COPY_AB_TO_NV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static const struct spi_device_id max5487_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) { "MAX5487", 10 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) { "MAX5488", 50 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) { "MAX5489", 100 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) MODULE_DEVICE_TABLE(spi, max5487_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static const struct acpi_device_id max5487_acpi_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) { "MAX5487", 10 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) { "MAX5488", 50 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) { "MAX5489", 100 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) MODULE_DEVICE_TABLE(acpi, max5487_acpi_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static struct spi_driver max5487_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .name = "max5487",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) .acpi_match_table = ACPI_PTR(max5487_acpi_match),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .id_table = max5487_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) .probe = max5487_spi_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .remove = max5487_spi_remove
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) module_spi_driver(max5487_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) MODULE_AUTHOR("Cristina-Gabriela Moraru <cristina.moraru09@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) MODULE_DESCRIPTION("max5487 SPI driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) MODULE_LICENSE("GPL v2");