/drivers/staging/iio/accel/kxsd9.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t · C · 354 lines · 286 code · 43 blank · 25 comment · 14 complexity · 957fa180317575180c73b4609f94047b MD5 · raw file

  1. /*
  2. * kxsd9.c simple support for the Kionix KXSD9 3D
  3. * accelerometer.
  4. *
  5. * Copyright (c) 2008-2009 Jonathan Cameron <jic23@cam.ac.uk>
  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. * The i2c interface is very similar, so shouldn't be a problem once
  12. * I have a suitable wire made up.
  13. *
  14. * TODO: Support the motion detector
  15. * Uses register address incrementing so could have a
  16. * heavily optimized ring buffer access function.
  17. */
  18. #include <linux/device.h>
  19. #include <linux/kernel.h>
  20. #include <linux/spi/spi.h>
  21. #include <linux/sysfs.h>
  22. #include <linux/slab.h>
  23. #include "../iio.h"
  24. #include "../sysfs.h"
  25. #include "../adc/adc.h"
  26. #include "accel.h"
  27. #define KXSD9_REG_X 0x00
  28. #define KXSD9_REG_Y 0x02
  29. #define KXSD9_REG_Z 0x04
  30. #define KXSD9_REG_AUX 0x06
  31. #define KXSD9_REG_RESET 0x0a
  32. #define KXSD9_REG_CTRL_C 0x0c
  33. #define KXSD9_FS_8 0x00
  34. #define KXSD9_FS_6 0x01
  35. #define KXSD9_FS_4 0x02
  36. #define KXSD9_FS_2 0x03
  37. #define KXSD9_FS_MASK 0x03
  38. #define KXSD9_REG_CTRL_B 0x0d
  39. #define KXSD9_REG_CTRL_A 0x0e
  40. #define KXSD9_READ(a) (0x80 | (a))
  41. #define KXSD9_WRITE(a) (a)
  42. #define KXSD9_SCALE_2G "0.011978"
  43. #define KXSD9_SCALE_4G "0.023927"
  44. #define KXSD9_SCALE_6G "0.035934"
  45. #define KXSD9_SCALE_8G "0.047853"
  46. #define KXSD9_STATE_RX_SIZE 2
  47. #define KXSD9_STATE_TX_SIZE 4
  48. /**
  49. * struct kxsd9_state - device related storage
  50. * @buf_lock: protect the rx and tx buffers.
  51. * @us: spi device
  52. * @rx: single rx buffer storage
  53. * @tx: single tx buffer storage
  54. **/
  55. struct kxsd9_state {
  56. struct mutex buf_lock;
  57. struct spi_device *us;
  58. u8 rx[KXSD9_STATE_RX_SIZE] ____cacheline_aligned;
  59. u8 tx[KXSD9_STATE_TX_SIZE];
  60. };
  61. /* This may want to move to mili g to allow for non integer ranges */
  62. static ssize_t kxsd9_read_scale(struct device *dev,
  63. struct device_attribute *attr,
  64. char *buf)
  65. {
  66. int ret;
  67. ssize_t len = 0;
  68. struct iio_dev *indio_dev = dev_get_drvdata(dev);
  69. struct kxsd9_state *st = iio_priv(indio_dev);
  70. struct spi_transfer xfer = {
  71. .bits_per_word = 8,
  72. .len = 2,
  73. .cs_change = 1,
  74. .tx_buf = st->tx,
  75. .rx_buf = st->rx,
  76. };
  77. struct spi_message msg;
  78. mutex_lock(&st->buf_lock);
  79. st->tx[0] = KXSD9_READ(KXSD9_REG_CTRL_C);
  80. st->tx[1] = 0;
  81. spi_message_init(&msg);
  82. spi_message_add_tail(&xfer, &msg);
  83. ret = spi_sync(st->us, &msg);
  84. if (ret)
  85. goto error_ret;
  86. switch (st->rx[1] & KXSD9_FS_MASK) {
  87. case KXSD9_FS_8:
  88. len += sprintf(buf, "%s\n", KXSD9_SCALE_8G);
  89. break;
  90. case KXSD9_FS_6:
  91. len += sprintf(buf, "%s\n", KXSD9_SCALE_6G);
  92. break;
  93. case KXSD9_FS_4:
  94. len += sprintf(buf, "%s\n", KXSD9_SCALE_4G);
  95. break;
  96. case KXSD9_FS_2:
  97. len += sprintf(buf, "%s\n", KXSD9_SCALE_2G);
  98. break;
  99. }
  100. error_ret:
  101. mutex_unlock(&st->buf_lock);
  102. return ret ? ret : len;
  103. }
  104. static ssize_t kxsd9_write_scale(struct device *dev,
  105. struct device_attribute *attr,
  106. const char *buf,
  107. size_t len)
  108. {
  109. struct spi_message msg;
  110. int ret;
  111. struct iio_dev *indio_dev = dev_get_drvdata(dev);
  112. struct kxsd9_state *st = iio_priv(indio_dev);
  113. u8 val;
  114. struct spi_transfer xfers[] = {
  115. {
  116. .bits_per_word = 8,
  117. .len = 2,
  118. .cs_change = 1,
  119. .tx_buf = st->tx,
  120. .rx_buf = st->rx,
  121. }, {
  122. .bits_per_word = 8,
  123. .len = 2,
  124. .cs_change = 1,
  125. .tx_buf = st->tx,
  126. },
  127. };
  128. if (!strncmp(buf, KXSD9_SCALE_8G,
  129. strlen(buf) < strlen(KXSD9_SCALE_8G)
  130. ? strlen(buf) : strlen(KXSD9_SCALE_8G)))
  131. val = KXSD9_FS_8;
  132. else if (!strncmp(buf, KXSD9_SCALE_6G,
  133. strlen(buf) < strlen(KXSD9_SCALE_6G)
  134. ? strlen(buf) : strlen(KXSD9_SCALE_6G)))
  135. val = KXSD9_FS_6;
  136. else if (!strncmp(buf, KXSD9_SCALE_4G,
  137. strlen(buf) < strlen(KXSD9_SCALE_4G)
  138. ? strlen(buf) : strlen(KXSD9_SCALE_4G)))
  139. val = KXSD9_FS_4;
  140. else if (!strncmp(buf, KXSD9_SCALE_2G,
  141. strlen(buf) < strlen(KXSD9_SCALE_2G)
  142. ? strlen(buf) : strlen(KXSD9_SCALE_2G)))
  143. val = KXSD9_FS_2;
  144. else
  145. return -EINVAL;
  146. mutex_lock(&st->buf_lock);
  147. st->tx[0] = KXSD9_READ(KXSD9_REG_CTRL_C);
  148. st->tx[1] = 0;
  149. spi_message_init(&msg);
  150. spi_message_add_tail(&xfers[0], &msg);
  151. ret = spi_sync(st->us, &msg);
  152. if (ret)
  153. goto error_ret;
  154. st->tx[0] = KXSD9_WRITE(KXSD9_REG_CTRL_C);
  155. st->tx[1] = (st->rx[1] & ~KXSD9_FS_MASK) | val;
  156. spi_message_init(&msg);
  157. spi_message_add_tail(&xfers[1], &msg);
  158. ret = spi_sync(st->us, &msg);
  159. error_ret:
  160. mutex_unlock(&st->buf_lock);
  161. return ret ? ret : len;
  162. }
  163. static ssize_t kxsd9_read_accel(struct device *dev,
  164. struct device_attribute *attr,
  165. char *buf)
  166. {
  167. struct spi_message msg;
  168. int ret;
  169. ssize_t len = 0;
  170. u16 val;
  171. struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
  172. struct iio_dev *indio_dev = dev_get_drvdata(dev);
  173. struct kxsd9_state *st = iio_priv(indio_dev);
  174. struct spi_transfer xfers[] = {
  175. {
  176. .bits_per_word = 8,
  177. .len = 1,
  178. .cs_change = 0,
  179. .delay_usecs = 200,
  180. .tx_buf = st->tx,
  181. }, {
  182. .bits_per_word = 8,
  183. .len = 2,
  184. .cs_change = 1,
  185. .rx_buf = st->rx,
  186. },
  187. };
  188. mutex_lock(&st->buf_lock);
  189. st->tx[0] = KXSD9_READ(this_attr->address);
  190. spi_message_init(&msg);
  191. spi_message_add_tail(&xfers[0], &msg);
  192. spi_message_add_tail(&xfers[1], &msg);
  193. ret = spi_sync(st->us, &msg);
  194. if (ret)
  195. goto error_ret;
  196. val = (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0);
  197. len = sprintf(buf, "%d\n", val);
  198. error_ret:
  199. mutex_unlock(&st->buf_lock);
  200. return ret ? ret : len;
  201. }
  202. static IIO_DEV_ATTR_ACCEL_X(kxsd9_read_accel, KXSD9_REG_X);
  203. static IIO_DEV_ATTR_ACCEL_Y(kxsd9_read_accel, KXSD9_REG_Y);
  204. static IIO_DEV_ATTR_ACCEL_Z(kxsd9_read_accel, KXSD9_REG_Z);
  205. static IIO_DEV_ATTR_IN_RAW(0, kxsd9_read_accel, KXSD9_REG_AUX);
  206. static IIO_DEVICE_ATTR(accel_scale,
  207. S_IRUGO | S_IWUSR,
  208. kxsd9_read_scale,
  209. kxsd9_write_scale,
  210. 0);
  211. static IIO_CONST_ATTR(accel_scale_available,
  212. KXSD9_SCALE_2G " "
  213. KXSD9_SCALE_4G " "
  214. KXSD9_SCALE_6G " "
  215. KXSD9_SCALE_8G);
  216. static struct attribute *kxsd9_attributes[] = {
  217. &iio_dev_attr_accel_x_raw.dev_attr.attr,
  218. &iio_dev_attr_accel_y_raw.dev_attr.attr,
  219. &iio_dev_attr_accel_z_raw.dev_attr.attr,
  220. &iio_dev_attr_in0_raw.dev_attr.attr,
  221. &iio_dev_attr_accel_scale.dev_attr.attr,
  222. &iio_const_attr_accel_scale_available.dev_attr.attr,
  223. NULL,
  224. };
  225. static const struct attribute_group kxsd9_attribute_group = {
  226. .attrs = kxsd9_attributes,
  227. };
  228. static int __devinit kxsd9_power_up(struct kxsd9_state *st)
  229. {
  230. struct spi_transfer xfers[2] = {
  231. {
  232. .bits_per_word = 8,
  233. .len = 2,
  234. .cs_change = 1,
  235. .tx_buf = st->tx,
  236. }, {
  237. .bits_per_word = 8,
  238. .len = 2,
  239. .cs_change = 1,
  240. .tx_buf = st->tx + 2,
  241. },
  242. };
  243. struct spi_message msg;
  244. st->tx[0] = 0x0d;
  245. st->tx[1] = 0x40;
  246. st->tx[2] = 0x0c;
  247. st->tx[3] = 0x9b;
  248. spi_message_init(&msg);
  249. spi_message_add_tail(&xfers[0], &msg);
  250. spi_message_add_tail(&xfers[1], &msg);
  251. return spi_sync(st->us, &msg);
  252. };
  253. static const struct iio_info kxsd9_info = {
  254. .attrs = &kxsd9_attribute_group,
  255. .driver_module = THIS_MODULE,
  256. };
  257. static int __devinit kxsd9_probe(struct spi_device *spi)
  258. {
  259. struct iio_dev *indio_dev;
  260. struct kxsd9_state *st;
  261. int ret = 0;
  262. indio_dev = iio_allocate_device(sizeof(*st));
  263. if (indio_dev == NULL) {
  264. ret = -ENOMEM;
  265. goto error_ret;
  266. }
  267. st = iio_priv(indio_dev);
  268. spi_set_drvdata(spi, indio_dev);
  269. st->us = spi;
  270. mutex_init(&st->buf_lock);
  271. indio_dev->dev.parent = &spi->dev;
  272. indio_dev->info = &kxsd9_info;
  273. indio_dev->modes = INDIO_DIRECT_MODE;
  274. ret = iio_device_register(indio_dev);
  275. if (ret)
  276. goto error_free_dev;
  277. spi->mode = SPI_MODE_0;
  278. spi_setup(spi);
  279. kxsd9_power_up(st);
  280. return 0;
  281. error_free_dev:
  282. iio_free_device(indio_dev);
  283. error_ret:
  284. return ret;
  285. }
  286. static int __devexit kxsd9_remove(struct spi_device *spi)
  287. {
  288. iio_device_unregister(spi_get_drvdata(spi));
  289. return 0;
  290. }
  291. static struct spi_driver kxsd9_driver = {
  292. .driver = {
  293. .name = "kxsd9",
  294. .owner = THIS_MODULE,
  295. },
  296. .probe = kxsd9_probe,
  297. .remove = __devexit_p(kxsd9_remove),
  298. };
  299. static __init int kxsd9_spi_init(void)
  300. {
  301. return spi_register_driver(&kxsd9_driver);
  302. }
  303. module_init(kxsd9_spi_init);
  304. static __exit void kxsd9_spi_exit(void)
  305. {
  306. spi_unregister_driver(&kxsd9_driver);
  307. }
  308. module_exit(kxsd9_spi_exit);
  309. MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
  310. MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
  311. MODULE_LICENSE("GPL v2");