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#include <linux/bitops.h> 22 23#include <linux/iio/iio.h> 24#include <linux/iio/sysfs.h> 25 26#define DRV_NAME "ad2s1200" 27 28/* input pin sample and rdvel is controlled by driver */ 29#define AD2S1200_PN 2 30 31/* input clock on serial interface */ 32#define AD2S1200_HZ 8192000 33/* clock period in nano second */ 34#define AD2S1200_TSCLK (1000000000/AD2S1200_HZ) 35 36struct ad2s1200_state { 37 struct mutex lock; 38 struct spi_device *sdev; 39 int sample; 40 int rdvel; 41 u8 rx[2] ____cacheline_aligned; 42}; 43 44static int ad2s1200_read_raw(struct iio_dev *indio_dev, 45 struct iio_chan_spec const *chan, 46 int *val, 47 int *val2, 48 long m) 49{ 50 int ret = 0; 51 s16 vel; 52 struct ad2s1200_state *st = iio_priv(indio_dev); 53 54 mutex_lock(&st->lock); 55 gpio_set_value(st->sample, 0); 56 /* delay (6 * AD2S1200_TSCLK + 20) nano seconds */ 57 udelay(1); 58 gpio_set_value(st->sample, 1); 59 gpio_set_value(st->rdvel, !!(chan->type == IIO_ANGL)); 60 ret = spi_read(st->sdev, st->rx, 2); 61 if (ret < 0) { 62 mutex_unlock(&st->lock); 63 return ret; 64 } 65 66 switch (chan->type) { 67 case IIO_ANGL: 68 *val = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); 69 break; 70 case IIO_ANGL_VEL: 71 vel = (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); 72 vel = sign_extend32(vel, 11); 73 *val = vel; 74 break; 75 default: 76 mutex_unlock(&st->lock); 77 return -EINVAL; 78 } 79 /* delay (2 * AD2S1200_TSCLK + 20) ns for sample pulse */ 80 udelay(1); 81 mutex_unlock(&st->lock); 82 return IIO_VAL_INT; 83} 84 85static const struct iio_chan_spec ad2s1200_channels[] = { 86 { 87 .type = IIO_ANGL, 88 .indexed = 1, 89 .channel = 0, 90 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 91 }, { 92 .type = IIO_ANGL_VEL, 93 .indexed = 1, 94 .channel = 0, 95 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 96 } 97}; 98 99static const struct iio_info ad2s1200_info = { 100 .read_raw = &ad2s1200_read_raw, 101 .driver_module = THIS_MODULE, 102}; 103 104static int ad2s1200_probe(struct spi_device *spi) 105{ 106 struct ad2s1200_state *st; 107 struct iio_dev *indio_dev; 108 int pn, ret = 0; 109 unsigned short *pins = spi->dev.platform_data; 110 111 for (pn = 0; pn < AD2S1200_PN; pn++) { 112 ret = devm_gpio_request_one(&spi->dev, pins[pn], GPIOF_DIR_OUT, 113 DRV_NAME); 114 if (ret) { 115 dev_err(&spi->dev, "request gpio pin %d failed\n", 116 pins[pn]); 117 return ret; 118 } 119 } 120 indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); 121 if (!indio_dev) 122 return -ENOMEM; 123 spi_set_drvdata(spi, indio_dev); 124 st = iio_priv(indio_dev); 125 mutex_init(&st->lock); 126 st->sdev = spi; 127 st->sample = pins[0]; 128 st->rdvel = pins[1]; 129 130 indio_dev->dev.parent = &spi->dev; 131 indio_dev->info = &ad2s1200_info; 132 indio_dev->modes = INDIO_DIRECT_MODE; 133 indio_dev->channels = ad2s1200_channels; 134 indio_dev->num_channels = ARRAY_SIZE(ad2s1200_channels); 135 indio_dev->name = spi_get_device_id(spi)->name; 136 137 ret = devm_iio_device_register(&spi->dev, indio_dev); 138 if (ret) 139 return ret; 140 141 spi->max_speed_hz = AD2S1200_HZ; 142 spi->mode = SPI_MODE_3; 143 spi_setup(spi); 144 145 return 0; 146} 147 148static const struct spi_device_id ad2s1200_id[] = { 149 { "ad2s1200" }, 150 { "ad2s1205" }, 151 {} 152}; 153MODULE_DEVICE_TABLE(spi, ad2s1200_id); 154 155static struct spi_driver ad2s1200_driver = { 156 .driver = { 157 .name = DRV_NAME, 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