Commit | Line | Data |
---|---|---|
817e5c65 GY |
1 | /* |
2 | * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210 | |
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> | |
99c97852 | 19 | #include <linux/module.h> |
817e5c65 | 20 | |
06458e27 JC |
21 | #include <linux/iio/iio.h> |
22 | #include <linux/iio/sysfs.h> | |
b19e9ad5 | 23 | #include "ad2s1210.h" |
817e5c65 GY |
24 | |
25 | #define DRV_NAME "ad2s1210" | |
26 | ||
b19e9ad5 JC |
27 | #define AD2S1210_DEF_CONTROL 0x7E |
28 | ||
29 | #define AD2S1210_MSB_IS_HIGH 0x80 | |
30 | #define AD2S1210_MSB_IS_LOW 0x7F | |
31 | #define AD2S1210_PHASE_LOCK_RANGE_44 0x20 | |
32 | #define AD2S1210_ENABLE_HYSTERESIS 0x10 | |
33 | #define AD2S1210_SET_ENRES1 0x08 | |
34 | #define AD2S1210_SET_ENRES0 0x04 | |
35 | #define AD2S1210_SET_RES1 0x02 | |
36 | #define AD2S1210_SET_RES0 0x01 | |
37 | ||
38 | #define AD2S1210_SET_ENRESOLUTION (AD2S1210_SET_ENRES1 | \ | |
39 | AD2S1210_SET_ENRES0) | |
40 | #define AD2S1210_SET_RESOLUTION (AD2S1210_SET_RES1 | AD2S1210_SET_RES0) | |
41 | ||
42 | #define AD2S1210_REG_POSITION 0x80 | |
43 | #define AD2S1210_REG_VELOCITY 0x82 | |
44 | #define AD2S1210_REG_LOS_THRD 0x88 | |
45 | #define AD2S1210_REG_DOS_OVR_THRD 0x89 | |
46 | #define AD2S1210_REG_DOS_MIS_THRD 0x8A | |
47 | #define AD2S1210_REG_DOS_RST_MAX_THRD 0x8B | |
48 | #define AD2S1210_REG_DOS_RST_MIN_THRD 0x8C | |
49 | #define AD2S1210_REG_LOT_HIGH_THRD 0x8D | |
50 | #define AD2S1210_REG_LOT_LOW_THRD 0x8E | |
51 | #define AD2S1210_REG_EXCIT_FREQ 0x91 | |
52 | #define AD2S1210_REG_CONTROL 0x92 | |
53 | #define AD2S1210_REG_SOFT_RESET 0xF0 | |
54 | #define AD2S1210_REG_FAULT 0xFF | |
817e5c65 GY |
55 | |
56 | /* pin SAMPLE, A0, A1, RES0, RES1, is controlled by driver */ | |
57 | #define AD2S1210_SAA 3 | |
817e5c65 GY |
58 | #define AD2S1210_PN (AD2S1210_SAA + AD2S1210_RES) |
59 | ||
60 | #define AD2S1210_MIN_CLKIN 6144000 | |
61 | #define AD2S1210_MAX_CLKIN 10240000 | |
62 | #define AD2S1210_MIN_EXCIT 2000 | |
63 | #define AD2S1210_MAX_EXCIT 20000 | |
64 | #define AD2S1210_MIN_FCW 0x4 | |
65 | #define AD2S1210_MAX_FCW 0x50 | |
66 | ||
67 | /* default input clock on serial interface */ | |
68 | #define AD2S1210_DEF_CLKIN 8192000 | |
69 | /* clock period in nano second */ | |
70 | #define AD2S1210_DEF_TCK (1000000000/AD2S1210_DEF_CLKIN) | |
71 | #define AD2S1210_DEF_EXCIT 10000 | |
72 | ||
73 | enum ad2s1210_mode { | |
74 | MOD_POS = 0, | |
75 | MOD_VEL, | |
817e5c65 | 76 | MOD_CONFIG, |
b19e9ad5 | 77 | MOD_RESERVED, |
817e5c65 GY |
78 | }; |
79 | ||
b19e9ad5 | 80 | static const unsigned int ad2s1210_resolution_value[] = { 10, 12, 14, 16 }; |
817e5c65 GY |
81 | |
82 | struct ad2s1210_state { | |
b19e9ad5 | 83 | const struct ad2s1210_platform_data *pdata; |
817e5c65 | 84 | struct mutex lock; |
817e5c65 | 85 | struct spi_device *sdev; |
817e5c65 GY |
86 | unsigned int fclkin; |
87 | unsigned int fexcit; | |
b19e9ad5 JC |
88 | bool hysteresis; |
89 | bool old_data; | |
90 | u8 resolution; | |
91 | enum ad2s1210_mode mode; | |
92 | u8 rx[2] ____cacheline_aligned; | |
93 | u8 tx[2] ____cacheline_aligned; | |
817e5c65 GY |
94 | }; |
95 | ||
b19e9ad5 JC |
96 | static const int ad2s1210_mode_vals[4][2] = { |
97 | [MOD_POS] = { 0, 0 }, | |
98 | [MOD_VEL] = { 0, 1 }, | |
99 | [MOD_CONFIG] = { 1, 0 }, | |
100 | }; | |
101 | static inline void ad2s1210_set_mode(enum ad2s1210_mode mode, | |
102 | struct ad2s1210_state *st) | |
817e5c65 | 103 | { |
b19e9ad5 JC |
104 | gpio_set_value(st->pdata->a[0], ad2s1210_mode_vals[mode][0]); |
105 | gpio_set_value(st->pdata->a[1], ad2s1210_mode_vals[mode][1]); | |
817e5c65 GY |
106 | st->mode = mode; |
107 | } | |
108 | ||
109 | /* write 1 bytes (address or data) to the chip */ | |
b19e9ad5 | 110 | static int ad2s1210_config_write(struct ad2s1210_state *st, u8 data) |
817e5c65 | 111 | { |
b19e9ad5 | 112 | int ret; |
817e5c65 | 113 | |
b19e9ad5 | 114 | ad2s1210_set_mode(MOD_CONFIG, st); |
817e5c65 | 115 | st->tx[0] = data; |
b19e9ad5 JC |
116 | ret = spi_write(st->sdev, st->tx, 1); |
117 | if (ret < 0) | |
817e5c65 | 118 | return ret; |
b19e9ad5 JC |
119 | st->old_data = true; |
120 | ||
121 | return 0; | |
817e5c65 GY |
122 | } |
123 | ||
124 | /* read value from one of the registers */ | |
b19e9ad5 JC |
125 | static int ad2s1210_config_read(struct ad2s1210_state *st, |
126 | unsigned char address) | |
127 | { | |
128 | struct spi_transfer xfer = { | |
129 | .len = 2, | |
130 | .rx_buf = st->rx, | |
131 | .tx_buf = st->tx, | |
132 | }; | |
817e5c65 GY |
133 | struct spi_message msg; |
134 | int ret = 0; | |
135 | ||
b19e9ad5 | 136 | ad2s1210_set_mode(MOD_CONFIG, st); |
817e5c65 | 137 | spi_message_init(&msg); |
b19e9ad5 JC |
138 | spi_message_add_tail(&xfer, &msg); |
139 | st->tx[0] = address | AD2S1210_MSB_IS_HIGH; | |
140 | st->tx[1] = AD2S1210_REG_FAULT; | |
817e5c65 | 141 | ret = spi_sync(st->sdev, &msg); |
b19e9ad5 | 142 | if (ret < 0) |
817e5c65 | 143 | return ret; |
b19e9ad5 JC |
144 | st->old_data = true; |
145 | ||
146 | return st->rx[1]; | |
817e5c65 GY |
147 | } |
148 | ||
b19e9ad5 JC |
149 | static inline |
150 | int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st) | |
817e5c65 | 151 | { |
b19e9ad5 | 152 | int ret; |
817e5c65 | 153 | unsigned char fcw; |
b19e9ad5 | 154 | |
817e5c65 | 155 | fcw = (unsigned char)(st->fexcit * (1 << 15) / st->fclkin); |
b19e9ad5 | 156 | if (fcw < AD2S1210_MIN_FCW || fcw > AD2S1210_MAX_FCW) { |
817e5c65 | 157 | pr_err("ad2s1210: FCW out of range\n"); |
b19e9ad5 JC |
158 | return -ERANGE; |
159 | } | |
160 | ||
161 | ret = ad2s1210_config_write(st, AD2S1210_REG_EXCIT_FREQ); | |
162 | if (ret < 0) | |
163 | return ret; | |
164 | ||
165 | return ad2s1210_config_write(st, fcw); | |
817e5c65 GY |
166 | } |
167 | ||
b19e9ad5 | 168 | static unsigned char ad2s1210_read_resolution_pin(struct ad2s1210_state *st) |
817e5c65 | 169 | { |
b19e9ad5 JC |
170 | return ad2s1210_resolution_value[ |
171 | (gpio_get_value(st->pdata->res[0]) << 1) | | |
172 | gpio_get_value(st->pdata->res[1])]; | |
817e5c65 | 173 | } |
b19e9ad5 JC |
174 | |
175 | static const int ad2s1210_res_pins[4][2] = { | |
176 | { 0, 0 }, {0, 1}, {1, 0}, {1, 1} | |
177 | }; | |
178 | ||
179 | static inline void ad2s1210_set_resolution_pin(struct ad2s1210_state *st) | |
817e5c65 | 180 | { |
b19e9ad5 JC |
181 | gpio_set_value(st->pdata->res[0], |
182 | ad2s1210_res_pins[(st->resolution - 10)/2][0]); | |
183 | gpio_set_value(st->pdata->res[1], | |
184 | ad2s1210_res_pins[(st->resolution - 10)/2][1]); | |
817e5c65 | 185 | } |
817e5c65 | 186 | |
b19e9ad5 | 187 | static inline int ad2s1210_soft_reset(struct ad2s1210_state *st) |
817e5c65 | 188 | { |
b19e9ad5 JC |
189 | int ret; |
190 | ||
191 | ret = ad2s1210_config_write(st, AD2S1210_REG_SOFT_RESET); | |
192 | if (ret < 0) | |
193 | return ret; | |
194 | ||
195 | return ad2s1210_config_write(st, 0x0); | |
817e5c65 GY |
196 | } |
197 | ||
817e5c65 | 198 | static ssize_t ad2s1210_store_softreset(struct device *dev, |
b19e9ad5 JC |
199 | struct device_attribute *attr, |
200 | const char *buf, | |
201 | size_t len) | |
817e5c65 | 202 | { |
a651cf9b | 203 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
b19e9ad5 JC |
204 | int ret; |
205 | ||
817e5c65 | 206 | mutex_lock(&st->lock); |
b19e9ad5 | 207 | ret = ad2s1210_soft_reset(st); |
817e5c65 | 208 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
209 | |
210 | return ret < 0 ? ret : len; | |
817e5c65 GY |
211 | } |
212 | ||
213 | static ssize_t ad2s1210_show_fclkin(struct device *dev, | |
b19e9ad5 JC |
214 | struct device_attribute *attr, |
215 | char *buf) | |
817e5c65 | 216 | { |
a651cf9b | 217 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
817e5c65 GY |
218 | return sprintf(buf, "%d\n", st->fclkin); |
219 | } | |
220 | ||
221 | static ssize_t ad2s1210_store_fclkin(struct device *dev, | |
b19e9ad5 JC |
222 | struct device_attribute *attr, |
223 | const char *buf, | |
224 | size_t len) | |
817e5c65 | 225 | { |
a651cf9b | 226 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
817e5c65 GY |
227 | unsigned long fclkin; |
228 | int ret; | |
229 | ||
230 | ret = strict_strtoul(buf, 10, &fclkin); | |
b19e9ad5 JC |
231 | if (ret) |
232 | return ret; | |
233 | if (fclkin < AD2S1210_MIN_CLKIN || fclkin > AD2S1210_MAX_CLKIN) { | |
817e5c65 GY |
234 | pr_err("ad2s1210: fclkin out of range\n"); |
235 | return -EINVAL; | |
236 | } | |
b19e9ad5 JC |
237 | |
238 | mutex_lock(&st->lock); | |
239 | st->fclkin = fclkin; | |
240 | ||
241 | ret = ad2s1210_update_frequency_control_word(st); | |
242 | if (ret < 0) | |
243 | goto error_ret; | |
244 | ret = ad2s1210_soft_reset(st); | |
245 | error_ret: | |
817e5c65 | 246 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
247 | |
248 | return ret < 0 ? ret : len; | |
817e5c65 GY |
249 | } |
250 | ||
251 | static ssize_t ad2s1210_show_fexcit(struct device *dev, | |
b19e9ad5 JC |
252 | struct device_attribute *attr, |
253 | char *buf) | |
817e5c65 | 254 | { |
a651cf9b | 255 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
817e5c65 GY |
256 | return sprintf(buf, "%d\n", st->fexcit); |
257 | } | |
258 | ||
259 | static ssize_t ad2s1210_store_fexcit(struct device *dev, | |
b19e9ad5 JC |
260 | struct device_attribute *attr, |
261 | const char *buf, size_t len) | |
817e5c65 | 262 | { |
a651cf9b | 263 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
817e5c65 GY |
264 | unsigned long fexcit; |
265 | int ret; | |
266 | ||
267 | ret = strict_strtoul(buf, 10, &fexcit); | |
b19e9ad5 JC |
268 | if (ret < 0) |
269 | return ret; | |
270 | if (fexcit < AD2S1210_MIN_EXCIT || fexcit > AD2S1210_MAX_EXCIT) { | |
817e5c65 GY |
271 | pr_err("ad2s1210: excitation frequency out of range\n"); |
272 | return -EINVAL; | |
273 | } | |
b19e9ad5 JC |
274 | mutex_lock(&st->lock); |
275 | st->fexcit = fexcit; | |
276 | ret = ad2s1210_update_frequency_control_word(st); | |
277 | if (ret < 0) | |
278 | goto error_ret; | |
279 | ret = ad2s1210_soft_reset(st); | |
280 | error_ret: | |
817e5c65 | 281 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
282 | |
283 | return ret < 0 ? ret : len; | |
817e5c65 GY |
284 | } |
285 | ||
286 | static ssize_t ad2s1210_show_control(struct device *dev, | |
b19e9ad5 JC |
287 | struct device_attribute *attr, |
288 | char *buf) | |
817e5c65 | 289 | { |
a651cf9b | 290 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
b19e9ad5 | 291 | int ret; |
817e5c65 | 292 | mutex_lock(&st->lock); |
b19e9ad5 | 293 | ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); |
817e5c65 | 294 | mutex_unlock(&st->lock); |
b19e9ad5 | 295 | return ret < 0 ? ret : sprintf(buf, "0x%x\n", ret); |
817e5c65 GY |
296 | } |
297 | ||
298 | static ssize_t ad2s1210_store_control(struct device *dev, | |
299 | struct device_attribute *attr, | |
300 | const char *buf, size_t len) | |
301 | { | |
a651cf9b | 302 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
817e5c65 GY |
303 | unsigned long udata; |
304 | unsigned char data; | |
305 | int ret; | |
306 | ||
307 | ret = strict_strtoul(buf, 16, &udata); | |
b19e9ad5 JC |
308 | if (ret) |
309 | return -EINVAL; | |
310 | ||
817e5c65 | 311 | mutex_lock(&st->lock); |
b19e9ad5 JC |
312 | ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL); |
313 | if (ret < 0) | |
314 | goto error_ret; | |
315 | data = udata & AD2S1210_MSB_IS_LOW; | |
316 | ret = ad2s1210_config_write(st, data); | |
317 | if (ret < 0) | |
318 | goto error_ret; | |
319 | ||
320 | ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); | |
321 | if (ret < 0) | |
322 | goto error_ret; | |
323 | if (ret & AD2S1210_MSB_IS_HIGH) { | |
817e5c65 GY |
324 | ret = -EIO; |
325 | pr_err("ad2s1210: write control register fail\n"); | |
326 | goto error_ret; | |
327 | } | |
b19e9ad5 JC |
328 | st->resolution |
329 | = ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION]; | |
330 | if (st->pdata->gpioin) { | |
331 | data = ad2s1210_read_resolution_pin(st); | |
332 | if (data != st->resolution) | |
333 | pr_warning("ad2s1210: resolution settings not match\n"); | |
334 | } else | |
335 | ad2s1210_set_resolution_pin(st); | |
336 | ||
817e5c65 | 337 | ret = len; |
b19e9ad5 JC |
338 | st->hysteresis = !!(data & AD2S1210_ENABLE_HYSTERESIS); |
339 | ||
817e5c65 GY |
340 | error_ret: |
341 | mutex_unlock(&st->lock); | |
342 | return ret; | |
343 | } | |
344 | ||
345 | static ssize_t ad2s1210_show_resolution(struct device *dev, | |
346 | struct device_attribute *attr, char *buf) | |
347 | { | |
a651cf9b | 348 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
817e5c65 GY |
349 | return sprintf(buf, "%d\n", st->resolution); |
350 | } | |
351 | ||
352 | static ssize_t ad2s1210_store_resolution(struct device *dev, | |
353 | struct device_attribute *attr, | |
354 | const char *buf, size_t len) | |
355 | { | |
a651cf9b | 356 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
817e5c65 GY |
357 | unsigned char data; |
358 | unsigned long udata; | |
359 | int ret; | |
360 | ||
361 | ret = strict_strtoul(buf, 10, &udata); | |
b19e9ad5 | 362 | if (ret || udata < 10 || udata > 16) { |
817e5c65 GY |
363 | pr_err("ad2s1210: resolution out of range\n"); |
364 | return -EINVAL; | |
365 | } | |
366 | mutex_lock(&st->lock); | |
b19e9ad5 JC |
367 | ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); |
368 | if (ret < 0) | |
369 | goto error_ret; | |
370 | data = ret; | |
371 | data &= ~AD2S1210_SET_RESOLUTION; | |
372 | data |= (udata - 10) >> 1; | |
373 | ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL); | |
374 | if (ret < 0) | |
375 | goto error_ret; | |
376 | ret = ad2s1210_config_write(st, data & AD2S1210_MSB_IS_LOW); | |
377 | if (ret < 0) | |
378 | goto error_ret; | |
379 | ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); | |
380 | if (ret < 0) | |
381 | goto error_ret; | |
382 | data = ret; | |
383 | if (data & AD2S1210_MSB_IS_HIGH) { | |
817e5c65 GY |
384 | ret = -EIO; |
385 | pr_err("ad2s1210: setting resolution fail\n"); | |
386 | goto error_ret; | |
387 | } | |
b19e9ad5 JC |
388 | st->resolution |
389 | = ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION]; | |
390 | if (st->pdata->gpioin) { | |
391 | data = ad2s1210_read_resolution_pin(st); | |
392 | if (data != st->resolution) | |
393 | pr_warning("ad2s1210: resolution settings not match\n"); | |
394 | } else | |
395 | ad2s1210_set_resolution_pin(st); | |
817e5c65 GY |
396 | ret = len; |
397 | error_ret: | |
398 | mutex_unlock(&st->lock); | |
399 | return ret; | |
400 | } | |
b19e9ad5 | 401 | |
817e5c65 GY |
402 | /* read the fault register since last sample */ |
403 | static ssize_t ad2s1210_show_fault(struct device *dev, | |
404 | struct device_attribute *attr, char *buf) | |
405 | { | |
a651cf9b | 406 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
b19e9ad5 | 407 | int ret; |
817e5c65 GY |
408 | |
409 | mutex_lock(&st->lock); | |
b19e9ad5 | 410 | ret = ad2s1210_config_read(st, AD2S1210_REG_FAULT); |
817e5c65 | 411 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
412 | |
413 | return ret ? ret : sprintf(buf, "0x%x\n", ret); | |
817e5c65 GY |
414 | } |
415 | ||
416 | static ssize_t ad2s1210_clear_fault(struct device *dev, | |
b19e9ad5 JC |
417 | struct device_attribute *attr, |
418 | const char *buf, | |
419 | size_t len) | |
817e5c65 | 420 | { |
a651cf9b | 421 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
b19e9ad5 | 422 | int ret; |
817e5c65 GY |
423 | |
424 | mutex_lock(&st->lock); | |
b19e9ad5 | 425 | gpio_set_value(st->pdata->sample, 0); |
817e5c65 GY |
426 | /* delay (2 * tck + 20) nano seconds */ |
427 | udelay(1); | |
b19e9ad5 JC |
428 | gpio_set_value(st->pdata->sample, 1); |
429 | ret = ad2s1210_config_read(st, AD2S1210_REG_FAULT); | |
430 | if (ret < 0) | |
431 | goto error_ret; | |
432 | gpio_set_value(st->pdata->sample, 0); | |
433 | gpio_set_value(st->pdata->sample, 1); | |
434 | error_ret: | |
817e5c65 GY |
435 | mutex_unlock(&st->lock); |
436 | ||
b19e9ad5 | 437 | return ret < 0 ? ret : len; |
817e5c65 GY |
438 | } |
439 | ||
440 | static ssize_t ad2s1210_show_reg(struct device *dev, | |
b19e9ad5 JC |
441 | struct device_attribute *attr, |
442 | char *buf) | |
817e5c65 | 443 | { |
a651cf9b | 444 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
817e5c65 | 445 | struct iio_dev_attr *iattr = to_iio_dev_attr(attr); |
b19e9ad5 | 446 | int ret; |
817e5c65 GY |
447 | |
448 | mutex_lock(&st->lock); | |
b19e9ad5 | 449 | ret = ad2s1210_config_read(st, iattr->address); |
817e5c65 | 450 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
451 | |
452 | return ret < 0 ? ret : sprintf(buf, "%d\n", ret); | |
817e5c65 GY |
453 | } |
454 | ||
455 | static ssize_t ad2s1210_store_reg(struct device *dev, | |
456 | struct device_attribute *attr, const char *buf, size_t len) | |
457 | { | |
a651cf9b | 458 | struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); |
817e5c65 GY |
459 | unsigned long data; |
460 | int ret; | |
461 | struct iio_dev_attr *iattr = to_iio_dev_attr(attr); | |
462 | ||
463 | ret = strict_strtoul(buf, 10, &data); | |
464 | if (ret) | |
465 | return -EINVAL; | |
466 | mutex_lock(&st->lock); | |
b19e9ad5 JC |
467 | ret = ad2s1210_config_write(st, iattr->address); |
468 | if (ret < 0) | |
469 | goto error_ret; | |
470 | ret = ad2s1210_config_write(st, data & AD2S1210_MSB_IS_LOW); | |
471 | error_ret: | |
817e5c65 | 472 | mutex_unlock(&st->lock); |
b19e9ad5 | 473 | return ret < 0 ? ret : len; |
817e5c65 GY |
474 | } |
475 | ||
29148543 JC |
476 | static int ad2s1210_read_raw(struct iio_dev *indio_dev, |
477 | struct iio_chan_spec const *chan, | |
478 | int *val, | |
479 | int *val2, | |
480 | long m) | |
817e5c65 | 481 | { |
29148543 JC |
482 | struct ad2s1210_state *st = iio_priv(indio_dev); |
483 | bool negative; | |
817e5c65 | 484 | int ret = 0; |
817e5c65 | 485 | u16 pos; |
817e5c65 | 486 | s16 vel; |
817e5c65 | 487 | |
817e5c65 | 488 | mutex_lock(&st->lock); |
b19e9ad5 | 489 | gpio_set_value(st->pdata->sample, 0); |
817e5c65 GY |
490 | /* delay (6 * tck + 20) nano seconds */ |
491 | udelay(1); | |
492 | ||
29148543 JC |
493 | switch (chan->type) { |
494 | case IIO_ANGL: | |
495 | ad2s1210_set_mode(MOD_POS, st); | |
496 | break; | |
497 | case IIO_ANGL_VEL: | |
498 | ad2s1210_set_mode(MOD_VEL, st); | |
499 | break; | |
500 | default: | |
501 | ret = -EINVAL; | |
502 | break; | |
503 | } | |
504 | if (ret < 0) | |
505 | goto error_ret; | |
b19e9ad5 | 506 | ret = spi_read(st->sdev, st->rx, 2); |
29148543 | 507 | if (ret < 0) |
817e5c65 | 508 | goto error_ret; |
29148543 JC |
509 | |
510 | switch (chan->type) { | |
511 | case IIO_ANGL: | |
512 | pos = be16_to_cpup((u16 *)st->rx); | |
513 | if (st->hysteresis) | |
514 | pos >>= 16 - st->resolution; | |
515 | *val = pos; | |
516 | ret = IIO_VAL_INT; | |
517 | break; | |
518 | case IIO_ANGL_VEL: | |
519 | negative = st->rx[0] & 0x80; | |
520 | vel = be16_to_cpup((s16 *)st->rx); | |
521 | vel >>= 16 - st->resolution; | |
522 | if (vel & 0x8000) { | |
523 | negative = (0xffff >> st->resolution) << st->resolution; | |
524 | vel |= negative; | |
525 | } | |
526 | *val = vel; | |
527 | ret = IIO_VAL_INT; | |
528 | break; | |
529 | default: | |
530 | mutex_unlock(&st->lock); | |
531 | return -EINVAL; | |
817e5c65 | 532 | } |
29148543 | 533 | |
817e5c65 | 534 | error_ret: |
b19e9ad5 | 535 | gpio_set_value(st->pdata->sample, 1); |
817e5c65 GY |
536 | /* delay (2 * tck + 20) nano seconds */ |
537 | udelay(1); | |
538 | mutex_unlock(&st->lock); | |
29148543 | 539 | return ret; |
817e5c65 GY |
540 | } |
541 | ||
983bbfd0 | 542 | static IIO_DEVICE_ATTR(reset, S_IWUSR, |
b19e9ad5 | 543 | NULL, ad2s1210_store_softreset, 0); |
983bbfd0 | 544 | static IIO_DEVICE_ATTR(fclkin, S_IRUGO | S_IWUSR, |
b19e9ad5 | 545 | ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0); |
983bbfd0 | 546 | static IIO_DEVICE_ATTR(fexcit, S_IRUGO | S_IWUSR, |
b19e9ad5 | 547 | ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0); |
983bbfd0 | 548 | static IIO_DEVICE_ATTR(control, S_IRUGO | S_IWUSR, |
b19e9ad5 | 549 | ad2s1210_show_control, ad2s1210_store_control, 0); |
983bbfd0 | 550 | static IIO_DEVICE_ATTR(bits, S_IRUGO | S_IWUSR, |
b19e9ad5 | 551 | ad2s1210_show_resolution, ad2s1210_store_resolution, 0); |
983bbfd0 | 552 | static IIO_DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, |
b19e9ad5 | 553 | ad2s1210_show_fault, ad2s1210_clear_fault, 0); |
29148543 | 554 | |
983bbfd0 | 555 | static IIO_DEVICE_ATTR(los_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
556 | ad2s1210_show_reg, ad2s1210_store_reg, |
557 | AD2S1210_REG_LOS_THRD); | |
983bbfd0 | 558 | static IIO_DEVICE_ATTR(dos_ovr_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
559 | ad2s1210_show_reg, ad2s1210_store_reg, |
560 | AD2S1210_REG_DOS_OVR_THRD); | |
983bbfd0 | 561 | static IIO_DEVICE_ATTR(dos_mis_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
562 | ad2s1210_show_reg, ad2s1210_store_reg, |
563 | AD2S1210_REG_DOS_MIS_THRD); | |
983bbfd0 | 564 | static IIO_DEVICE_ATTR(dos_rst_max_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
565 | ad2s1210_show_reg, ad2s1210_store_reg, |
566 | AD2S1210_REG_DOS_RST_MAX_THRD); | |
983bbfd0 | 567 | static IIO_DEVICE_ATTR(dos_rst_min_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
568 | ad2s1210_show_reg, ad2s1210_store_reg, |
569 | AD2S1210_REG_DOS_RST_MIN_THRD); | |
983bbfd0 | 570 | static IIO_DEVICE_ATTR(lot_high_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
571 | ad2s1210_show_reg, ad2s1210_store_reg, |
572 | AD2S1210_REG_LOT_HIGH_THRD); | |
983bbfd0 | 573 | static IIO_DEVICE_ATTR(lot_low_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
574 | ad2s1210_show_reg, ad2s1210_store_reg, |
575 | AD2S1210_REG_LOT_LOW_THRD); | |
817e5c65 | 576 | |
29148543 | 577 | |
f4e4b955 | 578 | static const struct iio_chan_spec ad2s1210_channels[] = { |
29148543 JC |
579 | { |
580 | .type = IIO_ANGL, | |
581 | .indexed = 1, | |
582 | .channel = 0, | |
62465770 | 583 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, |
29148543 JC |
584 | }, { |
585 | .type = IIO_ANGL_VEL, | |
586 | .indexed = 1, | |
587 | .channel = 0, | |
62465770 | 588 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, |
29148543 JC |
589 | } |
590 | }; | |
591 | ||
817e5c65 | 592 | static struct attribute *ad2s1210_attributes[] = { |
817e5c65 GY |
593 | &iio_dev_attr_reset.dev_attr.attr, |
594 | &iio_dev_attr_fclkin.dev_attr.attr, | |
595 | &iio_dev_attr_fexcit.dev_attr.attr, | |
596 | &iio_dev_attr_control.dev_attr.attr, | |
597 | &iio_dev_attr_bits.dev_attr.attr, | |
598 | &iio_dev_attr_fault.dev_attr.attr, | |
817e5c65 GY |
599 | &iio_dev_attr_los_thrd.dev_attr.attr, |
600 | &iio_dev_attr_dos_ovr_thrd.dev_attr.attr, | |
601 | &iio_dev_attr_dos_mis_thrd.dev_attr.attr, | |
602 | &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr, | |
603 | &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr, | |
604 | &iio_dev_attr_lot_high_thrd.dev_attr.attr, | |
605 | &iio_dev_attr_lot_low_thrd.dev_attr.attr, | |
606 | NULL, | |
607 | }; | |
608 | ||
609 | static const struct attribute_group ad2s1210_attribute_group = { | |
817e5c65 GY |
610 | .attrs = ad2s1210_attributes, |
611 | }; | |
612 | ||
613 | static int __devinit ad2s1210_initial(struct ad2s1210_state *st) | |
614 | { | |
615 | unsigned char data; | |
616 | int ret; | |
617 | ||
618 | mutex_lock(&st->lock); | |
b19e9ad5 JC |
619 | if (st->pdata->gpioin) |
620 | st->resolution = ad2s1210_read_resolution_pin(st); | |
621 | else | |
622 | ad2s1210_set_resolution_pin(st); | |
623 | ||
624 | ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL); | |
625 | if (ret < 0) | |
626 | goto error_ret; | |
627 | data = AD2S1210_DEF_CONTROL & ~(AD2S1210_SET_RESOLUTION); | |
628 | data |= (st->resolution - 10) >> 1; | |
629 | ret = ad2s1210_config_write(st, data); | |
630 | if (ret < 0) | |
631 | goto error_ret; | |
632 | ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); | |
633 | if (ret < 0) | |
817e5c65 GY |
634 | goto error_ret; |
635 | ||
b19e9ad5 | 636 | if (ret & AD2S1210_MSB_IS_HIGH) { |
817e5c65 GY |
637 | ret = -EIO; |
638 | goto error_ret; | |
639 | } | |
640 | ||
b19e9ad5 JC |
641 | ret = ad2s1210_update_frequency_control_word(st); |
642 | if (ret < 0) | |
643 | goto error_ret; | |
644 | ret = ad2s1210_soft_reset(st); | |
817e5c65 GY |
645 | error_ret: |
646 | mutex_unlock(&st->lock); | |
647 | return ret; | |
648 | } | |
649 | ||
6fe8135f | 650 | static const struct iio_info ad2s1210_info = { |
29148543 | 651 | .read_raw = &ad2s1210_read_raw, |
6fe8135f JC |
652 | .attrs = &ad2s1210_attribute_group, |
653 | .driver_module = THIS_MODULE, | |
654 | }; | |
655 | ||
b19e9ad5 JC |
656 | static int ad2s1210_setup_gpios(struct ad2s1210_state *st) |
657 | { | |
b19e9ad5 | 658 | unsigned long flags = st->pdata->gpioin ? GPIOF_DIR_IN : GPIOF_DIR_OUT; |
93decf36 JC |
659 | struct gpio ad2s1210_gpios[] = { |
660 | { st->pdata->sample, GPIOF_DIR_IN, "sample" }, | |
661 | { st->pdata->a[0], flags, "a0" }, | |
662 | { st->pdata->a[1], flags, "a1" }, | |
663 | { st->pdata->res[0], flags, "res0" }, | |
664 | { st->pdata->res[0], flags, "res1" }, | |
665 | }; | |
b19e9ad5 | 666 | |
93decf36 | 667 | return gpio_request_array(ad2s1210_gpios, ARRAY_SIZE(ad2s1210_gpios)); |
b19e9ad5 JC |
668 | } |
669 | ||
670 | static void ad2s1210_free_gpios(struct ad2s1210_state *st) | |
671 | { | |
93decf36 JC |
672 | unsigned long flags = st->pdata->gpioin ? GPIOF_DIR_IN : GPIOF_DIR_OUT; |
673 | struct gpio ad2s1210_gpios[] = { | |
674 | { st->pdata->sample, GPIOF_DIR_IN, "sample" }, | |
675 | { st->pdata->a[0], flags, "a0" }, | |
676 | { st->pdata->a[1], flags, "a1" }, | |
677 | { st->pdata->res[0], flags, "res0" }, | |
678 | { st->pdata->res[0], flags, "res1" }, | |
679 | }; | |
680 | ||
681 | gpio_free_array(ad2s1210_gpios, ARRAY_SIZE(ad2s1210_gpios)); | |
b19e9ad5 JC |
682 | } |
683 | ||
817e5c65 GY |
684 | static int __devinit ad2s1210_probe(struct spi_device *spi) |
685 | { | |
b19e9ad5 | 686 | struct iio_dev *indio_dev; |
817e5c65 | 687 | struct ad2s1210_state *st; |
b19e9ad5 JC |
688 | int ret; |
689 | ||
690 | if (spi->dev.platform_data == NULL) | |
691 | return -EINVAL; | |
817e5c65 | 692 | |
7cbb7537 | 693 | indio_dev = iio_device_alloc(sizeof(*st)); |
b19e9ad5 | 694 | if (indio_dev == NULL) { |
817e5c65 GY |
695 | ret = -ENOMEM; |
696 | goto error_ret; | |
697 | } | |
b19e9ad5 JC |
698 | st = iio_priv(indio_dev); |
699 | st->pdata = spi->dev.platform_data; | |
700 | ret = ad2s1210_setup_gpios(st); | |
701 | if (ret < 0) | |
702 | goto error_free_dev; | |
703 | ||
704 | spi_set_drvdata(spi, indio_dev); | |
817e5c65 GY |
705 | |
706 | mutex_init(&st->lock); | |
707 | st->sdev = spi; | |
b19e9ad5 | 708 | st->hysteresis = true; |
817e5c65 | 709 | st->mode = MOD_CONFIG; |
b19e9ad5 | 710 | st->resolution = 12; |
817e5c65 | 711 | st->fexcit = AD2S1210_DEF_EXCIT; |
817e5c65 | 712 | |
b19e9ad5 JC |
713 | indio_dev->dev.parent = &spi->dev; |
714 | indio_dev->info = &ad2s1210_info; | |
715 | indio_dev->modes = INDIO_DIRECT_MODE; | |
29148543 JC |
716 | indio_dev->channels = ad2s1210_channels; |
717 | indio_dev->num_channels = ARRAY_SIZE(ad2s1210_channels); | |
bf52f059 | 718 | indio_dev->name = spi_get_device_id(spi)->name; |
817e5c65 | 719 | |
b19e9ad5 | 720 | ret = iio_device_register(indio_dev); |
817e5c65 | 721 | if (ret) |
b19e9ad5 | 722 | goto error_free_gpios; |
817e5c65 | 723 | |
b19e9ad5 | 724 | st->fclkin = spi->max_speed_hz; |
817e5c65 GY |
725 | spi->mode = SPI_MODE_3; |
726 | spi_setup(spi); | |
817e5c65 | 727 | ad2s1210_initial(st); |
b19e9ad5 | 728 | |
817e5c65 GY |
729 | return 0; |
730 | ||
b19e9ad5 JC |
731 | error_free_gpios: |
732 | ad2s1210_free_gpios(st); | |
817e5c65 | 733 | error_free_dev: |
7cbb7537 | 734 | iio_device_free(indio_dev); |
817e5c65 | 735 | error_ret: |
817e5c65 GY |
736 | return ret; |
737 | } | |
738 | ||
739 | static int __devexit ad2s1210_remove(struct spi_device *spi) | |
740 | { | |
b19e9ad5 | 741 | struct iio_dev *indio_dev = spi_get_drvdata(spi); |
26d25ae3 | 742 | |
3e394407 | 743 | iio_device_unregister(indio_dev); |
d2fffd6c | 744 | ad2s1210_free_gpios(iio_priv(indio_dev)); |
7cbb7537 | 745 | iio_device_free(indio_dev); |
817e5c65 GY |
746 | |
747 | return 0; | |
748 | } | |
749 | ||
bf52f059 JC |
750 | static const struct spi_device_id ad2s1210_id[] = { |
751 | { "ad2s1210" }, | |
752 | {} | |
753 | }; | |
55e4390c | 754 | MODULE_DEVICE_TABLE(spi, ad2s1210_id); |
bf52f059 | 755 | |
817e5c65 GY |
756 | static struct spi_driver ad2s1210_driver = { |
757 | .driver = { | |
758 | .name = DRV_NAME, | |
759 | .owner = THIS_MODULE, | |
760 | }, | |
761 | .probe = ad2s1210_probe, | |
762 | .remove = __devexit_p(ad2s1210_remove), | |
bf52f059 | 763 | .id_table = ad2s1210_id, |
817e5c65 | 764 | }; |
ae6ae6fe | 765 | module_spi_driver(ad2s1210_driver); |
817e5c65 GY |
766 | |
767 | MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>"); | |
768 | MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver"); | |
769 | MODULE_LICENSE("GPL v2"); |