File Index
Files and directories
Sign in
FILE

x9250.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/potentiometer/x9250.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *
  4 * x9250.c  --  Renesas X9250 potentiometers IIO driver
  5 *
  6 * Copyright 2023 CS GROUP France
  7 *
  8 * Author: Herve Codina <herve.codina@bootlin.com>
  9 */
 10
 11#include <linux/delay.h>
 12#include <linux/gpio/consumer.h>
 13#include <linux/iio/iio.h>
 14#include <linux/limits.h>
 15#include <linux/module.h>
 16#include <linux/regulator/consumer.h>
 17#include <linux/slab.h>
 18#include <linux/spi/spi.h>
 19
 20struct x9250_cfg {
 21	const char *name;
 22	int kohms;
 23};
 24
 25struct x9250 {
 26	struct spi_device *spi;
 27	const struct x9250_cfg *cfg;
 28	struct gpio_desc *wp_gpio;
 29};
 30
 31#define X9250_ID		0x50
 32#define X9250_CMD_RD_WCR(_p)    (0x90 | (_p))
 33#define X9250_CMD_WR_WCR(_p)    (0xa0 | (_p))
 34
 35static int x9250_write8(struct x9250 *x9250, u8 cmd, u8 val)
 36{
 37	u8 txbuf[3];
 38
 39	txbuf[0] = X9250_ID;
 40	txbuf[1] = cmd;
 41	txbuf[2] = val;
 42
 43	return spi_write_then_read(x9250->spi, txbuf, ARRAY_SIZE(txbuf), NULL, 0);
 44}
 45
 46static int x9250_read8(struct x9250 *x9250, u8 cmd, u8 *val)
 47{
 48	u8 txbuf[2];
 49
 50	txbuf[0] = X9250_ID;
 51	txbuf[1] = cmd;
 52
 53	return spi_write_then_read(x9250->spi, txbuf, ARRAY_SIZE(txbuf), val, 1);
 54}
 55
 56#define X9250_CHANNEL(ch) {						\
 57	.type = IIO_RESISTANCE,						\
 58	.indexed = 1,							\
 59	.output = 1,							\
 60	.channel = (ch),						\
 61	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\
 62	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\
 63	.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_RAW),	\
 64}
 65
 66static const struct iio_chan_spec x9250_channels[] = {
 67	X9250_CHANNEL(0),
 68	X9250_CHANNEL(1),
 69	X9250_CHANNEL(2),
 70	X9250_CHANNEL(3),
 71};
 72
 73static int x9250_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
 74			  int *val, int *val2, long mask)
 75{
 76	struct x9250 *x9250 = iio_priv(indio_dev);
 77	int ch = chan->channel;
 78	int ret;
 79	u8 v;
 80
 81	switch (mask) {
 82	case IIO_CHAN_INFO_RAW:
 83		ret = x9250_read8(x9250, X9250_CMD_RD_WCR(ch), &v);
 84		if (ret)
 85			return ret;
 86		*val = v;
 87		return IIO_VAL_INT;
 88
 89	case IIO_CHAN_INFO_SCALE:
 90		*val = 1000 * x9250->cfg->kohms;
 91		*val2 = U8_MAX;
 92		return IIO_VAL_FRACTIONAL;
 93	}
 94
 95	return -EINVAL;
 96}
 97
 98static int x9250_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
 99			    const int **vals, int *type, int *length, long mask)
100{
101	static const int range[] = {0, 1, 255}; /* min, step, max */
102
103	switch (mask) {
104	case IIO_CHAN_INFO_RAW:
105		*length = ARRAY_SIZE(range);
106		*vals = range;
107		*type = IIO_VAL_INT;
108		return IIO_AVAIL_RANGE;
109	}
110
111	return -EINVAL;
112}
113
114static int x9250_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
115			   int val, int val2, long mask)
116{
117	struct x9250 *x9250 = iio_priv(indio_dev);
118	int ch = chan->channel;
119	int ret;
120
121	if (mask != IIO_CHAN_INFO_RAW)
122		return -EINVAL;
123
124	if (val > U8_MAX || val < 0)
125		return -EINVAL;
126
127	gpiod_set_value_cansleep(x9250->wp_gpio, 0);
128	ret = x9250_write8(x9250, X9250_CMD_WR_WCR(ch), val);
129	gpiod_set_value_cansleep(x9250->wp_gpio, 1);
130
131	return ret;
132}
133
134static const struct iio_info x9250_info = {
135	.read_raw = x9250_read_raw,
136	.read_avail = x9250_read_avail,
137	.write_raw = x9250_write_raw,
138};
139
140enum x9250_type {
141	X9250T,
142	X9250U,
143};
144
145static const struct x9250_cfg x9250_cfg[] = {
146	[X9250T] = { .name = "x9250t", .kohms =  100, },
147	[X9250U] = { .name = "x9250u", .kohms =  50, },
148};
149
150static const char *const x9250_regulator_names[] = {
151	"vcc",
152	"avp",
153	"avn",
154};
155
156static int x9250_probe(struct spi_device *spi)
157{
158	struct iio_dev *indio_dev;
159	struct x9250 *x9250;
160	int ret;
161
162	ret = devm_regulator_bulk_get_enable(&spi->dev, ARRAY_SIZE(x9250_regulator_names),
163					     x9250_regulator_names);
164	if (ret)
165		return dev_err_probe(&spi->dev, ret, "Failed to get regulators\n");
166
167	/*
168	 * The x9250 needs a 5ms maximum delay after the power-supplies are set
169	 * before performing the first write (1ms for the first read).
170	 */
171	usleep_range(5000, 6000);
172
173	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*x9250));
174	if (!indio_dev)
175		return -ENOMEM;
176
177	x9250 = iio_priv(indio_dev);
178	x9250->spi = spi;
179	x9250->cfg = spi_get_device_match_data(spi);
180	x9250->wp_gpio = devm_gpiod_get_optional(&spi->dev, "wp", GPIOD_OUT_LOW);
181	if (IS_ERR(x9250->wp_gpio))
182		return dev_err_probe(&spi->dev, PTR_ERR(x9250->wp_gpio),
183				     "failed to get wp gpio\n");
184
185	indio_dev->info = &x9250_info;
186	indio_dev->channels = x9250_channels;
187	indio_dev->num_channels = ARRAY_SIZE(x9250_channels);
188	indio_dev->name = x9250->cfg->name;
189
190	return devm_iio_device_register(&spi->dev, indio_dev);
191}
192
193static const struct of_device_id x9250_of_match[] = {
194	{ .compatible = "renesas,x9250t", .data = &x9250_cfg[X9250T]},
195	{ .compatible = "renesas,x9250u", .data = &x9250_cfg[X9250U]},
196	{ }
197};
198MODULE_DEVICE_TABLE(of, x9250_of_match);
199
200static const struct spi_device_id x9250_id_table[] = {
201	{ "x9250t", (kernel_ulong_t)&x9250_cfg[X9250T] },
202	{ "x9250u", (kernel_ulong_t)&x9250_cfg[X9250U] },
203	{ }
204};
205MODULE_DEVICE_TABLE(spi, x9250_id_table);
206
207static struct spi_driver x9250_spi_driver = {
208	.driver  = {
209		.name = "x9250",
210		.of_match_table = x9250_of_match,
211	},
212	.id_table = x9250_id_table,
213	.probe  = x9250_probe,
214};
215
216module_spi_driver(x9250_spi_driver);
217
218MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
219MODULE_DESCRIPTION("X9250 ALSA SoC driver");
220MODULE_LICENSE("GPL");
~/ Read-only file preview.