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 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, ®); 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, ®); 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 <arthur.becker@sentec.com>"); 281 MODULE_LICENSE("GPL"); 282