cm3232.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * CM3232 Ambient Light Sensor
  4. *
  5. * Copyright (C) 2014-2015 Capella Microsystems Inc.
  6. * Author: Kevin Tsai <ktsai@capellamicro.com>
  7. *
  8. * IIO driver for CM3232 (7-bit I2C slave address 0x10).
  9. */
  10. #include <linux/i2c.h>
  11. #include <linux/module.h>
  12. #include <linux/mod_devicetable.h>
  13. #include <linux/iio/iio.h>
  14. #include <linux/iio/sysfs.h>
  15. #include <linux/init.h>
  16. /* Registers Address */
  17. #define CM3232_REG_ADDR_CMD 0x00
  18. #define CM3232_REG_ADDR_ALS 0x50
  19. #define CM3232_REG_ADDR_ID 0x53
  20. #define CM3232_CMD_ALS_DISABLE BIT(0)
  21. #define CM3232_CMD_ALS_IT_SHIFT 2
  22. #define CM3232_CMD_ALS_IT_MASK (BIT(2) | BIT(3) | BIT(4))
  23. #define CM3232_CMD_ALS_IT_DEFAULT (0x01 << CM3232_CMD_ALS_IT_SHIFT)
  24. #define CM3232_CMD_ALS_RESET BIT(6)
  25. #define CM3232_CMD_DEFAULT CM3232_CMD_ALS_IT_DEFAULT
  26. #define CM3232_HW_ID 0x32
  27. #define CM3232_CALIBSCALE_DEFAULT 100000
  28. #define CM3232_CALIBSCALE_RESOLUTION 100000
  29. #define CM3232_MLUX_PER_LUX 1000
  30. #define CM3232_MLUX_PER_BIT_DEFAULT 64
  31. #define CM3232_MLUX_PER_BIT_BASE_IT 100000
  32. static const struct {
  33. int val;
  34. int val2;
  35. u8 it;
  36. } cm3232_als_it_scales[] = {
  37. {0, 100000, 0}, /* 0.100000 */
  38. {0, 200000, 1}, /* 0.200000 */
  39. {0, 400000, 2}, /* 0.400000 */
  40. {0, 800000, 3}, /* 0.800000 */
  41. {1, 600000, 4}, /* 1.600000 */
  42. {3, 200000, 5}, /* 3.200000 */
  43. };
  44. struct cm3232_als_info {
  45. u8 regs_cmd_default;
  46. u8 hw_id;
  47. int calibscale;
  48. int mlux_per_bit;
  49. int mlux_per_bit_base_it;
  50. };
  51. static struct cm3232_als_info cm3232_als_info_default = {
  52. .regs_cmd_default = CM3232_CMD_DEFAULT,
  53. .hw_id = CM3232_HW_ID,
  54. .calibscale = CM3232_CALIBSCALE_DEFAULT,
  55. .mlux_per_bit = CM3232_MLUX_PER_BIT_DEFAULT,
  56. .mlux_per_bit_base_it = CM3232_MLUX_PER_BIT_BASE_IT,
  57. };
  58. struct cm3232_chip {
  59. struct i2c_client *client;
  60. struct cm3232_als_info *als_info;
  61. u8 regs_cmd;
  62. u16 regs_als;
  63. };
  64. /**
  65. * cm3232_reg_init() - Initialize CM3232
  66. * @chip: pointer of struct cm3232_chip.
  67. *
  68. * Check and initialize CM3232 ambient light sensor.
  69. *
  70. * Return: 0 for success; otherwise for error code.
  71. */
  72. static int cm3232_reg_init(struct cm3232_chip *chip)
  73. {
  74. struct i2c_client *client = chip->client;
  75. s32 ret;
  76. chip->als_info = &cm3232_als_info_default;
  77. /* Identify device */
  78. ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ID);
  79. if (ret < 0) {
  80. dev_err(&chip->client->dev, "Error reading addr_id\n");
  81. return ret;
  82. }
  83. if ((ret & 0xFF) != chip->als_info->hw_id)
  84. return -ENODEV;
  85. /* Disable and reset device */
  86. chip->regs_cmd = CM3232_CMD_ALS_DISABLE | CM3232_CMD_ALS_RESET;
  87. ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
  88. chip->regs_cmd);
  89. if (ret < 0) {
  90. dev_err(&chip->client->dev, "Error writing reg_cmd\n");
  91. return ret;
  92. }
  93. /* Register default value */
  94. chip->regs_cmd = chip->als_info->regs_cmd_default;
  95. /* Configure register */
  96. ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
  97. chip->regs_cmd);
  98. if (ret < 0)
  99. dev_err(&chip->client->dev, "Error writing reg_cmd\n");
  100. return ret;
  101. }
  102. /**
  103. * cm3232_read_als_it() - Get sensor integration time
  104. * @chip: pointer of struct cm3232_chip
  105. * @val: pointer of int to load the integration (sec).
  106. * @val2: pointer of int to load the integration time (microsecond).
  107. *
  108. * Report the current integration time.
  109. *
  110. * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
  111. */
  112. static int cm3232_read_als_it(struct cm3232_chip *chip, int *val, int *val2)
  113. {
  114. u16 als_it;
  115. int i;
  116. als_it = chip->regs_cmd;
  117. als_it &= CM3232_CMD_ALS_IT_MASK;
  118. als_it >>= CM3232_CMD_ALS_IT_SHIFT;
  119. for (i = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++) {
  120. if (als_it == cm3232_als_it_scales[i].it) {
  121. *val = cm3232_als_it_scales[i].val;
  122. *val2 = cm3232_als_it_scales[i].val2;
  123. return IIO_VAL_INT_PLUS_MICRO;
  124. }
  125. }
  126. return -EINVAL;
  127. }
  128. /**
  129. * cm3232_write_als_it() - Write sensor integration time
  130. * @chip: pointer of struct cm3232_chip.
  131. * @val: integration time in second.
  132. * @val2: integration time in microsecond.
  133. *
  134. * Convert integration time to sensor value.
  135. *
  136. * Return: i2c_smbus_write_byte_data command return value.
  137. */
  138. static int cm3232_write_als_it(struct cm3232_chip *chip, int val, int val2)
  139. {
  140. struct i2c_client *client = chip->client;
  141. u16 als_it, cmd;
  142. int i;
  143. s32 ret;
  144. for (i = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++) {
  145. if (val == cm3232_als_it_scales[i].val &&
  146. val2 == cm3232_als_it_scales[i].val2) {
  147. als_it = cm3232_als_it_scales[i].it;
  148. als_it <<= CM3232_CMD_ALS_IT_SHIFT;
  149. cmd = chip->regs_cmd & ~CM3232_CMD_ALS_IT_MASK;
  150. cmd |= als_it;
  151. ret = i2c_smbus_write_byte_data(client,
  152. CM3232_REG_ADDR_CMD,
  153. cmd);
  154. if (ret < 0)
  155. return ret;
  156. chip->regs_cmd = cmd;
  157. return 0;
  158. }
  159. }
  160. return -EINVAL;
  161. }
  162. /**
  163. * cm3232_get_lux() - report current lux value
  164. * @chip: pointer of struct cm3232_chip.
  165. *
  166. * Convert sensor data to lux. It depends on integration
  167. * time and calibscale variable.
  168. *
  169. * Return: Zero or positive value is lux, otherwise error code.
  170. */
  171. static int cm3232_get_lux(struct cm3232_chip *chip)
  172. {
  173. struct i2c_client *client = chip->client;
  174. struct cm3232_als_info *als_info = chip->als_info;
  175. int ret;
  176. int val, val2;
  177. int als_it;
  178. u64 lux;
  179. /* Calculate mlux per bit based on als_it */
  180. ret = cm3232_read_als_it(chip, &val, &val2);
  181. if (ret < 0)
  182. return -EINVAL;
  183. als_it = val * 1000000 + val2;
  184. lux = (__force u64)als_info->mlux_per_bit;
  185. lux *= als_info->mlux_per_bit_base_it;
  186. lux = div_u64(lux, als_it);
  187. ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ALS);
  188. if (ret < 0) {
  189. dev_err(&client->dev, "Error reading reg_addr_als\n");
  190. return ret;
  191. }
  192. chip->regs_als = (u16)ret;
  193. lux *= chip->regs_als;
  194. lux *= als_info->calibscale;
  195. lux = div_u64(lux, CM3232_CALIBSCALE_RESOLUTION);
  196. lux = div_u64(lux, CM3232_MLUX_PER_LUX);
  197. if (lux > 0xFFFF)
  198. lux = 0xFFFF;
  199. return (int)lux;
  200. }
  201. static int cm3232_read_raw(struct iio_dev *indio_dev,
  202. struct iio_chan_spec const *chan,
  203. int *val, int *val2, long mask)
  204. {
  205. struct cm3232_chip *chip = iio_priv(indio_dev);
  206. struct cm3232_als_info *als_info = chip->als_info;
  207. int ret;
  208. switch (mask) {
  209. case IIO_CHAN_INFO_PROCESSED:
  210. ret = cm3232_get_lux(chip);
  211. if (ret < 0)
  212. return ret;
  213. *val = ret;
  214. return IIO_VAL_INT;
  215. case IIO_CHAN_INFO_CALIBSCALE:
  216. *val = als_info->calibscale;
  217. return IIO_VAL_INT;
  218. case IIO_CHAN_INFO_INT_TIME:
  219. return cm3232_read_als_it(chip, val, val2);
  220. }
  221. return -EINVAL;
  222. }
  223. static int cm3232_write_raw(struct iio_dev *indio_dev,
  224. struct iio_chan_spec const *chan,
  225. int val, int val2, long mask)
  226. {
  227. struct cm3232_chip *chip = iio_priv(indio_dev);
  228. struct cm3232_als_info *als_info = chip->als_info;
  229. switch (mask) {
  230. case IIO_CHAN_INFO_CALIBSCALE:
  231. als_info->calibscale = val;
  232. return 0;
  233. case IIO_CHAN_INFO_INT_TIME:
  234. return cm3232_write_als_it(chip, val, val2);
  235. }
  236. return -EINVAL;
  237. }
  238. /**
  239. * cm3232_get_it_available() - Get available ALS IT value
  240. * @dev: pointer of struct device.
  241. * @attr: pointer of struct device_attribute.
  242. * @buf: pointer of return string buffer.
  243. *
  244. * Display the available integration time in second.
  245. *
  246. * Return: string length.
  247. */
  248. static ssize_t cm3232_get_it_available(struct device *dev,
  249. struct device_attribute *attr, char *buf)
  250. {
  251. int i, len;
  252. for (i = 0, len = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++)
  253. len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
  254. cm3232_als_it_scales[i].val,
  255. cm3232_als_it_scales[i].val2);
  256. return len + scnprintf(buf + len, PAGE_SIZE - len, "\n");
  257. }
  258. static const struct iio_chan_spec cm3232_channels[] = {
  259. {
  260. .type = IIO_LIGHT,
  261. .info_mask_separate =
  262. BIT(IIO_CHAN_INFO_PROCESSED) |
  263. BIT(IIO_CHAN_INFO_CALIBSCALE) |
  264. BIT(IIO_CHAN_INFO_INT_TIME),
  265. }
  266. };
  267. static IIO_DEVICE_ATTR(in_illuminance_integration_time_available,
  268. S_IRUGO, cm3232_get_it_available, NULL, 0);
  269. static struct attribute *cm3232_attributes[] = {
  270. &iio_dev_attr_in_illuminance_integration_time_available.dev_attr.attr,
  271. NULL,
  272. };
  273. static const struct attribute_group cm3232_attribute_group = {
  274. .attrs = cm3232_attributes
  275. };
  276. static const struct iio_info cm3232_info = {
  277. .read_raw = &cm3232_read_raw,
  278. .write_raw = &cm3232_write_raw,
  279. .attrs = &cm3232_attribute_group,
  280. };
  281. static int cm3232_probe(struct i2c_client *client)
  282. {
  283. const struct i2c_device_id *id = i2c_client_get_device_id(client);
  284. struct cm3232_chip *chip;
  285. struct iio_dev *indio_dev;
  286. int ret;
  287. indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
  288. if (!indio_dev)
  289. return -ENOMEM;
  290. chip = iio_priv(indio_dev);
  291. i2c_set_clientdata(client, indio_dev);
  292. chip->client = client;
  293. indio_dev->channels = cm3232_channels;
  294. indio_dev->num_channels = ARRAY_SIZE(cm3232_channels);
  295. indio_dev->info = &cm3232_info;
  296. indio_dev->name = id->name;
  297. indio_dev->modes = INDIO_DIRECT_MODE;
  298. ret = cm3232_reg_init(chip);
  299. if (ret) {
  300. dev_err(&client->dev,
  301. "%s: register init failed\n",
  302. __func__);
  303. return ret;
  304. }
  305. return iio_device_register(indio_dev);
  306. }
  307. static void cm3232_remove(struct i2c_client *client)
  308. {
  309. struct iio_dev *indio_dev = i2c_get_clientdata(client);
  310. i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
  311. CM3232_CMD_ALS_DISABLE);
  312. iio_device_unregister(indio_dev);
  313. }
  314. static const struct i2c_device_id cm3232_id[] = {
  315. { "cm3232" },
  316. {}
  317. };
  318. static int cm3232_suspend(struct device *dev)
  319. {
  320. struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
  321. struct cm3232_chip *chip = iio_priv(indio_dev);
  322. struct i2c_client *client = chip->client;
  323. int ret;
  324. chip->regs_cmd |= CM3232_CMD_ALS_DISABLE;
  325. ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
  326. chip->regs_cmd);
  327. return ret;
  328. }
  329. static int cm3232_resume(struct device *dev)
  330. {
  331. struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
  332. struct cm3232_chip *chip = iio_priv(indio_dev);
  333. struct i2c_client *client = chip->client;
  334. int ret;
  335. chip->regs_cmd &= ~CM3232_CMD_ALS_DISABLE;
  336. ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
  337. chip->regs_cmd | CM3232_CMD_ALS_RESET);
  338. return ret;
  339. }
  340. static DEFINE_SIMPLE_DEV_PM_OPS(cm3232_pm_ops, cm3232_suspend, cm3232_resume);
  341. MODULE_DEVICE_TABLE(i2c, cm3232_id);
  342. static const struct of_device_id cm3232_of_match[] = {
  343. {.compatible = "capella,cm3232"},
  344. {}
  345. };
  346. MODULE_DEVICE_TABLE(of, cm3232_of_match);
  347. static struct i2c_driver cm3232_driver = {
  348. .driver = {
  349. .name = "cm3232",
  350. .of_match_table = cm3232_of_match,
  351. .pm = pm_sleep_ptr(&cm3232_pm_ops),
  352. },
  353. .id_table = cm3232_id,
  354. .probe = cm3232_probe,
  355. .remove = cm3232_remove,
  356. };
  357. module_i2c_driver(cm3232_driver);
  358. MODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>");
  359. MODULE_DESCRIPTION("CM3232 ambient light sensor driver");
  360. MODULE_LICENSE("GPL");