Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: light: introduce si1133

e-mail received from Silicon Lab to confirm that the licensing
isn't a problem.

"
Dear Maxime Roussin-Belanger,

The LUX calculation code only works with Si1133.
As long as the software is used with Silicon Lab's sensor product,
I don't see any problem.

Regards,
Tony
"

Signed-off-by: Maxime Roussin-Bélanger <maxime.roussinbelanger@gmail.com>
Reviewed-by: Jean-Francois Dagenais <jeff.dagenais@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Maxime Roussin-Bélanger and committed by
Jonathan Cameron
e01e7eaf c0e4e0fd

+1103
+22
Documentation/ABI/testing/sysfs-bus-iio-light-si1133
··· 1 + What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ir_small_raw 2 + KernelVersion: 4.18 3 + Contact: linux-iio@vger.kernel.org 4 + Description: 5 + Unit-less infrared intensity. The intensity is measured from 1 6 + dark photodiode. "small" indicate the surface area capturing 7 + infrared. 8 + 9 + What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ir_large_raw 10 + KernelVersion: 4.18 11 + Contact: linux-iio@vger.kernel.org 12 + Description: 13 + Unit-less infrared intensity. The intensity is measured from 4 14 + dark photodiodes. "large" indicate the surface area capturing 15 + infrared. 16 + 17 + What: /sys/bus/iio/devices/iio:deviceX/in_intensity_large_raw 18 + KernelVersion: 4.18 19 + Contact: linux-iio@vger.kernel.org 20 + Description: 21 + Unit-less light intensity with more diodes. 22 +
+12
drivers/iio/light/Kconfig
··· 1 + 1 2 # 2 3 # Light sensors 3 4 # ··· 319 318 320 319 This driver can also be built as a module. If so, the module 321 320 will be called pa12203001. 321 + 322 + config SI1133 323 + tristate "SI1133 UV Index Sensor and Ambient Light Sensor" 324 + depends on I2C 325 + select REGMAP_I2C 326 + help 327 + Say Y here if you want to build a driver for the Silicon Labs SI1133 328 + UV Index Sensor and Ambient Light Sensor chip. 329 + 330 + To compile this driver as a module, choose M here: the module will be 331 + called si1133. 322 332 323 333 config SI1145 324 334 tristate "SI1132 and SI1141/2/3/5/6/7 combined ALS, UV index and proximity sensor"
+1
drivers/iio/light/Makefile
··· 32 32 obj-$(CONFIG_PA12203001) += pa12203001.o 33 33 obj-$(CONFIG_RPR0521) += rpr0521.o 34 34 obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o 35 + obj-$(CONFIG_SI1133) += si1133.o 35 36 obj-$(CONFIG_SI1145) += si1145.o 36 37 obj-$(CONFIG_STK3310) += stk3310.o 37 38 obj-$(CONFIG_ST_UVIS25) += st_uvis25_core.o
+1068
drivers/iio/light/si1133.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * si1133.c - Support for Silabs SI1133 combined ambient 4 + * light and UV index sensors 5 + * 6 + * Copyright 2018 Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com> 7 + */ 8 + 9 + #include <linux/delay.h> 10 + #include <linux/i2c.h> 11 + #include <linux/interrupt.h> 12 + #include <linux/module.h> 13 + #include <linux/regmap.h> 14 + 15 + #include <linux/iio/iio.h> 16 + #include <linux/iio/sysfs.h> 17 + 18 + #include <linux/util_macros.h> 19 + 20 + #define SI1133_REG_PART_ID 0x00 21 + #define SI1133_REG_REV_ID 0x01 22 + #define SI1133_REG_MFR_ID 0x02 23 + #define SI1133_REG_INFO0 0x03 24 + #define SI1133_REG_INFO1 0x04 25 + 26 + #define SI1133_PART_ID 0x33 27 + 28 + #define SI1133_REG_HOSTIN0 0x0A 29 + #define SI1133_REG_COMMAND 0x0B 30 + #define SI1133_REG_IRQ_ENABLE 0x0F 31 + #define SI1133_REG_RESPONSE1 0x10 32 + #define SI1133_REG_RESPONSE0 0x11 33 + #define SI1133_REG_IRQ_STATUS 0x12 34 + #define SI1133_REG_MEAS_RATE 0x1A 35 + 36 + #define SI1133_IRQ_CHANNEL_ENABLE 0xF 37 + 38 + #define SI1133_CMD_RESET_CTR 0x00 39 + #define SI1133_CMD_RESET_SW 0x01 40 + #define SI1133_CMD_FORCE 0x11 41 + #define SI1133_CMD_START_AUTONOMOUS 0x13 42 + #define SI1133_CMD_PARAM_SET 0x80 43 + #define SI1133_CMD_PARAM_QUERY 0x40 44 + #define SI1133_CMD_PARAM_MASK 0x3F 45 + 46 + #define SI1133_CMD_ERR_MASK BIT(4) 47 + #define SI1133_CMD_SEQ_MASK 0xF 48 + #define SI1133_MAX_CMD_CTR 0xF 49 + 50 + #define SI1133_PARAM_REG_CHAN_LIST 0x01 51 + #define SI1133_PARAM_REG_ADCCONFIG(x) ((x) * 4) + 2 52 + #define SI1133_PARAM_REG_ADCSENS(x) ((x) * 4) + 3 53 + #define SI1133_PARAM_REG_ADCPOST(x) ((x) * 4) + 4 54 + 55 + #define SI1133_ADCMUX_MASK 0x1F 56 + 57 + #define SI1133_ADCCONFIG_DECIM_RATE(x) (x) << 5 58 + 59 + #define SI1133_ADCSENS_SCALE_MASK 0x70 60 + #define SI1133_ADCSENS_SCALE_SHIFT 4 61 + #define SI1133_ADCSENS_HSIG_MASK BIT(7) 62 + #define SI1133_ADCSENS_HSIG_SHIFT 7 63 + #define SI1133_ADCSENS_HW_GAIN_MASK 0xF 64 + #define SI1133_ADCSENS_NB_MEAS(x) fls(x) << SI1133_ADCSENS_SCALE_SHIFT 65 + 66 + #define SI1133_ADCPOST_24BIT_EN BIT(6) 67 + #define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (x & GENMASK(2, 0)) << 3 68 + 69 + #define SI1133_PARAM_ADCMUX_SMALL_IR 0x0 70 + #define SI1133_PARAM_ADCMUX_MED_IR 0x1 71 + #define SI1133_PARAM_ADCMUX_LARGE_IR 0x2 72 + #define SI1133_PARAM_ADCMUX_WHITE 0xB 73 + #define SI1133_PARAM_ADCMUX_LARGE_WHITE 0xD 74 + #define SI1133_PARAM_ADCMUX_UV 0x18 75 + #define SI1133_PARAM_ADCMUX_UV_DEEP 0x19 76 + 77 + #define SI1133_ERR_INVALID_CMD 0x0 78 + #define SI1133_ERR_INVALID_LOCATION_CMD 0x1 79 + #define SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION 0x2 80 + #define SI1133_ERR_OUTPUT_BUFFER_OVERFLOW 0x3 81 + 82 + #define SI1133_COMPLETION_TIMEOUT_MS 500 83 + 84 + #define SI1133_CMD_MINSLEEP_US_LOW 5000 85 + #define SI1133_CMD_MINSLEEP_US_HIGH 7500 86 + #define SI1133_CMD_TIMEOUT_MS 25 87 + #define SI1133_CMD_LUX_TIMEOUT_MS 5000 88 + #define SI1133_CMD_TIMEOUT_US SI1133_CMD_TIMEOUT_MS * 1000 89 + 90 + #define SI1133_REG_HOSTOUT(x) (x) + 0x13 91 + 92 + #define SI1133_MEASUREMENT_FREQUENCY 1250 93 + 94 + #define SI1133_X_ORDER_MASK 0x0070 95 + #define SI1133_Y_ORDER_MASK 0x0007 96 + #define si1133_get_x_order(m) ((m) & SI1133_X_ORDER_MASK) >> 4 97 + #define si1133_get_y_order(m) ((m) & SI1133_Y_ORDER_MASK) 98 + 99 + #define SI1133_LUX_ADC_MASK 0xE 100 + #define SI1133_ADC_THRESHOLD 16000 101 + #define SI1133_INPUT_FRACTION_HIGH 7 102 + #define SI1133_INPUT_FRACTION_LOW 15 103 + #define SI1133_LUX_OUTPUT_FRACTION 12 104 + #define SI1133_LUX_BUFFER_SIZE 9 105 + 106 + static const int si1133_scale_available[] = { 107 + 1, 2, 4, 8, 16, 32, 64, 128}; 108 + 109 + static IIO_CONST_ATTR(scale_available, "1 2 4 8 16 32 64 128"); 110 + 111 + static IIO_CONST_ATTR_INT_TIME_AVAIL("0.0244 0.0488 0.0975 0.195 0.390 0.780 " 112 + "1.560 3.120 6.24 12.48 25.0 50.0"); 113 + 114 + /* A.K.A. HW_GAIN in datasheet */ 115 + enum si1133_int_time { 116 + _24_4_us = 0, 117 + _48_8_us = 1, 118 + _97_5_us = 2, 119 + _195_0_us = 3, 120 + _390_0_us = 4, 121 + _780_0_us = 5, 122 + _1_560_0_us = 6, 123 + _3_120_0_us = 7, 124 + _6_240_0_us = 8, 125 + _12_480_0_us = 9, 126 + _25_ms = 10, 127 + _50_ms = 11, 128 + }; 129 + 130 + /* Integration time in milliseconds, nanoseconds */ 131 + static const int si1133_int_time_table[][2] = { 132 + [_24_4_us] = {0, 24400}, 133 + [_48_8_us] = {0, 48800}, 134 + [_97_5_us] = {0, 97500}, 135 + [_195_0_us] = {0, 195000}, 136 + [_390_0_us] = {0, 390000}, 137 + [_780_0_us] = {0, 780000}, 138 + [_1_560_0_us] = {1, 560000}, 139 + [_3_120_0_us] = {3, 120000}, 140 + [_6_240_0_us] = {6, 240000}, 141 + [_12_480_0_us] = {12, 480000}, 142 + [_25_ms] = {25, 000000}, 143 + [_50_ms] = {50, 000000}, 144 + }; 145 + 146 + static const struct regmap_range si1133_reg_ranges[] = { 147 + regmap_reg_range(0x00, 0x02), 148 + regmap_reg_range(0x0A, 0x0B), 149 + regmap_reg_range(0x0F, 0x0F), 150 + regmap_reg_range(0x10, 0x12), 151 + regmap_reg_range(0x13, 0x2C), 152 + }; 153 + 154 + static const struct regmap_range si1133_reg_ro_ranges[] = { 155 + regmap_reg_range(0x00, 0x02), 156 + regmap_reg_range(0x10, 0x2C), 157 + }; 158 + 159 + static const struct regmap_range si1133_precious_ranges[] = { 160 + regmap_reg_range(0x12, 0x12), 161 + }; 162 + 163 + static const struct regmap_access_table si1133_write_ranges_table = { 164 + .yes_ranges = si1133_reg_ranges, 165 + .n_yes_ranges = ARRAY_SIZE(si1133_reg_ranges), 166 + .no_ranges = si1133_reg_ro_ranges, 167 + .n_no_ranges = ARRAY_SIZE(si1133_reg_ro_ranges), 168 + }; 169 + 170 + static const struct regmap_access_table si1133_read_ranges_table = { 171 + .yes_ranges = si1133_reg_ranges, 172 + .n_yes_ranges = ARRAY_SIZE(si1133_reg_ranges), 173 + }; 174 + 175 + static const struct regmap_access_table si1133_precious_table = { 176 + .yes_ranges = si1133_precious_ranges, 177 + .n_yes_ranges = ARRAY_SIZE(si1133_precious_ranges), 178 + }; 179 + 180 + static const struct regmap_config si1133_regmap_config = { 181 + .reg_bits = 8, 182 + .val_bits = 8, 183 + 184 + .max_register = 0x2C, 185 + 186 + .wr_table = &si1133_write_ranges_table, 187 + .rd_table = &si1133_read_ranges_table, 188 + 189 + .precious_table = &si1133_precious_table, 190 + }; 191 + 192 + struct si1133_data { 193 + struct regmap *regmap; 194 + struct i2c_client *client; 195 + 196 + /* Lock protecting one command at a time can be processed */ 197 + struct mutex mutex; 198 + 199 + int rsp_seq; 200 + u8 scan_mask; 201 + u8 adc_sens[6]; 202 + u8 adc_config[6]; 203 + 204 + struct completion completion; 205 + }; 206 + 207 + struct si1133_coeff { 208 + s16 info; 209 + u16 mag; 210 + }; 211 + 212 + struct si1133_lux_coeff { 213 + struct si1133_coeff coeff_high[4]; 214 + struct si1133_coeff coeff_low[9]; 215 + }; 216 + 217 + static const struct si1133_lux_coeff lux_coeff = { 218 + { 219 + { 0, 209}, 220 + { 1665, 93}, 221 + { 2064, 65}, 222 + {-2671, 234} 223 + }, 224 + { 225 + { 0, 0}, 226 + { 1921, 29053}, 227 + {-1022, 36363}, 228 + { 2320, 20789}, 229 + { -367, 57909}, 230 + {-1774, 38240}, 231 + { -608, 46775}, 232 + {-1503, 51831}, 233 + {-1886, 58928} 234 + } 235 + }; 236 + 237 + static int si1133_calculate_polynomial_inner(u32 input, u8 fraction, u16 mag, 238 + s8 shift) 239 + { 240 + return ((input << fraction) / mag) << shift; 241 + } 242 + 243 + static int si1133_calculate_output(u32 x, u32 y, u8 x_order, u8 y_order, 244 + u8 input_fraction, s8 sign, 245 + const struct si1133_coeff *coeffs) 246 + { 247 + s8 shift; 248 + int x1 = 1; 249 + int x2 = 1; 250 + int y1 = 1; 251 + int y2 = 1; 252 + 253 + shift = ((u16)coeffs->info & 0xFF00) >> 8; 254 + shift ^= 0xFF; 255 + shift += 1; 256 + shift = -shift; 257 + 258 + if (x_order > 0) { 259 + x1 = si1133_calculate_polynomial_inner(x, input_fraction, 260 + coeffs->mag, shift); 261 + if (x_order > 1) 262 + x2 = x1; 263 + } 264 + 265 + if (y_order > 0) { 266 + y1 = si1133_calculate_polynomial_inner(y, input_fraction, 267 + coeffs->mag, shift); 268 + if (y_order > 1) 269 + y2 = y1; 270 + } 271 + 272 + return sign * x1 * x2 * y1 * y2; 273 + } 274 + 275 + /* 276 + * The algorithm is from: 277 + * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00716 278 + */ 279 + static int si1133_calc_polynomial(u32 x, u32 y, u8 input_fraction, u8 num_coeff, 280 + const struct si1133_coeff *coeffs) 281 + { 282 + u8 x_order, y_order; 283 + u8 counter; 284 + s8 sign; 285 + int output = 0; 286 + 287 + for (counter = 0; counter < num_coeff; counter++) { 288 + if (coeffs->info < 0) 289 + sign = -1; 290 + else 291 + sign = 1; 292 + 293 + x_order = si1133_get_x_order(coeffs->info); 294 + y_order = si1133_get_y_order(coeffs->info); 295 + 296 + if ((x_order == 0) && (y_order == 0)) 297 + output += 298 + sign * coeffs->mag << SI1133_LUX_OUTPUT_FRACTION; 299 + else 300 + output += si1133_calculate_output(x, y, x_order, 301 + y_order, 302 + input_fraction, sign, 303 + coeffs); 304 + coeffs++; 305 + } 306 + 307 + return abs(output); 308 + } 309 + 310 + static int si1133_cmd_reset_sw(struct si1133_data *data) 311 + { 312 + struct device *dev = &data->client->dev; 313 + unsigned int resp; 314 + unsigned long timeout; 315 + int err; 316 + 317 + err = regmap_write(data->regmap, SI1133_REG_COMMAND, 318 + SI1133_CMD_RESET_SW); 319 + if (err) 320 + return err; 321 + 322 + timeout = jiffies + msecs_to_jiffies(SI1133_CMD_TIMEOUT_MS); 323 + while (true) { 324 + err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp); 325 + if (err == -ENXIO) { 326 + usleep_range(SI1133_CMD_MINSLEEP_US_LOW, 327 + SI1133_CMD_MINSLEEP_US_HIGH); 328 + continue; 329 + } 330 + 331 + if ((resp & SI1133_MAX_CMD_CTR) == SI1133_MAX_CMD_CTR) 332 + break; 333 + 334 + if (time_after(jiffies, timeout)) { 335 + dev_warn(dev, "Timeout on reset ctr resp: %d\n", resp); 336 + return -ETIMEDOUT; 337 + } 338 + } 339 + 340 + if (!err) 341 + data->rsp_seq = SI1133_MAX_CMD_CTR; 342 + 343 + return err; 344 + } 345 + 346 + static int si1133_parse_response_err(struct device *dev, u32 resp, u8 cmd) 347 + { 348 + resp &= 0xF; 349 + 350 + switch (resp) { 351 + case SI1133_ERR_OUTPUT_BUFFER_OVERFLOW: 352 + dev_warn(dev, "Output buffer overflow: %#02hhx\n", cmd); 353 + return -EOVERFLOW; 354 + case SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION: 355 + dev_warn(dev, "Saturation of the ADC or overflow of accumulation: %#02hhx\n", 356 + cmd); 357 + return -EOVERFLOW; 358 + case SI1133_ERR_INVALID_LOCATION_CMD: 359 + dev_warn(dev, 360 + "Parameter access to an invalid location: %#02hhx\n", 361 + cmd); 362 + return -EINVAL; 363 + case SI1133_ERR_INVALID_CMD: 364 + dev_warn(dev, "Invalid command %#02hhx\n", cmd); 365 + return -EINVAL; 366 + default: 367 + dev_warn(dev, "Unknown error %#02hhx\n", cmd); 368 + return -EINVAL; 369 + } 370 + } 371 + 372 + static int si1133_cmd_reset_counter(struct si1133_data *data) 373 + { 374 + int err = regmap_write(data->regmap, SI1133_REG_COMMAND, 375 + SI1133_CMD_RESET_CTR); 376 + if (err) 377 + return err; 378 + 379 + data->rsp_seq = 0; 380 + 381 + return 0; 382 + } 383 + 384 + static int si1133_command(struct si1133_data *data, u8 cmd) 385 + { 386 + struct device *dev = &data->client->dev; 387 + u32 resp; 388 + int err; 389 + int expected_seq; 390 + 391 + mutex_lock(&data->mutex); 392 + 393 + expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR; 394 + 395 + if (cmd == SI1133_CMD_FORCE) 396 + reinit_completion(&data->completion); 397 + 398 + err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd); 399 + if (err) { 400 + dev_warn(dev, "Failed to write command %#02hhx, ret=%d\n", cmd, 401 + err); 402 + goto out; 403 + } 404 + 405 + if (cmd == SI1133_CMD_FORCE) { 406 + /* wait for irq */ 407 + if (!wait_for_completion_timeout(&data->completion, 408 + msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) { 409 + err = -ETIMEDOUT; 410 + goto out; 411 + } 412 + } else { 413 + err = regmap_read_poll_timeout(data->regmap, 414 + SI1133_REG_RESPONSE0, resp, 415 + (resp & SI1133_CMD_SEQ_MASK) == 416 + expected_seq || 417 + (resp & SI1133_CMD_ERR_MASK), 418 + SI1133_CMD_MINSLEEP_US_LOW, 419 + SI1133_CMD_TIMEOUT_MS * 1000); 420 + if (err) { 421 + dev_warn(dev, 422 + "Failed to read command %#02hhx, ret=%d\n", 423 + cmd, err); 424 + goto out; 425 + } 426 + } 427 + 428 + if (resp & SI1133_CMD_ERR_MASK) { 429 + err = si1133_parse_response_err(dev, resp, cmd); 430 + si1133_cmd_reset_counter(data); 431 + } else { 432 + data->rsp_seq = expected_seq; 433 + } 434 + 435 + out: 436 + mutex_unlock(&data->mutex); 437 + 438 + return err; 439 + } 440 + 441 + static int si1133_param_set(struct si1133_data *data, u8 param, u32 value) 442 + { 443 + int err = regmap_write(data->regmap, SI1133_REG_HOSTIN0, value); 444 + 445 + if (err) 446 + return err; 447 + 448 + return si1133_command(data, SI1133_CMD_PARAM_SET | 449 + (param & SI1133_CMD_PARAM_MASK)); 450 + } 451 + 452 + static int si1133_param_query(struct si1133_data *data, u8 param, u32 *result) 453 + { 454 + int err = si1133_command(data, SI1133_CMD_PARAM_QUERY | 455 + (param & SI1133_CMD_PARAM_MASK)); 456 + if (err) 457 + return err; 458 + 459 + return regmap_read(data->regmap, SI1133_REG_RESPONSE1, result); 460 + } 461 + 462 + #define SI1133_CHANNEL(_ch, _type) \ 463 + .type = _type, \ 464 + .channel = _ch, \ 465 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 466 + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | \ 467 + BIT(IIO_CHAN_INFO_SCALE) | \ 468 + BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ 469 + 470 + static const struct iio_chan_spec si1133_channels[] = { 471 + { 472 + .type = IIO_LIGHT, 473 + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 474 + .channel = 0, 475 + }, 476 + { 477 + SI1133_CHANNEL(SI1133_PARAM_ADCMUX_WHITE, IIO_INTENSITY) 478 + .channel2 = IIO_MOD_LIGHT_BOTH, 479 + }, 480 + { 481 + SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_WHITE, IIO_INTENSITY) 482 + .channel2 = IIO_MOD_LIGHT_BOTH, 483 + .extend_name = "large", 484 + }, 485 + { 486 + SI1133_CHANNEL(SI1133_PARAM_ADCMUX_SMALL_IR, IIO_INTENSITY) 487 + .extend_name = "small", 488 + .modified = 1, 489 + .channel2 = IIO_MOD_LIGHT_IR, 490 + }, 491 + { 492 + SI1133_CHANNEL(SI1133_PARAM_ADCMUX_MED_IR, IIO_INTENSITY) 493 + .modified = 1, 494 + .channel2 = IIO_MOD_LIGHT_IR, 495 + }, 496 + { 497 + SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_IR, IIO_INTENSITY) 498 + .extend_name = "large", 499 + .modified = 1, 500 + .channel2 = IIO_MOD_LIGHT_IR, 501 + }, 502 + { 503 + SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV, IIO_UVINDEX) 504 + }, 505 + { 506 + SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV_DEEP, IIO_UVINDEX) 507 + .modified = 1, 508 + .channel2 = IIO_MOD_LIGHT_DUV, 509 + } 510 + }; 511 + 512 + static int si1133_get_int_time_index(int milliseconds, int nanoseconds) 513 + { 514 + int i; 515 + 516 + for (i = 0; i < ARRAY_SIZE(si1133_int_time_table); i++) { 517 + if (milliseconds == si1133_int_time_table[i][0] && 518 + nanoseconds == si1133_int_time_table[i][1]) 519 + return i; 520 + } 521 + return -EINVAL; 522 + } 523 + 524 + static int si1133_set_integration_time(struct si1133_data *data, u8 adc, 525 + int milliseconds, int nanoseconds) 526 + { 527 + int index; 528 + 529 + index = si1133_get_int_time_index(milliseconds, nanoseconds); 530 + if (index < 0) 531 + return index; 532 + 533 + data->adc_sens[adc] &= 0xF0; 534 + data->adc_sens[adc] |= index; 535 + 536 + return si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(0), 537 + data->adc_sens[adc]); 538 + } 539 + 540 + static int si1133_set_chlist(struct si1133_data *data, u8 scan_mask) 541 + { 542 + /* channel list already set, no need to reprogram */ 543 + if (data->scan_mask == scan_mask) 544 + return 0; 545 + 546 + data->scan_mask = scan_mask; 547 + 548 + return si1133_param_set(data, SI1133_PARAM_REG_CHAN_LIST, scan_mask); 549 + } 550 + 551 + static int si1133_chan_set_adcconfig(struct si1133_data *data, u8 adc, 552 + u8 adc_config) 553 + { 554 + int err; 555 + 556 + err = si1133_param_set(data, SI1133_PARAM_REG_ADCCONFIG(adc), 557 + adc_config); 558 + if (err) 559 + return err; 560 + 561 + data->adc_config[adc] = adc_config; 562 + 563 + return 0; 564 + } 565 + 566 + static int si1133_update_adcconfig(struct si1133_data *data, uint8_t adc, 567 + u8 mask, u8 shift, u8 value) 568 + { 569 + u32 adc_config; 570 + int err; 571 + 572 + err = si1133_param_query(data, SI1133_PARAM_REG_ADCCONFIG(adc), 573 + &adc_config); 574 + if (err) 575 + return err; 576 + 577 + adc_config &= ~mask; 578 + adc_config |= (value << shift); 579 + 580 + return si1133_chan_set_adcconfig(data, adc, adc_config); 581 + } 582 + 583 + static int si1133_set_adcmux(struct si1133_data *data, u8 adc, u8 mux) 584 + { 585 + if ((mux & data->adc_config[adc]) == mux) 586 + return 0; /* mux already set to correct value */ 587 + 588 + return si1133_update_adcconfig(data, adc, SI1133_ADCMUX_MASK, 0, mux); 589 + } 590 + 591 + static int si1133_force_measurement(struct si1133_data *data) 592 + { 593 + return si1133_command(data, SI1133_CMD_FORCE); 594 + } 595 + 596 + static int si1133_bulk_read(struct si1133_data *data, u8 start_reg, u8 length, 597 + u8 *buffer) 598 + { 599 + int err; 600 + 601 + err = si1133_force_measurement(data); 602 + if (err) 603 + return err; 604 + 605 + return regmap_bulk_read(data->regmap, start_reg, buffer, length); 606 + } 607 + 608 + static int si1133_measure(struct si1133_data *data, 609 + struct iio_chan_spec const *chan, 610 + int *val) 611 + { 612 + int err; 613 + 614 + __be16 resp; 615 + 616 + err = si1133_set_adcmux(data, 0, chan->channel); 617 + if (err) 618 + return err; 619 + 620 + /* Deactivate lux measurements if they were active */ 621 + err = si1133_set_chlist(data, BIT(0)); 622 + if (err) 623 + return err; 624 + 625 + err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), sizeof(resp), 626 + (u8 *)&resp); 627 + if (err) 628 + return err; 629 + 630 + *val = be16_to_cpu(resp); 631 + 632 + return err; 633 + } 634 + 635 + static irqreturn_t si1133_threaded_irq_handler(int irq, void *private) 636 + { 637 + struct iio_dev *iio_dev = private; 638 + struct si1133_data *data = iio_priv(iio_dev); 639 + u32 irq_status; 640 + int err; 641 + 642 + err = regmap_read(data->regmap, SI1133_REG_IRQ_STATUS, &irq_status); 643 + if (err) { 644 + dev_err_ratelimited(&iio_dev->dev, "Error reading IRQ\n"); 645 + goto out; 646 + } 647 + 648 + if (irq_status != data->scan_mask) 649 + return IRQ_NONE; 650 + 651 + out: 652 + complete(&data->completion); 653 + 654 + return IRQ_HANDLED; 655 + } 656 + 657 + static int si1133_scale_to_swgain(int scale_integer, int scale_fractional) 658 + { 659 + scale_integer = find_closest(scale_integer, si1133_scale_available, 660 + ARRAY_SIZE(si1133_scale_available)); 661 + if (scale_integer < 0 || 662 + scale_integer > ARRAY_SIZE(si1133_scale_available) || 663 + scale_fractional != 0) 664 + return -EINVAL; 665 + 666 + return scale_integer; 667 + } 668 + 669 + static int si1133_chan_set_adcsens(struct si1133_data *data, u8 adc, 670 + u8 adc_sens) 671 + { 672 + int err; 673 + 674 + err = si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(adc), adc_sens); 675 + if (err) 676 + return err; 677 + 678 + data->adc_sens[adc] = adc_sens; 679 + 680 + return 0; 681 + } 682 + 683 + static int si1133_update_adcsens(struct si1133_data *data, u8 mask, 684 + u8 shift, u8 value) 685 + { 686 + int err; 687 + u32 adc_sens; 688 + 689 + err = si1133_param_query(data, SI1133_PARAM_REG_ADCSENS(0), 690 + &adc_sens); 691 + if (err) 692 + return err; 693 + 694 + adc_sens &= ~mask; 695 + adc_sens |= (value << shift); 696 + 697 + return si1133_chan_set_adcsens(data, 0, adc_sens); 698 + } 699 + 700 + static int si1133_get_lux(struct si1133_data *data, int *val) 701 + { 702 + int err; 703 + int lux; 704 + u32 high_vis; 705 + u32 low_vis; 706 + u32 ir; 707 + u8 buffer[SI1133_LUX_BUFFER_SIZE]; 708 + 709 + /* Activate lux channels */ 710 + err = si1133_set_chlist(data, SI1133_LUX_ADC_MASK); 711 + if (err) 712 + return err; 713 + 714 + err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), 715 + SI1133_LUX_BUFFER_SIZE, buffer); 716 + if (err) 717 + return err; 718 + 719 + high_vis = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2]; 720 + low_vis = (buffer[3] << 16) | (buffer[4] << 8) | buffer[5]; 721 + ir = (buffer[6] << 16) | (buffer[7] << 8) | buffer[8]; 722 + 723 + if (high_vis > SI1133_ADC_THRESHOLD || ir > SI1133_ADC_THRESHOLD) 724 + lux = si1133_calc_polynomial(high_vis, ir, 725 + SI1133_INPUT_FRACTION_HIGH, 726 + ARRAY_SIZE(lux_coeff.coeff_high), 727 + &lux_coeff.coeff_high[0]); 728 + else 729 + lux = si1133_calc_polynomial(low_vis, ir, 730 + SI1133_INPUT_FRACTION_LOW, 731 + ARRAY_SIZE(lux_coeff.coeff_low), 732 + &lux_coeff.coeff_low[0]); 733 + 734 + *val = lux >> SI1133_LUX_OUTPUT_FRACTION; 735 + 736 + return err; 737 + } 738 + 739 + static int si1133_read_raw(struct iio_dev *iio_dev, 740 + struct iio_chan_spec const *chan, 741 + int *val, int *val2, long mask) 742 + { 743 + struct si1133_data *data = iio_priv(iio_dev); 744 + u8 adc_sens = data->adc_sens[0]; 745 + int err; 746 + 747 + switch (mask) { 748 + case IIO_CHAN_INFO_PROCESSED: 749 + switch (chan->type) { 750 + case IIO_LIGHT: 751 + err = si1133_get_lux(data, val); 752 + if (err) 753 + return err; 754 + 755 + return IIO_VAL_INT; 756 + default: 757 + return -EINVAL; 758 + } 759 + case IIO_CHAN_INFO_RAW: 760 + switch (chan->type) { 761 + case IIO_INTENSITY: 762 + case IIO_UVINDEX: 763 + err = si1133_measure(data, chan, val); 764 + if (err) 765 + return err; 766 + 767 + return IIO_VAL_INT; 768 + default: 769 + return -EINVAL; 770 + } 771 + case IIO_CHAN_INFO_INT_TIME: 772 + switch (chan->type) { 773 + case IIO_INTENSITY: 774 + case IIO_UVINDEX: 775 + adc_sens &= SI1133_ADCSENS_HW_GAIN_MASK; 776 + 777 + *val = si1133_int_time_table[adc_sens][0]; 778 + *val2 = si1133_int_time_table[adc_sens][1]; 779 + return IIO_VAL_INT_PLUS_MICRO; 780 + default: 781 + return -EINVAL; 782 + } 783 + case IIO_CHAN_INFO_SCALE: 784 + switch (chan->type) { 785 + case IIO_INTENSITY: 786 + case IIO_UVINDEX: 787 + adc_sens &= SI1133_ADCSENS_SCALE_MASK; 788 + adc_sens >>= SI1133_ADCSENS_SCALE_SHIFT; 789 + 790 + *val = BIT(adc_sens); 791 + 792 + return IIO_VAL_INT; 793 + default: 794 + return -EINVAL; 795 + } 796 + case IIO_CHAN_INFO_HARDWAREGAIN: 797 + switch (chan->type) { 798 + case IIO_INTENSITY: 799 + case IIO_UVINDEX: 800 + adc_sens >>= SI1133_ADCSENS_HSIG_SHIFT; 801 + 802 + *val = adc_sens; 803 + 804 + return IIO_VAL_INT; 805 + default: 806 + return -EINVAL; 807 + } 808 + default: 809 + return -EINVAL; 810 + } 811 + } 812 + 813 + static int si1133_write_raw(struct iio_dev *iio_dev, 814 + struct iio_chan_spec const *chan, 815 + int val, int val2, long mask) 816 + { 817 + struct si1133_data *data = iio_priv(iio_dev); 818 + 819 + switch (mask) { 820 + case IIO_CHAN_INFO_SCALE: 821 + switch (chan->type) { 822 + case IIO_INTENSITY: 823 + case IIO_UVINDEX: 824 + val = si1133_scale_to_swgain(val, val2); 825 + if (val < 0) 826 + return val; 827 + 828 + return si1133_update_adcsens(data, 829 + SI1133_ADCSENS_SCALE_MASK, 830 + SI1133_ADCSENS_SCALE_SHIFT, 831 + val); 832 + default: 833 + return -EINVAL; 834 + } 835 + case IIO_CHAN_INFO_INT_TIME: 836 + return si1133_set_integration_time(data, 0, val, val2); 837 + case IIO_CHAN_INFO_HARDWAREGAIN: 838 + switch (chan->type) { 839 + case IIO_INTENSITY: 840 + case IIO_UVINDEX: 841 + if (val != 0 || val != 1) 842 + return -EINVAL; 843 + 844 + return si1133_update_adcsens(data, 845 + SI1133_ADCSENS_HSIG_MASK, 846 + SI1133_ADCSENS_HSIG_SHIFT, 847 + val); 848 + default: 849 + return -EINVAL; 850 + } 851 + default: 852 + return -EINVAL; 853 + } 854 + } 855 + 856 + static struct attribute *si1133_attributes[] = { 857 + &iio_const_attr_integration_time_available.dev_attr.attr, 858 + &iio_const_attr_scale_available.dev_attr.attr, 859 + NULL, 860 + }; 861 + 862 + static const struct attribute_group si1133_attribute_group = { 863 + .attrs = si1133_attributes, 864 + }; 865 + 866 + static const struct iio_info si1133_info = { 867 + .read_raw = si1133_read_raw, 868 + .write_raw = si1133_write_raw, 869 + .attrs = &si1133_attribute_group, 870 + }; 871 + 872 + /* 873 + * si1133_init_lux_channels - Configure 3 different channels(adc) (1,2 and 3) 874 + * The channel configuration for the lux measurement was taken from : 875 + * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00578 876 + * 877 + * Reserved the channel 0 for the other raw measurements 878 + */ 879 + static int si1133_init_lux_channels(struct si1133_data *data) 880 + { 881 + int err; 882 + 883 + err = si1133_chan_set_adcconfig(data, 1, 884 + SI1133_ADCCONFIG_DECIM_RATE(1) | 885 + SI1133_PARAM_ADCMUX_LARGE_WHITE); 886 + if (err) 887 + return err; 888 + 889 + err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(1), 890 + SI1133_ADCPOST_24BIT_EN | 891 + SI1133_ADCPOST_POSTSHIFT_BITQTY(0)); 892 + if (err) 893 + return err; 894 + err = si1133_chan_set_adcsens(data, 1, SI1133_ADCSENS_HSIG_MASK | 895 + SI1133_ADCSENS_NB_MEAS(64) | _48_8_us); 896 + if (err) 897 + return err; 898 + 899 + err = si1133_chan_set_adcconfig(data, 2, 900 + SI1133_ADCCONFIG_DECIM_RATE(1) | 901 + SI1133_PARAM_ADCMUX_LARGE_WHITE); 902 + if (err) 903 + return err; 904 + 905 + err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(2), 906 + SI1133_ADCPOST_24BIT_EN | 907 + SI1133_ADCPOST_POSTSHIFT_BITQTY(2)); 908 + if (err) 909 + return err; 910 + 911 + err = si1133_chan_set_adcsens(data, 2, SI1133_ADCSENS_HSIG_MASK | 912 + SI1133_ADCSENS_NB_MEAS(1) | _3_120_0_us); 913 + if (err) 914 + return err; 915 + 916 + err = si1133_chan_set_adcconfig(data, 3, 917 + SI1133_ADCCONFIG_DECIM_RATE(1) | 918 + SI1133_PARAM_ADCMUX_MED_IR); 919 + if (err) 920 + return err; 921 + 922 + err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(3), 923 + SI1133_ADCPOST_24BIT_EN | 924 + SI1133_ADCPOST_POSTSHIFT_BITQTY(2)); 925 + if (err) 926 + return err; 927 + 928 + return si1133_chan_set_adcsens(data, 3, SI1133_ADCSENS_HSIG_MASK | 929 + SI1133_ADCSENS_NB_MEAS(64) | _48_8_us); 930 + } 931 + 932 + static int si1133_initialize(struct si1133_data *data) 933 + { 934 + int err; 935 + 936 + err = si1133_cmd_reset_sw(data); 937 + if (err) 938 + return err; 939 + 940 + /* Turn off autonomous mode */ 941 + err = si1133_param_set(data, SI1133_REG_MEAS_RATE, 0); 942 + if (err) 943 + return err; 944 + 945 + err = si1133_init_lux_channels(data); 946 + if (err) 947 + return err; 948 + 949 + return regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, 950 + SI1133_IRQ_CHANNEL_ENABLE); 951 + } 952 + 953 + static int si1133_validate_ids(struct iio_dev *iio_dev) 954 + { 955 + struct si1133_data *data = iio_priv(iio_dev); 956 + 957 + unsigned int part_id, rev_id, mfr_id; 958 + int err; 959 + 960 + err = regmap_read(data->regmap, SI1133_REG_PART_ID, &part_id); 961 + if (err) 962 + return err; 963 + 964 + err = regmap_read(data->regmap, SI1133_REG_REV_ID, &rev_id); 965 + if (err) 966 + return err; 967 + 968 + err = regmap_read(data->regmap, SI1133_REG_MFR_ID, &mfr_id); 969 + if (err) 970 + return err; 971 + 972 + dev_info(&iio_dev->dev, 973 + "Device ID part %#02hhx rev %#02hhx mfr %#02hhx\n", 974 + part_id, rev_id, mfr_id); 975 + if (part_id != SI1133_PART_ID) { 976 + dev_err(&iio_dev->dev, 977 + "Part ID mismatch got %#02hhx, expected %#02x\n", 978 + part_id, SI1133_PART_ID); 979 + return -ENODEV; 980 + } 981 + 982 + return 0; 983 + } 984 + 985 + static int si1133_probe(struct i2c_client *client, 986 + const struct i2c_device_id *id) 987 + { 988 + struct si1133_data *data; 989 + struct iio_dev *iio_dev; 990 + int err; 991 + 992 + iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 993 + if (!iio_dev) 994 + return -ENOMEM; 995 + 996 + data = iio_priv(iio_dev); 997 + 998 + init_completion(&data->completion); 999 + 1000 + data->regmap = devm_regmap_init_i2c(client, &si1133_regmap_config); 1001 + if (IS_ERR(data->regmap)) { 1002 + err = PTR_ERR(data->regmap); 1003 + dev_err(&client->dev, "Failed to initialise regmap: %d\n", err); 1004 + return err; 1005 + } 1006 + 1007 + i2c_set_clientdata(client, iio_dev); 1008 + data->client = client; 1009 + 1010 + iio_dev->dev.parent = &client->dev; 1011 + iio_dev->name = id->name; 1012 + iio_dev->channels = si1133_channels; 1013 + iio_dev->num_channels = ARRAY_SIZE(si1133_channels); 1014 + iio_dev->info = &si1133_info; 1015 + iio_dev->modes = INDIO_DIRECT_MODE; 1016 + 1017 + mutex_init(&data->mutex); 1018 + 1019 + err = si1133_validate_ids(iio_dev); 1020 + if (err) 1021 + return err; 1022 + 1023 + err = si1133_initialize(data); 1024 + if (err) { 1025 + dev_err(&client->dev, 1026 + "Error when initializing chip: %d\n", err); 1027 + return err; 1028 + } 1029 + 1030 + if (!client->irq) { 1031 + dev_err(&client->dev, 1032 + "Required interrupt not provided, cannot proceed\n"); 1033 + return -EINVAL; 1034 + } 1035 + 1036 + err = devm_request_threaded_irq(&client->dev, client->irq, 1037 + NULL, 1038 + si1133_threaded_irq_handler, 1039 + IRQF_ONESHOT | IRQF_SHARED, 1040 + client->name, iio_dev); 1041 + if (err) { 1042 + dev_warn(&client->dev, "Request irq %d failed: %i\n", 1043 + client->irq, err); 1044 + return err; 1045 + } 1046 + 1047 + return devm_iio_device_register(&client->dev, iio_dev); 1048 + } 1049 + 1050 + static const struct i2c_device_id si1133_ids[] = { 1051 + { "si1133", 0 }, 1052 + { } 1053 + }; 1054 + MODULE_DEVICE_TABLE(i2c, si1133_ids); 1055 + 1056 + static struct i2c_driver si1133_driver = { 1057 + .driver = { 1058 + .name = "si1133", 1059 + }, 1060 + .probe = si1133_probe, 1061 + .id_table = si1133_ids, 1062 + }; 1063 + 1064 + module_i2c_driver(si1133_driver); 1065 + 1066 + MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>"); 1067 + MODULE_DESCRIPTION("Silabs SI1133, UV index sensor and ambient light sensor driver"); 1068 + MODULE_LICENSE("GPL");