vl6180.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * vl6180.c - Support for STMicroelectronics VL6180 ALS, range and proximity
  4. * sensor
  5. *
  6. * Copyright 2017 Peter Meerwald-Stadler <[email protected]>
  7. * Copyright 2017 Manivannan Sadhasivam <[email protected]>
  8. *
  9. * IIO driver for VL6180 (7-bit I2C slave address 0x29)
  10. *
  11. * Range: 0 to 100mm
  12. * ALS: < 1 Lux up to 100 kLux
  13. * IR: 850nm
  14. *
  15. * TODO: irq, threshold events, continuous mode, hardware buffer
  16. */
  17. #include <linux/module.h>
  18. #include <linux/mod_devicetable.h>
  19. #include <linux/i2c.h>
  20. #include <linux/mutex.h>
  21. #include <linux/err.h>
  22. #include <linux/of.h>
  23. #include <linux/delay.h>
  24. #include <linux/util_macros.h>
  25. #include <linux/iio/iio.h>
  26. #include <linux/iio/sysfs.h>
  27. #define VL6180_DRV_NAME "vl6180"
  28. /* Device identification register and value */
  29. #define VL6180_MODEL_ID 0x000
  30. #define VL6180_MODEL_ID_VAL 0xb4
  31. /* Configuration registers */
  32. #define VL6180_INTR_CONFIG 0x014
  33. #define VL6180_INTR_CLEAR 0x015
  34. #define VL6180_OUT_OF_RESET 0x016
  35. #define VL6180_HOLD 0x017
  36. #define VL6180_RANGE_START 0x018
  37. #define VL6180_ALS_START 0x038
  38. #define VL6180_ALS_GAIN 0x03f
  39. #define VL6180_ALS_IT 0x040
  40. /* Status registers */
  41. #define VL6180_RANGE_STATUS 0x04d
  42. #define VL6180_ALS_STATUS 0x04e
  43. #define VL6180_INTR_STATUS 0x04f
  44. /* Result value registers */
  45. #define VL6180_ALS_VALUE 0x050
  46. #define VL6180_RANGE_VALUE 0x062
  47. #define VL6180_RANGE_RATE 0x066
  48. /* bits of the RANGE_START and ALS_START register */
  49. #define VL6180_MODE_CONT BIT(1) /* continuous mode */
  50. #define VL6180_STARTSTOP BIT(0) /* start measurement, auto-reset */
  51. /* bits of the INTR_STATUS and INTR_CONFIG register */
  52. #define VL6180_ALS_READY BIT(5)
  53. #define VL6180_RANGE_READY BIT(2)
  54. /* bits of the INTR_CLEAR register */
  55. #define VL6180_CLEAR_ERROR BIT(2)
  56. #define VL6180_CLEAR_ALS BIT(1)
  57. #define VL6180_CLEAR_RANGE BIT(0)
  58. /* bits of the HOLD register */
  59. #define VL6180_HOLD_ON BIT(0)
  60. /* default value for the ALS_IT register */
  61. #define VL6180_ALS_IT_100 0x63 /* 100 ms */
  62. /* values for the ALS_GAIN register */
  63. #define VL6180_ALS_GAIN_1 0x46
  64. #define VL6180_ALS_GAIN_1_25 0x45
  65. #define VL6180_ALS_GAIN_1_67 0x44
  66. #define VL6180_ALS_GAIN_2_5 0x43
  67. #define VL6180_ALS_GAIN_5 0x42
  68. #define VL6180_ALS_GAIN_10 0x41
  69. #define VL6180_ALS_GAIN_20 0x40
  70. #define VL6180_ALS_GAIN_40 0x47
  71. struct vl6180_data {
  72. struct i2c_client *client;
  73. struct mutex lock;
  74. unsigned int als_gain_milli;
  75. unsigned int als_it_ms;
  76. };
  77. enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX };
  78. /**
  79. * struct vl6180_chan_regs - Registers for accessing channels
  80. * @drdy_mask: Data ready bit in status register
  81. * @start_reg: Conversion start register
  82. * @value_reg: Result value register
  83. * @word: Register word length
  84. */
  85. struct vl6180_chan_regs {
  86. u8 drdy_mask;
  87. u16 start_reg, value_reg;
  88. bool word;
  89. };
  90. static const struct vl6180_chan_regs vl6180_chan_regs_table[] = {
  91. [VL6180_ALS] = {
  92. .drdy_mask = VL6180_ALS_READY,
  93. .start_reg = VL6180_ALS_START,
  94. .value_reg = VL6180_ALS_VALUE,
  95. .word = true,
  96. },
  97. [VL6180_RANGE] = {
  98. .drdy_mask = VL6180_RANGE_READY,
  99. .start_reg = VL6180_RANGE_START,
  100. .value_reg = VL6180_RANGE_VALUE,
  101. .word = false,
  102. },
  103. [VL6180_PROX] = {
  104. .drdy_mask = VL6180_RANGE_READY,
  105. .start_reg = VL6180_RANGE_START,
  106. .value_reg = VL6180_RANGE_RATE,
  107. .word = true,
  108. },
  109. };
  110. static int vl6180_read(struct i2c_client *client, u16 cmd, void *databuf,
  111. u8 len)
  112. {
  113. __be16 cmdbuf = cpu_to_be16(cmd);
  114. struct i2c_msg msgs[2] = {
  115. { .addr = client->addr, .len = sizeof(cmdbuf), .buf = (u8 *) &cmdbuf },
  116. { .addr = client->addr, .len = len, .buf = databuf,
  117. .flags = I2C_M_RD } };
  118. int ret;
  119. ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
  120. if (ret < 0)
  121. dev_err(&client->dev, "failed reading register 0x%04x\n", cmd);
  122. return ret;
  123. }
  124. static int vl6180_read_byte(struct i2c_client *client, u16 cmd)
  125. {
  126. u8 data;
  127. int ret;
  128. ret = vl6180_read(client, cmd, &data, sizeof(data));
  129. if (ret < 0)
  130. return ret;
  131. return data;
  132. }
  133. static int vl6180_read_word(struct i2c_client *client, u16 cmd)
  134. {
  135. __be16 data;
  136. int ret;
  137. ret = vl6180_read(client, cmd, &data, sizeof(data));
  138. if (ret < 0)
  139. return ret;
  140. return be16_to_cpu(data);
  141. }
  142. static int vl6180_write_byte(struct i2c_client *client, u16 cmd, u8 val)
  143. {
  144. u8 buf[3];
  145. struct i2c_msg msgs[1] = {
  146. { .addr = client->addr, .len = sizeof(buf), .buf = (u8 *) &buf } };
  147. int ret;
  148. buf[0] = cmd >> 8;
  149. buf[1] = cmd & 0xff;
  150. buf[2] = val;
  151. ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
  152. if (ret < 0) {
  153. dev_err(&client->dev, "failed writing register 0x%04x\n", cmd);
  154. return ret;
  155. }
  156. return 0;
  157. }
  158. static int vl6180_write_word(struct i2c_client *client, u16 cmd, u16 val)
  159. {
  160. __be16 buf[2];
  161. struct i2c_msg msgs[1] = {
  162. { .addr = client->addr, .len = sizeof(buf), .buf = (u8 *) &buf } };
  163. int ret;
  164. buf[0] = cpu_to_be16(cmd);
  165. buf[1] = cpu_to_be16(val);
  166. ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
  167. if (ret < 0) {
  168. dev_err(&client->dev, "failed writing register 0x%04x\n", cmd);
  169. return ret;
  170. }
  171. return 0;
  172. }
  173. static int vl6180_measure(struct vl6180_data *data, int addr)
  174. {
  175. struct i2c_client *client = data->client;
  176. int tries = 20, ret;
  177. u16 value;
  178. mutex_lock(&data->lock);
  179. /* Start single shot measurement */
  180. ret = vl6180_write_byte(client,
  181. vl6180_chan_regs_table[addr].start_reg, VL6180_STARTSTOP);
  182. if (ret < 0)
  183. goto fail;
  184. while (tries--) {
  185. ret = vl6180_read_byte(client, VL6180_INTR_STATUS);
  186. if (ret < 0)
  187. goto fail;
  188. if (ret & vl6180_chan_regs_table[addr].drdy_mask)
  189. break;
  190. msleep(20);
  191. }
  192. if (tries < 0) {
  193. ret = -EIO;
  194. goto fail;
  195. }
  196. /* Read result value from appropriate registers */
  197. ret = vl6180_chan_regs_table[addr].word ?
  198. vl6180_read_word(client, vl6180_chan_regs_table[addr].value_reg) :
  199. vl6180_read_byte(client, vl6180_chan_regs_table[addr].value_reg);
  200. if (ret < 0)
  201. goto fail;
  202. value = ret;
  203. /* Clear the interrupt flag after data read */
  204. ret = vl6180_write_byte(client, VL6180_INTR_CLEAR,
  205. VL6180_CLEAR_ERROR | VL6180_CLEAR_ALS | VL6180_CLEAR_RANGE);
  206. if (ret < 0)
  207. goto fail;
  208. ret = value;
  209. fail:
  210. mutex_unlock(&data->lock);
  211. return ret;
  212. }
  213. static const struct iio_chan_spec vl6180_channels[] = {
  214. {
  215. .type = IIO_LIGHT,
  216. .address = VL6180_ALS,
  217. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  218. BIT(IIO_CHAN_INFO_INT_TIME) |
  219. BIT(IIO_CHAN_INFO_SCALE) |
  220. BIT(IIO_CHAN_INFO_HARDWAREGAIN),
  221. }, {
  222. .type = IIO_DISTANCE,
  223. .address = VL6180_RANGE,
  224. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  225. BIT(IIO_CHAN_INFO_SCALE),
  226. }, {
  227. .type = IIO_PROXIMITY,
  228. .address = VL6180_PROX,
  229. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  230. }
  231. };
  232. /*
  233. * Available Ambient Light Sensor gain settings, 1/1000th, and
  234. * corresponding setting for the VL6180_ALS_GAIN register
  235. */
  236. static const int vl6180_als_gain_tab[8] = {
  237. 1000, 1250, 1670, 2500, 5000, 10000, 20000, 40000
  238. };
  239. static const u8 vl6180_als_gain_tab_bits[8] = {
  240. VL6180_ALS_GAIN_1, VL6180_ALS_GAIN_1_25,
  241. VL6180_ALS_GAIN_1_67, VL6180_ALS_GAIN_2_5,
  242. VL6180_ALS_GAIN_5, VL6180_ALS_GAIN_10,
  243. VL6180_ALS_GAIN_20, VL6180_ALS_GAIN_40
  244. };
  245. static int vl6180_read_raw(struct iio_dev *indio_dev,
  246. struct iio_chan_spec const *chan,
  247. int *val, int *val2, long mask)
  248. {
  249. struct vl6180_data *data = iio_priv(indio_dev);
  250. int ret;
  251. switch (mask) {
  252. case IIO_CHAN_INFO_RAW:
  253. ret = vl6180_measure(data, chan->address);
  254. if (ret < 0)
  255. return ret;
  256. *val = ret;
  257. return IIO_VAL_INT;
  258. case IIO_CHAN_INFO_INT_TIME:
  259. *val = data->als_it_ms;
  260. *val2 = 1000;
  261. return IIO_VAL_FRACTIONAL;
  262. case IIO_CHAN_INFO_SCALE:
  263. switch (chan->type) {
  264. case IIO_LIGHT:
  265. /* one ALS count is 0.32 Lux @ gain 1, IT 100 ms */
  266. *val = 32000; /* 0.32 * 1000 * 100 */
  267. *val2 = data->als_gain_milli * data->als_it_ms;
  268. return IIO_VAL_FRACTIONAL;
  269. case IIO_DISTANCE:
  270. *val = 0; /* sensor reports mm, scale to meter */
  271. *val2 = 1000;
  272. break;
  273. default:
  274. return -EINVAL;
  275. }
  276. return IIO_VAL_INT_PLUS_MICRO;
  277. case IIO_CHAN_INFO_HARDWAREGAIN:
  278. *val = data->als_gain_milli;
  279. *val2 = 1000;
  280. return IIO_VAL_FRACTIONAL;
  281. default:
  282. return -EINVAL;
  283. }
  284. }
  285. static IIO_CONST_ATTR(als_gain_available, "1 1.25 1.67 2.5 5 10 20 40");
  286. static struct attribute *vl6180_attributes[] = {
  287. &iio_const_attr_als_gain_available.dev_attr.attr,
  288. NULL
  289. };
  290. static const struct attribute_group vl6180_attribute_group = {
  291. .attrs = vl6180_attributes,
  292. };
  293. /* HOLD is needed before updating any config registers */
  294. static int vl6180_hold(struct vl6180_data *data, bool hold)
  295. {
  296. return vl6180_write_byte(data->client, VL6180_HOLD,
  297. hold ? VL6180_HOLD_ON : 0);
  298. }
  299. static int vl6180_set_als_gain(struct vl6180_data *data, int val, int val2)
  300. {
  301. int i, ret, gain;
  302. if (val < 1 || val > 40)
  303. return -EINVAL;
  304. gain = (val * 1000000 + val2) / 1000;
  305. if (gain < 1 || gain > 40000)
  306. return -EINVAL;
  307. i = find_closest(gain, vl6180_als_gain_tab,
  308. ARRAY_SIZE(vl6180_als_gain_tab));
  309. mutex_lock(&data->lock);
  310. ret = vl6180_hold(data, true);
  311. if (ret < 0)
  312. goto fail;
  313. ret = vl6180_write_byte(data->client, VL6180_ALS_GAIN,
  314. vl6180_als_gain_tab_bits[i]);
  315. if (ret >= 0)
  316. data->als_gain_milli = vl6180_als_gain_tab[i];
  317. fail:
  318. vl6180_hold(data, false);
  319. mutex_unlock(&data->lock);
  320. return ret;
  321. }
  322. static int vl6180_set_it(struct vl6180_data *data, int val, int val2)
  323. {
  324. int ret, it_ms;
  325. it_ms = DIV_ROUND_CLOSEST(val2, 1000); /* round to ms */
  326. if (val != 0 || it_ms < 1 || it_ms > 512)
  327. return -EINVAL;
  328. mutex_lock(&data->lock);
  329. ret = vl6180_hold(data, true);
  330. if (ret < 0)
  331. goto fail;
  332. ret = vl6180_write_word(data->client, VL6180_ALS_IT, it_ms - 1);
  333. if (ret >= 0)
  334. data->als_it_ms = it_ms;
  335. fail:
  336. vl6180_hold(data, false);
  337. mutex_unlock(&data->lock);
  338. return ret;
  339. }
  340. static int vl6180_write_raw(struct iio_dev *indio_dev,
  341. struct iio_chan_spec const *chan,
  342. int val, int val2, long mask)
  343. {
  344. struct vl6180_data *data = iio_priv(indio_dev);
  345. switch (mask) {
  346. case IIO_CHAN_INFO_INT_TIME:
  347. return vl6180_set_it(data, val, val2);
  348. case IIO_CHAN_INFO_HARDWAREGAIN:
  349. if (chan->type != IIO_LIGHT)
  350. return -EINVAL;
  351. return vl6180_set_als_gain(data, val, val2);
  352. default:
  353. return -EINVAL;
  354. }
  355. }
  356. static const struct iio_info vl6180_info = {
  357. .read_raw = vl6180_read_raw,
  358. .write_raw = vl6180_write_raw,
  359. .attrs = &vl6180_attribute_group,
  360. };
  361. static int vl6180_init(struct vl6180_data *data)
  362. {
  363. struct i2c_client *client = data->client;
  364. int ret;
  365. ret = vl6180_read_byte(client, VL6180_MODEL_ID);
  366. if (ret < 0)
  367. return ret;
  368. if (ret != VL6180_MODEL_ID_VAL) {
  369. dev_err(&client->dev, "invalid model ID %02x\n", ret);
  370. return -ENODEV;
  371. }
  372. ret = vl6180_hold(data, true);
  373. if (ret < 0)
  374. return ret;
  375. ret = vl6180_read_byte(client, VL6180_OUT_OF_RESET);
  376. if (ret < 0)
  377. return ret;
  378. /*
  379. * Detect false reset condition here. This bit is always set when the
  380. * system comes out of reset.
  381. */
  382. if (ret != 0x01)
  383. dev_info(&client->dev, "device is not fresh out of reset\n");
  384. /* Enable ALS and Range ready interrupts */
  385. ret = vl6180_write_byte(client, VL6180_INTR_CONFIG,
  386. VL6180_ALS_READY | VL6180_RANGE_READY);
  387. if (ret < 0)
  388. return ret;
  389. /* ALS integration time: 100ms */
  390. data->als_it_ms = 100;
  391. ret = vl6180_write_word(client, VL6180_ALS_IT, VL6180_ALS_IT_100);
  392. if (ret < 0)
  393. return ret;
  394. /* ALS gain: 1 */
  395. data->als_gain_milli = 1000;
  396. ret = vl6180_write_byte(client, VL6180_ALS_GAIN, VL6180_ALS_GAIN_1);
  397. if (ret < 0)
  398. return ret;
  399. ret = vl6180_write_byte(client, VL6180_OUT_OF_RESET, 0x00);
  400. if (ret < 0)
  401. return ret;
  402. return vl6180_hold(data, false);
  403. }
  404. static int vl6180_probe(struct i2c_client *client,
  405. const struct i2c_device_id *id)
  406. {
  407. struct vl6180_data *data;
  408. struct iio_dev *indio_dev;
  409. int ret;
  410. indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
  411. if (!indio_dev)
  412. return -ENOMEM;
  413. data = iio_priv(indio_dev);
  414. i2c_set_clientdata(client, indio_dev);
  415. data->client = client;
  416. mutex_init(&data->lock);
  417. indio_dev->info = &vl6180_info;
  418. indio_dev->channels = vl6180_channels;
  419. indio_dev->num_channels = ARRAY_SIZE(vl6180_channels);
  420. indio_dev->name = VL6180_DRV_NAME;
  421. indio_dev->modes = INDIO_DIRECT_MODE;
  422. ret = vl6180_init(data);
  423. if (ret < 0)
  424. return ret;
  425. return devm_iio_device_register(&client->dev, indio_dev);
  426. }
  427. static const struct of_device_id vl6180_of_match[] = {
  428. { .compatible = "st,vl6180", },
  429. { },
  430. };
  431. MODULE_DEVICE_TABLE(of, vl6180_of_match);
  432. static const struct i2c_device_id vl6180_id[] = {
  433. { "vl6180", 0 },
  434. { }
  435. };
  436. MODULE_DEVICE_TABLE(i2c, vl6180_id);
  437. static struct i2c_driver vl6180_driver = {
  438. .driver = {
  439. .name = VL6180_DRV_NAME,
  440. .of_match_table = vl6180_of_match,
  441. },
  442. .probe = vl6180_probe,
  443. .id_table = vl6180_id,
  444. };
  445. module_i2c_driver(vl6180_driver);
  446. MODULE_AUTHOR("Peter Meerwald-Stadler <[email protected]>");
  447. MODULE_AUTHOR("Manivannan Sadhasivam <[email protected]>");
  448. MODULE_DESCRIPTION("STMicro VL6180 ALS, range and proximity sensor driver");
  449. MODULE_LICENSE("GPL");