/drivers/staging/iio/resolver/ad2s120x.c
C | 177 lines | 136 code | 26 blank | 15 comment | 9 complexity | b6cfebde4352d3323edb33e28910a036 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
1/* 2 * ad2s120x.c simple support for the ADI Resolver to Digital Converters: AD2S1200/1205 3 * 4 * Copyright (c) 2010-2010 Analog Devices Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 */ 11#include <linux/types.h> 12#include <linux/mutex.h> 13#include <linux/device.h> 14#include <linux/spi/spi.h> 15#include <linux/slab.h> 16#include <linux/sysfs.h> 17#include <linux/delay.h> 18#include <linux/gpio.h> 19 20#include "../iio.h" 21#include "../sysfs.h" 22 23#define DRV_NAME "ad2s120x" 24 25/* input pin sample and rdvel is controlled by driver */ 26#define AD2S120X_PN 2 27 28/* input clock on serial interface */ 29#define AD2S120X_HZ 8192000 30/* clock period in nano second */ 31#define AD2S120X_TSCLK (1000000000/AD2S120X_HZ) 32 33struct ad2s120x_state { 34 struct mutex lock; 35 struct spi_device *sdev; 36 int sample; 37 int rdvel; 38 u8 rx[2] ____cacheline_aligned; 39}; 40 41static ssize_t ad2s120x_show_val(struct device *dev, 42 struct device_attribute *attr, char *buf) 43{ 44 int ret = 0; 45 ssize_t len = 0; 46 u16 pos; 47 s16 vel; 48 u8 status; 49 struct ad2s120x_state *st = iio_priv(dev_get_drvdata(dev)); 50 struct iio_dev_attr *iattr = to_iio_dev_attr(attr); 51 52 mutex_lock(&st->lock); 53 54 gpio_set_value(st->sample, 0); 55 /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */ 56 udelay(1); 57 gpio_set_value(st->sample, 1); 58 gpio_set_value(st->rdvel, iattr->address); 59 ret = spi_read(st->sdev, st->rx, 2); 60 if (ret < 0) 61 goto error_ret; 62 status = st->rx[1]; 63 if (iattr->address) 64 pos = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); 65 else { 66 vel = (st->rx[0] & 0x80) ? 0xf000 : 0; 67 vel |= (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); 68 } 69 len = sprintf(buf, "%d %c%c%c%c ", iattr->address ? pos : vel, 70 (status & 0x8) ? 'P' : 'V', 71 (status & 0x4) ? 'd' : '_', 72 (status & 0x2) ? 'l' : '_', 73 (status & 0x1) ? '1' : '0'); 74error_ret: 75 /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */ 76 udelay(1); 77 mutex_unlock(&st->lock); 78 79 return ret ? ret : len; 80} 81 82static IIO_DEVICE_ATTR(pos, S_IRUGO, ad2s120x_show_val, NULL, 1); 83static IIO_DEVICE_ATTR(vel, S_IRUGO, ad2s120x_show_val, NULL, 0); 84 85static struct attribute *ad2s120x_attributes[] = { 86 &iio_dev_attr_pos.dev_attr.attr, 87 &iio_dev_attr_vel.dev_attr.attr, 88 NULL, 89}; 90 91static const struct attribute_group ad2s120x_attribute_group = { 92 .attrs = ad2s120x_attributes, 93}; 94 95static const struct iio_info ad2s120x_info = { 96 .attrs = &ad2s120x_attribute_group, 97 .driver_module = THIS_MODULE, 98}; 99 100static int __devinit ad2s120x_probe(struct spi_device *spi) 101{ 102 struct ad2s120x_state *st; 103 struct iio_dev *indio_dev; 104 int pn, ret = 0; 105 unsigned short *pins = spi->dev.platform_data; 106 107 for (pn = 0; pn < AD2S120X_PN; pn++) 108 if (gpio_request_one(pins[pn], GPIOF_DIR_OUT, DRV_NAME)) { 109 pr_err("%s: request gpio pin %d failed\n", 110 DRV_NAME, pins[pn]); 111 goto error_ret; 112 } 113 indio_dev = iio_allocate_device(sizeof(*st)); 114 if (indio_dev == NULL) { 115 ret = -ENOMEM; 116 goto error_ret; 117 } 118 spi_set_drvdata(spi, indio_dev); 119 st = iio_priv(indio_dev); 120 mutex_init(&st->lock); 121 st->sdev = spi; 122 st->sample = pins[0]; 123 st->rdvel = pins[1]; 124 125 indio_dev->dev.parent = &spi->dev; 126 indio_dev->info = &ad2s120x_info; 127 indio_dev->modes = INDIO_DIRECT_MODE; 128 129 ret = iio_device_register(indio_dev); 130 if (ret) 131 goto error_free_dev; 132 133 spi->max_speed_hz = AD2S120X_HZ; 134 spi->mode = SPI_MODE_3; 135 spi_setup(spi); 136 137 return 0; 138 139error_free_dev: 140 iio_free_device(indio_dev); 141error_ret: 142 for (--pn; pn >= 0; pn--) 143 gpio_free(pins[pn]); 144 return ret; 145} 146 147static int __devexit ad2s120x_remove(struct spi_device *spi) 148{ 149 iio_device_unregister(spi_get_drvdata(spi)); 150 151 return 0; 152} 153 154static struct spi_driver ad2s120x_driver = { 155 .driver = { 156 .name = DRV_NAME, 157 .owner = THIS_MODULE, 158 }, 159 .probe = ad2s120x_probe, 160 .remove = __devexit_p(ad2s120x_remove), 161}; 162 163static __init int ad2s120x_spi_init(void) 164{ 165 return spi_register_driver(&ad2s120x_driver); 166} 167module_init(ad2s120x_spi_init); 168 169static __exit void ad2s120x_spi_exit(void) 170{ 171 spi_unregister_driver(&ad2s120x_driver); 172} 173module_exit(ad2s120x_spi_exit); 174 175MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>"); 176MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver"); 177MODULE_LICENSE("GPL v2");