1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Vishay VEML3328 RGBCIR light sensor driver 4 * 5 * Copyright (c) 2026 Joshua Crofts <joshua.crofts1@gmail.com> 6 * 7 * Datasheet: https://www.vishay.com/docs/84968/veml3328.pdf 8 */ 9 10 #include <linux/array_size.h> 11 #include <linux/bitfield.h> 12 #include <linux/bits.h> 13 #include <linux/cleanup.h> 14 #include <linux/delay.h> 15 #include <linux/err.h> 16 #include <linux/i2c.h> 17 #include <linux/module.h> 18 #include <linux/mod_devicetable.h> 19 #include <linux/mutex.h> 20 #include <linux/pm_runtime.h> 21 #include <linux/regmap.h> 22 #include <linux/regulator/consumer.h> 23 #include <linux/time.h> 24 #include <linux/types.h> 25 26 #include <linux/iio/iio.h> 27 28 #define VEML3328_REG_CONF 0x00 29 #define VEML3328_REG_ID 0x0c 30 #define VEML3328_REG_DATA_C 0x04 31 #define VEML3328_REG_DATA_R 0x05 32 #define VEML3328_REG_DATA_G 0x06 33 #define VEML3328_REG_DATA_B 0x07 34 #define VEML3328_REG_DATA_IR 0x08 35 36 #define VEML3328_CONF_IT_MASK GENMASK(5, 4) 37 #define VEML3328_CONF_GAIN_MASK GENMASK(11, 10) 38 39 #define VEML3328_MAX_IT_TIME (400 * USEC_PER_MSEC) 40 41 #define VEML3328_ID_VAL 0x28 42 43 #define VEML3328_SHUTDOWN (BIT(0) | BIT(15)) 44 45 struct veml3328_data { 46 struct regmap *regmap; 47 /* Ensure read-modify-write sequences are not interrupted. */ 48 struct mutex lock; 49 }; 50 51 static const struct regmap_config veml3328_regmap_config = { 52 .name = "veml3328", 53 .reg_bits = 8, 54 .val_bits = 16, 55 .max_register = VEML3328_REG_ID, 56 .val_format_endian = REGMAP_ENDIAN_LITTLE, 57 }; 58 59 #define VEML3328_CHAN_SPEC(_color, _addr) { \ 60 .type = IIO_INTENSITY, \ 61 .modified = 1, \ 62 .channel2 = IIO_MOD_LIGHT_##_color, \ 63 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 64 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 65 .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ 66 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \ 67 .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), \ 68 .address = _addr, \ 69 } 70 71 static const struct iio_chan_spec veml3328_channels[] = { 72 { 73 .type = IIO_LIGHT, 74 75 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 76 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), 77 .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), 78 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), 79 .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), 80 .address = VEML3328_REG_DATA_G, 81 }, 82 VEML3328_CHAN_SPEC(CLEAR, VEML3328_REG_DATA_C), 83 VEML3328_CHAN_SPEC(RED, VEML3328_REG_DATA_R), 84 VEML3328_CHAN_SPEC(GREEN, VEML3328_REG_DATA_G), 85 VEML3328_CHAN_SPEC(BLUE, VEML3328_REG_DATA_B), 86 VEML3328_CHAN_SPEC(IR, VEML3328_REG_DATA_IR), 87 }; 88 89 /* 90 * Precomputed scale values (micro units). 91 * Formula for calculation: 0.384 * (50000 / IT_us) * (1 / Gain) 92 * Gain indexes: 0 (x0.5), 1 (x1), 2 (x2), 3 (x4) 93 * IT indexes: 0 (50ms), 1 (100ms), 2 (200ms), 3 (400ms) 94 */ 95 static const int veml3328_scale_vals[4][8] = { 96 { 0, 768000, 0, 384000, 0, 192000, 0, 96000 }, 97 { 0, 384000, 0, 192000, 0, 96000, 0, 48000 }, 98 { 0, 192000, 0, 96000, 0, 48000, 0, 24000 }, 99 { 0, 96000, 0, 48000, 0, 24000, 0, 12000 }, 100 }; 101 102 /* integration times in microseconds */ 103 static const int veml3328_it_times[][2] = { 104 { 0, 50 * USEC_PER_MSEC }, 105 { 0, 100 * USEC_PER_MSEC }, 106 { 0, 200 * USEC_PER_MSEC }, 107 { 0, 400 * USEC_PER_MSEC }, 108 }; 109 110 static int veml3328_power_down(struct veml3328_data *data) 111 { 112 return regmap_set_bits(data->regmap, VEML3328_REG_CONF, 113 VEML3328_SHUTDOWN); 114 } 115 116 static int veml3328_power_up(struct veml3328_data *data) 117 { 118 int ret; 119 120 ret = regmap_clear_bits(data->regmap, VEML3328_REG_CONF, 121 VEML3328_SHUTDOWN); 122 if (ret) 123 return ret; 124 125 /* 126 * Sleep for maximum integration time to ensure sensor is powered on 127 * correctly. 128 */ 129 fsleep(VEML3328_MAX_IT_TIME); 130 131 return 0; 132 } 133 134 static void veml3328_power_down_action(void *data) 135 { 136 veml3328_power_down(data); 137 } 138 139 static int veml3328_read_raw(struct iio_dev *indio_dev, 140 struct iio_chan_spec const *chan, 141 int *val, int *val2, long mask) 142 { 143 struct veml3328_data *data = iio_priv(indio_dev); 144 struct regmap *regmap = data->regmap; 145 struct device *dev = regmap_get_device(regmap); 146 unsigned int reg_val; 147 int it_inx, gain_inx; 148 int ret; 149 150 PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm); 151 ret = PM_RUNTIME_ACQUIRE_ERR(&pm); 152 if (ret) 153 return ret; 154 155 switch (mask) { 156 case IIO_CHAN_INFO_RAW: 157 ret = regmap_read(regmap, chan->address, ®_val); 158 if (ret) 159 return ret; 160 161 *val = reg_val; 162 return IIO_VAL_INT; 163 164 case IIO_CHAN_INFO_INT_TIME: 165 ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); 166 if (ret) 167 return ret; 168 169 it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); 170 if (it_inx >= ARRAY_SIZE(veml3328_it_times)) 171 return -EINVAL; 172 173 *val = veml3328_it_times[it_inx][0]; 174 *val2 = veml3328_it_times[it_inx][1]; 175 return IIO_VAL_INT_PLUS_MICRO; 176 177 case IIO_CHAN_INFO_SCALE: 178 ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); 179 if (ret) 180 return ret; 181 182 it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); 183 gain_inx = FIELD_GET(VEML3328_CONF_GAIN_MASK, reg_val); 184 185 if (it_inx >= ARRAY_SIZE(veml3328_it_times) || gain_inx >= 4) 186 return -EINVAL; 187 188 /* Stride by 2 through the flattened array to match (val, val2) */ 189 *val = veml3328_scale_vals[it_inx][gain_inx * 2]; 190 *val2 = veml3328_scale_vals[it_inx][gain_inx * 2 + 1]; 191 192 return IIO_VAL_INT_PLUS_MICRO; 193 194 default: 195 return -EINVAL; 196 } 197 } 198 199 static int veml3328_read_avail(struct iio_dev *indio_dev, 200 struct iio_chan_spec const *chan, 201 const int **vals, int *type, int *length, 202 long mask) 203 { 204 struct veml3328_data *data = iio_priv(indio_dev); 205 struct regmap *regmap = data->regmap; 206 struct device *dev = regmap_get_device(data->regmap); 207 unsigned int reg_val; 208 int ret, it_inx; 209 210 switch (mask) { 211 case IIO_CHAN_INFO_INT_TIME: 212 *length = ARRAY_SIZE(veml3328_it_times) * 2; 213 *vals = (const int *)veml3328_it_times; 214 *type = IIO_VAL_INT_PLUS_MICRO; 215 return IIO_AVAIL_LIST; 216 217 case IIO_CHAN_INFO_SCALE: { 218 PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm); 219 ret = PM_RUNTIME_ACQUIRE_ERR(&pm); 220 if (ret) 221 return ret; 222 223 ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); 224 if (ret) 225 return ret; 226 227 it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); 228 if (it_inx >= ARRAY_SIZE(veml3328_it_times)) 229 return -EINVAL; 230 231 *length = 8; 232 *vals = (const int *)veml3328_scale_vals[it_inx]; 233 *type = IIO_VAL_INT_PLUS_MICRO; 234 return IIO_AVAIL_LIST; 235 } 236 default: 237 return -EINVAL; 238 } 239 } 240 241 static int veml3328_write_raw(struct iio_dev *indio_dev, 242 struct iio_chan_spec const *chan, 243 int val, int val2, long mask) 244 { 245 struct veml3328_data *data = iio_priv(indio_dev); 246 struct regmap *regmap = data->regmap; 247 struct device *dev = regmap_get_device(regmap); 248 unsigned int reg_val; 249 int i, it_inx; 250 int ret; 251 252 PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(dev, pm); 253 ret = PM_RUNTIME_ACQUIRE_ERR(&pm); 254 if (ret) 255 return ret; 256 257 guard(mutex)(&data->lock); 258 259 switch (mask) { 260 case IIO_CHAN_INFO_INT_TIME: 261 if (val != 0) 262 return -EINVAL; 263 264 for (i = 0; i < ARRAY_SIZE(veml3328_it_times); i++) { 265 if (veml3328_it_times[i][1] == val2) 266 break; 267 } 268 269 if (i == ARRAY_SIZE(veml3328_it_times)) 270 return -EINVAL; 271 272 return regmap_update_bits(regmap, VEML3328_REG_CONF, 273 VEML3328_CONF_IT_MASK, 274 FIELD_PREP(VEML3328_CONF_IT_MASK, i)); 275 276 case IIO_CHAN_INFO_SCALE: 277 ret = regmap_read(regmap, VEML3328_REG_CONF, ®_val); 278 if (ret) 279 return ret; 280 281 it_inx = FIELD_GET(VEML3328_CONF_IT_MASK, reg_val); 282 if (it_inx >= ARRAY_SIZE(veml3328_it_times)) 283 return -EINVAL; 284 285 for (i = 0; i < 4; i++) { 286 if (val == veml3328_scale_vals[it_inx][i * 2] && 287 val2 == veml3328_scale_vals[it_inx][i * 2 + 1]) 288 break; 289 } 290 291 if (i == 4) 292 return -EINVAL; 293 294 return regmap_update_bits(regmap, VEML3328_REG_CONF, 295 VEML3328_CONF_GAIN_MASK, 296 FIELD_PREP(VEML3328_CONF_GAIN_MASK, i)); 297 298 default: 299 return -EINVAL; 300 } 301 } 302 303 static const struct iio_info veml3328_info = { 304 .read_raw = veml3328_read_raw, 305 .write_raw = veml3328_write_raw, 306 .read_avail = veml3328_read_avail, 307 }; 308 309 static int veml3328_probe(struct i2c_client *client) 310 { 311 struct device *dev = &client->dev; 312 struct veml3328_data *data; 313 struct iio_dev *indio_dev; 314 unsigned int reg_val; 315 int ret; 316 317 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 318 if (!indio_dev) 319 return -ENOMEM; 320 321 data = iio_priv(indio_dev); 322 i2c_set_clientdata(client, indio_dev); 323 324 data->regmap = devm_regmap_init_i2c(client, &veml3328_regmap_config); 325 if (IS_ERR(data->regmap)) 326 return dev_err_probe(dev, PTR_ERR(data->regmap), 327 "Failed to initialize regmap\n"); 328 329 ret = devm_mutex_init(dev, &data->lock); 330 if (ret) 331 return ret; 332 333 ret = devm_regulator_get_enable(dev, "vdd"); 334 if (ret) 335 return dev_err_probe(dev, ret, "Failed to enable regulator\n"); 336 337 ret = regmap_read(data->regmap, VEML3328_REG_ID, ®_val); 338 if (ret) 339 return dev_err_probe(dev, ret, "Failed to read ID register\n"); 340 341 if ((reg_val & 0xff) != VEML3328_ID_VAL) 342 dev_warn(dev, "Unknown device ID: 0x%02x\n", reg_val & 0xff); 343 344 ret = veml3328_power_up(data); 345 if (ret) 346 return dev_err_probe(dev, ret, "Failed to power on sensor\n"); 347 348 ret = devm_add_action_or_reset(dev, veml3328_power_down_action, data); 349 if (ret) 350 return dev_err_probe(dev, ret, "Failed to register teardown\n"); 351 352 indio_dev->name = "veml3328"; 353 indio_dev->modes = INDIO_DIRECT_MODE; 354 indio_dev->info = &veml3328_info; 355 indio_dev->channels = veml3328_channels; 356 indio_dev->num_channels = ARRAY_SIZE(veml3328_channels); 357 358 pm_runtime_set_active(dev); 359 pm_runtime_set_autosuspend_delay(dev, 2000); 360 pm_runtime_use_autosuspend(dev); 361 362 ret = devm_pm_runtime_enable(dev); 363 if (ret) 364 return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); 365 366 return devm_iio_device_register(dev, indio_dev); 367 } 368 369 static int veml3328_runtime_suspend(struct device *dev) 370 { 371 struct veml3328_data *data = iio_priv(dev_get_drvdata(dev)); 372 int ret; 373 374 ret = veml3328_power_down(data); 375 if (ret) 376 dev_err(dev, "Failed to suspend: %d\n", ret); 377 378 return ret; 379 } 380 381 static int veml3328_runtime_resume(struct device *dev) 382 { 383 struct veml3328_data *data = iio_priv(dev_get_drvdata(dev)); 384 int ret; 385 386 ret = veml3328_power_up(data); 387 if (ret) 388 dev_err(dev, "Failed to resume: %d\n", ret); 389 390 return ret; 391 } 392 393 static DEFINE_RUNTIME_DEV_PM_OPS(veml3328_pm_ops, 394 veml3328_runtime_suspend, 395 veml3328_runtime_resume, 396 NULL); 397 398 static const struct of_device_id veml3328_of_match[] = { 399 { .compatible = "vishay,veml3328" }, 400 { } 401 }; 402 MODULE_DEVICE_TABLE(of, veml3328_of_match); 403 404 static const struct i2c_device_id veml3328_id[] = { 405 { .name = "veml3328" }, 406 { } 407 }; 408 MODULE_DEVICE_TABLE(i2c, veml3328_id); 409 410 static struct i2c_driver veml3328_driver = { 411 .driver = { 412 .name = "veml3328", 413 .of_match_table = veml3328_of_match, 414 .pm = pm_ptr(&veml3328_pm_ops), 415 }, 416 .probe = veml3328_probe, 417 .id_table = veml3328_id, 418 }; 419 module_i2c_driver(veml3328_driver); 420 421 MODULE_AUTHOR("Joshua Crofts <joshua.crofts1@gmail.com>"); 422 MODULE_DESCRIPTION("VEML3328 RGBCIR Light Sensor"); 423 MODULE_LICENSE("GPL"); 424