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