blob: 17b89623418cf6740de0c73def1e85f05afc4018 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Graf Yangffd7a622010-10-27 21:44:20 -04002/*
Jonathan Cameron10e4a522011-10-05 15:28:02 +01003 * ad2s1200.c simple support for the ADI Resolver to Digital Converters:
4 * AD2S1200/1205
Graf Yangffd7a622010-10-27 21:44:20 -04005 *
David Veenstra9c3e81ab2018-05-18 20:23:25 +02006 * Copyright (c) 2018-2018 David Veenstra <davidjulianveenstra@gmail.com>
Graf Yangffd7a622010-10-27 21:44:20 -04007 * Copyright (c) 2010-2010 Analog Devices Inc.
Graf Yangffd7a622010-10-27 21:44:20 -04008 */
David Veenstrad99066e2018-04-20 21:29:52 +02009
David Veenstra972c0c32018-04-20 21:28:52 +020010#include <linux/bitops.h>
Graf Yangffd7a622010-10-27 21:44:20 -040011#include <linux/delay.h>
David Veenstra972c0c32018-04-20 21:28:52 +020012#include <linux/device.h>
Graf Yangffd7a622010-10-27 21:44:20 -040013#include <linux/gpio.h>
David Veenstra5af93e62018-05-18 20:21:56 +020014#include <linux/gpio/consumer.h>
Paul Gortmaker99c97852011-07-03 15:49:50 -040015#include <linux/module.h>
David Veenstra972c0c32018-04-20 21:28:52 +020016#include <linux/mutex.h>
17#include <linux/spi/spi.h>
18#include <linux/sysfs.h>
19#include <linux/types.h>
Graf Yangffd7a622010-10-27 21:44:20 -040020
Jonathan Cameron06458e22012-04-25 15:54:58 +010021#include <linux/iio/iio.h>
22#include <linux/iio/sysfs.h>
Graf Yangffd7a622010-10-27 21:44:20 -040023
Jonathan Cameron10e4a522011-10-05 15:28:02 +010024#define DRV_NAME "ad2s1200"
Graf Yangffd7a622010-10-27 21:44:20 -040025
Graf Yangffd7a622010-10-27 21:44:20 -040026/* input clock on serial interface */
Jonathan Cameron10e4a522011-10-05 15:28:02 +010027#define AD2S1200_HZ 8192000
Graf Yangffd7a622010-10-27 21:44:20 -040028/* clock period in nano second */
Eva Rachel Retuyacdd6dee2016-02-18 18:59:34 +080029#define AD2S1200_TSCLK (1000000000 / AD2S1200_HZ)
Graf Yangffd7a622010-10-27 21:44:20 -040030
David Veenstrabc683b42018-05-18 20:21:34 +020031/**
32 * struct ad2s1200_state - driver instance specific data.
33 * @lock: protects both the GPIO pins and the rx buffer.
34 * @sdev: spi device.
35 * @sample: GPIO pin SAMPLE.
36 * @rdvel: GPIO pin RDVEL.
37 * @rx: buffer for spi transfers.
38 */
Jonathan Cameron10e4a522011-10-05 15:28:02 +010039struct ad2s1200_state {
Graf Yangffd7a622010-10-27 21:44:20 -040040 struct mutex lock;
Graf Yangffd7a622010-10-27 21:44:20 -040041 struct spi_device *sdev;
David Veenstra5af93e62018-05-18 20:21:56 +020042 struct gpio_desc *sample;
43 struct gpio_desc *rdvel;
David Veenstra0bd3d332018-04-23 00:03:03 +020044 __be16 rx ____cacheline_aligned;
Graf Yangffd7a622010-10-27 21:44:20 -040045};
46
Jonathan Cameron9c5ed822011-10-05 15:28:01 +010047static int ad2s1200_read_raw(struct iio_dev *indio_dev,
Eva Rachel Retuyaae6394a2016-02-18 18:59:33 +080048 struct iio_chan_spec const *chan,
49 int *val,
50 int *val2,
51 long m)
Graf Yangffd7a622010-10-27 21:44:20 -040052{
David Veenstra05982252018-04-20 21:29:08 +020053 struct ad2s1200_state *st = iio_priv(indio_dev);
David Veenstrac1b6a7d2018-05-18 20:21:23 +020054 int ret;
Graf Yangffd7a622010-10-27 21:44:20 -040055
David Veenstrad3e6ed82018-05-18 20:23:01 +020056 switch (m) {
57 case IIO_CHAN_INFO_SCALE:
58 switch (chan->type) {
David Veenstraf9db7372018-05-18 20:23:14 +020059 case IIO_ANGL:
60 /* 2 * Pi / (2^12 - 1) ~= 0.001534355 */
61 *val = 0;
62 *val2 = 1534355;
63 return IIO_VAL_INT_PLUS_NANO;
David Veenstrad3e6ed82018-05-18 20:23:01 +020064 case IIO_ANGL_VEL:
65 /* 2 * Pi ~= 6.283185 */
66 *val = 6;
67 *val2 = 283185;
68 return IIO_VAL_INT_PLUS_MICRO;
69 default:
70 return -EINVAL;
71 }
72 break;
73 case IIO_CHAN_INFO_RAW:
74 mutex_lock(&st->lock);
75 gpiod_set_value(st->sample, 0);
David Veenstrad99066e2018-04-20 21:29:52 +020076
David Veenstrad3e6ed82018-05-18 20:23:01 +020077 /* delay (6 * AD2S1200_TSCLK + 20) nano seconds */
78 udelay(1);
79 gpiod_set_value(st->sample, 1);
80 gpiod_set_value(st->rdvel, !!(chan->type == IIO_ANGL));
David Veenstrad99066e2018-04-20 21:29:52 +020081
David Veenstrad3e6ed82018-05-18 20:23:01 +020082 ret = spi_read(st->sdev, &st->rx, 2);
83 if (ret < 0) {
84 mutex_unlock(&st->lock);
85 return ret;
86 }
87
88 switch (chan->type) {
89 case IIO_ANGL:
90 *val = be16_to_cpup(&st->rx) >> 4;
91 break;
92 case IIO_ANGL_VEL:
93 *val = sign_extend32(be16_to_cpup(&st->rx) >> 4, 11);
94 break;
95 default:
96 mutex_unlock(&st->lock);
97 return -EINVAL;
98 }
99
100 /* delay (2 * AD2S1200_TSCLK + 20) ns for sample pulse */
101 udelay(1);
Jonathan Cameron9c5ed822011-10-05 15:28:01 +0100102 mutex_unlock(&st->lock);
Jonathan Cameron9c5ed822011-10-05 15:28:01 +0100103
David Veenstrad3e6ed82018-05-18 20:23:01 +0200104 return IIO_VAL_INT;
Jonathan Cameron9c5ed822011-10-05 15:28:01 +0100105 default:
David Veenstrad3e6ed82018-05-18 20:23:01 +0200106 break;
Jonathan Cameron9c5ed822011-10-05 15:28:01 +0100107 }
David Veenstrad99066e2018-04-20 21:29:52 +0200108
David Veenstrad3e6ed82018-05-18 20:23:01 +0200109 return -EINVAL;
Graf Yangffd7a622010-10-27 21:44:20 -0400110}
111
Jonathan Cameron9c5ed822011-10-05 15:28:01 +0100112static const struct iio_chan_spec ad2s1200_channels[] = {
113 {
114 .type = IIO_ANGL,
115 .indexed = 1,
116 .channel = 0,
Jonathan Cameron910b51f2013-02-27 19:41:20 +0000117 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
David Veenstraf9db7372018-05-18 20:23:14 +0200118 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
Jonathan Cameron9c5ed822011-10-05 15:28:01 +0100119 }, {
120 .type = IIO_ANGL_VEL,
121 .indexed = 1,
122 .channel = 0,
Jonathan Cameron910b51f2013-02-27 19:41:20 +0000123 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
David Veenstrad3e6ed82018-05-18 20:23:01 +0200124 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
Jonathan Cameron9c5ed822011-10-05 15:28:01 +0100125 }
Graf Yangffd7a622010-10-27 21:44:20 -0400126};
127
Jonathan Cameron10e4a522011-10-05 15:28:02 +0100128static const struct iio_info ad2s1200_info = {
simran singhal67cba022017-03-11 19:56:43 +0530129 .read_raw = ad2s1200_read_raw,
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100130};
131
Bill Pemberton4ae1c612012-11-19 13:21:57 -0500132static int ad2s1200_probe(struct spi_device *spi)
Graf Yangffd7a622010-10-27 21:44:20 -0400133{
Jonathan Cameron10e4a522011-10-05 15:28:02 +0100134 struct ad2s1200_state *st;
Jonathan Cameron8f2bd832011-06-27 13:07:52 +0100135 struct iio_dev *indio_dev;
David Veenstra19469802018-05-18 20:22:32 +0200136 int ret;
David Veenstrad99066e2018-04-20 21:29:52 +0200137
Sachin Kamat8d1b0b42013-09-11 10:55:00 +0100138 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
139 if (!indio_dev)
140 return -ENOMEM;
David Veenstrad99066e2018-04-20 21:29:52 +0200141
Jonathan Cameron8f2bd832011-06-27 13:07:52 +0100142 spi_set_drvdata(spi, indio_dev);
143 st = iio_priv(indio_dev);
Graf Yangffd7a622010-10-27 21:44:20 -0400144 mutex_init(&st->lock);
145 st->sdev = spi;
David Veenstra19469802018-05-18 20:22:32 +0200146
147 st->sample = devm_gpiod_get(&spi->dev, "adi,sample", GPIOD_OUT_LOW);
148 if (IS_ERR(st->sample)) {
149 dev_err(&spi->dev, "Failed to claim SAMPLE gpio: err=%ld\n",
150 PTR_ERR(st->sample));
151 return PTR_ERR(st->sample);
152 }
153
154 st->rdvel = devm_gpiod_get(&spi->dev, "adi,rdvel", GPIOD_OUT_LOW);
155 if (IS_ERR(st->rdvel)) {
156 dev_err(&spi->dev, "Failed to claim RDVEL gpio: err=%ld\n",
157 PTR_ERR(st->rdvel));
158 return PTR_ERR(st->rdvel);
159 }
Graf Yangffd7a622010-10-27 21:44:20 -0400160
Jonathan Cameron8f2bd832011-06-27 13:07:52 +0100161 indio_dev->dev.parent = &spi->dev;
Jonathan Cameron10e4a522011-10-05 15:28:02 +0100162 indio_dev->info = &ad2s1200_info;
Jonathan Cameron8f2bd832011-06-27 13:07:52 +0100163 indio_dev->modes = INDIO_DIRECT_MODE;
Jonathan Cameron9c5ed822011-10-05 15:28:01 +0100164 indio_dev->channels = ad2s1200_channels;
165 indio_dev->num_channels = ARRAY_SIZE(ad2s1200_channels);
Jonathan Cameron10e4a522011-10-05 15:28:02 +0100166 indio_dev->name = spi_get_device_id(spi)->name;
Graf Yangffd7a622010-10-27 21:44:20 -0400167
Jonathan Cameron10e4a522011-10-05 15:28:02 +0100168 spi->max_speed_hz = AD2S1200_HZ;
Graf Yangffd7a622010-10-27 21:44:20 -0400169 spi->mode = SPI_MODE_3;
David Veenstra94cdefa2018-05-18 20:21:44 +0200170 ret = spi_setup(spi);
Graf Yangffd7a622010-10-27 21:44:20 -0400171
David Veenstra94cdefa2018-05-18 20:21:44 +0200172 if (ret < 0) {
173 dev_err(&spi->dev, "spi_setup failed!\n");
174 return ret;
175 }
176
177 return devm_iio_device_register(&spi->dev, indio_dev);
Graf Yangffd7a622010-10-27 21:44:20 -0400178}
179
David Veenstra2363c012018-05-18 20:22:41 +0200180static const struct of_device_id ad2s1200_of_match[] = {
181 { .compatible = "adi,ad2s1200", },
182 { .compatible = "adi,ad2s1205", },
183 { }
184};
185MODULE_DEVICE_TABLE(of, ad2s1200_of_match);
186
Jonathan Cameron10e4a522011-10-05 15:28:02 +0100187static const struct spi_device_id ad2s1200_id[] = {
188 { "ad2s1200" },
189 { "ad2s1205" },
190 {}
191};
Lars-Peter Clausen55e43902011-11-16 08:53:31 +0100192MODULE_DEVICE_TABLE(spi, ad2s1200_id);
Jonathan Cameron10e4a522011-10-05 15:28:02 +0100193
194static struct spi_driver ad2s1200_driver = {
Graf Yangffd7a622010-10-27 21:44:20 -0400195 .driver = {
196 .name = DRV_NAME,
David Veenstra2363c012018-05-18 20:22:41 +0200197 .of_match_table = of_match_ptr(ad2s1200_of_match),
Graf Yangffd7a622010-10-27 21:44:20 -0400198 },
Jonathan Cameron10e4a522011-10-05 15:28:02 +0100199 .probe = ad2s1200_probe,
Jonathan Cameron10e4a522011-10-05 15:28:02 +0100200 .id_table = ad2s1200_id,
Graf Yangffd7a622010-10-27 21:44:20 -0400201};
Lars-Peter Clausenae6ae6f2011-11-16 10:13:39 +0100202module_spi_driver(ad2s1200_driver);
Graf Yangffd7a622010-10-27 21:44:20 -0400203
David Veenstra9c3e81ab2018-05-18 20:23:25 +0200204MODULE_AUTHOR("David Veenstra <davidjulianveenstra@gmail.com>");
Graf Yangffd7a622010-10-27 21:44:20 -0400205MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
206MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver");
207MODULE_LICENSE("GPL v2");