zopt2201.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * zopt2201.c - Support for IDT ZOPT2201 ambient light and UV B sensor
  4. *
  5. * Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
  6. *
  7. * Datasheet: https://www.idt.com/document/dst/zopt2201-datasheet
  8. * 7-bit I2C slave addresses 0x53 (default) or 0x52 (programmed)
  9. *
  10. * TODO: interrupt support, ALS/UVB raw mode
  11. */
  12. #include <linux/module.h>
  13. #include <linux/i2c.h>
  14. #include <linux/mutex.h>
  15. #include <linux/err.h>
  16. #include <linux/delay.h>
  17. #include <linux/iio/iio.h>
  18. #include <linux/iio/sysfs.h>
  19. #include <linux/unaligned.h>
  20. #define ZOPT2201_DRV_NAME "zopt2201"
  21. /* Registers */
  22. #define ZOPT2201_MAIN_CTRL 0x00
  23. #define ZOPT2201_LS_MEAS_RATE 0x04
  24. #define ZOPT2201_LS_GAIN 0x05
  25. #define ZOPT2201_PART_ID 0x06
  26. #define ZOPT2201_MAIN_STATUS 0x07
  27. #define ZOPT2201_ALS_DATA 0x0d /* LSB first, 13 to 20 bits */
  28. #define ZOPT2201_UVB_DATA 0x10 /* LSB first, 13 to 20 bits */
  29. #define ZOPT2201_UV_COMP_DATA 0x13 /* LSB first, 13 to 20 bits */
  30. #define ZOPT2201_COMP_DATA 0x16 /* LSB first, 13 to 20 bits */
  31. #define ZOPT2201_INT_CFG 0x19
  32. #define ZOPT2201_INT_PST 0x1a
  33. #define ZOPT2201_MAIN_CTRL_LS_MODE BIT(3) /* 0 .. ALS, 1 .. UV B */
  34. #define ZOPT2201_MAIN_CTRL_LS_EN BIT(1)
  35. /* Values for ZOPT2201_LS_MEAS_RATE resolution / bit width */
  36. #define ZOPT2201_MEAS_RES_20BIT 0 /* takes 400 ms */
  37. #define ZOPT2201_MEAS_RES_19BIT 1 /* takes 200 ms */
  38. #define ZOPT2201_MEAS_RES_18BIT 2 /* takes 100 ms, default */
  39. #define ZOPT2201_MEAS_RES_17BIT 3 /* takes 50 ms */
  40. #define ZOPT2201_MEAS_RES_16BIT 4 /* takes 25 ms */
  41. #define ZOPT2201_MEAS_RES_13BIT 5 /* takes 3.125 ms */
  42. #define ZOPT2201_MEAS_RES_SHIFT 4
  43. /* Values for ZOPT2201_LS_MEAS_RATE measurement rate */
  44. #define ZOPT2201_MEAS_FREQ_25MS 0
  45. #define ZOPT2201_MEAS_FREQ_50MS 1
  46. #define ZOPT2201_MEAS_FREQ_100MS 2 /* default */
  47. #define ZOPT2201_MEAS_FREQ_200MS 3
  48. #define ZOPT2201_MEAS_FREQ_500MS 4
  49. #define ZOPT2201_MEAS_FREQ_1000MS 5
  50. #define ZOPT2201_MEAS_FREQ_2000MS 6
  51. /* Values for ZOPT2201_LS_GAIN */
  52. #define ZOPT2201_LS_GAIN_1 0
  53. #define ZOPT2201_LS_GAIN_3 1
  54. #define ZOPT2201_LS_GAIN_6 2
  55. #define ZOPT2201_LS_GAIN_9 3
  56. #define ZOPT2201_LS_GAIN_18 4
  57. /* Values for ZOPT2201_MAIN_STATUS */
  58. #define ZOPT2201_MAIN_STATUS_POWERON BIT(5)
  59. #define ZOPT2201_MAIN_STATUS_INT BIT(4)
  60. #define ZOPT2201_MAIN_STATUS_DRDY BIT(3)
  61. #define ZOPT2201_PART_NUMBER 0xb2
  62. struct zopt2201_data {
  63. struct i2c_client *client;
  64. struct mutex lock;
  65. u8 gain;
  66. u8 res;
  67. u8 rate;
  68. };
  69. static const struct {
  70. unsigned int gain; /* gain factor */
  71. unsigned int scale; /* micro lux per count */
  72. } zopt2201_gain_als[] = {
  73. { 1, 19200000 },
  74. { 3, 6400000 },
  75. { 6, 3200000 },
  76. { 9, 2133333 },
  77. { 18, 1066666 },
  78. };
  79. static const struct {
  80. unsigned int gain; /* gain factor */
  81. unsigned int scale; /* micro W/m2 per count */
  82. } zopt2201_gain_uvb[] = {
  83. { 1, 460800 },
  84. { 3, 153600 },
  85. { 6, 76800 },
  86. { 9, 51200 },
  87. { 18, 25600 },
  88. };
  89. static const struct {
  90. unsigned int bits; /* sensor resolution in bits */
  91. unsigned long us; /* measurement time in micro seconds */
  92. } zopt2201_resolution[] = {
  93. { 20, 400000 },
  94. { 19, 200000 },
  95. { 18, 100000 },
  96. { 17, 50000 },
  97. { 16, 25000 },
  98. { 13, 3125 },
  99. };
  100. static const struct {
  101. unsigned int scale, uscale; /* scale factor as integer + micro */
  102. u8 gain; /* gain register value */
  103. u8 res; /* resolution register value */
  104. } zopt2201_scale_als[] = {
  105. { 19, 200000, 0, 5 },
  106. { 6, 400000, 1, 5 },
  107. { 3, 200000, 2, 5 },
  108. { 2, 400000, 0, 4 },
  109. { 2, 133333, 3, 5 },
  110. { 1, 200000, 0, 3 },
  111. { 1, 66666, 4, 5 },
  112. { 0, 800000, 1, 4 },
  113. { 0, 600000, 0, 2 },
  114. { 0, 400000, 2, 4 },
  115. { 0, 300000, 0, 1 },
  116. { 0, 266666, 3, 4 },
  117. { 0, 200000, 2, 3 },
  118. { 0, 150000, 0, 0 },
  119. { 0, 133333, 4, 4 },
  120. { 0, 100000, 2, 2 },
  121. { 0, 66666, 4, 3 },
  122. { 0, 50000, 2, 1 },
  123. { 0, 33333, 4, 2 },
  124. { 0, 25000, 2, 0 },
  125. { 0, 16666, 4, 1 },
  126. { 0, 8333, 4, 0 },
  127. };
  128. static const struct {
  129. unsigned int scale, uscale; /* scale factor as integer + micro */
  130. u8 gain; /* gain register value */
  131. u8 res; /* resolution register value */
  132. } zopt2201_scale_uvb[] = {
  133. { 0, 460800, 0, 5 },
  134. { 0, 153600, 1, 5 },
  135. { 0, 76800, 2, 5 },
  136. { 0, 57600, 0, 4 },
  137. { 0, 51200, 3, 5 },
  138. { 0, 28800, 0, 3 },
  139. { 0, 25600, 4, 5 },
  140. { 0, 19200, 1, 4 },
  141. { 0, 14400, 0, 2 },
  142. { 0, 9600, 2, 4 },
  143. { 0, 7200, 0, 1 },
  144. { 0, 6400, 3, 4 },
  145. { 0, 4800, 2, 3 },
  146. { 0, 3600, 0, 0 },
  147. { 0, 3200, 4, 4 },
  148. { 0, 2400, 2, 2 },
  149. { 0, 1600, 4, 3 },
  150. { 0, 1200, 2, 1 },
  151. { 0, 800, 4, 2 },
  152. { 0, 600, 2, 0 },
  153. { 0, 400, 4, 1 },
  154. { 0, 200, 4, 0 },
  155. };
  156. static int zopt2201_enable_mode(struct zopt2201_data *data, bool uvb_mode)
  157. {
  158. u8 out = ZOPT2201_MAIN_CTRL_LS_EN;
  159. if (uvb_mode)
  160. out |= ZOPT2201_MAIN_CTRL_LS_MODE;
  161. return i2c_smbus_write_byte_data(data->client, ZOPT2201_MAIN_CTRL, out);
  162. }
  163. static int zopt2201_read(struct zopt2201_data *data, u8 reg)
  164. {
  165. struct i2c_client *client = data->client;
  166. int tries = 10;
  167. u8 buf[3];
  168. int ret;
  169. mutex_lock(&data->lock);
  170. ret = zopt2201_enable_mode(data, reg == ZOPT2201_UVB_DATA);
  171. if (ret < 0)
  172. goto fail;
  173. while (tries--) {
  174. unsigned long t = zopt2201_resolution[data->res].us;
  175. if (t <= 20000)
  176. usleep_range(t, t + 1000);
  177. else
  178. msleep(t / 1000);
  179. ret = i2c_smbus_read_byte_data(client, ZOPT2201_MAIN_STATUS);
  180. if (ret < 0)
  181. goto fail;
  182. if (ret & ZOPT2201_MAIN_STATUS_DRDY)
  183. break;
  184. }
  185. if (tries < 0) {
  186. ret = -ETIMEDOUT;
  187. goto fail;
  188. }
  189. ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf);
  190. if (ret < 0)
  191. goto fail;
  192. ret = i2c_smbus_write_byte_data(client, ZOPT2201_MAIN_CTRL, 0x00);
  193. if (ret < 0)
  194. goto fail;
  195. mutex_unlock(&data->lock);
  196. return get_unaligned_le24(&buf[0]);
  197. fail:
  198. mutex_unlock(&data->lock);
  199. return ret;
  200. }
  201. static const struct iio_chan_spec zopt2201_channels[] = {
  202. {
  203. .type = IIO_LIGHT,
  204. .address = ZOPT2201_ALS_DATA,
  205. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  206. BIT(IIO_CHAN_INFO_SCALE),
  207. .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
  208. },
  209. {
  210. .type = IIO_INTENSITY,
  211. .modified = 1,
  212. .channel2 = IIO_MOD_LIGHT_UV,
  213. .address = ZOPT2201_UVB_DATA,
  214. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  215. BIT(IIO_CHAN_INFO_SCALE),
  216. .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
  217. },
  218. {
  219. .type = IIO_UVINDEX,
  220. .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
  221. },
  222. };
  223. static int zopt2201_read_raw(struct iio_dev *indio_dev,
  224. struct iio_chan_spec const *chan,
  225. int *val, int *val2, long mask)
  226. {
  227. struct zopt2201_data *data = iio_priv(indio_dev);
  228. u64 tmp;
  229. int ret;
  230. switch (mask) {
  231. case IIO_CHAN_INFO_RAW:
  232. ret = zopt2201_read(data, chan->address);
  233. if (ret < 0)
  234. return ret;
  235. *val = ret;
  236. return IIO_VAL_INT;
  237. case IIO_CHAN_INFO_PROCESSED:
  238. ret = zopt2201_read(data, ZOPT2201_UVB_DATA);
  239. if (ret < 0)
  240. return ret;
  241. *val = ret * 18 *
  242. (1 << (20 - zopt2201_resolution[data->res].bits)) /
  243. zopt2201_gain_uvb[data->gain].gain;
  244. return IIO_VAL_INT;
  245. case IIO_CHAN_INFO_SCALE:
  246. switch (chan->address) {
  247. case ZOPT2201_ALS_DATA:
  248. *val = zopt2201_gain_als[data->gain].scale;
  249. break;
  250. case ZOPT2201_UVB_DATA:
  251. *val = zopt2201_gain_uvb[data->gain].scale;
  252. break;
  253. default:
  254. return -EINVAL;
  255. }
  256. *val2 = 1000000;
  257. *val2 *= (1 << (zopt2201_resolution[data->res].bits - 13));
  258. tmp = div_s64(*val * 1000000ULL, *val2);
  259. *val = div_s64_rem(tmp, 1000000, val2);
  260. return IIO_VAL_INT_PLUS_MICRO;
  261. case IIO_CHAN_INFO_INT_TIME:
  262. *val = 0;
  263. *val2 = zopt2201_resolution[data->res].us;
  264. return IIO_VAL_INT_PLUS_MICRO;
  265. default:
  266. return -EINVAL;
  267. }
  268. }
  269. static int zopt2201_set_resolution(struct zopt2201_data *data, u8 res)
  270. {
  271. int ret;
  272. ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_MEAS_RATE,
  273. (res << ZOPT2201_MEAS_RES_SHIFT) |
  274. data->rate);
  275. if (ret < 0)
  276. return ret;
  277. data->res = res;
  278. return 0;
  279. }
  280. static int zopt2201_write_resolution(struct zopt2201_data *data,
  281. int val, int val2)
  282. {
  283. int i, ret;
  284. if (val != 0)
  285. return -EINVAL;
  286. for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
  287. if (val2 == zopt2201_resolution[i].us) {
  288. mutex_lock(&data->lock);
  289. ret = zopt2201_set_resolution(data, i);
  290. mutex_unlock(&data->lock);
  291. return ret;
  292. }
  293. return -EINVAL;
  294. }
  295. static int zopt2201_set_gain(struct zopt2201_data *data, u8 gain)
  296. {
  297. int ret;
  298. ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_GAIN, gain);
  299. if (ret < 0)
  300. return ret;
  301. data->gain = gain;
  302. return 0;
  303. }
  304. static int zopt2201_write_scale_als_by_idx(struct zopt2201_data *data, int idx)
  305. {
  306. int ret;
  307. mutex_lock(&data->lock);
  308. ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
  309. if (ret < 0)
  310. goto unlock;
  311. ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
  312. unlock:
  313. mutex_unlock(&data->lock);
  314. return ret;
  315. }
  316. static int zopt2201_write_scale_als(struct zopt2201_data *data,
  317. int val, int val2)
  318. {
  319. int i;
  320. for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
  321. if (val == zopt2201_scale_als[i].scale &&
  322. val2 == zopt2201_scale_als[i].uscale) {
  323. return zopt2201_write_scale_als_by_idx(data, i);
  324. }
  325. return -EINVAL;
  326. }
  327. static int zopt2201_write_scale_uvb_by_idx(struct zopt2201_data *data, int idx)
  328. {
  329. int ret;
  330. mutex_lock(&data->lock);
  331. ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
  332. if (ret < 0)
  333. goto unlock;
  334. ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
  335. unlock:
  336. mutex_unlock(&data->lock);
  337. return ret;
  338. }
  339. static int zopt2201_write_scale_uvb(struct zopt2201_data *data,
  340. int val, int val2)
  341. {
  342. int i;
  343. for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
  344. if (val == zopt2201_scale_uvb[i].scale &&
  345. val2 == zopt2201_scale_uvb[i].uscale)
  346. return zopt2201_write_scale_uvb_by_idx(data, i);
  347. return -EINVAL;
  348. }
  349. static int zopt2201_write_raw(struct iio_dev *indio_dev,
  350. struct iio_chan_spec const *chan,
  351. int val, int val2, long mask)
  352. {
  353. struct zopt2201_data *data = iio_priv(indio_dev);
  354. switch (mask) {
  355. case IIO_CHAN_INFO_INT_TIME:
  356. return zopt2201_write_resolution(data, val, val2);
  357. case IIO_CHAN_INFO_SCALE:
  358. switch (chan->address) {
  359. case ZOPT2201_ALS_DATA:
  360. return zopt2201_write_scale_als(data, val, val2);
  361. case ZOPT2201_UVB_DATA:
  362. return zopt2201_write_scale_uvb(data, val, val2);
  363. default:
  364. return -EINVAL;
  365. }
  366. }
  367. return -EINVAL;
  368. }
  369. static ssize_t zopt2201_show_int_time_available(struct device *dev,
  370. struct device_attribute *attr,
  371. char *buf)
  372. {
  373. size_t len = 0;
  374. int i;
  375. for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
  376. len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06lu ",
  377. zopt2201_resolution[i].us);
  378. buf[len - 1] = '\n';
  379. return len;
  380. }
  381. static IIO_DEV_ATTR_INT_TIME_AVAIL(zopt2201_show_int_time_available);
  382. static ssize_t zopt2201_show_als_scale_avail(struct device *dev,
  383. struct device_attribute *attr,
  384. char *buf)
  385. {
  386. ssize_t len = 0;
  387. int i;
  388. for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
  389. len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
  390. zopt2201_scale_als[i].scale,
  391. zopt2201_scale_als[i].uscale);
  392. buf[len - 1] = '\n';
  393. return len;
  394. }
  395. static ssize_t zopt2201_show_uvb_scale_avail(struct device *dev,
  396. struct device_attribute *attr,
  397. char *buf)
  398. {
  399. ssize_t len = 0;
  400. int i;
  401. for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
  402. len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
  403. zopt2201_scale_uvb[i].scale,
  404. zopt2201_scale_uvb[i].uscale);
  405. buf[len - 1] = '\n';
  406. return len;
  407. }
  408. static IIO_DEVICE_ATTR(in_illuminance_scale_available, 0444,
  409. zopt2201_show_als_scale_avail, NULL, 0);
  410. static IIO_DEVICE_ATTR(in_intensity_uv_scale_available, 0444,
  411. zopt2201_show_uvb_scale_avail, NULL, 0);
  412. static struct attribute *zopt2201_attributes[] = {
  413. &iio_dev_attr_integration_time_available.dev_attr.attr,
  414. &iio_dev_attr_in_illuminance_scale_available.dev_attr.attr,
  415. &iio_dev_attr_in_intensity_uv_scale_available.dev_attr.attr,
  416. NULL
  417. };
  418. static const struct attribute_group zopt2201_attribute_group = {
  419. .attrs = zopt2201_attributes,
  420. };
  421. static const struct iio_info zopt2201_info = {
  422. .read_raw = zopt2201_read_raw,
  423. .write_raw = zopt2201_write_raw,
  424. .attrs = &zopt2201_attribute_group,
  425. };
  426. static int zopt2201_probe(struct i2c_client *client)
  427. {
  428. struct zopt2201_data *data;
  429. struct iio_dev *indio_dev;
  430. int ret;
  431. if (!i2c_check_functionality(client->adapter,
  432. I2C_FUNC_SMBUS_READ_I2C_BLOCK))
  433. return -EOPNOTSUPP;
  434. ret = i2c_smbus_read_byte_data(client, ZOPT2201_PART_ID);
  435. if (ret < 0)
  436. return ret;
  437. if (ret != ZOPT2201_PART_NUMBER)
  438. return -ENODEV;
  439. indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
  440. if (!indio_dev)
  441. return -ENOMEM;
  442. data = iio_priv(indio_dev);
  443. i2c_set_clientdata(client, indio_dev);
  444. data->client = client;
  445. mutex_init(&data->lock);
  446. indio_dev->info = &zopt2201_info;
  447. indio_dev->channels = zopt2201_channels;
  448. indio_dev->num_channels = ARRAY_SIZE(zopt2201_channels);
  449. indio_dev->name = ZOPT2201_DRV_NAME;
  450. indio_dev->modes = INDIO_DIRECT_MODE;
  451. data->rate = ZOPT2201_MEAS_FREQ_100MS;
  452. ret = zopt2201_set_resolution(data, ZOPT2201_MEAS_RES_18BIT);
  453. if (ret < 0)
  454. return ret;
  455. ret = zopt2201_set_gain(data, ZOPT2201_LS_GAIN_3);
  456. if (ret < 0)
  457. return ret;
  458. return devm_iio_device_register(&client->dev, indio_dev);
  459. }
  460. static const struct i2c_device_id zopt2201_id[] = {
  461. { "zopt2201" },
  462. { }
  463. };
  464. MODULE_DEVICE_TABLE(i2c, zopt2201_id);
  465. static struct i2c_driver zopt2201_driver = {
  466. .driver = {
  467. .name = ZOPT2201_DRV_NAME,
  468. },
  469. .probe = zopt2201_probe,
  470. .id_table = zopt2201_id,
  471. };
  472. module_i2c_driver(zopt2201_driver);
  473. MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
  474. MODULE_DESCRIPTION("IDT ZOPT2201 ambient light and UV B sensor driver");
  475. MODULE_LICENSE("GPL");