Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: max5481: Add support for Maxim digital potentiometers

Add implementation for Maxim Integrated 5481, 5482, 5483,
and 5484 digital potentiometer devices.

Datasheet:
http://datasheets.maximintegrated.com/en/ds/MAX5481-MAX5484.pdf

Signed-off-by: Maury Anderson <maury.anderson@rockwellcollins.com>
Signed-off-by: Matthew Weber <matthew.weber@rockwellcollins.com>
Signed-off-by: Slawomir Stepien <sst@poczta.fm>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>

authored by

Matt Weber and committed by
Jonathan Cameron
df1fd2de ba34b3a2

+258
+23
Documentation/devicetree/bindings/iio/potentiometer/max5481.txt
··· 1 + * Maxim Linear-Taper Digital Potentiometer MAX5481-MAX5484 2 + 3 + The node for this driver must be a child node of a SPI controller, hence 4 + all mandatory properties described in 5 + 6 + Documentation/devicetree/bindings/spi/spi-bus.txt 7 + 8 + must be specified. 9 + 10 + Required properties: 11 + - compatible: Must be one of the following, depending on the 12 + model: 13 + "maxim,max5481" 14 + "maxim,max5482" 15 + "maxim,max5483" 16 + "maxim,max5484" 17 + 18 + Example: 19 + max548x: max548x@0 { 20 + compatible = "maxim,max5482"; 21 + spi-max-frequency = <7000000>; 22 + reg = <0>; /* chip-select */ 23 + };
+11
drivers/iio/potentiometer/Kconfig
··· 15 15 To compile this driver as a module, choose M here: the 16 16 module will be called ds1803. 17 17 18 + config MAX5481 19 + tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver" 20 + depends on SPI 21 + help 22 + Say yes here to build support for the Maxim 23 + MAX5481, MAX5482, MAX5483, MAX5484 digital potentiometer 24 + chips. 25 + 26 + To compile this driver as a module, choose M here: the 27 + module will be called max5481. 28 + 18 29 config MAX5487 19 30 tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver" 20 31 depends on SPI
+1
drivers/iio/potentiometer/Makefile
··· 4 4 5 5 # When adding new entries keep the list in alphabetical order 6 6 obj-$(CONFIG_DS1803) += ds1803.o 7 + obj-$(CONFIG_MAX5481) += max5481.o 7 8 obj-$(CONFIG_MAX5487) += max5487.o 8 9 obj-$(CONFIG_MCP4131) += mcp4131.o 9 10 obj-$(CONFIG_MCP4531) += mcp4531.o
+223
drivers/iio/potentiometer/max5481.c
··· 1 + /* 2 + * Maxim Integrated MAX5481-MAX5484 digital potentiometer driver 3 + * Copyright 2016 Rockwell Collins 4 + * 5 + * Datasheet: 6 + * http://datasheets.maximintegrated.com/en/ds/MAX5481-MAX5484.pdf 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the gnu general public license version 2 as 10 + * published by the free software foundation. 11 + * 12 + */ 13 + 14 + #include <linux/acpi.h> 15 + #include <linux/iio/iio.h> 16 + #include <linux/iio/sysfs.h> 17 + #include <linux/module.h> 18 + #include <linux/of.h> 19 + #include <linux/of_device.h> 20 + #include <linux/spi/spi.h> 21 + 22 + /* write wiper reg */ 23 + #define MAX5481_WRITE_WIPER (0 << 4) 24 + /* copy wiper reg to NV reg */ 25 + #define MAX5481_COPY_AB_TO_NV (2 << 4) 26 + /* copy NV reg to wiper reg */ 27 + #define MAX5481_COPY_NV_TO_AB (3 << 4) 28 + 29 + #define MAX5481_MAX_POS 1023 30 + 31 + enum max5481_variant { 32 + max5481, 33 + max5482, 34 + max5483, 35 + max5484, 36 + }; 37 + 38 + struct max5481_cfg { 39 + int kohms; 40 + }; 41 + 42 + static const struct max5481_cfg max5481_cfg[] = { 43 + [max5481] = { .kohms = 10, }, 44 + [max5482] = { .kohms = 50, }, 45 + [max5483] = { .kohms = 10, }, 46 + [max5484] = { .kohms = 50, }, 47 + }; 48 + 49 + struct max5481_data { 50 + struct spi_device *spi; 51 + const struct max5481_cfg *cfg; 52 + u8 msg[3] ____cacheline_aligned; 53 + }; 54 + 55 + #define MAX5481_CHANNEL { \ 56 + .type = IIO_RESISTANCE, \ 57 + .indexed = 1, \ 58 + .output = 1, \ 59 + .channel = 0, \ 60 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 61 + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 62 + } 63 + 64 + static const struct iio_chan_spec max5481_channels[] = { 65 + MAX5481_CHANNEL, 66 + }; 67 + 68 + static int max5481_write_cmd(struct max5481_data *data, u8 cmd, u16 val) 69 + { 70 + struct spi_device *spi = data->spi; 71 + 72 + data->msg[0] = cmd; 73 + 74 + switch (cmd) { 75 + case MAX5481_WRITE_WIPER: 76 + data->msg[1] = val >> 2; 77 + data->msg[2] = (val & 0x3) << 6; 78 + return spi_write(spi, data->msg, 3); 79 + 80 + case MAX5481_COPY_AB_TO_NV: 81 + case MAX5481_COPY_NV_TO_AB: 82 + return spi_write(spi, data->msg, 1); 83 + 84 + default: 85 + return -EIO; 86 + } 87 + } 88 + 89 + static int max5481_read_raw(struct iio_dev *indio_dev, 90 + struct iio_chan_spec const *chan, 91 + int *val, int *val2, long mask) 92 + { 93 + struct max5481_data *data = iio_priv(indio_dev); 94 + 95 + if (mask != IIO_CHAN_INFO_SCALE) 96 + return -EINVAL; 97 + 98 + *val = 1000 * data->cfg->kohms; 99 + *val2 = MAX5481_MAX_POS; 100 + 101 + return IIO_VAL_FRACTIONAL; 102 + } 103 + 104 + static int max5481_write_raw(struct iio_dev *indio_dev, 105 + struct iio_chan_spec const *chan, 106 + int val, int val2, long mask) 107 + { 108 + struct max5481_data *data = iio_priv(indio_dev); 109 + 110 + if (mask != IIO_CHAN_INFO_RAW) 111 + return -EINVAL; 112 + 113 + if (val < 0 || val > MAX5481_MAX_POS) 114 + return -EINVAL; 115 + 116 + return max5481_write_cmd(data, MAX5481_WRITE_WIPER, val); 117 + } 118 + 119 + static const struct iio_info max5481_info = { 120 + .read_raw = max5481_read_raw, 121 + .write_raw = max5481_write_raw, 122 + .driver_module = THIS_MODULE, 123 + }; 124 + 125 + #if defined(CONFIG_OF) 126 + static const struct of_device_id max5481_match[] = { 127 + { .compatible = "maxim,max5481", .data = &max5481_cfg[max5481] }, 128 + { .compatible = "maxim,max5482", .data = &max5481_cfg[max5482] }, 129 + { .compatible = "maxim,max5483", .data = &max5481_cfg[max5483] }, 130 + { .compatible = "maxim,max5484", .data = &max5481_cfg[max5484] }, 131 + { } 132 + }; 133 + MODULE_DEVICE_TABLE(of, max5481_match); 134 + #endif 135 + 136 + static int max5481_probe(struct spi_device *spi) 137 + { 138 + struct iio_dev *indio_dev; 139 + struct max5481_data *data; 140 + const struct spi_device_id *id = spi_get_device_id(spi); 141 + const struct of_device_id *match; 142 + int ret; 143 + 144 + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data)); 145 + if (!indio_dev) 146 + return -ENOMEM; 147 + 148 + dev_set_drvdata(&spi->dev, indio_dev); 149 + data = iio_priv(indio_dev); 150 + 151 + data->spi = spi; 152 + 153 + match = of_match_device(of_match_ptr(max5481_match), &spi->dev); 154 + if (match) 155 + data->cfg = of_device_get_match_data(&spi->dev); 156 + else 157 + data->cfg = &max5481_cfg[id->driver_data]; 158 + 159 + indio_dev->name = id->name; 160 + indio_dev->dev.parent = &spi->dev; 161 + indio_dev->modes = INDIO_DIRECT_MODE; 162 + 163 + /* variant specific configuration */ 164 + indio_dev->info = &max5481_info; 165 + indio_dev->channels = max5481_channels; 166 + indio_dev->num_channels = ARRAY_SIZE(max5481_channels); 167 + 168 + /* restore wiper from NV */ 169 + ret = max5481_write_cmd(data, MAX5481_COPY_NV_TO_AB, 0); 170 + if (ret < 0) 171 + return ret; 172 + 173 + return iio_device_register(indio_dev); 174 + } 175 + 176 + static int max5481_remove(struct spi_device *spi) 177 + { 178 + struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev); 179 + struct max5481_data *data = iio_priv(indio_dev); 180 + 181 + iio_device_unregister(indio_dev); 182 + 183 + /* save wiper reg to NV reg */ 184 + return max5481_write_cmd(data, MAX5481_COPY_AB_TO_NV, 0); 185 + } 186 + 187 + static const struct spi_device_id max5481_id_table[] = { 188 + { "max5481", max5481 }, 189 + { "max5482", max5482 }, 190 + { "max5483", max5483 }, 191 + { "max5484", max5484 }, 192 + { } 193 + }; 194 + MODULE_DEVICE_TABLE(spi, max5481_id_table); 195 + 196 + #if defined(CONFIG_ACPI) 197 + static const struct acpi_device_id max5481_acpi_match[] = { 198 + { "max5481", max5481 }, 199 + { "max5482", max5482 }, 200 + { "max5483", max5483 }, 201 + { "max5484", max5484 }, 202 + { } 203 + }; 204 + MODULE_DEVICE_TABLE(acpi, max5481_acpi_match); 205 + #endif 206 + 207 + static struct spi_driver max5481_driver = { 208 + .driver = { 209 + .name = "max5481", 210 + .owner = THIS_MODULE, 211 + .of_match_table = of_match_ptr(max5481_match), 212 + .acpi_match_table = ACPI_PTR(max5481_acpi_match), 213 + }, 214 + .probe = max5481_probe, 215 + .remove = max5481_remove, 216 + .id_table = max5481_id_table, 217 + }; 218 + 219 + module_spi_driver(max5481_driver); 220 + 221 + MODULE_AUTHOR("Maury Anderson <maury.anderson@rockwellcollins.com>"); 222 + MODULE_DESCRIPTION("max5481 SPI driver"); 223 + MODULE_LICENSE("GPL v2");