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