iqs621-als.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Azoteq IQS621/622 Ambient Light Sensors
  4. *
  5. * Copyright (C) 2019 Jeff LaBundy <[email protected]>
  6. */
  7. #include <linux/device.h>
  8. #include <linux/iio/events.h>
  9. #include <linux/iio/iio.h>
  10. #include <linux/kernel.h>
  11. #include <linux/mfd/iqs62x.h>
  12. #include <linux/module.h>
  13. #include <linux/mutex.h>
  14. #include <linux/notifier.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/regmap.h>
  17. #define IQS621_ALS_FLAGS_LIGHT BIT(7)
  18. #define IQS621_ALS_FLAGS_RANGE GENMASK(3, 0)
  19. #define IQS621_ALS_UI_OUT 0x17
  20. #define IQS621_ALS_THRESH_DARK 0x80
  21. #define IQS621_ALS_THRESH_LIGHT 0x81
  22. #define IQS622_IR_RANGE 0x15
  23. #define IQS622_IR_FLAGS 0x16
  24. #define IQS622_IR_FLAGS_TOUCH BIT(1)
  25. #define IQS622_IR_FLAGS_PROX BIT(0)
  26. #define IQS622_IR_UI_OUT 0x17
  27. #define IQS622_IR_THRESH_PROX 0x91
  28. #define IQS622_IR_THRESH_TOUCH 0x92
  29. struct iqs621_als_private {
  30. struct iqs62x_core *iqs62x;
  31. struct iio_dev *indio_dev;
  32. struct notifier_block notifier;
  33. struct mutex lock;
  34. bool light_en;
  35. bool range_en;
  36. bool prox_en;
  37. u8 als_flags;
  38. u8 ir_flags_mask;
  39. u8 ir_flags;
  40. u8 thresh_light;
  41. u8 thresh_dark;
  42. u8 thresh_prox;
  43. };
  44. static int iqs621_als_init(struct iqs621_als_private *iqs621_als)
  45. {
  46. struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
  47. unsigned int event_mask = 0;
  48. int ret;
  49. switch (iqs621_als->ir_flags_mask) {
  50. case IQS622_IR_FLAGS_TOUCH:
  51. ret = regmap_write(iqs62x->regmap, IQS622_IR_THRESH_TOUCH,
  52. iqs621_als->thresh_prox);
  53. break;
  54. case IQS622_IR_FLAGS_PROX:
  55. ret = regmap_write(iqs62x->regmap, IQS622_IR_THRESH_PROX,
  56. iqs621_als->thresh_prox);
  57. break;
  58. default:
  59. ret = regmap_write(iqs62x->regmap, IQS621_ALS_THRESH_LIGHT,
  60. iqs621_als->thresh_light);
  61. if (ret)
  62. return ret;
  63. ret = regmap_write(iqs62x->regmap, IQS621_ALS_THRESH_DARK,
  64. iqs621_als->thresh_dark);
  65. }
  66. if (ret)
  67. return ret;
  68. if (iqs621_als->light_en || iqs621_als->range_en)
  69. event_mask |= iqs62x->dev_desc->als_mask;
  70. if (iqs621_als->prox_en)
  71. event_mask |= iqs62x->dev_desc->ir_mask;
  72. return regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
  73. event_mask, 0);
  74. }
  75. static int iqs621_als_notifier(struct notifier_block *notifier,
  76. unsigned long event_flags, void *context)
  77. {
  78. struct iqs62x_event_data *event_data = context;
  79. struct iqs621_als_private *iqs621_als;
  80. struct iio_dev *indio_dev;
  81. bool light_new, light_old;
  82. bool prox_new, prox_old;
  83. u8 range_new, range_old;
  84. s64 timestamp;
  85. int ret;
  86. iqs621_als = container_of(notifier, struct iqs621_als_private,
  87. notifier);
  88. indio_dev = iqs621_als->indio_dev;
  89. timestamp = iio_get_time_ns(indio_dev);
  90. mutex_lock(&iqs621_als->lock);
  91. if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
  92. ret = iqs621_als_init(iqs621_als);
  93. if (ret) {
  94. dev_err(indio_dev->dev.parent,
  95. "Failed to re-initialize device: %d\n", ret);
  96. ret = NOTIFY_BAD;
  97. } else {
  98. ret = NOTIFY_OK;
  99. }
  100. goto err_mutex;
  101. }
  102. if (!iqs621_als->light_en && !iqs621_als->range_en &&
  103. !iqs621_als->prox_en) {
  104. ret = NOTIFY_DONE;
  105. goto err_mutex;
  106. }
  107. /* IQS621 only */
  108. light_new = event_data->als_flags & IQS621_ALS_FLAGS_LIGHT;
  109. light_old = iqs621_als->als_flags & IQS621_ALS_FLAGS_LIGHT;
  110. if (iqs621_als->light_en && light_new && !light_old)
  111. iio_push_event(indio_dev,
  112. IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
  113. IIO_EV_TYPE_THRESH,
  114. IIO_EV_DIR_RISING),
  115. timestamp);
  116. else if (iqs621_als->light_en && !light_new && light_old)
  117. iio_push_event(indio_dev,
  118. IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
  119. IIO_EV_TYPE_THRESH,
  120. IIO_EV_DIR_FALLING),
  121. timestamp);
  122. /* IQS621 and IQS622 */
  123. range_new = event_data->als_flags & IQS621_ALS_FLAGS_RANGE;
  124. range_old = iqs621_als->als_flags & IQS621_ALS_FLAGS_RANGE;
  125. if (iqs621_als->range_en && (range_new > range_old))
  126. iio_push_event(indio_dev,
  127. IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
  128. IIO_EV_TYPE_CHANGE,
  129. IIO_EV_DIR_RISING),
  130. timestamp);
  131. else if (iqs621_als->range_en && (range_new < range_old))
  132. iio_push_event(indio_dev,
  133. IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
  134. IIO_EV_TYPE_CHANGE,
  135. IIO_EV_DIR_FALLING),
  136. timestamp);
  137. /* IQS622 only */
  138. prox_new = event_data->ir_flags & iqs621_als->ir_flags_mask;
  139. prox_old = iqs621_als->ir_flags & iqs621_als->ir_flags_mask;
  140. if (iqs621_als->prox_en && prox_new && !prox_old)
  141. iio_push_event(indio_dev,
  142. IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
  143. IIO_EV_TYPE_THRESH,
  144. IIO_EV_DIR_RISING),
  145. timestamp);
  146. else if (iqs621_als->prox_en && !prox_new && prox_old)
  147. iio_push_event(indio_dev,
  148. IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
  149. IIO_EV_TYPE_THRESH,
  150. IIO_EV_DIR_FALLING),
  151. timestamp);
  152. iqs621_als->als_flags = event_data->als_flags;
  153. iqs621_als->ir_flags = event_data->ir_flags;
  154. ret = NOTIFY_OK;
  155. err_mutex:
  156. mutex_unlock(&iqs621_als->lock);
  157. return ret;
  158. }
  159. static void iqs621_als_notifier_unregister(void *context)
  160. {
  161. struct iqs621_als_private *iqs621_als = context;
  162. struct iio_dev *indio_dev = iqs621_als->indio_dev;
  163. int ret;
  164. ret = blocking_notifier_chain_unregister(&iqs621_als->iqs62x->nh,
  165. &iqs621_als->notifier);
  166. if (ret)
  167. dev_err(indio_dev->dev.parent,
  168. "Failed to unregister notifier: %d\n", ret);
  169. }
  170. static int iqs621_als_read_raw(struct iio_dev *indio_dev,
  171. struct iio_chan_spec const *chan,
  172. int *val, int *val2, long mask)
  173. {
  174. struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
  175. struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
  176. int ret;
  177. __le16 val_buf;
  178. switch (chan->type) {
  179. case IIO_INTENSITY:
  180. ret = regmap_read(iqs62x->regmap, chan->address, val);
  181. if (ret)
  182. return ret;
  183. *val &= IQS621_ALS_FLAGS_RANGE;
  184. return IIO_VAL_INT;
  185. case IIO_PROXIMITY:
  186. case IIO_LIGHT:
  187. ret = regmap_raw_read(iqs62x->regmap, chan->address, &val_buf,
  188. sizeof(val_buf));
  189. if (ret)
  190. return ret;
  191. *val = le16_to_cpu(val_buf);
  192. return IIO_VAL_INT;
  193. default:
  194. return -EINVAL;
  195. }
  196. }
  197. static int iqs621_als_read_event_config(struct iio_dev *indio_dev,
  198. const struct iio_chan_spec *chan,
  199. enum iio_event_type type,
  200. enum iio_event_direction dir)
  201. {
  202. struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
  203. int ret;
  204. mutex_lock(&iqs621_als->lock);
  205. switch (chan->type) {
  206. case IIO_LIGHT:
  207. ret = iqs621_als->light_en;
  208. break;
  209. case IIO_INTENSITY:
  210. ret = iqs621_als->range_en;
  211. break;
  212. case IIO_PROXIMITY:
  213. ret = iqs621_als->prox_en;
  214. break;
  215. default:
  216. ret = -EINVAL;
  217. }
  218. mutex_unlock(&iqs621_als->lock);
  219. return ret;
  220. }
  221. static int iqs621_als_write_event_config(struct iio_dev *indio_dev,
  222. const struct iio_chan_spec *chan,
  223. enum iio_event_type type,
  224. enum iio_event_direction dir,
  225. int state)
  226. {
  227. struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
  228. struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
  229. unsigned int val;
  230. int ret;
  231. mutex_lock(&iqs621_als->lock);
  232. ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->als_flags, &val);
  233. if (ret)
  234. goto err_mutex;
  235. iqs621_als->als_flags = val;
  236. switch (chan->type) {
  237. case IIO_LIGHT:
  238. ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
  239. iqs62x->dev_desc->als_mask,
  240. iqs621_als->range_en || state ? 0 :
  241. 0xFF);
  242. if (!ret)
  243. iqs621_als->light_en = state;
  244. break;
  245. case IIO_INTENSITY:
  246. ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
  247. iqs62x->dev_desc->als_mask,
  248. iqs621_als->light_en || state ? 0 :
  249. 0xFF);
  250. if (!ret)
  251. iqs621_als->range_en = state;
  252. break;
  253. case IIO_PROXIMITY:
  254. ret = regmap_read(iqs62x->regmap, IQS622_IR_FLAGS, &val);
  255. if (ret)
  256. goto err_mutex;
  257. iqs621_als->ir_flags = val;
  258. ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
  259. iqs62x->dev_desc->ir_mask,
  260. state ? 0 : 0xFF);
  261. if (!ret)
  262. iqs621_als->prox_en = state;
  263. break;
  264. default:
  265. ret = -EINVAL;
  266. }
  267. err_mutex:
  268. mutex_unlock(&iqs621_als->lock);
  269. return ret;
  270. }
  271. static int iqs621_als_read_event_value(struct iio_dev *indio_dev,
  272. const struct iio_chan_spec *chan,
  273. enum iio_event_type type,
  274. enum iio_event_direction dir,
  275. enum iio_event_info info,
  276. int *val, int *val2)
  277. {
  278. struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
  279. int ret = IIO_VAL_INT;
  280. mutex_lock(&iqs621_als->lock);
  281. switch (dir) {
  282. case IIO_EV_DIR_RISING:
  283. *val = iqs621_als->thresh_light * 16;
  284. break;
  285. case IIO_EV_DIR_FALLING:
  286. *val = iqs621_als->thresh_dark * 4;
  287. break;
  288. case IIO_EV_DIR_EITHER:
  289. if (iqs621_als->ir_flags_mask == IQS622_IR_FLAGS_TOUCH)
  290. *val = iqs621_als->thresh_prox * 4;
  291. else
  292. *val = iqs621_als->thresh_prox;
  293. break;
  294. default:
  295. ret = -EINVAL;
  296. }
  297. mutex_unlock(&iqs621_als->lock);
  298. return ret;
  299. }
  300. static int iqs621_als_write_event_value(struct iio_dev *indio_dev,
  301. const struct iio_chan_spec *chan,
  302. enum iio_event_type type,
  303. enum iio_event_direction dir,
  304. enum iio_event_info info,
  305. int val, int val2)
  306. {
  307. struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
  308. struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
  309. unsigned int thresh_reg, thresh_val;
  310. u8 ir_flags_mask, *thresh_cache;
  311. int ret = -EINVAL;
  312. mutex_lock(&iqs621_als->lock);
  313. switch (dir) {
  314. case IIO_EV_DIR_RISING:
  315. thresh_reg = IQS621_ALS_THRESH_LIGHT;
  316. thresh_val = val / 16;
  317. thresh_cache = &iqs621_als->thresh_light;
  318. ir_flags_mask = 0;
  319. break;
  320. case IIO_EV_DIR_FALLING:
  321. thresh_reg = IQS621_ALS_THRESH_DARK;
  322. thresh_val = val / 4;
  323. thresh_cache = &iqs621_als->thresh_dark;
  324. ir_flags_mask = 0;
  325. break;
  326. case IIO_EV_DIR_EITHER:
  327. /*
  328. * The IQS622 supports two detection thresholds, both measured
  329. * in the same arbitrary units reported by read_raw: proximity
  330. * (0 through 255 in steps of 1), and touch (0 through 1020 in
  331. * steps of 4).
  332. *
  333. * Based on the single detection threshold chosen by the user,
  334. * select the hardware threshold that gives the best trade-off
  335. * between range and resolution.
  336. *
  337. * By default, the close-range (but coarse) touch threshold is
  338. * chosen during probe.
  339. */
  340. switch (val) {
  341. case 0 ... 255:
  342. thresh_reg = IQS622_IR_THRESH_PROX;
  343. thresh_val = val;
  344. ir_flags_mask = IQS622_IR_FLAGS_PROX;
  345. break;
  346. case 256 ... 1020:
  347. thresh_reg = IQS622_IR_THRESH_TOUCH;
  348. thresh_val = val / 4;
  349. ir_flags_mask = IQS622_IR_FLAGS_TOUCH;
  350. break;
  351. default:
  352. goto err_mutex;
  353. }
  354. thresh_cache = &iqs621_als->thresh_prox;
  355. break;
  356. default:
  357. goto err_mutex;
  358. }
  359. if (thresh_val > 0xFF)
  360. goto err_mutex;
  361. ret = regmap_write(iqs62x->regmap, thresh_reg, thresh_val);
  362. if (ret)
  363. goto err_mutex;
  364. *thresh_cache = thresh_val;
  365. iqs621_als->ir_flags_mask = ir_flags_mask;
  366. err_mutex:
  367. mutex_unlock(&iqs621_als->lock);
  368. return ret;
  369. }
  370. static const struct iio_info iqs621_als_info = {
  371. .read_raw = &iqs621_als_read_raw,
  372. .read_event_config = iqs621_als_read_event_config,
  373. .write_event_config = iqs621_als_write_event_config,
  374. .read_event_value = iqs621_als_read_event_value,
  375. .write_event_value = iqs621_als_write_event_value,
  376. };
  377. static const struct iio_event_spec iqs621_als_range_events[] = {
  378. {
  379. .type = IIO_EV_TYPE_CHANGE,
  380. .dir = IIO_EV_DIR_EITHER,
  381. .mask_separate = BIT(IIO_EV_INFO_ENABLE),
  382. },
  383. };
  384. static const struct iio_event_spec iqs621_als_light_events[] = {
  385. {
  386. .type = IIO_EV_TYPE_THRESH,
  387. .dir = IIO_EV_DIR_EITHER,
  388. .mask_separate = BIT(IIO_EV_INFO_ENABLE),
  389. },
  390. {
  391. .type = IIO_EV_TYPE_THRESH,
  392. .dir = IIO_EV_DIR_RISING,
  393. .mask_separate = BIT(IIO_EV_INFO_VALUE),
  394. },
  395. {
  396. .type = IIO_EV_TYPE_THRESH,
  397. .dir = IIO_EV_DIR_FALLING,
  398. .mask_separate = BIT(IIO_EV_INFO_VALUE),
  399. },
  400. };
  401. static const struct iio_chan_spec iqs621_als_channels[] = {
  402. {
  403. .type = IIO_INTENSITY,
  404. .address = IQS621_ALS_FLAGS,
  405. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  406. .event_spec = iqs621_als_range_events,
  407. .num_event_specs = ARRAY_SIZE(iqs621_als_range_events),
  408. },
  409. {
  410. .type = IIO_LIGHT,
  411. .address = IQS621_ALS_UI_OUT,
  412. .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
  413. .event_spec = iqs621_als_light_events,
  414. .num_event_specs = ARRAY_SIZE(iqs621_als_light_events),
  415. },
  416. };
  417. static const struct iio_event_spec iqs622_als_prox_events[] = {
  418. {
  419. .type = IIO_EV_TYPE_THRESH,
  420. .dir = IIO_EV_DIR_EITHER,
  421. .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
  422. BIT(IIO_EV_INFO_VALUE),
  423. },
  424. };
  425. static const struct iio_chan_spec iqs622_als_channels[] = {
  426. {
  427. .type = IIO_INTENSITY,
  428. .channel2 = IIO_MOD_LIGHT_BOTH,
  429. .address = IQS622_ALS_FLAGS,
  430. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  431. .event_spec = iqs621_als_range_events,
  432. .num_event_specs = ARRAY_SIZE(iqs621_als_range_events),
  433. .modified = true,
  434. },
  435. {
  436. .type = IIO_INTENSITY,
  437. .channel2 = IIO_MOD_LIGHT_IR,
  438. .address = IQS622_IR_RANGE,
  439. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  440. .modified = true,
  441. },
  442. {
  443. .type = IIO_PROXIMITY,
  444. .address = IQS622_IR_UI_OUT,
  445. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  446. .event_spec = iqs622_als_prox_events,
  447. .num_event_specs = ARRAY_SIZE(iqs622_als_prox_events),
  448. },
  449. };
  450. static int iqs621_als_probe(struct platform_device *pdev)
  451. {
  452. struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
  453. struct iqs621_als_private *iqs621_als;
  454. struct iio_dev *indio_dev;
  455. unsigned int val;
  456. int ret;
  457. indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*iqs621_als));
  458. if (!indio_dev)
  459. return -ENOMEM;
  460. iqs621_als = iio_priv(indio_dev);
  461. iqs621_als->iqs62x = iqs62x;
  462. iqs621_als->indio_dev = indio_dev;
  463. if (iqs62x->dev_desc->prod_num == IQS622_PROD_NUM) {
  464. ret = regmap_read(iqs62x->regmap, IQS622_IR_THRESH_TOUCH,
  465. &val);
  466. if (ret)
  467. return ret;
  468. iqs621_als->thresh_prox = val;
  469. iqs621_als->ir_flags_mask = IQS622_IR_FLAGS_TOUCH;
  470. indio_dev->channels = iqs622_als_channels;
  471. indio_dev->num_channels = ARRAY_SIZE(iqs622_als_channels);
  472. } else {
  473. ret = regmap_read(iqs62x->regmap, IQS621_ALS_THRESH_LIGHT,
  474. &val);
  475. if (ret)
  476. return ret;
  477. iqs621_als->thresh_light = val;
  478. ret = regmap_read(iqs62x->regmap, IQS621_ALS_THRESH_DARK,
  479. &val);
  480. if (ret)
  481. return ret;
  482. iqs621_als->thresh_dark = val;
  483. indio_dev->channels = iqs621_als_channels;
  484. indio_dev->num_channels = ARRAY_SIZE(iqs621_als_channels);
  485. }
  486. indio_dev->modes = INDIO_DIRECT_MODE;
  487. indio_dev->name = iqs62x->dev_desc->dev_name;
  488. indio_dev->info = &iqs621_als_info;
  489. mutex_init(&iqs621_als->lock);
  490. iqs621_als->notifier.notifier_call = iqs621_als_notifier;
  491. ret = blocking_notifier_chain_register(&iqs621_als->iqs62x->nh,
  492. &iqs621_als->notifier);
  493. if (ret) {
  494. dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
  495. return ret;
  496. }
  497. ret = devm_add_action_or_reset(&pdev->dev,
  498. iqs621_als_notifier_unregister,
  499. iqs621_als);
  500. if (ret)
  501. return ret;
  502. return devm_iio_device_register(&pdev->dev, indio_dev);
  503. }
  504. static struct platform_driver iqs621_als_platform_driver = {
  505. .driver = {
  506. .name = "iqs621-als",
  507. },
  508. .probe = iqs621_als_probe,
  509. };
  510. module_platform_driver(iqs621_als_platform_driver);
  511. MODULE_AUTHOR("Jeff LaBundy <[email protected]>");
  512. MODULE_DESCRIPTION("Azoteq IQS621/622 Ambient Light Sensors");
  513. MODULE_LICENSE("GPL");
  514. MODULE_ALIAS("platform:iqs621-als");