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 GY |
20 | |
21 | #include "../iio.h" | |
22 | #include "../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 | ||
198 | ||
199 | /* return the OLD DATA since last spi bus write */ | |
200 | static ssize_t ad2s1210_show_raw(struct device *dev, | |
b19e9ad5 JC |
201 | struct device_attribute *attr, |
202 | char *buf) | |
817e5c65 | 203 | { |
b19e9ad5 JC |
204 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
205 | int ret = 0; | |
817e5c65 GY |
206 | |
207 | mutex_lock(&st->lock); | |
208 | if (st->old_data) { | |
209 | ret = sprintf(buf, "0x%x\n", st->rx[0]); | |
b19e9ad5 JC |
210 | st->old_data = false; |
211 | } | |
817e5c65 | 212 | mutex_unlock(&st->lock); |
b19e9ad5 | 213 | |
817e5c65 GY |
214 | return ret; |
215 | } | |
216 | ||
217 | static ssize_t ad2s1210_store_raw(struct device *dev, | |
b19e9ad5 JC |
218 | struct device_attribute *attr, |
219 | const char *buf, | |
220 | size_t len) | |
817e5c65 | 221 | { |
b19e9ad5 | 222 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 GY |
223 | unsigned long udata; |
224 | unsigned char data; | |
225 | int ret; | |
226 | ||
227 | ret = strict_strtoul(buf, 16, &udata); | |
228 | if (ret) | |
229 | return -EINVAL; | |
b19e9ad5 | 230 | |
817e5c65 GY |
231 | data = udata & 0xff; |
232 | mutex_lock(&st->lock); | |
b19e9ad5 | 233 | ret = ad2s1210_config_write(st, data); |
817e5c65 | 234 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
235 | |
236 | return ret < 0 ? ret : len; | |
817e5c65 GY |
237 | } |
238 | ||
239 | static ssize_t ad2s1210_store_softreset(struct device *dev, | |
b19e9ad5 JC |
240 | struct device_attribute *attr, |
241 | const char *buf, | |
242 | size_t len) | |
817e5c65 | 243 | { |
b19e9ad5 JC |
244 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
245 | int ret; | |
246 | ||
817e5c65 | 247 | mutex_lock(&st->lock); |
b19e9ad5 | 248 | ret = ad2s1210_soft_reset(st); |
817e5c65 | 249 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
250 | |
251 | return ret < 0 ? ret : len; | |
817e5c65 GY |
252 | } |
253 | ||
254 | static ssize_t ad2s1210_show_fclkin(struct device *dev, | |
b19e9ad5 JC |
255 | struct device_attribute *attr, |
256 | char *buf) | |
817e5c65 | 257 | { |
b19e9ad5 | 258 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 GY |
259 | return sprintf(buf, "%d\n", st->fclkin); |
260 | } | |
261 | ||
262 | static ssize_t ad2s1210_store_fclkin(struct device *dev, | |
b19e9ad5 JC |
263 | struct device_attribute *attr, |
264 | const char *buf, | |
265 | size_t len) | |
817e5c65 | 266 | { |
b19e9ad5 | 267 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 GY |
268 | unsigned long fclkin; |
269 | int ret; | |
270 | ||
271 | ret = strict_strtoul(buf, 10, &fclkin); | |
b19e9ad5 JC |
272 | if (ret) |
273 | return ret; | |
274 | if (fclkin < AD2S1210_MIN_CLKIN || fclkin > AD2S1210_MAX_CLKIN) { | |
817e5c65 GY |
275 | pr_err("ad2s1210: fclkin out of range\n"); |
276 | return -EINVAL; | |
277 | } | |
b19e9ad5 JC |
278 | |
279 | mutex_lock(&st->lock); | |
280 | st->fclkin = fclkin; | |
281 | ||
282 | ret = ad2s1210_update_frequency_control_word(st); | |
283 | if (ret < 0) | |
284 | goto error_ret; | |
285 | ret = ad2s1210_soft_reset(st); | |
286 | error_ret: | |
817e5c65 | 287 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
288 | |
289 | return ret < 0 ? ret : len; | |
817e5c65 GY |
290 | } |
291 | ||
292 | static ssize_t ad2s1210_show_fexcit(struct device *dev, | |
b19e9ad5 JC |
293 | struct device_attribute *attr, |
294 | char *buf) | |
817e5c65 | 295 | { |
b19e9ad5 | 296 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 GY |
297 | return sprintf(buf, "%d\n", st->fexcit); |
298 | } | |
299 | ||
300 | static ssize_t ad2s1210_store_fexcit(struct device *dev, | |
b19e9ad5 JC |
301 | struct device_attribute *attr, |
302 | const char *buf, size_t len) | |
817e5c65 | 303 | { |
b19e9ad5 | 304 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 GY |
305 | unsigned long fexcit; |
306 | int ret; | |
307 | ||
308 | ret = strict_strtoul(buf, 10, &fexcit); | |
b19e9ad5 JC |
309 | if (ret < 0) |
310 | return ret; | |
311 | if (fexcit < AD2S1210_MIN_EXCIT || fexcit > AD2S1210_MAX_EXCIT) { | |
817e5c65 GY |
312 | pr_err("ad2s1210: excitation frequency out of range\n"); |
313 | return -EINVAL; | |
314 | } | |
b19e9ad5 JC |
315 | mutex_lock(&st->lock); |
316 | st->fexcit = fexcit; | |
317 | ret = ad2s1210_update_frequency_control_word(st); | |
318 | if (ret < 0) | |
319 | goto error_ret; | |
320 | ret = ad2s1210_soft_reset(st); | |
321 | error_ret: | |
817e5c65 | 322 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
323 | |
324 | return ret < 0 ? ret : len; | |
817e5c65 GY |
325 | } |
326 | ||
327 | static ssize_t ad2s1210_show_control(struct device *dev, | |
b19e9ad5 JC |
328 | struct device_attribute *attr, |
329 | char *buf) | |
817e5c65 | 330 | { |
b19e9ad5 JC |
331 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
332 | int ret; | |
817e5c65 | 333 | mutex_lock(&st->lock); |
b19e9ad5 | 334 | ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); |
817e5c65 | 335 | mutex_unlock(&st->lock); |
b19e9ad5 | 336 | return ret < 0 ? ret : sprintf(buf, "0x%x\n", ret); |
817e5c65 GY |
337 | } |
338 | ||
339 | static ssize_t ad2s1210_store_control(struct device *dev, | |
340 | struct device_attribute *attr, | |
341 | const char *buf, size_t len) | |
342 | { | |
b19e9ad5 | 343 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 GY |
344 | unsigned long udata; |
345 | unsigned char data; | |
346 | int ret; | |
347 | ||
348 | ret = strict_strtoul(buf, 16, &udata); | |
b19e9ad5 JC |
349 | if (ret) |
350 | return -EINVAL; | |
351 | ||
817e5c65 | 352 | mutex_lock(&st->lock); |
b19e9ad5 JC |
353 | ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL); |
354 | if (ret < 0) | |
355 | goto error_ret; | |
356 | data = udata & AD2S1210_MSB_IS_LOW; | |
357 | ret = ad2s1210_config_write(st, data); | |
358 | if (ret < 0) | |
359 | goto error_ret; | |
360 | ||
361 | ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); | |
362 | if (ret < 0) | |
363 | goto error_ret; | |
364 | if (ret & AD2S1210_MSB_IS_HIGH) { | |
817e5c65 GY |
365 | ret = -EIO; |
366 | pr_err("ad2s1210: write control register fail\n"); | |
367 | goto error_ret; | |
368 | } | |
b19e9ad5 JC |
369 | st->resolution |
370 | = ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION]; | |
371 | if (st->pdata->gpioin) { | |
372 | data = ad2s1210_read_resolution_pin(st); | |
373 | if (data != st->resolution) | |
374 | pr_warning("ad2s1210: resolution settings not match\n"); | |
375 | } else | |
376 | ad2s1210_set_resolution_pin(st); | |
377 | ||
817e5c65 | 378 | ret = len; |
b19e9ad5 JC |
379 | st->hysteresis = !!(data & AD2S1210_ENABLE_HYSTERESIS); |
380 | ||
817e5c65 GY |
381 | error_ret: |
382 | mutex_unlock(&st->lock); | |
383 | return ret; | |
384 | } | |
385 | ||
386 | static ssize_t ad2s1210_show_resolution(struct device *dev, | |
387 | struct device_attribute *attr, char *buf) | |
388 | { | |
b19e9ad5 | 389 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 GY |
390 | return sprintf(buf, "%d\n", st->resolution); |
391 | } | |
392 | ||
393 | static ssize_t ad2s1210_store_resolution(struct device *dev, | |
394 | struct device_attribute *attr, | |
395 | const char *buf, size_t len) | |
396 | { | |
b19e9ad5 | 397 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 GY |
398 | unsigned char data; |
399 | unsigned long udata; | |
400 | int ret; | |
401 | ||
402 | ret = strict_strtoul(buf, 10, &udata); | |
b19e9ad5 | 403 | if (ret || udata < 10 || udata > 16) { |
817e5c65 GY |
404 | pr_err("ad2s1210: resolution out of range\n"); |
405 | return -EINVAL; | |
406 | } | |
407 | mutex_lock(&st->lock); | |
b19e9ad5 JC |
408 | ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); |
409 | if (ret < 0) | |
410 | goto error_ret; | |
411 | data = ret; | |
412 | data &= ~AD2S1210_SET_RESOLUTION; | |
413 | data |= (udata - 10) >> 1; | |
414 | ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL); | |
415 | if (ret < 0) | |
416 | goto error_ret; | |
417 | ret = ad2s1210_config_write(st, data & AD2S1210_MSB_IS_LOW); | |
418 | if (ret < 0) | |
419 | goto error_ret; | |
420 | ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); | |
421 | if (ret < 0) | |
422 | goto error_ret; | |
423 | data = ret; | |
424 | if (data & AD2S1210_MSB_IS_HIGH) { | |
817e5c65 GY |
425 | ret = -EIO; |
426 | pr_err("ad2s1210: setting resolution fail\n"); | |
427 | goto error_ret; | |
428 | } | |
b19e9ad5 JC |
429 | st->resolution |
430 | = ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION]; | |
431 | if (st->pdata->gpioin) { | |
432 | data = ad2s1210_read_resolution_pin(st); | |
433 | if (data != st->resolution) | |
434 | pr_warning("ad2s1210: resolution settings not match\n"); | |
435 | } else | |
436 | ad2s1210_set_resolution_pin(st); | |
817e5c65 GY |
437 | ret = len; |
438 | error_ret: | |
439 | mutex_unlock(&st->lock); | |
440 | return ret; | |
441 | } | |
b19e9ad5 | 442 | |
817e5c65 GY |
443 | /* read the fault register since last sample */ |
444 | static ssize_t ad2s1210_show_fault(struct device *dev, | |
445 | struct device_attribute *attr, char *buf) | |
446 | { | |
b19e9ad5 JC |
447 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
448 | int ret; | |
817e5c65 GY |
449 | |
450 | mutex_lock(&st->lock); | |
b19e9ad5 | 451 | ret = ad2s1210_config_read(st, AD2S1210_REG_FAULT); |
817e5c65 | 452 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
453 | |
454 | return ret ? ret : sprintf(buf, "0x%x\n", ret); | |
817e5c65 GY |
455 | } |
456 | ||
457 | static ssize_t ad2s1210_clear_fault(struct device *dev, | |
b19e9ad5 JC |
458 | struct device_attribute *attr, |
459 | const char *buf, | |
460 | size_t len) | |
817e5c65 | 461 | { |
b19e9ad5 JC |
462 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
463 | int ret; | |
817e5c65 GY |
464 | |
465 | mutex_lock(&st->lock); | |
b19e9ad5 | 466 | gpio_set_value(st->pdata->sample, 0); |
817e5c65 GY |
467 | /* delay (2 * tck + 20) nano seconds */ |
468 | udelay(1); | |
b19e9ad5 JC |
469 | gpio_set_value(st->pdata->sample, 1); |
470 | ret = ad2s1210_config_read(st, AD2S1210_REG_FAULT); | |
471 | if (ret < 0) | |
472 | goto error_ret; | |
473 | gpio_set_value(st->pdata->sample, 0); | |
474 | gpio_set_value(st->pdata->sample, 1); | |
475 | error_ret: | |
817e5c65 GY |
476 | mutex_unlock(&st->lock); |
477 | ||
b19e9ad5 | 478 | return ret < 0 ? ret : len; |
817e5c65 GY |
479 | } |
480 | ||
481 | static ssize_t ad2s1210_show_reg(struct device *dev, | |
b19e9ad5 JC |
482 | struct device_attribute *attr, |
483 | char *buf) | |
817e5c65 | 484 | { |
b19e9ad5 | 485 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 | 486 | struct iio_dev_attr *iattr = to_iio_dev_attr(attr); |
b19e9ad5 | 487 | int ret; |
817e5c65 GY |
488 | |
489 | mutex_lock(&st->lock); | |
b19e9ad5 | 490 | ret = ad2s1210_config_read(st, iattr->address); |
817e5c65 | 491 | mutex_unlock(&st->lock); |
b19e9ad5 JC |
492 | |
493 | return ret < 0 ? ret : sprintf(buf, "%d\n", ret); | |
817e5c65 GY |
494 | } |
495 | ||
496 | static ssize_t ad2s1210_store_reg(struct device *dev, | |
497 | struct device_attribute *attr, const char *buf, size_t len) | |
498 | { | |
b19e9ad5 | 499 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 GY |
500 | unsigned long data; |
501 | int ret; | |
502 | struct iio_dev_attr *iattr = to_iio_dev_attr(attr); | |
503 | ||
504 | ret = strict_strtoul(buf, 10, &data); | |
505 | if (ret) | |
506 | return -EINVAL; | |
507 | mutex_lock(&st->lock); | |
b19e9ad5 JC |
508 | ret = ad2s1210_config_write(st, iattr->address); |
509 | if (ret < 0) | |
510 | goto error_ret; | |
511 | ret = ad2s1210_config_write(st, data & AD2S1210_MSB_IS_LOW); | |
512 | error_ret: | |
817e5c65 | 513 | mutex_unlock(&st->lock); |
b19e9ad5 | 514 | return ret < 0 ? ret : len; |
817e5c65 GY |
515 | } |
516 | ||
517 | static ssize_t ad2s1210_show_pos(struct device *dev, | |
b19e9ad5 JC |
518 | struct device_attribute *attr, |
519 | char *buf) | |
817e5c65 | 520 | { |
817e5c65 GY |
521 | int ret = 0; |
522 | ssize_t len = 0; | |
523 | u16 pos; | |
b19e9ad5 | 524 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 | 525 | |
817e5c65 | 526 | mutex_lock(&st->lock); |
b19e9ad5 | 527 | gpio_set_value(st->pdata->sample, 0); |
817e5c65 GY |
528 | /* delay (6 * tck + 20) nano seconds */ |
529 | udelay(1); | |
530 | ||
b19e9ad5 JC |
531 | ad2s1210_set_mode(MOD_POS, st); |
532 | ret = spi_read(st->sdev, st->rx, 2); | |
817e5c65 GY |
533 | if (ret) |
534 | goto error_ret; | |
b19e9ad5 | 535 | pos = be16_to_cpup((u16 *)st->rx); |
817e5c65 GY |
536 | if (st->hysteresis) |
537 | pos >>= 16 - st->resolution; | |
538 | len = sprintf(buf, "%d\n", pos); | |
539 | error_ret: | |
b19e9ad5 | 540 | gpio_set_value(st->pdata->sample, 1); |
817e5c65 GY |
541 | /* delay (2 * tck + 20) nano seconds */ |
542 | udelay(1); | |
543 | mutex_unlock(&st->lock); | |
544 | ||
b19e9ad5 | 545 | return ret < 0 ? ret : len; |
817e5c65 GY |
546 | } |
547 | ||
548 | static ssize_t ad2s1210_show_vel(struct device *dev, | |
b19e9ad5 JC |
549 | struct device_attribute *attr, |
550 | char *buf) | |
817e5c65 | 551 | { |
817e5c65 GY |
552 | unsigned short negative; |
553 | int ret = 0; | |
554 | ssize_t len = 0; | |
555 | s16 vel; | |
b19e9ad5 | 556 | struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev)); |
817e5c65 | 557 | |
817e5c65 | 558 | mutex_lock(&st->lock); |
b19e9ad5 | 559 | gpio_set_value(st->pdata->sample, 0); |
817e5c65 GY |
560 | /* delay (6 * tck + 20) nano seconds */ |
561 | udelay(1); | |
562 | ||
b19e9ad5 JC |
563 | ad2s1210_set_mode(MOD_VEL, st); |
564 | ret = spi_read(st->sdev, st->rx, 2); | |
817e5c65 GY |
565 | if (ret) |
566 | goto error_ret; | |
567 | negative = st->rx[0] & 0x80; | |
b19e9ad5 | 568 | vel = be16_to_cpup((s16 *)st->rx); |
817e5c65 | 569 | vel >>= 16 - st->resolution; |
b19e9ad5 | 570 | if (vel & 0x8000) { |
817e5c65 GY |
571 | negative = (0xffff >> st->resolution) << st->resolution; |
572 | vel |= negative; | |
573 | } | |
574 | len = sprintf(buf, "%d\n", vel); | |
575 | error_ret: | |
b19e9ad5 | 576 | gpio_set_value(st->pdata->sample, 1); |
817e5c65 GY |
577 | /* delay (2 * tck + 20) nano seconds */ |
578 | udelay(1); | |
579 | mutex_unlock(&st->lock); | |
580 | ||
b19e9ad5 | 581 | return ret < 0 ? ret : len; |
817e5c65 GY |
582 | } |
583 | ||
983bbfd0 | 584 | static IIO_DEVICE_ATTR(raw_io, S_IRUGO | S_IWUSR, |
b19e9ad5 | 585 | ad2s1210_show_raw, ad2s1210_store_raw, 0); |
983bbfd0 | 586 | static IIO_DEVICE_ATTR(reset, S_IWUSR, |
b19e9ad5 | 587 | NULL, ad2s1210_store_softreset, 0); |
983bbfd0 | 588 | static IIO_DEVICE_ATTR(fclkin, S_IRUGO | S_IWUSR, |
b19e9ad5 | 589 | ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0); |
983bbfd0 | 590 | static IIO_DEVICE_ATTR(fexcit, S_IRUGO | S_IWUSR, |
b19e9ad5 | 591 | ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0); |
983bbfd0 | 592 | static IIO_DEVICE_ATTR(control, S_IRUGO | S_IWUSR, |
b19e9ad5 | 593 | ad2s1210_show_control, ad2s1210_store_control, 0); |
983bbfd0 | 594 | static IIO_DEVICE_ATTR(bits, S_IRUGO | S_IWUSR, |
b19e9ad5 | 595 | ad2s1210_show_resolution, ad2s1210_store_resolution, 0); |
983bbfd0 | 596 | static IIO_DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
597 | ad2s1210_show_fault, ad2s1210_clear_fault, 0); |
598 | static IIO_DEVICE_ATTR(pos, S_IRUGO, ad2s1210_show_pos, NULL, 0); | |
599 | static IIO_DEVICE_ATTR(vel, S_IRUGO, ad2s1210_show_vel, NULL, 0); | |
983bbfd0 | 600 | static IIO_DEVICE_ATTR(los_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
601 | ad2s1210_show_reg, ad2s1210_store_reg, |
602 | AD2S1210_REG_LOS_THRD); | |
983bbfd0 | 603 | static IIO_DEVICE_ATTR(dos_ovr_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
604 | ad2s1210_show_reg, ad2s1210_store_reg, |
605 | AD2S1210_REG_DOS_OVR_THRD); | |
983bbfd0 | 606 | static IIO_DEVICE_ATTR(dos_mis_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
607 | ad2s1210_show_reg, ad2s1210_store_reg, |
608 | AD2S1210_REG_DOS_MIS_THRD); | |
983bbfd0 | 609 | static IIO_DEVICE_ATTR(dos_rst_max_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
610 | ad2s1210_show_reg, ad2s1210_store_reg, |
611 | AD2S1210_REG_DOS_RST_MAX_THRD); | |
983bbfd0 | 612 | static IIO_DEVICE_ATTR(dos_rst_min_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
613 | ad2s1210_show_reg, ad2s1210_store_reg, |
614 | AD2S1210_REG_DOS_RST_MIN_THRD); | |
983bbfd0 | 615 | static IIO_DEVICE_ATTR(lot_high_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
616 | ad2s1210_show_reg, ad2s1210_store_reg, |
617 | AD2S1210_REG_LOT_HIGH_THRD); | |
983bbfd0 | 618 | static IIO_DEVICE_ATTR(lot_low_thrd, S_IRUGO | S_IWUSR, |
b19e9ad5 JC |
619 | ad2s1210_show_reg, ad2s1210_store_reg, |
620 | AD2S1210_REG_LOT_LOW_THRD); | |
817e5c65 GY |
621 | |
622 | static struct attribute *ad2s1210_attributes[] = { | |
817e5c65 GY |
623 | &iio_dev_attr_raw_io.dev_attr.attr, |
624 | &iio_dev_attr_reset.dev_attr.attr, | |
625 | &iio_dev_attr_fclkin.dev_attr.attr, | |
626 | &iio_dev_attr_fexcit.dev_attr.attr, | |
627 | &iio_dev_attr_control.dev_attr.attr, | |
628 | &iio_dev_attr_bits.dev_attr.attr, | |
629 | &iio_dev_attr_fault.dev_attr.attr, | |
630 | &iio_dev_attr_pos.dev_attr.attr, | |
631 | &iio_dev_attr_vel.dev_attr.attr, | |
817e5c65 GY |
632 | &iio_dev_attr_los_thrd.dev_attr.attr, |
633 | &iio_dev_attr_dos_ovr_thrd.dev_attr.attr, | |
634 | &iio_dev_attr_dos_mis_thrd.dev_attr.attr, | |
635 | &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr, | |
636 | &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr, | |
637 | &iio_dev_attr_lot_high_thrd.dev_attr.attr, | |
638 | &iio_dev_attr_lot_low_thrd.dev_attr.attr, | |
639 | NULL, | |
640 | }; | |
641 | ||
642 | static const struct attribute_group ad2s1210_attribute_group = { | |
817e5c65 GY |
643 | .attrs = ad2s1210_attributes, |
644 | }; | |
645 | ||
646 | static int __devinit ad2s1210_initial(struct ad2s1210_state *st) | |
647 | { | |
648 | unsigned char data; | |
649 | int ret; | |
650 | ||
651 | mutex_lock(&st->lock); | |
b19e9ad5 JC |
652 | if (st->pdata->gpioin) |
653 | st->resolution = ad2s1210_read_resolution_pin(st); | |
654 | else | |
655 | ad2s1210_set_resolution_pin(st); | |
656 | ||
657 | ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL); | |
658 | if (ret < 0) | |
659 | goto error_ret; | |
660 | data = AD2S1210_DEF_CONTROL & ~(AD2S1210_SET_RESOLUTION); | |
661 | data |= (st->resolution - 10) >> 1; | |
662 | ret = ad2s1210_config_write(st, data); | |
663 | if (ret < 0) | |
664 | goto error_ret; | |
665 | ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL); | |
666 | if (ret < 0) | |
817e5c65 GY |
667 | goto error_ret; |
668 | ||
b19e9ad5 | 669 | if (ret & AD2S1210_MSB_IS_HIGH) { |
817e5c65 GY |
670 | ret = -EIO; |
671 | goto error_ret; | |
672 | } | |
673 | ||
b19e9ad5 JC |
674 | ret = ad2s1210_update_frequency_control_word(st); |
675 | if (ret < 0) | |
676 | goto error_ret; | |
677 | ret = ad2s1210_soft_reset(st); | |
817e5c65 GY |
678 | error_ret: |
679 | mutex_unlock(&st->lock); | |
680 | return ret; | |
681 | } | |
682 | ||
6fe8135f JC |
683 | static const struct iio_info ad2s1210_info = { |
684 | .attrs = &ad2s1210_attribute_group, | |
685 | .driver_module = THIS_MODULE, | |
686 | }; | |
687 | ||
b19e9ad5 JC |
688 | static int ad2s1210_setup_gpios(struct ad2s1210_state *st) |
689 | { | |
690 | int ret; | |
691 | unsigned long flags = st->pdata->gpioin ? GPIOF_DIR_IN : GPIOF_DIR_OUT; | |
692 | ||
693 | ret = gpio_request_one(st->pdata->sample, GPIOF_DIR_IN, "sample"); | |
694 | if (ret < 0) | |
695 | goto error_ret; | |
696 | ret = gpio_request_one(st->pdata->a[0], flags, "a0"); | |
697 | if (ret < 0) | |
698 | goto error_free_sample; | |
699 | ret = gpio_request_one(st->pdata->a[1], flags, "a1"); | |
700 | if (ret < 0) | |
701 | goto error_free_a0; | |
702 | ret = gpio_request_one(st->pdata->res[1], flags, "res0"); | |
703 | if (ret < 0) | |
704 | goto error_free_a1; | |
705 | ret = gpio_request_one(st->pdata->res[1], flags, "res1"); | |
706 | if (ret < 0) | |
707 | goto error_free_res0; | |
708 | ||
709 | return 0; | |
710 | error_free_res0: | |
711 | gpio_free(st->pdata->res[0]); | |
712 | error_free_a1: | |
713 | gpio_free(st->pdata->a[1]); | |
714 | error_free_a0: | |
715 | gpio_free(st->pdata->a[0]); | |
716 | error_free_sample: | |
717 | gpio_free(st->pdata->sample); | |
718 | error_ret: | |
719 | return ret; | |
720 | } | |
721 | ||
722 | static void ad2s1210_free_gpios(struct ad2s1210_state *st) | |
723 | { | |
724 | gpio_free(st->pdata->res[1]); | |
725 | gpio_free(st->pdata->res[0]); | |
726 | gpio_free(st->pdata->a[1]); | |
727 | gpio_free(st->pdata->a[0]); | |
728 | gpio_free(st->pdata->sample); | |
729 | } | |
730 | ||
817e5c65 GY |
731 | static int __devinit ad2s1210_probe(struct spi_device *spi) |
732 | { | |
b19e9ad5 | 733 | struct iio_dev *indio_dev; |
817e5c65 | 734 | struct ad2s1210_state *st; |
b19e9ad5 JC |
735 | int ret; |
736 | ||
737 | if (spi->dev.platform_data == NULL) | |
738 | return -EINVAL; | |
817e5c65 | 739 | |
b19e9ad5 JC |
740 | indio_dev = iio_allocate_device(sizeof(*st)); |
741 | if (indio_dev == NULL) { | |
817e5c65 GY |
742 | ret = -ENOMEM; |
743 | goto error_ret; | |
744 | } | |
b19e9ad5 JC |
745 | st = iio_priv(indio_dev); |
746 | st->pdata = spi->dev.platform_data; | |
747 | ret = ad2s1210_setup_gpios(st); | |
748 | if (ret < 0) | |
749 | goto error_free_dev; | |
750 | ||
751 | spi_set_drvdata(spi, indio_dev); | |
817e5c65 GY |
752 | |
753 | mutex_init(&st->lock); | |
754 | st->sdev = spi; | |
b19e9ad5 | 755 | st->hysteresis = true; |
817e5c65 | 756 | st->mode = MOD_CONFIG; |
b19e9ad5 | 757 | st->resolution = 12; |
817e5c65 | 758 | st->fexcit = AD2S1210_DEF_EXCIT; |
817e5c65 | 759 | |
b19e9ad5 JC |
760 | indio_dev->dev.parent = &spi->dev; |
761 | indio_dev->info = &ad2s1210_info; | |
762 | indio_dev->modes = INDIO_DIRECT_MODE; | |
bf52f059 | 763 | indio_dev->name = spi_get_device_id(spi)->name; |
817e5c65 | 764 | |
b19e9ad5 | 765 | ret = iio_device_register(indio_dev); |
817e5c65 | 766 | if (ret) |
b19e9ad5 | 767 | goto error_free_gpios; |
817e5c65 | 768 | |
b19e9ad5 | 769 | st->fclkin = spi->max_speed_hz; |
817e5c65 GY |
770 | spi->mode = SPI_MODE_3; |
771 | spi_setup(spi); | |
817e5c65 | 772 | ad2s1210_initial(st); |
b19e9ad5 | 773 | |
817e5c65 GY |
774 | return 0; |
775 | ||
b19e9ad5 JC |
776 | error_free_gpios: |
777 | ad2s1210_free_gpios(st); | |
817e5c65 | 778 | error_free_dev: |
b19e9ad5 | 779 | iio_free_device(indio_dev); |
817e5c65 | 780 | error_ret: |
817e5c65 GY |
781 | return ret; |
782 | } | |
783 | ||
784 | static int __devexit ad2s1210_remove(struct spi_device *spi) | |
785 | { | |
b19e9ad5 JC |
786 | struct iio_dev *indio_dev = spi_get_drvdata(spi); |
787 | struct ad2s1210_state *st = iio_priv(indio_dev); | |
26d25ae3 | 788 | |
b19e9ad5 | 789 | ad2s1210_free_gpios(st); |
3e394407 | 790 | iio_device_unregister(indio_dev); |
817e5c65 GY |
791 | |
792 | return 0; | |
793 | } | |
794 | ||
bf52f059 JC |
795 | static const struct spi_device_id ad2s1210_id[] = { |
796 | { "ad2s1210" }, | |
797 | {} | |
798 | }; | |
799 | ||
817e5c65 GY |
800 | static struct spi_driver ad2s1210_driver = { |
801 | .driver = { | |
802 | .name = DRV_NAME, | |
803 | .owner = THIS_MODULE, | |
804 | }, | |
805 | .probe = ad2s1210_probe, | |
806 | .remove = __devexit_p(ad2s1210_remove), | |
bf52f059 | 807 | .id_table = ad2s1210_id, |
817e5c65 GY |
808 | }; |
809 | ||
810 | static __init int ad2s1210_spi_init(void) | |
811 | { | |
812 | return spi_register_driver(&ad2s1210_driver); | |
813 | } | |
814 | module_init(ad2s1210_spi_init); | |
815 | ||
816 | static __exit void ad2s1210_spi_exit(void) | |
817 | { | |
818 | spi_unregister_driver(&ad2s1210_driver); | |
819 | } | |
820 | module_exit(ad2s1210_spi_exit); | |
821 | ||
822 | MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>"); | |
823 | MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver"); | |
824 | MODULE_LICENSE("GPL v2"); |