1/* 2 * ad2s1200.c simple support for the ADI Resolver to Digital Converters: 3 * AD2S1200/1205 4 * 5 * Copyright (c) 2010-2010 Analog Devices Inc. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 */ 12#include <linux/types.h> 13#include <linux/mutex.h> 14#include <linux/device.h> 15#include <linux/spi/spi.h> 16#include <linux/slab.h> 17#include <linux/sysfs.h> 18#include <linux/delay.h> 19#include <linux/gpio.h> 20#include <linux/module.h> 21 22#include <linux/iio/iio.h> 23#include <linux/iio/sysfs.h> 24 25#define DRV_NAME "ad2s1200" 26 27/* input pin sample and rdvel is controlled by driver */ 28#define AD2S1200_PN 2 29 30/* input clock on serial interface */ 31#define AD2S1200_HZ 8192000 32/* clock period in nano second */ 33#define AD2S1200_TSCLK (1000000000/AD2S1200_HZ) 34 35struct ad2s1200_state { 36 struct mutex lock; 37 struct spi_device *sdev; 38 int sample; 39 int rdvel; 40 u8 rx[2] ____cacheline_aligned; 41}; 42 43static int ad2s1200_read_raw(struct iio_dev *indio_dev, 44 struct iio_chan_spec const *chan, 45 int *val, 46 int *val2, 47 long m) 48{ 49 int ret = 0; 50 s16 vel; 51 struct ad2s1200_state *st = iio_priv(indio_dev); 52 53 mutex_lock(&st->lock); 54 gpio_set_value(st->sample, 0); 55 /* delay (6 * AD2S1200_TSCLK + 20) nano seconds */ 56 udelay(1); 57 gpio_set_value(st->sample, 1); 58 gpio_set_value(st->rdvel, !!(chan->type == IIO_ANGL)); 59 ret = spi_read(st->sdev, st->rx, 2); 60 if (ret < 0) { 61 mutex_unlock(&st->lock); 62 return ret; 63 } 64 65 switch (chan->type) { 66 case IIO_ANGL: 67 *val = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); 68 break; 69 case IIO_ANGL_VEL: 70 vel = (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); 71 vel = (vel << 4) >> 4; 72 *val = vel; 73 break; 74 default: 75 mutex_unlock(&st->lock); 76 return -EINVAL; 77 } 78 /* delay (2 * AD2S1200_TSCLK + 20) ns for sample pulse */ 79 udelay(1); 80 mutex_unlock(&st->lock); 81 return IIO_VAL_INT; 82} 83 84static const struct iio_chan_spec ad2s1200_channels[] = { 85 { 86 .type = IIO_ANGL, 87 .indexed = 1, 88 .channel = 0, 89 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 90 }, { 91 .type = IIO_ANGL_VEL, 92 .indexed = 1, 93 .channel = 0, 94 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 95 } 96}; 97 98static const struct iio_info ad2s1200_info = { 99 .read_raw = &ad2s1200_read_raw, 100 .driver_module = THIS_MODULE, 101}; 102 103static int ad2s1200_probe(struct spi_device *spi) 104{ 105 struct ad2s1200_state *st; 106 struct iio_dev *indio_dev; 107 int pn, ret = 0; 108 unsigned short *pins = spi->dev.platform_data; 109 110 for (pn = 0; pn < AD2S1200_PN; pn++) { 111 ret = devm_gpio_request_one(&spi->dev, pins[pn], GPIOF_DIR_OUT, 112 DRV_NAME); 113 if (ret) { 114 dev_err(&spi->dev, "request gpio pin %d failed\n", 115 pins[pn]); 116 return ret; 117 } 118 } 119 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 120 if (!indio_dev) 121 return -ENOMEM; 122 spi_set_drvdata(spi, indio_dev); 123 st = iio_priv(indio_dev); 124 mutex_init(&st->lock); 125 st->sdev = spi; 126 st->sample = pins[0]; 127 st->rdvel = pins[1]; 128 129 indio_dev->dev.parent = &spi->dev; 130 indio_dev->info = &ad2s1200_info; 131 indio_dev->modes = INDIO_DIRECT_MODE; 132 indio_dev->channels = ad2s1200_channels; 133 indio_dev->num_channels = ARRAY_SIZE(ad2s1200_channels); 134 indio_dev->name = spi_get_device_id(spi)->name; 135 136 ret = devm_iio_device_register(&spi->dev, indio_dev); 137 if (ret) 138 return ret; 139 140 spi->max_speed_hz = AD2S1200_HZ; 141 spi->mode = SPI_MODE_3; 142 spi_setup(spi); 143 144 return 0; 145} 146 147static const struct spi_device_id ad2s1200_id[] = { 148 { "ad2s1200" }, 149 { "ad2s1205" }, 150 {} 151}; 152MODULE_DEVICE_TABLE(spi, ad2s1200_id); 153 154static struct spi_driver ad2s1200_driver = { 155 .driver = { 156 .name = DRV_NAME, 157 .owner = THIS_MODULE, 158 }, 159 .probe = ad2s1200_probe, 160 .id_table = ad2s1200_id, 161}; 162module_spi_driver(ad2s1200_driver); 163 164MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>"); 165MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver"); 166MODULE_LICENSE("GPL v2"); 167