xref: /linux/drivers/iio/resolver/ad2s1200.c (revision ad28d315544074a7e9bfa07014263760e57855d2)
1*ad28d315SDavid Veenstra /*
2*ad28d315SDavid Veenstra  * ad2s1200.c simple support for the ADI Resolver to Digital Converters:
3*ad28d315SDavid Veenstra  * AD2S1200/1205
4*ad28d315SDavid Veenstra  *
5*ad28d315SDavid Veenstra  * Copyright (c) 2018-2018 David Veenstra <davidjulianveenstra@gmail.com>
6*ad28d315SDavid Veenstra  * Copyright (c) 2010-2010 Analog Devices Inc.
7*ad28d315SDavid Veenstra  *
8*ad28d315SDavid Veenstra  * This program is free software; you can redistribute it and/or modify
9*ad28d315SDavid Veenstra  * it under the terms of the GNU General Public License version 2 as
10*ad28d315SDavid Veenstra  * published by the Free Software Foundation.
11*ad28d315SDavid Veenstra  */
12*ad28d315SDavid Veenstra 
13*ad28d315SDavid Veenstra #include <linux/bitops.h>
14*ad28d315SDavid Veenstra #include <linux/delay.h>
15*ad28d315SDavid Veenstra #include <linux/device.h>
16*ad28d315SDavid Veenstra #include <linux/gpio.h>
17*ad28d315SDavid Veenstra #include <linux/gpio/consumer.h>
18*ad28d315SDavid Veenstra #include <linux/module.h>
19*ad28d315SDavid Veenstra #include <linux/mutex.h>
20*ad28d315SDavid Veenstra #include <linux/spi/spi.h>
21*ad28d315SDavid Veenstra #include <linux/sysfs.h>
22*ad28d315SDavid Veenstra #include <linux/types.h>
23*ad28d315SDavid Veenstra 
24*ad28d315SDavid Veenstra #include <linux/iio/iio.h>
25*ad28d315SDavid Veenstra #include <linux/iio/sysfs.h>
26*ad28d315SDavid Veenstra 
27*ad28d315SDavid Veenstra #define DRV_NAME "ad2s1200"
28*ad28d315SDavid Veenstra 
29*ad28d315SDavid Veenstra /* input clock on serial interface */
30*ad28d315SDavid Veenstra #define AD2S1200_HZ	8192000
31*ad28d315SDavid Veenstra /* clock period in nano second */
32*ad28d315SDavid Veenstra #define AD2S1200_TSCLK	(1000000000 / AD2S1200_HZ)
33*ad28d315SDavid Veenstra 
34*ad28d315SDavid Veenstra /**
35*ad28d315SDavid Veenstra  * struct ad2s1200_state - driver instance specific data.
36*ad28d315SDavid Veenstra  * @lock:	protects both the GPIO pins and the rx buffer.
37*ad28d315SDavid Veenstra  * @sdev:	spi device.
38*ad28d315SDavid Veenstra  * @sample:	GPIO pin SAMPLE.
39*ad28d315SDavid Veenstra  * @rdvel:	GPIO pin RDVEL.
40*ad28d315SDavid Veenstra  * @rx:		buffer for spi transfers.
41*ad28d315SDavid Veenstra  */
42*ad28d315SDavid Veenstra struct ad2s1200_state {
43*ad28d315SDavid Veenstra 	struct mutex lock;
44*ad28d315SDavid Veenstra 	struct spi_device *sdev;
45*ad28d315SDavid Veenstra 	struct gpio_desc *sample;
46*ad28d315SDavid Veenstra 	struct gpio_desc *rdvel;
47*ad28d315SDavid Veenstra 	__be16 rx ____cacheline_aligned;
48*ad28d315SDavid Veenstra };
49*ad28d315SDavid Veenstra 
50*ad28d315SDavid Veenstra static int ad2s1200_read_raw(struct iio_dev *indio_dev,
51*ad28d315SDavid Veenstra 			     struct iio_chan_spec const *chan,
52*ad28d315SDavid Veenstra 			     int *val,
53*ad28d315SDavid Veenstra 			     int *val2,
54*ad28d315SDavid Veenstra 			     long m)
55*ad28d315SDavid Veenstra {
56*ad28d315SDavid Veenstra 	struct ad2s1200_state *st = iio_priv(indio_dev);
57*ad28d315SDavid Veenstra 	int ret;
58*ad28d315SDavid Veenstra 
59*ad28d315SDavid Veenstra 	switch (m) {
60*ad28d315SDavid Veenstra 	case IIO_CHAN_INFO_SCALE:
61*ad28d315SDavid Veenstra 		switch (chan->type) {
62*ad28d315SDavid Veenstra 		case IIO_ANGL:
63*ad28d315SDavid Veenstra 			/* 2 * Pi / (2^12 - 1) ~= 0.001534355 */
64*ad28d315SDavid Veenstra 			*val = 0;
65*ad28d315SDavid Veenstra 			*val2 = 1534355;
66*ad28d315SDavid Veenstra 			return IIO_VAL_INT_PLUS_NANO;
67*ad28d315SDavid Veenstra 		case IIO_ANGL_VEL:
68*ad28d315SDavid Veenstra 			/* 2 * Pi ~= 6.283185 */
69*ad28d315SDavid Veenstra 			*val = 6;
70*ad28d315SDavid Veenstra 			*val2 = 283185;
71*ad28d315SDavid Veenstra 			return IIO_VAL_INT_PLUS_MICRO;
72*ad28d315SDavid Veenstra 		default:
73*ad28d315SDavid Veenstra 			return -EINVAL;
74*ad28d315SDavid Veenstra 		}
75*ad28d315SDavid Veenstra 		break;
76*ad28d315SDavid Veenstra 	case IIO_CHAN_INFO_RAW:
77*ad28d315SDavid Veenstra 		mutex_lock(&st->lock);
78*ad28d315SDavid Veenstra 		gpiod_set_value(st->sample, 0);
79*ad28d315SDavid Veenstra 
80*ad28d315SDavid Veenstra 		/* delay (6 * AD2S1200_TSCLK + 20) nano seconds */
81*ad28d315SDavid Veenstra 		udelay(1);
82*ad28d315SDavid Veenstra 		gpiod_set_value(st->sample, 1);
83*ad28d315SDavid Veenstra 		gpiod_set_value(st->rdvel, !!(chan->type == IIO_ANGL));
84*ad28d315SDavid Veenstra 
85*ad28d315SDavid Veenstra 		ret = spi_read(st->sdev, &st->rx, 2);
86*ad28d315SDavid Veenstra 		if (ret < 0) {
87*ad28d315SDavid Veenstra 			mutex_unlock(&st->lock);
88*ad28d315SDavid Veenstra 			return ret;
89*ad28d315SDavid Veenstra 		}
90*ad28d315SDavid Veenstra 
91*ad28d315SDavid Veenstra 		switch (chan->type) {
92*ad28d315SDavid Veenstra 		case IIO_ANGL:
93*ad28d315SDavid Veenstra 			*val = be16_to_cpup(&st->rx) >> 4;
94*ad28d315SDavid Veenstra 			break;
95*ad28d315SDavid Veenstra 		case IIO_ANGL_VEL:
96*ad28d315SDavid Veenstra 			*val = sign_extend32(be16_to_cpup(&st->rx) >> 4, 11);
97*ad28d315SDavid Veenstra 			break;
98*ad28d315SDavid Veenstra 		default:
99*ad28d315SDavid Veenstra 			mutex_unlock(&st->lock);
100*ad28d315SDavid Veenstra 			return -EINVAL;
101*ad28d315SDavid Veenstra 		}
102*ad28d315SDavid Veenstra 
103*ad28d315SDavid Veenstra 		/* delay (2 * AD2S1200_TSCLK + 20) ns for sample pulse */
104*ad28d315SDavid Veenstra 		udelay(1);
105*ad28d315SDavid Veenstra 		mutex_unlock(&st->lock);
106*ad28d315SDavid Veenstra 
107*ad28d315SDavid Veenstra 		return IIO_VAL_INT;
108*ad28d315SDavid Veenstra 	default:
109*ad28d315SDavid Veenstra 		break;
110*ad28d315SDavid Veenstra 	}
111*ad28d315SDavid Veenstra 
112*ad28d315SDavid Veenstra 	return -EINVAL;
113*ad28d315SDavid Veenstra }
114*ad28d315SDavid Veenstra 
115*ad28d315SDavid Veenstra static const struct iio_chan_spec ad2s1200_channels[] = {
116*ad28d315SDavid Veenstra 	{
117*ad28d315SDavid Veenstra 		.type = IIO_ANGL,
118*ad28d315SDavid Veenstra 		.indexed = 1,
119*ad28d315SDavid Veenstra 		.channel = 0,
120*ad28d315SDavid Veenstra 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
121*ad28d315SDavid Veenstra 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
122*ad28d315SDavid Veenstra 	}, {
123*ad28d315SDavid Veenstra 		.type = IIO_ANGL_VEL,
124*ad28d315SDavid Veenstra 		.indexed = 1,
125*ad28d315SDavid Veenstra 		.channel = 0,
126*ad28d315SDavid Veenstra 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
127*ad28d315SDavid Veenstra 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
128*ad28d315SDavid Veenstra 	}
129*ad28d315SDavid Veenstra };
130*ad28d315SDavid Veenstra 
131*ad28d315SDavid Veenstra static const struct iio_info ad2s1200_info = {
132*ad28d315SDavid Veenstra 	.read_raw = ad2s1200_read_raw,
133*ad28d315SDavid Veenstra };
134*ad28d315SDavid Veenstra 
135*ad28d315SDavid Veenstra static int ad2s1200_probe(struct spi_device *spi)
136*ad28d315SDavid Veenstra {
137*ad28d315SDavid Veenstra 	struct ad2s1200_state *st;
138*ad28d315SDavid Veenstra 	struct iio_dev *indio_dev;
139*ad28d315SDavid Veenstra 	int ret;
140*ad28d315SDavid Veenstra 
141*ad28d315SDavid Veenstra 	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
142*ad28d315SDavid Veenstra 	if (!indio_dev)
143*ad28d315SDavid Veenstra 		return -ENOMEM;
144*ad28d315SDavid Veenstra 
145*ad28d315SDavid Veenstra 	spi_set_drvdata(spi, indio_dev);
146*ad28d315SDavid Veenstra 	st = iio_priv(indio_dev);
147*ad28d315SDavid Veenstra 	mutex_init(&st->lock);
148*ad28d315SDavid Veenstra 	st->sdev = spi;
149*ad28d315SDavid Veenstra 
150*ad28d315SDavid Veenstra 	st->sample = devm_gpiod_get(&spi->dev, "adi,sample", GPIOD_OUT_LOW);
151*ad28d315SDavid Veenstra 	if (IS_ERR(st->sample)) {
152*ad28d315SDavid Veenstra 		dev_err(&spi->dev, "Failed to claim SAMPLE gpio: err=%ld\n",
153*ad28d315SDavid Veenstra 			PTR_ERR(st->sample));
154*ad28d315SDavid Veenstra 		return PTR_ERR(st->sample);
155*ad28d315SDavid Veenstra 	}
156*ad28d315SDavid Veenstra 
157*ad28d315SDavid Veenstra 	st->rdvel = devm_gpiod_get(&spi->dev, "adi,rdvel", GPIOD_OUT_LOW);
158*ad28d315SDavid Veenstra 	if (IS_ERR(st->rdvel)) {
159*ad28d315SDavid Veenstra 		dev_err(&spi->dev, "Failed to claim RDVEL gpio: err=%ld\n",
160*ad28d315SDavid Veenstra 			PTR_ERR(st->rdvel));
161*ad28d315SDavid Veenstra 		return PTR_ERR(st->rdvel);
162*ad28d315SDavid Veenstra 	}
163*ad28d315SDavid Veenstra 
164*ad28d315SDavid Veenstra 	indio_dev->dev.parent = &spi->dev;
165*ad28d315SDavid Veenstra 	indio_dev->info = &ad2s1200_info;
166*ad28d315SDavid Veenstra 	indio_dev->modes = INDIO_DIRECT_MODE;
167*ad28d315SDavid Veenstra 	indio_dev->channels = ad2s1200_channels;
168*ad28d315SDavid Veenstra 	indio_dev->num_channels = ARRAY_SIZE(ad2s1200_channels);
169*ad28d315SDavid Veenstra 	indio_dev->name = spi_get_device_id(spi)->name;
170*ad28d315SDavid Veenstra 
171*ad28d315SDavid Veenstra 	spi->max_speed_hz = AD2S1200_HZ;
172*ad28d315SDavid Veenstra 	spi->mode = SPI_MODE_3;
173*ad28d315SDavid Veenstra 	ret = spi_setup(spi);
174*ad28d315SDavid Veenstra 
175*ad28d315SDavid Veenstra 	if (ret < 0) {
176*ad28d315SDavid Veenstra 		dev_err(&spi->dev, "spi_setup failed!\n");
177*ad28d315SDavid Veenstra 		return ret;
178*ad28d315SDavid Veenstra 	}
179*ad28d315SDavid Veenstra 
180*ad28d315SDavid Veenstra 	return devm_iio_device_register(&spi->dev, indio_dev);
181*ad28d315SDavid Veenstra }
182*ad28d315SDavid Veenstra 
183*ad28d315SDavid Veenstra static const struct of_device_id ad2s1200_of_match[] = {
184*ad28d315SDavid Veenstra 	{ .compatible = "adi,ad2s1200", },
185*ad28d315SDavid Veenstra 	{ .compatible = "adi,ad2s1205", },
186*ad28d315SDavid Veenstra 	{ }
187*ad28d315SDavid Veenstra };
188*ad28d315SDavid Veenstra MODULE_DEVICE_TABLE(of, ad2s1200_of_match);
189*ad28d315SDavid Veenstra 
190*ad28d315SDavid Veenstra static const struct spi_device_id ad2s1200_id[] = {
191*ad28d315SDavid Veenstra 	{ "ad2s1200" },
192*ad28d315SDavid Veenstra 	{ "ad2s1205" },
193*ad28d315SDavid Veenstra 	{}
194*ad28d315SDavid Veenstra };
195*ad28d315SDavid Veenstra MODULE_DEVICE_TABLE(spi, ad2s1200_id);
196*ad28d315SDavid Veenstra 
197*ad28d315SDavid Veenstra static struct spi_driver ad2s1200_driver = {
198*ad28d315SDavid Veenstra 	.driver = {
199*ad28d315SDavid Veenstra 		.name = DRV_NAME,
200*ad28d315SDavid Veenstra 		.of_match_table = of_match_ptr(ad2s1200_of_match),
201*ad28d315SDavid Veenstra 	},
202*ad28d315SDavid Veenstra 	.probe = ad2s1200_probe,
203*ad28d315SDavid Veenstra 	.id_table = ad2s1200_id,
204*ad28d315SDavid Veenstra };
205*ad28d315SDavid Veenstra module_spi_driver(ad2s1200_driver);
206*ad28d315SDavid Veenstra 
207*ad28d315SDavid Veenstra MODULE_AUTHOR("David Veenstra <davidjulianveenstra@gmail.com>");
208*ad28d315SDavid Veenstra MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
209*ad28d315SDavid Veenstra MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver");
210*ad28d315SDavid Veenstra MODULE_LICENSE("GPL v2");
211