File Index
Files and directories
Sign in
FILE

max5481.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/potentiometer/max5481.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Maxim Integrated MAX5481-MAX5484 digital potentiometer driver
  4 * Copyright 2016 Rockwell Collins
  5 *
  6 * Datasheet:
  7 * https://datasheets.maximintegrated.com/en/ds/MAX5481-MAX5484.pdf
  8 */
  9
 10#include <linux/iio/iio.h>
 11#include <linux/iio/sysfs.h>
 12#include <linux/module.h>
 13#include <linux/mod_devicetable.h>
 14#include <linux/property.h>
 15#include <linux/spi/spi.h>
 16
 17/* write wiper reg */
 18#define MAX5481_WRITE_WIPER (0 << 4)
 19/* copy wiper reg to NV reg */
 20#define MAX5481_COPY_AB_TO_NV (2 << 4)
 21/* copy NV reg to wiper reg */
 22#define MAX5481_COPY_NV_TO_AB (3 << 4)
 23
 24#define MAX5481_MAX_POS    1023
 25
 26enum max5481_variant {
 27	max5481,
 28	max5482,
 29	max5483,
 30	max5484,
 31};
 32
 33struct max5481_cfg {
 34	int kohms;
 35};
 36
 37static const struct max5481_cfg max5481_cfg[] = {
 38	[max5481] = { .kohms =  10, },
 39	[max5482] = { .kohms =  50, },
 40	[max5483] = { .kohms =  10, },
 41	[max5484] = { .kohms =  50, },
 42};
 43
 44struct max5481_data {
 45	struct spi_device *spi;
 46	const struct max5481_cfg *cfg;
 47	u8 msg[3] __aligned(IIO_DMA_MINALIGN);
 48};
 49
 50#define MAX5481_CHANNEL {					\
 51	.type = IIO_RESISTANCE,					\
 52	.indexed = 1,						\
 53	.output = 1,						\
 54	.channel = 0,						\
 55	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
 56	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
 57}
 58
 59static const struct iio_chan_spec max5481_channels[] = {
 60	MAX5481_CHANNEL,
 61};
 62
 63static int max5481_write_cmd(struct max5481_data *data, u8 cmd, u16 val)
 64{
 65	struct spi_device *spi = data->spi;
 66
 67	data->msg[0] = cmd;
 68
 69	switch (cmd) {
 70	case MAX5481_WRITE_WIPER:
 71		data->msg[1] = val >> 2;
 72		data->msg[2] = (val & 0x3) << 6;
 73		return spi_write(spi, data->msg, 3);
 74
 75	case MAX5481_COPY_AB_TO_NV:
 76	case MAX5481_COPY_NV_TO_AB:
 77		return spi_write(spi, data->msg, 1);
 78
 79	default:
 80		return -EIO;
 81	}
 82}
 83
 84static int max5481_read_raw(struct iio_dev *indio_dev,
 85		struct iio_chan_spec const *chan,
 86		int *val, int *val2, long mask)
 87{
 88	struct max5481_data *data = iio_priv(indio_dev);
 89
 90	if (mask != IIO_CHAN_INFO_SCALE)
 91		return -EINVAL;
 92
 93	*val = 1000 * data->cfg->kohms;
 94	*val2 = MAX5481_MAX_POS;
 95
 96	return IIO_VAL_FRACTIONAL;
 97}
 98
 99static int max5481_write_raw(struct iio_dev *indio_dev,
100		struct iio_chan_spec const *chan,
101		int val, int val2, long mask)
102{
103	struct max5481_data *data = iio_priv(indio_dev);
104
105	if (mask != IIO_CHAN_INFO_RAW)
106		return -EINVAL;
107
108	if (val < 0 || val > MAX5481_MAX_POS)
109		return -EINVAL;
110
111	return max5481_write_cmd(data, MAX5481_WRITE_WIPER, val);
112}
113
114static const struct iio_info max5481_info = {
115	.read_raw = max5481_read_raw,
116	.write_raw = max5481_write_raw,
117};
118
119static const struct of_device_id max5481_match[] = {
120	{ .compatible = "maxim,max5481", .data = &max5481_cfg[max5481] },
121	{ .compatible = "maxim,max5482", .data = &max5481_cfg[max5482] },
122	{ .compatible = "maxim,max5483", .data = &max5481_cfg[max5483] },
123	{ .compatible = "maxim,max5484", .data = &max5481_cfg[max5484] },
124	{ }
125};
126MODULE_DEVICE_TABLE(of, max5481_match);
127
128static void max5481_wiper_save(void *data)
129{
130	max5481_write_cmd(data, MAX5481_COPY_AB_TO_NV, 0);
131}
132
133static int max5481_probe(struct spi_device *spi)
134{
135	struct iio_dev *indio_dev;
136	struct max5481_data *data;
137	const struct spi_device_id *id = spi_get_device_id(spi);
138	int ret;
139
140	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
141	if (!indio_dev)
142		return -ENOMEM;
143
144	data = iio_priv(indio_dev);
145
146	data->spi = spi;
147
148	data->cfg = device_get_match_data(&spi->dev);
149	if (!data->cfg)
150		data->cfg = &max5481_cfg[id->driver_data];
151
152	indio_dev->name = id->name;
153	indio_dev->modes = INDIO_DIRECT_MODE;
154
155	/* variant specific configuration */
156	indio_dev->info = &max5481_info;
157	indio_dev->channels = max5481_channels;
158	indio_dev->num_channels = ARRAY_SIZE(max5481_channels);
159
160	/* restore wiper from NV */
161	ret = max5481_write_cmd(data, MAX5481_COPY_NV_TO_AB, 0);
162	if (ret < 0)
163		return ret;
164
165	ret = devm_add_action(&spi->dev, max5481_wiper_save, data);
166	if (ret < 0)
167		return ret;
168
169	return devm_iio_device_register(&spi->dev, indio_dev);
170}
171
172static const struct spi_device_id max5481_id_table[] = {
173	{ "max5481", max5481 },
174	{ "max5482", max5482 },
175	{ "max5483", max5483 },
176	{ "max5484", max5484 },
177	{ }
178};
179MODULE_DEVICE_TABLE(spi, max5481_id_table);
180
181static struct spi_driver max5481_driver = {
182	.driver = {
183		.name  = "max5481",
184		.of_match_table = max5481_match,
185	},
186	.probe = max5481_probe,
187	.id_table = max5481_id_table,
188};
189
190module_spi_driver(max5481_driver);
191
192MODULE_AUTHOR("Maury Anderson <maury.anderson@rockwellcollins.com>");
193MODULE_DESCRIPTION("max5481 SPI driver");
194MODULE_LICENSE("GPL v2");
~/ Read-only file preview.