1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * IIO driver for Lite-On LTR390 ALS and UV sensor 4 * (7-bit I2C slave address 0x53) 5 * 6 * Based on the work of: 7 * Shreeya Patel and Shi Zhigang (LTRF216 Driver) 8 * 9 * Copyright (C) 2023 Anshul Dalal <anshulusr@gmail.com> 10 * 11 * Datasheet: 12 * https://optoelectronics.liteon.com/upload/download/DS86-2015-0004/LTR-390UV_Final_%20DS_V1%201.pdf 13 * 14 * TODO: 15 * - Support for configurable gain and resolution 16 * - Sensor suspend/resume support 17 * - Add support for reading the ALS 18 * - Interrupt support 19 */ 20 21 #include <linux/i2c.h> 22 #include <linux/math.h> 23 #include <linux/module.h> 24 #include <linux/mutex.h> 25 #include <linux/regmap.h> 26 #include <linux/bitfield.h> 27 28 #include <linux/iio/iio.h> 29 30 #include <linux/unaligned.h> 31 32 #define LTR390_MAIN_CTRL 0x00 33 #define LTR390_ALS_UVS_MEAS_RATE 0x04 34 #define LTR390_ALS_UVS_GAIN 0x05 35 #define LTR390_PART_ID 0x06 36 #define LTR390_ALS_DATA 0x0D 37 #define LTR390_UVS_DATA 0x10 38 #define LTR390_INT_CFG 0x19 39 40 #define LTR390_PART_NUMBER_ID 0xb 41 #define LTR390_ALS_UVS_GAIN_MASK 0x07 42 #define LTR390_ALS_UVS_INT_TIME_MASK 0x70 43 #define LTR390_ALS_UVS_INT_TIME(x) FIELD_PREP(LTR390_ALS_UVS_INT_TIME_MASK, (x)) 44 45 #define LTR390_SW_RESET BIT(4) 46 #define LTR390_UVS_MODE BIT(3) 47 #define LTR390_SENSOR_ENABLE BIT(1) 48 49 #define LTR390_FRACTIONAL_PRECISION 100 50 51 /* 52 * At 20-bit resolution (integration time: 400ms) and 18x gain, 2300 counts of 53 * the sensor are equal to 1 UV Index [Datasheet Page#8]. 54 * 55 * For the default resolution of 18-bit (integration time: 100ms) and default 56 * gain of 3x, the counts/uvi are calculated as follows: 57 * 2300 / ((3/18) * (100/400)) = 95.83 58 */ 59 #define LTR390_COUNTS_PER_UVI 96 60 61 /* 62 * Window Factor is needed when the device is under Window glass with coated 63 * tinted ink. This is to compensate for the light loss due to the lower 64 * transmission rate of the window glass and helps * in calculating lux. 65 */ 66 #define LTR390_WINDOW_FACTOR 1 67 68 enum ltr390_mode { 69 LTR390_SET_ALS_MODE, 70 LTR390_SET_UVS_MODE, 71 }; 72 73 struct ltr390_data { 74 struct regmap *regmap; 75 struct i2c_client *client; 76 /* Protects device from simulataneous reads */ 77 struct mutex lock; 78 enum ltr390_mode mode; 79 int gain; 80 int int_time_us; 81 }; 82 83 static const struct regmap_config ltr390_regmap_config = { 84 .name = "ltr390", 85 .reg_bits = 8, 86 .reg_stride = 1, 87 .val_bits = 8, 88 }; 89 90 static int ltr390_register_read(struct ltr390_data *data, u8 register_address) 91 { 92 struct device *dev = &data->client->dev; 93 int ret; 94 u8 recieve_buffer[3]; 95 96 ret = regmap_bulk_read(data->regmap, register_address, recieve_buffer, 97 sizeof(recieve_buffer)); 98 if (ret) { 99 dev_err(dev, "failed to read measurement data"); 100 return ret; 101 } 102 103 return get_unaligned_le24(recieve_buffer); 104 } 105 106 static int ltr390_set_mode(struct ltr390_data *data, enum ltr390_mode mode) 107 { 108 int ret; 109 110 if (data->mode == mode) 111 return 0; 112 113 switch (mode) { 114 case LTR390_SET_ALS_MODE: 115 ret = regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_UVS_MODE); 116 break; 117 118 case LTR390_SET_UVS_MODE: 119 ret = regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_UVS_MODE); 120 break; 121 } 122 123 if (ret) 124 return ret; 125 126 data->mode = mode; 127 return 0; 128 } 129 130 static int ltr390_counts_per_uvi(struct ltr390_data *data) 131 { 132 const int orig_gain = 18; 133 const int orig_int_time = 400; 134 135 return DIV_ROUND_CLOSEST(23 * data->gain * data->int_time_us, 10 * orig_gain * orig_int_time); 136 } 137 138 static int ltr390_read_raw(struct iio_dev *iio_device, 139 struct iio_chan_spec const *chan, int *val, 140 int *val2, long mask) 141 { 142 int ret; 143 struct ltr390_data *data = iio_priv(iio_device); 144 145 guard(mutex)(&data->lock); 146 switch (mask) { 147 case IIO_CHAN_INFO_RAW: 148 switch (chan->type) { 149 case IIO_UVINDEX: 150 ret = ltr390_set_mode(data, LTR390_SET_UVS_MODE); 151 if (ret < 0) 152 return ret; 153 154 ret = ltr390_register_read(data, LTR390_UVS_DATA); 155 if (ret < 0) 156 return ret; 157 break; 158 159 case IIO_LIGHT: 160 ret = ltr390_set_mode(data, LTR390_SET_ALS_MODE); 161 if (ret < 0) 162 return ret; 163 164 ret = ltr390_register_read(data, LTR390_ALS_DATA); 165 if (ret < 0) 166 return ret; 167 break; 168 169 default: 170 return -EINVAL; 171 } 172 *val = ret; 173 return IIO_VAL_INT; 174 case IIO_CHAN_INFO_SCALE: 175 switch (chan->type) { 176 case IIO_UVINDEX: 177 *val = LTR390_WINDOW_FACTOR * LTR390_FRACTIONAL_PRECISION; 178 *val2 = ltr390_counts_per_uvi(data); 179 return IIO_VAL_FRACTIONAL; 180 181 case IIO_LIGHT: 182 *val = LTR390_WINDOW_FACTOR * 6 * 100; 183 *val2 = data->gain * data->int_time_us; 184 return IIO_VAL_FRACTIONAL; 185 186 default: 187 return -EINVAL; 188 } 189 190 case IIO_CHAN_INFO_INT_TIME: 191 *val = data->int_time_us; 192 return IIO_VAL_INT; 193 194 default: 195 return -EINVAL; 196 } 197 } 198 199 /* integration time in us */ 200 static const int ltr390_int_time_map_us[] = { 400000, 200000, 100000, 50000, 25000, 12500 }; 201 static const int ltr390_gain_map[] = { 1, 3, 6, 9, 18 }; 202 203 static const struct iio_chan_spec ltr390_channels[] = { 204 /* UV sensor */ 205 { 206 .type = IIO_UVINDEX, 207 .scan_index = 0, 208 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 209 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), 210 .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SCALE) 211 }, 212 /* ALS sensor */ 213 { 214 .type = IIO_LIGHT, 215 .scan_index = 1, 216 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 217 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), 218 .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SCALE) 219 }, 220 }; 221 222 static int ltr390_set_gain(struct ltr390_data *data, int val) 223 { 224 int ret, idx; 225 226 for (idx = 0; idx < ARRAY_SIZE(ltr390_gain_map); idx++) { 227 if (ltr390_gain_map[idx] != val) 228 continue; 229 230 guard(mutex)(&data->lock); 231 ret = regmap_update_bits(data->regmap, 232 LTR390_ALS_UVS_GAIN, 233 LTR390_ALS_UVS_GAIN_MASK, idx); 234 if (ret) 235 return ret; 236 237 data->gain = ltr390_gain_map[idx]; 238 return 0; 239 } 240 241 return -EINVAL; 242 } 243 244 static int ltr390_set_int_time(struct ltr390_data *data, int val) 245 { 246 int ret, idx; 247 248 for (idx = 0; idx < ARRAY_SIZE(ltr390_int_time_map_us); idx++) { 249 if (ltr390_int_time_map_us[idx] != val) 250 continue; 251 252 guard(mutex)(&data->lock); 253 ret = regmap_update_bits(data->regmap, 254 LTR390_ALS_UVS_MEAS_RATE, 255 LTR390_ALS_UVS_INT_TIME_MASK, 256 LTR390_ALS_UVS_INT_TIME(idx)); 257 if (ret) 258 return ret; 259 260 data->int_time_us = ltr390_int_time_map_us[idx]; 261 return 0; 262 } 263 264 return -EINVAL; 265 } 266 267 static int ltr390_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, 268 const int **vals, int *type, int *length, long mask) 269 { 270 switch (mask) { 271 case IIO_CHAN_INFO_SCALE: 272 *length = ARRAY_SIZE(ltr390_gain_map); 273 *type = IIO_VAL_INT; 274 *vals = ltr390_gain_map; 275 return IIO_AVAIL_LIST; 276 case IIO_CHAN_INFO_INT_TIME: 277 *length = ARRAY_SIZE(ltr390_int_time_map_us); 278 *type = IIO_VAL_INT; 279 *vals = ltr390_int_time_map_us; 280 return IIO_AVAIL_LIST; 281 default: 282 return -EINVAL; 283 } 284 } 285 286 static int ltr390_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, 287 int val, int val2, long mask) 288 { 289 struct ltr390_data *data = iio_priv(indio_dev); 290 291 switch (mask) { 292 case IIO_CHAN_INFO_SCALE: 293 if (val2 != 0) 294 return -EINVAL; 295 296 return ltr390_set_gain(data, val); 297 298 case IIO_CHAN_INFO_INT_TIME: 299 if (val2 != 0) 300 return -EINVAL; 301 302 return ltr390_set_int_time(data, val); 303 304 default: 305 return -EINVAL; 306 } 307 } 308 309 static const struct iio_info ltr390_info = { 310 .read_raw = ltr390_read_raw, 311 .write_raw = ltr390_write_raw, 312 .read_avail = ltr390_read_avail, 313 }; 314 315 static int ltr390_probe(struct i2c_client *client) 316 { 317 struct ltr390_data *data; 318 struct iio_dev *indio_dev; 319 struct device *dev; 320 int ret, part_number; 321 322 dev = &client->dev; 323 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 324 if (!indio_dev) 325 return -ENOMEM; 326 327 data = iio_priv(indio_dev); 328 329 data->regmap = devm_regmap_init_i2c(client, <r390_regmap_config); 330 if (IS_ERR(data->regmap)) 331 return dev_err_probe(dev, PTR_ERR(data->regmap), 332 "regmap initialization failed\n"); 333 334 data->client = client; 335 /* default value of integration time from pg: 15 of the datasheet */ 336 data->int_time_us = 100000; 337 /* default value of gain from pg: 16 of the datasheet */ 338 data->gain = 3; 339 /* default mode for ltr390 is ALS mode */ 340 data->mode = LTR390_SET_ALS_MODE; 341 342 mutex_init(&data->lock); 343 344 indio_dev->info = <r390_info; 345 indio_dev->channels = ltr390_channels; 346 indio_dev->num_channels = ARRAY_SIZE(ltr390_channels); 347 indio_dev->name = "ltr390"; 348 349 ret = regmap_read(data->regmap, LTR390_PART_ID, &part_number); 350 if (ret) 351 return dev_err_probe(dev, ret, 352 "failed to get sensor's part id\n"); 353 /* Lower 4 bits of `part_number` change with hardware revisions */ 354 if (part_number >> 4 != LTR390_PART_NUMBER_ID) 355 dev_info(dev, "received invalid product id: 0x%x", part_number); 356 dev_dbg(dev, "LTR390, product id: 0x%x\n", part_number); 357 358 /* reset sensor, chip fails to respond to this, so ignore any errors */ 359 regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SW_RESET); 360 361 /* Wait for the registers to reset before proceeding */ 362 usleep_range(1000, 2000); 363 364 ret = regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SENSOR_ENABLE); 365 if (ret) 366 return dev_err_probe(dev, ret, "failed to enable the sensor\n"); 367 368 return devm_iio_device_register(dev, indio_dev); 369 } 370 371 static const struct i2c_device_id ltr390_id[] = { 372 { "ltr390" }, 373 { /* Sentinel */ } 374 }; 375 MODULE_DEVICE_TABLE(i2c, ltr390_id); 376 377 static const struct of_device_id ltr390_of_table[] = { 378 { .compatible = "liteon,ltr390" }, 379 { /* Sentinel */ } 380 }; 381 MODULE_DEVICE_TABLE(of, ltr390_of_table); 382 383 static struct i2c_driver ltr390_driver = { 384 .driver = { 385 .name = "ltr390", 386 .of_match_table = ltr390_of_table, 387 }, 388 .probe = ltr390_probe, 389 .id_table = ltr390_id, 390 }; 391 module_i2c_driver(ltr390_driver); 392 393 MODULE_AUTHOR("Anshul Dalal <anshulusr@gmail.com>"); 394 MODULE_DESCRIPTION("Lite-On LTR390 ALS and UV sensor Driver"); 395 MODULE_LICENSE("GPL"); 396