Commit | Line | Data |
---|---|---|
ffd7a62f | 1 | /* |
10e4a52b JC |
2 | * ad2s1200.c simple support for the ADI Resolver to Digital Converters: |
3 | * AD2S1200/1205 | |
ffd7a62f GY |
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> | |
99c97852 | 20 | #include <linux/module.h> |
ffd7a62f | 21 | |
06458e27 JC |
22 | #include <linux/iio/iio.h> |
23 | #include <linux/iio/sysfs.h> | |
ffd7a62f | 24 | |
10e4a52b | 25 | #define DRV_NAME "ad2s1200" |
ffd7a62f GY |
26 | |
27 | /* input pin sample and rdvel is controlled by driver */ | |
10e4a52b | 28 | #define AD2S1200_PN 2 |
ffd7a62f GY |
29 | |
30 | /* input clock on serial interface */ | |
10e4a52b | 31 | #define AD2S1200_HZ 8192000 |
ffd7a62f | 32 | /* clock period in nano second */ |
10e4a52b | 33 | #define AD2S1200_TSCLK (1000000000/AD2S1200_HZ) |
ffd7a62f | 34 | |
10e4a52b | 35 | struct ad2s1200_state { |
ffd7a62f | 36 | struct mutex lock; |
ffd7a62f | 37 | struct spi_device *sdev; |
8f2bd836 JC |
38 | int sample; |
39 | int rdvel; | |
40 | u8 rx[2] ____cacheline_aligned; | |
ffd7a62f GY |
41 | }; |
42 | ||
9c5ed829 JC |
43 | static 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) | |
ffd7a62f | 48 | { |
ffd7a62f | 49 | int ret = 0; |
ffd7a62f | 50 | s16 vel; |
10e4a52b | 51 | struct ad2s1200_state *st = iio_priv(indio_dev); |
ffd7a62f | 52 | |
ffd7a62f | 53 | mutex_lock(&st->lock); |
ffd7a62f | 54 | gpio_set_value(st->sample, 0); |
10e4a52b | 55 | /* delay (6 * AD2S1200_TSCLK + 20) nano seconds */ |
ffd7a62f GY |
56 | udelay(1); |
57 | gpio_set_value(st->sample, 1); | |
9c5ed829 | 58 | gpio_set_value(st->rdvel, !!(chan->type == IIO_ANGL)); |
8f2bd836 | 59 | ret = spi_read(st->sdev, st->rx, 2); |
9c5ed829 JC |
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 | default: | |
74 | mutex_unlock(&st->lock); | |
75 | return -EINVAL; | |
8f2bd836 | 76 | } |
10e4a52b | 77 | /* delay (2 * AD2S1200_TSCLK + 20) ns for sample pulse */ |
ffd7a62f GY |
78 | udelay(1); |
79 | mutex_unlock(&st->lock); | |
9c5ed829 | 80 | return IIO_VAL_INT; |
ffd7a62f GY |
81 | } |
82 | ||
9c5ed829 JC |
83 | static const struct iio_chan_spec ad2s1200_channels[] = { |
84 | { | |
85 | .type = IIO_ANGL, | |
86 | .indexed = 1, | |
87 | .channel = 0, | |
62465770 | 88 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, |
9c5ed829 JC |
89 | }, { |
90 | .type = IIO_ANGL_VEL, | |
91 | .indexed = 1, | |
92 | .channel = 0, | |
62465770 | 93 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, |
9c5ed829 | 94 | } |
ffd7a62f GY |
95 | }; |
96 | ||
10e4a52b | 97 | static const struct iio_info ad2s1200_info = { |
9c5ed829 | 98 | .read_raw = &ad2s1200_read_raw, |
6fe8135f JC |
99 | .driver_module = THIS_MODULE, |
100 | }; | |
101 | ||
10e4a52b | 102 | static int __devinit ad2s1200_probe(struct spi_device *spi) |
ffd7a62f | 103 | { |
10e4a52b | 104 | struct ad2s1200_state *st; |
8f2bd836 | 105 | struct iio_dev *indio_dev; |
ffd7a62f GY |
106 | int pn, ret = 0; |
107 | unsigned short *pins = spi->dev.platform_data; | |
108 | ||
10e4a52b | 109 | for (pn = 0; pn < AD2S1200_PN; pn++) |
8f2bd836 | 110 | if (gpio_request_one(pins[pn], GPIOF_DIR_OUT, DRV_NAME)) { |
ffd7a62f GY |
111 | pr_err("%s: request gpio pin %d failed\n", |
112 | DRV_NAME, pins[pn]); | |
113 | goto error_ret; | |
114 | } | |
8f2bd836 JC |
115 | indio_dev = iio_allocate_device(sizeof(*st)); |
116 | if (indio_dev == NULL) { | |
ffd7a62f GY |
117 | ret = -ENOMEM; |
118 | goto error_ret; | |
119 | } | |
8f2bd836 JC |
120 | spi_set_drvdata(spi, indio_dev); |
121 | st = iio_priv(indio_dev); | |
ffd7a62f GY |
122 | mutex_init(&st->lock); |
123 | st->sdev = spi; | |
124 | st->sample = pins[0]; | |
125 | st->rdvel = pins[1]; | |
126 | ||
8f2bd836 | 127 | indio_dev->dev.parent = &spi->dev; |
10e4a52b | 128 | indio_dev->info = &ad2s1200_info; |
8f2bd836 | 129 | indio_dev->modes = INDIO_DIRECT_MODE; |
9c5ed829 JC |
130 | indio_dev->channels = ad2s1200_channels; |
131 | indio_dev->num_channels = ARRAY_SIZE(ad2s1200_channels); | |
10e4a52b | 132 | indio_dev->name = spi_get_device_id(spi)->name; |
ffd7a62f | 133 | |
8f2bd836 | 134 | ret = iio_device_register(indio_dev); |
ffd7a62f GY |
135 | if (ret) |
136 | goto error_free_dev; | |
137 | ||
10e4a52b | 138 | spi->max_speed_hz = AD2S1200_HZ; |
ffd7a62f GY |
139 | spi->mode = SPI_MODE_3; |
140 | spi_setup(spi); | |
141 | ||
142 | return 0; | |
143 | ||
144 | error_free_dev: | |
8f2bd836 | 145 | iio_free_device(indio_dev); |
ffd7a62f GY |
146 | error_ret: |
147 | for (--pn; pn >= 0; pn--) | |
148 | gpio_free(pins[pn]); | |
149 | return ret; | |
150 | } | |
151 | ||
10e4a52b | 152 | static int __devexit ad2s1200_remove(struct spi_device *spi) |
ffd7a62f | 153 | { |
8f2bd836 | 154 | iio_device_unregister(spi_get_drvdata(spi)); |
d2fffd6c | 155 | iio_free_device(spi_get_drvdata(spi)); |
ffd7a62f GY |
156 | |
157 | return 0; | |
158 | } | |
159 | ||
10e4a52b JC |
160 | static const struct spi_device_id ad2s1200_id[] = { |
161 | { "ad2s1200" }, | |
162 | { "ad2s1205" }, | |
163 | {} | |
164 | }; | |
55e4390c | 165 | MODULE_DEVICE_TABLE(spi, ad2s1200_id); |
10e4a52b JC |
166 | |
167 | static struct spi_driver ad2s1200_driver = { | |
ffd7a62f GY |
168 | .driver = { |
169 | .name = DRV_NAME, | |
170 | .owner = THIS_MODULE, | |
171 | }, | |
10e4a52b JC |
172 | .probe = ad2s1200_probe, |
173 | .remove = __devexit_p(ad2s1200_remove), | |
174 | .id_table = ad2s1200_id, | |
ffd7a62f | 175 | }; |
ae6ae6fe | 176 | module_spi_driver(ad2s1200_driver); |
ffd7a62f GY |
177 | |
178 | MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>"); | |
179 | MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver"); | |
180 | MODULE_LICENSE("GPL v2"); |