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