brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · b40e5ac Raw
195 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Maxim Integrated MAX5481-MAX5484 digital potentiometer driver4 * Copyright 2016 Rockwell Collins5 *6 * Datasheet:7 * https://datasheets.maximintegrated.com/en/ds/MAX5481-MAX5484.pdf8 */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    102325 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");195