veml6040.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Vishay VEML6040 RGBW light sensor driver
  4. *
  5. * Copyright (C) 2024 Sentec AG
  6. * Author: Arthur Becker <arthur.becker@sentec.com>
  7. *
  8. */
  9. #include <linux/bitfield.h>
  10. #include <linux/err.h>
  11. #include <linux/i2c.h>
  12. #include <linux/iio/iio.h>
  13. #include <linux/iio/sysfs.h>
  14. #include <linux/module.h>
  15. #include <linux/regmap.h>
  16. /* VEML6040 Configuration Registers
  17. *
  18. * SD: Shutdown
  19. * AF: Auto / Force Mode (Auto Measurements On:0, Off:1)
  20. * TR: Trigger Measurement (when AF Bit is set)
  21. * IT: Integration Time
  22. */
  23. #define VEML6040_CONF_REG 0x000
  24. #define VEML6040_CONF_SD_MSK BIT(0)
  25. #define VEML6040_CONF_AF_MSK BIT(1)
  26. #define VEML6040_CONF_TR_MSK BIT(2)
  27. #define VEML6040_CONF_IT_MSK GENMASK(6, 4)
  28. #define VEML6040_CONF_IT_40_MS 0
  29. #define VEML6040_CONF_IT_80_MS 1
  30. #define VEML6040_CONF_IT_160_MS 2
  31. #define VEML6040_CONF_IT_320_MS 3
  32. #define VEML6040_CONF_IT_640_MS 4
  33. #define VEML6040_CONF_IT_1280_MS 5
  34. /* VEML6040 Read Only Registers */
  35. #define VEML6040_REG_R 0x08
  36. #define VEML6040_REG_G 0x09
  37. #define VEML6040_REG_B 0x0A
  38. #define VEML6040_REG_W 0x0B
  39. static const int veml6040_it_ms[] = { 40, 80, 160, 320, 640, 1280 };
  40. enum veml6040_chan {
  41. CH_RED,
  42. CH_GREEN,
  43. CH_BLUE,
  44. CH_WHITE,
  45. };
  46. struct veml6040_data {
  47. struct i2c_client *client;
  48. struct regmap *regmap;
  49. };
  50. static const struct regmap_config veml6040_regmap_config = {
  51. .name = "veml6040_regmap",
  52. .reg_bits = 8,
  53. .val_bits = 16,
  54. .max_register = VEML6040_REG_W,
  55. .val_format_endian = REGMAP_ENDIAN_LITTLE,
  56. };
  57. static int veml6040_read_raw(struct iio_dev *indio_dev,
  58. struct iio_chan_spec const *chan, int *val,
  59. int *val2, long mask)
  60. {
  61. int ret, reg, it_index;
  62. struct veml6040_data *data = iio_priv(indio_dev);
  63. struct regmap *regmap = data->regmap;
  64. struct device *dev = &data->client->dev;
  65. switch (mask) {
  66. case IIO_CHAN_INFO_RAW:
  67. ret = regmap_read(regmap, chan->address, &reg);
  68. if (ret) {
  69. dev_err(dev, "Data read failed: %d\n", ret);
  70. return ret;
  71. }
  72. *val = reg;
  73. return IIO_VAL_INT;
  74. case IIO_CHAN_INFO_INT_TIME:
  75. ret = regmap_read(regmap, VEML6040_CONF_REG, &reg);
  76. if (ret) {
  77. dev_err(dev, "Data read failed: %d\n", ret);
  78. return ret;
  79. }
  80. it_index = FIELD_GET(VEML6040_CONF_IT_MSK, reg);
  81. if (it_index >= ARRAY_SIZE(veml6040_it_ms)) {
  82. dev_err(dev, "Invalid Integration Time Set");
  83. return -EINVAL;
  84. }
  85. *val = veml6040_it_ms[it_index];
  86. return IIO_VAL_INT;
  87. default:
  88. return -EINVAL;
  89. }
  90. }
  91. static int veml6040_write_raw(struct iio_dev *indio_dev,
  92. struct iio_chan_spec const *chan, int val,
  93. int val2, long mask)
  94. {
  95. struct veml6040_data *data = iio_priv(indio_dev);
  96. switch (mask) {
  97. case IIO_CHAN_INFO_INT_TIME:
  98. for (int i = 0; i < ARRAY_SIZE(veml6040_it_ms); i++) {
  99. if (veml6040_it_ms[i] != val)
  100. continue;
  101. return regmap_update_bits(data->regmap,
  102. VEML6040_CONF_REG,
  103. VEML6040_CONF_IT_MSK,
  104. FIELD_PREP(VEML6040_CONF_IT_MSK, i));
  105. }
  106. return -EINVAL;
  107. default:
  108. return -EINVAL;
  109. }
  110. }
  111. static int veml6040_read_avail(struct iio_dev *indio_dev,
  112. struct iio_chan_spec const *chan,
  113. const int **vals, int *type, int *length,
  114. long mask)
  115. {
  116. switch (mask) {
  117. case IIO_CHAN_INFO_INT_TIME:
  118. *length = ARRAY_SIZE(veml6040_it_ms);
  119. *vals = veml6040_it_ms;
  120. *type = IIO_VAL_INT;
  121. return IIO_AVAIL_LIST;
  122. default:
  123. return -EINVAL;
  124. }
  125. }
  126. static const struct iio_info veml6040_info = {
  127. .read_raw = veml6040_read_raw,
  128. .write_raw = veml6040_write_raw,
  129. .read_avail = veml6040_read_avail,
  130. };
  131. static const struct iio_chan_spec veml6040_channels[] = {
  132. {
  133. .type = IIO_INTENSITY,
  134. .address = VEML6040_REG_R,
  135. .channel = CH_RED,
  136. .channel2 = IIO_MOD_LIGHT_RED,
  137. .modified = 1,
  138. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  139. .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME),
  140. .info_mask_shared_by_type_available =
  141. BIT(IIO_CHAN_INFO_INT_TIME),
  142. },
  143. {
  144. .type = IIO_INTENSITY,
  145. .address = VEML6040_REG_G,
  146. .channel = CH_GREEN,
  147. .channel2 = IIO_MOD_LIGHT_GREEN,
  148. .modified = 1,
  149. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  150. .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME),
  151. .info_mask_shared_by_type_available =
  152. BIT(IIO_CHAN_INFO_INT_TIME),
  153. },
  154. {
  155. .type = IIO_INTENSITY,
  156. .address = VEML6040_REG_B,
  157. .channel = CH_BLUE,
  158. .channel2 = IIO_MOD_LIGHT_BLUE,
  159. .modified = 1,
  160. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  161. .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME),
  162. .info_mask_shared_by_type_available =
  163. BIT(IIO_CHAN_INFO_INT_TIME),
  164. },
  165. {
  166. .type = IIO_INTENSITY,
  167. .address = VEML6040_REG_W,
  168. .channel = CH_WHITE,
  169. .channel2 = IIO_MOD_LIGHT_CLEAR,
  170. .modified = 1,
  171. .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  172. .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_INT_TIME),
  173. .info_mask_shared_by_type_available =
  174. BIT(IIO_CHAN_INFO_INT_TIME),
  175. }
  176. };
  177. static void veml6040_shutdown_action(void *data)
  178. {
  179. struct veml6040_data *veml6040_data = data;
  180. regmap_update_bits(veml6040_data->regmap, VEML6040_CONF_REG,
  181. VEML6040_CONF_SD_MSK, VEML6040_CONF_SD_MSK);
  182. }
  183. static int veml6040_probe(struct i2c_client *client)
  184. {
  185. struct device *dev = &client->dev;
  186. struct veml6040_data *data;
  187. struct iio_dev *indio_dev;
  188. struct regmap *regmap;
  189. const int init_config =
  190. FIELD_PREP(VEML6040_CONF_IT_MSK, VEML6040_CONF_IT_40_MS) |
  191. FIELD_PREP(VEML6040_CONF_AF_MSK, 0) |
  192. FIELD_PREP(VEML6040_CONF_SD_MSK, 0);
  193. int ret;
  194. if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
  195. return dev_err_probe(dev, -EOPNOTSUPP,
  196. "I2C adapter doesn't support plain I2C\n");
  197. indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
  198. if (!indio_dev)
  199. return dev_err_probe(dev, -ENOMEM,
  200. "IIO device allocation failed\n");
  201. regmap = devm_regmap_init_i2c(client, &veml6040_regmap_config);
  202. if (IS_ERR(regmap))
  203. return dev_err_probe(dev, PTR_ERR(regmap),
  204. "Regmap setup failed\n");
  205. data = iio_priv(indio_dev);
  206. i2c_set_clientdata(client, indio_dev);
  207. data->client = client;
  208. data->regmap = regmap;
  209. indio_dev->name = "veml6040";
  210. indio_dev->info = &veml6040_info;
  211. indio_dev->channels = veml6040_channels;
  212. indio_dev->num_channels = ARRAY_SIZE(veml6040_channels);
  213. indio_dev->modes = INDIO_DIRECT_MODE;
  214. ret = devm_regulator_get_enable(dev, "vdd");
  215. if (ret)
  216. return ret;
  217. ret = regmap_write(regmap, VEML6040_CONF_REG, init_config);
  218. if (ret)
  219. return dev_err_probe(dev, ret,
  220. "Could not set initial config\n");
  221. ret = devm_add_action_or_reset(dev, veml6040_shutdown_action, data);
  222. if (ret)
  223. return ret;
  224. return devm_iio_device_register(dev, indio_dev);
  225. }
  226. static const struct i2c_device_id veml6040_id_table[] = {
  227. {"veml6040"},
  228. {}
  229. };
  230. MODULE_DEVICE_TABLE(i2c, veml6040_id_table);
  231. static const struct of_device_id veml6040_of_match[] = {
  232. {.compatible = "vishay,veml6040"},
  233. {}
  234. };
  235. MODULE_DEVICE_TABLE(of, veml6040_of_match);
  236. static struct i2c_driver veml6040_driver = {
  237. .probe = veml6040_probe,
  238. .id_table = veml6040_id_table,
  239. .driver = {
  240. .name = "veml6040",
  241. .of_match_table = veml6040_of_match,
  242. },
  243. };
  244. module_i2c_driver(veml6040_driver);
  245. MODULE_DESCRIPTION("veml6040 RGBW light sensor driver");
  246. MODULE_AUTHOR("Arthur Becker <arthur.becker@sentec.com>");
  247. MODULE_LICENSE("GPL");