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