]> Git Repo - linux.git/blob - drivers/iio/light/veml6040.c
dma-mapping: don't return errors from dma_set_max_seg_size
[linux.git] / drivers / iio / light / veml6040.c
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 <[email protected]>
7  *
8  */
9
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>
17
18 /* VEML6040 Configuration Registers
19  *
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
24  */
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
36
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
42
43 static const int veml6040_it_ms[] = { 40, 80, 160, 320, 640, 1280 };
44
45 enum veml6040_chan {
46         CH_RED,
47         CH_GREEN,
48         CH_BLUE,
49         CH_WHITE,
50 };
51
52 struct veml6040_data {
53         struct i2c_client *client;
54         struct regmap *regmap;
55 };
56
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,
63 };
64
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)
68 {
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;
73
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;
80                 }
81                 *val = reg;
82                 return IIO_VAL_INT;
83
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;
89                 }
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;
94                 }
95                 *val = veml6040_it_ms[it_index];
96                 return IIO_VAL_INT;
97
98         default:
99                 return -EINVAL;
100         }
101 }
102
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)
106 {
107         struct veml6040_data *data = iio_priv(indio_dev);
108
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;
114
115                         return regmap_update_bits(data->regmap,
116                                         VEML6040_CONF_REG,
117                                         VEML6040_CONF_IT_MSK,
118                                         FIELD_PREP(VEML6040_CONF_IT_MSK, i));
119                 }
120                 return -EINVAL;
121         default:
122                 return -EINVAL;
123         }
124 }
125
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)
130 {
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;
137
138         default:
139                 return -EINVAL;
140         }
141 }
142
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,
147 };
148
149 static const struct iio_chan_spec veml6040_channels[] = {
150         {
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),
160         },
161         {
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),
171         },
172         {
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),
182         },
183         {
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),
193         }
194 };
195
196 static void veml6040_shutdown_action(void *data)
197 {
198         struct veml6040_data *veml6040_data = data;
199
200         regmap_update_bits(veml6040_data->regmap, VEML6040_CONF_REG,
201                            VEML6040_CONF_SD_MSK, VEML6040_CONF_SD_MSK);
202 }
203
204 static int veml6040_probe(struct i2c_client *client)
205 {
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;
215
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");
219
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");
224
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");
229
230         data = iio_priv(indio_dev);
231         i2c_set_clientdata(client, indio_dev);
232         data->client = client;
233         data->regmap = regmap;
234
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;
240
241         ret = devm_regulator_get_enable(dev, "vdd");
242         if (ret)
243                 return ret;
244
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");
249
250         ret = devm_add_action_or_reset(dev, veml6040_shutdown_action, data);
251         if (ret)
252                 return ret;
253
254         return devm_iio_device_register(dev, indio_dev);
255 }
256
257 static const struct i2c_device_id veml6040_id_table[] = {
258         {"veml6040"},
259         {}
260 };
261 MODULE_DEVICE_TABLE(i2c, veml6040_id_table);
262
263 static const struct of_device_id veml6040_of_match[] = {
264         {.compatible = "vishay,veml6040"},
265         {}
266 };
267 MODULE_DEVICE_TABLE(of, veml6040_of_match);
268
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,
275         },
276 };
277 module_i2c_driver(veml6040_driver);
278
279 MODULE_DESCRIPTION("veml6040 RGBW light sensor driver");
280 MODULE_AUTHOR("Arthur Becker <[email protected]>");
281 MODULE_LICENSE("GPL");
This page took 0.048652 seconds and 4 git commands to generate.