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

iio: light: ROHM BH1745 colour sensor

Add support for BH1745, which is an I2C colour sensor with red, green,
blue and clear channels. It has a programmable active low interrupt
pin. Interrupt occurs when the signal from the selected interrupt
source channel crosses set interrupt threshold high or low level.

Interrupt source for the device can be configured by enabling the
corresponding event. Interrupt latch is always enabled when setting
up interrupt.

Add myself as the maintainer for this driver in MAINTAINERS.

Signed-off-by: Mudit Sharma <muditsharma.info@gmail.com>
Reviewed-by: Ivan Orlov <ivan.orlov0322@gmail.com>
Reviewed-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20240718220208.331942-2-muditsharma.info@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Mudit Sharma and committed by
Jonathan Cameron
eab35358 876af455

+926
+6
MAINTAINERS
··· 19798 19798 F: drivers/power/supply/bd99954-charger.c 19799 19799 F: drivers/power/supply/bd99954-charger.h 19800 19800 19801 + ROHM BH1745 COLOUR SENSOR 19802 + M: Mudit Sharma <muditsharma.info@gmail.com> 19803 + L: linux-iio@vger.kernel.org 19804 + S: Maintained 19805 + F: drivers/iio/light/bh1745.c 19806 + 19801 19807 ROHM BH1750 AMBIENT LIGHT SENSOR DRIVER 19802 19808 M: Tomasz Duszynski <tduszyns@gmail.com> 19803 19809 S: Maintained
+13
drivers/iio/light/Kconfig
··· 114 114 This driver can also be built as a module. If so, the module 115 115 will be called as73211. 116 116 117 + config BH1745 118 + tristate "ROHM BH1745 colour sensor" 119 + depends on I2C 120 + select REGMAP_I2C 121 + select IIO_BUFFER 122 + select IIO_TRIGGERED_BUFFER 123 + select IIO_GTS_HELPER 124 + help 125 + Say Y here to build support for the ROHM bh1745 colour sensor. 126 + 127 + To compile this driver as a module, choose M here: the module will 128 + be called bh1745. 129 + 117 130 config BH1750 118 131 tristate "ROHM BH1750 ambient light sensor" 119 132 depends on I2C
+1
drivers/iio/light/Makefile
··· 13 13 obj-$(CONFIG_APDS9306) += apds9306.o 14 14 obj-$(CONFIG_APDS9960) += apds9960.o 15 15 obj-$(CONFIG_AS73211) += as73211.o 16 + obj-$(CONFIG_BH1745) += bh1745.o 16 17 obj-$(CONFIG_BH1750) += bh1750.o 17 18 obj-$(CONFIG_BH1780) += bh1780.o 18 19 obj-$(CONFIG_CM32181) += cm32181.o
+906
drivers/iio/light/bh1745.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * ROHM BH1745 digital colour sensor driver 4 + * 5 + * Copyright (C) Mudit Sharma <muditsharma.info@gmail.com> 6 + * 7 + * 7-bit I2C slave addresses: 8 + * 0x38 (ADDR pin low) 9 + * 0x39 (ADDR pin high) 10 + */ 11 + 12 + #include <linux/i2c.h> 13 + #include <linux/mutex.h> 14 + #include <linux/util_macros.h> 15 + #include <linux/iio/events.h> 16 + #include <linux/regmap.h> 17 + #include <linux/bits.h> 18 + #include <linux/bitfield.h> 19 + 20 + #include <linux/iio/iio.h> 21 + #include <linux/iio/sysfs.h> 22 + #include <linux/iio/trigger.h> 23 + #include <linux/iio/trigger_consumer.h> 24 + #include <linux/iio/triggered_buffer.h> 25 + #include <linux/iio/iio-gts-helper.h> 26 + 27 + /* BH1745 configuration registers */ 28 + 29 + /* System control */ 30 + #define BH1745_SYS_CTRL 0x40 31 + #define BH1745_SYS_CTRL_SW_RESET BIT(7) 32 + #define BH1745_SYS_CTRL_INTR_RESET BIT(6) 33 + #define BH1745_SYS_CTRL_PART_ID_MASK GENMASK(5, 0) 34 + #define BH1745_PART_ID 0x0B 35 + 36 + /* Mode control 1 */ 37 + #define BH1745_MODE_CTRL1 0x41 38 + #define BH1745_CTRL1_MEASUREMENT_TIME_MASK GENMASK(2, 0) 39 + 40 + /* Mode control 2 */ 41 + #define BH1745_MODE_CTRL2 0x42 42 + #define BH1745_CTRL2_RGBC_EN BIT(4) 43 + #define BH1745_CTRL2_ADC_GAIN_MASK GENMASK(1, 0) 44 + 45 + /* Interrupt */ 46 + #define BH1745_INTR 0x60 47 + #define BH1745_INTR_STATUS BIT(7) 48 + #define BH1745_INTR_SOURCE_MASK GENMASK(3, 2) 49 + #define BH1745_INTR_ENABLE BIT(0) 50 + 51 + #define BH1745_PERSISTENCE 0x61 52 + 53 + /* Threshold high */ 54 + #define BH1745_TH_LSB 0x62 55 + #define BH1745_TH_MSB 0x63 56 + 57 + /* Threshold low */ 58 + #define BH1745_TL_LSB 0x64 59 + #define BH1745_TL_MSB 0x65 60 + 61 + /* BH1745 data output regs */ 62 + #define BH1745_RED_LSB 0x50 63 + #define BH1745_RED_MSB 0x51 64 + #define BH1745_GREEN_LSB 0x52 65 + #define BH1745_GREEN_MSB 0x53 66 + #define BH1745_BLUE_LSB 0x54 67 + #define BH1745_BLUE_MSB 0x55 68 + #define BH1745_CLEAR_LSB 0x56 69 + #define BH1745_CLEAR_MSB 0x57 70 + 71 + #define BH1745_MANU_ID_REG 0x92 72 + 73 + /* From 16x max HW gain and 32x max integration time */ 74 + #define BH1745_MAX_GAIN 512 75 + 76 + enum bh1745_int_source { 77 + BH1745_INTR_SOURCE_RED, 78 + BH1745_INTR_SOURCE_GREEN, 79 + BH1745_INTR_SOURCE_BLUE, 80 + BH1745_INTR_SOURCE_CLEAR, 81 + }; 82 + 83 + enum bh1745_gain { 84 + BH1745_ADC_GAIN_1X, 85 + BH1745_ADC_GAIN_2X, 86 + BH1745_ADC_GAIN_16X, 87 + }; 88 + 89 + enum bh1745_measurement_time { 90 + BH1745_MEASUREMENT_TIME_160MS, 91 + BH1745_MEASUREMENT_TIME_320MS, 92 + BH1745_MEASUREMENT_TIME_640MS, 93 + BH1745_MEASUREMENT_TIME_1280MS, 94 + BH1745_MEASUREMENT_TIME_2560MS, 95 + BH1745_MEASUREMENT_TIME_5120MS, 96 + }; 97 + 98 + enum bh1745_presistence_value { 99 + BH1745_PRESISTENCE_UPDATE_TOGGLE, 100 + BH1745_PRESISTENCE_UPDATE_EACH_MEASUREMENT, 101 + BH1745_PRESISTENCE_UPDATE_FOUR_MEASUREMENT, 102 + BH1745_PRESISTENCE_UPDATE_EIGHT_MEASUREMENT, 103 + }; 104 + 105 + static const struct iio_gain_sel_pair bh1745_gain[] = { 106 + GAIN_SCALE_GAIN(1, BH1745_ADC_GAIN_1X), 107 + GAIN_SCALE_GAIN(2, BH1745_ADC_GAIN_2X), 108 + GAIN_SCALE_GAIN(16, BH1745_ADC_GAIN_16X), 109 + }; 110 + 111 + static const struct iio_itime_sel_mul bh1745_itimes[] = { 112 + GAIN_SCALE_ITIME_US(5120000, BH1745_MEASUREMENT_TIME_5120MS, 32), 113 + GAIN_SCALE_ITIME_US(2560000, BH1745_MEASUREMENT_TIME_2560MS, 16), 114 + GAIN_SCALE_ITIME_US(1280000, BH1745_MEASUREMENT_TIME_1280MS, 8), 115 + GAIN_SCALE_ITIME_US(640000, BH1745_MEASUREMENT_TIME_640MS, 4), 116 + GAIN_SCALE_ITIME_US(320000, BH1745_MEASUREMENT_TIME_320MS, 2), 117 + GAIN_SCALE_ITIME_US(160000, BH1745_MEASUREMENT_TIME_160MS, 1), 118 + }; 119 + 120 + struct bh1745_data { 121 + /* 122 + * Lock to prevent device setting update or read before 123 + * related calculations are completed 124 + */ 125 + struct mutex lock; 126 + struct regmap *regmap; 127 + struct device *dev; 128 + struct iio_trigger *trig; 129 + struct iio_gts gts; 130 + }; 131 + 132 + static const struct regmap_range bh1745_volatile_ranges[] = { 133 + regmap_reg_range(BH1745_MODE_CTRL2, BH1745_MODE_CTRL2), /* VALID */ 134 + regmap_reg_range(BH1745_RED_LSB, BH1745_CLEAR_MSB), /* Data */ 135 + regmap_reg_range(BH1745_INTR, BH1745_INTR), /* Interrupt */ 136 + }; 137 + 138 + static const struct regmap_access_table bh1745_volatile_regs = { 139 + .yes_ranges = bh1745_volatile_ranges, 140 + .n_yes_ranges = ARRAY_SIZE(bh1745_volatile_ranges), 141 + }; 142 + 143 + static const struct regmap_range bh1745_readable_ranges[] = { 144 + regmap_reg_range(BH1745_SYS_CTRL, BH1745_MODE_CTRL2), 145 + regmap_reg_range(BH1745_RED_LSB, BH1745_CLEAR_MSB), 146 + regmap_reg_range(BH1745_INTR, BH1745_INTR), 147 + regmap_reg_range(BH1745_PERSISTENCE, BH1745_TL_MSB), 148 + regmap_reg_range(BH1745_MANU_ID_REG, BH1745_MANU_ID_REG), 149 + }; 150 + 151 + static const struct regmap_access_table bh1745_readable_regs = { 152 + .yes_ranges = bh1745_readable_ranges, 153 + .n_yes_ranges = ARRAY_SIZE(bh1745_readable_ranges), 154 + }; 155 + 156 + static const struct regmap_range bh1745_writable_ranges[] = { 157 + regmap_reg_range(BH1745_SYS_CTRL, BH1745_MODE_CTRL2), 158 + regmap_reg_range(BH1745_INTR, BH1745_INTR), 159 + regmap_reg_range(BH1745_PERSISTENCE, BH1745_TL_MSB), 160 + }; 161 + 162 + static const struct regmap_access_table bh1745_writable_regs = { 163 + .yes_ranges = bh1745_writable_ranges, 164 + .n_yes_ranges = ARRAY_SIZE(bh1745_writable_ranges), 165 + }; 166 + 167 + static const struct regmap_config bh1745_regmap = { 168 + .reg_bits = 8, 169 + .val_bits = 8, 170 + .max_register = BH1745_MANU_ID_REG, 171 + .cache_type = REGCACHE_RBTREE, 172 + .volatile_table = &bh1745_volatile_regs, 173 + .wr_table = &bh1745_writable_regs, 174 + .rd_table = &bh1745_readable_regs, 175 + }; 176 + 177 + static const struct iio_event_spec bh1745_event_spec[] = { 178 + { 179 + .type = IIO_EV_TYPE_THRESH, 180 + .dir = IIO_EV_DIR_RISING, 181 + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), 182 + }, 183 + { 184 + .type = IIO_EV_TYPE_THRESH, 185 + .dir = IIO_EV_DIR_FALLING, 186 + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), 187 + }, 188 + { 189 + .type = IIO_EV_TYPE_THRESH, 190 + .dir = IIO_EV_DIR_EITHER, 191 + .mask_shared_by_type = BIT(IIO_EV_INFO_PERIOD), 192 + .mask_separate = BIT(IIO_EV_INFO_ENABLE), 193 + }, 194 + }; 195 + 196 + #define BH1745_CHANNEL(_colour, _si, _addr) \ 197 + { \ 198 + .type = IIO_INTENSITY, .modified = 1, \ 199 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 200 + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | \ 201 + BIT(IIO_CHAN_INFO_INT_TIME), \ 202 + .info_mask_shared_by_all_available = \ 203 + BIT(IIO_CHAN_INFO_SCALE) | \ 204 + BIT(IIO_CHAN_INFO_INT_TIME), \ 205 + .event_spec = bh1745_event_spec, \ 206 + .num_event_specs = ARRAY_SIZE(bh1745_event_spec), \ 207 + .channel2 = IIO_MOD_LIGHT_##_colour, .address = _addr, \ 208 + .scan_index = _si, \ 209 + .scan_type = { \ 210 + .sign = 'u', \ 211 + .realbits = 16, \ 212 + .storagebits = 16, \ 213 + .endianness = IIO_CPU, \ 214 + }, \ 215 + } 216 + 217 + static const struct iio_chan_spec bh1745_channels[] = { 218 + BH1745_CHANNEL(RED, 0, BH1745_RED_LSB), 219 + BH1745_CHANNEL(GREEN, 1, BH1745_GREEN_LSB), 220 + BH1745_CHANNEL(BLUE, 2, BH1745_BLUE_LSB), 221 + BH1745_CHANNEL(CLEAR, 3, BH1745_CLEAR_LSB), 222 + IIO_CHAN_SOFT_TIMESTAMP(4), 223 + }; 224 + 225 + static int bh1745_reset(struct bh1745_data *data) 226 + { 227 + return regmap_set_bits(data->regmap, BH1745_SYS_CTRL, 228 + BH1745_SYS_CTRL_SW_RESET | 229 + BH1745_SYS_CTRL_INTR_RESET); 230 + } 231 + 232 + static int bh1745_power_on(struct bh1745_data *data) 233 + { 234 + return regmap_set_bits(data->regmap, BH1745_MODE_CTRL2, 235 + BH1745_CTRL2_RGBC_EN); 236 + } 237 + 238 + static void bh1745_power_off(void *data_ptr) 239 + { 240 + struct bh1745_data *data = data_ptr; 241 + struct device *dev = data->dev; 242 + int ret; 243 + 244 + ret = regmap_clear_bits(data->regmap, BH1745_MODE_CTRL2, 245 + BH1745_CTRL2_RGBC_EN); 246 + if (ret) 247 + dev_err(dev, "Failed to turn off device\n"); 248 + } 249 + 250 + static int bh1745_get_scale(struct bh1745_data *data, int *val, int *val2) 251 + { 252 + int ret; 253 + int value; 254 + int gain_sel, int_time_sel; 255 + int gain; 256 + const struct iio_itime_sel_mul *int_time; 257 + 258 + ret = regmap_read(data->regmap, BH1745_MODE_CTRL2, &value); 259 + if (ret) 260 + return ret; 261 + 262 + gain_sel = FIELD_GET(BH1745_CTRL2_ADC_GAIN_MASK, value); 263 + gain = iio_gts_find_gain_by_sel(&data->gts, gain_sel); 264 + 265 + ret = regmap_read(data->regmap, BH1745_MODE_CTRL1, &value); 266 + if (ret) 267 + return ret; 268 + 269 + int_time_sel = FIELD_GET(BH1745_CTRL1_MEASUREMENT_TIME_MASK, value); 270 + int_time = iio_gts_find_itime_by_sel(&data->gts, int_time_sel); 271 + 272 + return iio_gts_get_scale(&data->gts, gain, int_time->time_us, val, 273 + val2); 274 + } 275 + 276 + static int bh1745_set_scale(struct bh1745_data *data, int val) 277 + { 278 + struct device *dev = data->dev; 279 + int ret; 280 + int value; 281 + int hw_gain_sel, current_int_time_sel, new_int_time_sel; 282 + 283 + ret = regmap_read(data->regmap, BH1745_MODE_CTRL1, &value); 284 + if (ret) 285 + return ret; 286 + 287 + current_int_time_sel = FIELD_GET(BH1745_CTRL1_MEASUREMENT_TIME_MASK, 288 + value); 289 + ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, 290 + current_int_time_sel, 291 + val, 0, &hw_gain_sel); 292 + if (ret) { 293 + for (int i = 0; i < data->gts.num_itime; i++) { 294 + new_int_time_sel = data->gts.itime_table[i].sel; 295 + 296 + if (new_int_time_sel == current_int_time_sel) 297 + continue; 298 + 299 + ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, 300 + new_int_time_sel, 301 + val, 0, 302 + &hw_gain_sel); 303 + if (!ret) 304 + break; 305 + } 306 + 307 + if (ret) { 308 + dev_dbg(dev, "Unsupported scale value requested: %d\n", 309 + val); 310 + return -EINVAL; 311 + } 312 + 313 + ret = regmap_write_bits(data->regmap, BH1745_MODE_CTRL1, 314 + BH1745_CTRL1_MEASUREMENT_TIME_MASK, 315 + new_int_time_sel); 316 + if (ret) 317 + return ret; 318 + } 319 + 320 + return regmap_write_bits(data->regmap, BH1745_MODE_CTRL2, 321 + BH1745_CTRL2_ADC_GAIN_MASK, hw_gain_sel); 322 + } 323 + 324 + static int bh1745_get_int_time(struct bh1745_data *data, int *val) 325 + { 326 + int ret; 327 + int value; 328 + int int_time, int_time_sel; 329 + 330 + ret = regmap_read(data->regmap, BH1745_MODE_CTRL1, &value); 331 + if (ret) 332 + return ret; 333 + 334 + int_time_sel = FIELD_GET(BH1745_CTRL1_MEASUREMENT_TIME_MASK, value); 335 + int_time = iio_gts_find_int_time_by_sel(&data->gts, int_time_sel); 336 + if (int_time < 0) 337 + return int_time; 338 + 339 + *val = int_time; 340 + 341 + return 0; 342 + } 343 + 344 + static int bh1745_set_int_time(struct bh1745_data *data, int val, int val2) 345 + { 346 + struct device *dev = data->dev; 347 + int ret; 348 + int value; 349 + int current_int_time, current_hwgain_sel, current_hwgain; 350 + int new_hwgain, new_hwgain_sel, new_int_time_sel; 351 + int req_int_time = (1000000 * val) + val2; 352 + 353 + if (!iio_gts_valid_time(&data->gts, req_int_time)) { 354 + dev_dbg(dev, "Unsupported integration time requested: %d\n", 355 + req_int_time); 356 + return -EINVAL; 357 + } 358 + 359 + ret = bh1745_get_int_time(data, &current_int_time); 360 + if (ret) 361 + return ret; 362 + 363 + if (current_int_time == req_int_time) 364 + return 0; 365 + 366 + ret = regmap_read(data->regmap, BH1745_MODE_CTRL2, &value); 367 + if (ret) 368 + return ret; 369 + 370 + current_hwgain_sel = FIELD_GET(BH1745_CTRL2_ADC_GAIN_MASK, value); 371 + current_hwgain = iio_gts_find_gain_by_sel(&data->gts, 372 + current_hwgain_sel); 373 + ret = iio_gts_find_new_gain_by_old_gain_time(&data->gts, current_hwgain, 374 + current_int_time, 375 + req_int_time, 376 + &new_hwgain); 377 + if (new_hwgain < 0) { 378 + dev_dbg(dev, "No corresponding gain for requested integration time\n"); 379 + return ret; 380 + } 381 + 382 + if (ret) { 383 + bool in_range; 384 + 385 + new_hwgain = iio_find_closest_gain_low(&data->gts, new_hwgain, 386 + &in_range); 387 + if (new_hwgain < 0) { 388 + new_hwgain = iio_gts_get_min_gain(&data->gts); 389 + if (new_hwgain < 0) 390 + return ret; 391 + } 392 + 393 + if (!in_range) 394 + dev_dbg(dev, "Optimal gain out of range\n"); 395 + 396 + dev_dbg(dev, "Scale changed, new hw_gain %d\n", new_hwgain); 397 + } 398 + 399 + new_hwgain_sel = iio_gts_find_sel_by_gain(&data->gts, new_hwgain); 400 + if (new_hwgain_sel < 0) 401 + return new_hwgain_sel; 402 + 403 + ret = regmap_write_bits(data->regmap, BH1745_MODE_CTRL2, 404 + BH1745_CTRL2_ADC_GAIN_MASK, 405 + new_hwgain_sel); 406 + if (ret) 407 + return ret; 408 + 409 + new_int_time_sel = iio_gts_find_sel_by_int_time(&data->gts, 410 + req_int_time); 411 + if (new_int_time_sel < 0) 412 + return new_int_time_sel; 413 + 414 + return regmap_write_bits(data->regmap, BH1745_MODE_CTRL1, 415 + BH1745_CTRL1_MEASUREMENT_TIME_MASK, 416 + new_int_time_sel); 417 + } 418 + 419 + static int bh1745_read_raw(struct iio_dev *indio_dev, 420 + struct iio_chan_spec const *chan, 421 + int *val, int *val2, long mask) 422 + { 423 + struct bh1745_data *data = iio_priv(indio_dev); 424 + int ret; 425 + int value; 426 + 427 + switch (mask) { 428 + case IIO_CHAN_INFO_RAW: 429 + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { 430 + ret = regmap_bulk_read(data->regmap, chan->address, 431 + &value, 2); 432 + if (ret) 433 + return ret; 434 + *val = value; 435 + 436 + return IIO_VAL_INT; 437 + } 438 + unreachable(); 439 + 440 + case IIO_CHAN_INFO_SCALE: { 441 + guard(mutex)(&data->lock); 442 + ret = bh1745_get_scale(data, val, val2); 443 + if (ret) 444 + return ret; 445 + 446 + return IIO_VAL_INT; 447 + } 448 + 449 + case IIO_CHAN_INFO_INT_TIME: { 450 + guard(mutex)(&data->lock); 451 + *val = 0; 452 + ret = bh1745_get_int_time(data, val2); 453 + if (ret) 454 + return 0; 455 + 456 + return IIO_VAL_INT_PLUS_MICRO; 457 + } 458 + 459 + default: 460 + return -EINVAL; 461 + } 462 + } 463 + 464 + static int bh1745_write_raw(struct iio_dev *indio_dev, 465 + struct iio_chan_spec const *chan, 466 + int val, int val2, long mask) 467 + { 468 + struct bh1745_data *data = iio_priv(indio_dev); 469 + 470 + guard(mutex)(&data->lock); 471 + switch (mask) { 472 + case IIO_CHAN_INFO_SCALE: 473 + return bh1745_set_scale(data, val); 474 + 475 + case IIO_CHAN_INFO_INT_TIME: 476 + return bh1745_set_int_time(data, val, val2); 477 + 478 + default: 479 + return -EINVAL; 480 + } 481 + } 482 + 483 + static int bh1745_write_raw_get_fmt(struct iio_dev *indio_dev, 484 + struct iio_chan_spec const *chan, 485 + long mask) 486 + { 487 + switch (mask) { 488 + case IIO_CHAN_INFO_SCALE: 489 + return IIO_VAL_INT; 490 + 491 + case IIO_CHAN_INFO_INT_TIME: 492 + return IIO_VAL_INT_PLUS_MICRO; 493 + 494 + default: 495 + return -EINVAL; 496 + } 497 + } 498 + 499 + static int bh1745_read_thresh(struct iio_dev *indio_dev, 500 + const struct iio_chan_spec *chan, 501 + enum iio_event_type type, 502 + enum iio_event_direction dir, 503 + enum iio_event_info info, int *val, int *val2) 504 + { 505 + struct bh1745_data *data = iio_priv(indio_dev); 506 + int ret; 507 + 508 + switch (info) { 509 + case IIO_EV_INFO_VALUE: 510 + switch (dir) { 511 + case IIO_EV_DIR_RISING: 512 + ret = regmap_bulk_read(data->regmap, BH1745_TH_LSB, 513 + val, 2); 514 + if (ret) 515 + return ret; 516 + 517 + return IIO_VAL_INT; 518 + 519 + case IIO_EV_DIR_FALLING: 520 + ret = regmap_bulk_read(data->regmap, BH1745_TL_LSB, 521 + val, 2); 522 + if (ret) 523 + return ret; 524 + 525 + return IIO_VAL_INT; 526 + 527 + default: 528 + return -EINVAL; 529 + } 530 + 531 + case IIO_EV_INFO_PERIOD: 532 + ret = regmap_read(data->regmap, BH1745_PERSISTENCE, val); 533 + if (ret) 534 + return ret; 535 + 536 + return IIO_VAL_INT; 537 + 538 + default: 539 + return -EINVAL; 540 + } 541 + } 542 + 543 + static int bh1745_write_thresh(struct iio_dev *indio_dev, 544 + const struct iio_chan_spec *chan, 545 + enum iio_event_type type, 546 + enum iio_event_direction dir, 547 + enum iio_event_info info, int val, int val2) 548 + { 549 + struct bh1745_data *data = iio_priv(indio_dev); 550 + int ret; 551 + 552 + switch (info) { 553 + case IIO_EV_INFO_VALUE: 554 + if (val < 0x0 || val > 0xFFFF) 555 + return -EINVAL; 556 + 557 + switch (dir) { 558 + case IIO_EV_DIR_RISING: 559 + ret = regmap_bulk_write(data->regmap, BH1745_TH_LSB, 560 + &val, 2); 561 + if (ret) 562 + return ret; 563 + 564 + return IIO_VAL_INT; 565 + 566 + case IIO_EV_DIR_FALLING: 567 + ret = regmap_bulk_write(data->regmap, BH1745_TL_LSB, 568 + &val, 2); 569 + if (ret) 570 + return ret; 571 + 572 + return IIO_VAL_INT; 573 + 574 + default: 575 + return -EINVAL; 576 + } 577 + 578 + case IIO_EV_INFO_PERIOD: 579 + if (val < BH1745_PRESISTENCE_UPDATE_TOGGLE || 580 + val > BH1745_PRESISTENCE_UPDATE_EIGHT_MEASUREMENT) 581 + return -EINVAL; 582 + ret = regmap_write(data->regmap, BH1745_PERSISTENCE, val); 583 + if (ret) 584 + return ret; 585 + 586 + return IIO_VAL_INT; 587 + 588 + default: 589 + return -EINVAL; 590 + } 591 + } 592 + 593 + static int bh1745_read_event_config(struct iio_dev *indio_dev, 594 + const struct iio_chan_spec *chan, 595 + enum iio_event_type type, 596 + enum iio_event_direction dir) 597 + { 598 + struct bh1745_data *data = iio_priv(indio_dev); 599 + int ret; 600 + int value; 601 + int int_src; 602 + 603 + ret = regmap_read(data->regmap, BH1745_INTR, &value); 604 + if (ret) 605 + return ret; 606 + 607 + if (!FIELD_GET(BH1745_INTR_ENABLE, value)) 608 + return 0; 609 + 610 + int_src = FIELD_GET(BH1745_INTR_SOURCE_MASK, value); 611 + 612 + switch (chan->channel2) { 613 + case IIO_MOD_LIGHT_RED: 614 + if (int_src == BH1745_INTR_SOURCE_RED) 615 + return 1; 616 + return 0; 617 + 618 + case IIO_MOD_LIGHT_GREEN: 619 + if (int_src == BH1745_INTR_SOURCE_GREEN) 620 + return 1; 621 + return 0; 622 + 623 + case IIO_MOD_LIGHT_BLUE: 624 + if (int_src == BH1745_INTR_SOURCE_BLUE) 625 + return 1; 626 + return 0; 627 + 628 + case IIO_MOD_LIGHT_CLEAR: 629 + if (int_src == BH1745_INTR_SOURCE_CLEAR) 630 + return 1; 631 + return 0; 632 + 633 + default: 634 + return -EINVAL; 635 + } 636 + } 637 + 638 + static int bh1745_write_event_config(struct iio_dev *indio_dev, 639 + const struct iio_chan_spec *chan, 640 + enum iio_event_type type, 641 + enum iio_event_direction dir, int state) 642 + { 643 + struct bh1745_data *data = iio_priv(indio_dev); 644 + int value; 645 + 646 + if (state == 0) 647 + return regmap_clear_bits(data->regmap, 648 + BH1745_INTR, BH1745_INTR_ENABLE); 649 + 650 + if (state == 1) { 651 + /* Latch is always enabled when enabling interrupt */ 652 + value = BH1745_INTR_ENABLE; 653 + 654 + switch (chan->channel2) { 655 + case IIO_MOD_LIGHT_RED: 656 + return regmap_write(data->regmap, BH1745_INTR, 657 + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, 658 + BH1745_INTR_SOURCE_RED)); 659 + 660 + case IIO_MOD_LIGHT_GREEN: 661 + return regmap_write(data->regmap, BH1745_INTR, 662 + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, 663 + BH1745_INTR_SOURCE_GREEN)); 664 + 665 + case IIO_MOD_LIGHT_BLUE: 666 + return regmap_write(data->regmap, BH1745_INTR, 667 + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, 668 + BH1745_INTR_SOURCE_BLUE)); 669 + 670 + case IIO_MOD_LIGHT_CLEAR: 671 + return regmap_write(data->regmap, BH1745_INTR, 672 + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, 673 + BH1745_INTR_SOURCE_CLEAR)); 674 + 675 + default: 676 + return -EINVAL; 677 + } 678 + } 679 + 680 + return -EINVAL; 681 + } 682 + 683 + static int bh1745_read_avail(struct iio_dev *indio_dev, 684 + struct iio_chan_spec const *chan, const int **vals, 685 + int *type, int *length, long mask) 686 + { 687 + struct bh1745_data *data = iio_priv(indio_dev); 688 + 689 + switch (mask) { 690 + case IIO_CHAN_INFO_INT_TIME: 691 + return iio_gts_avail_times(&data->gts, vals, type, length); 692 + 693 + case IIO_CHAN_INFO_SCALE: 694 + return iio_gts_all_avail_scales(&data->gts, vals, type, length); 695 + 696 + default: 697 + return -EINVAL; 698 + } 699 + } 700 + 701 + static const struct iio_info bh1745_info = { 702 + .read_raw = bh1745_read_raw, 703 + .write_raw = bh1745_write_raw, 704 + .write_raw_get_fmt = bh1745_write_raw_get_fmt, 705 + .read_event_value = bh1745_read_thresh, 706 + .write_event_value = bh1745_write_thresh, 707 + .read_event_config = bh1745_read_event_config, 708 + .write_event_config = bh1745_write_event_config, 709 + .read_avail = bh1745_read_avail, 710 + }; 711 + 712 + static irqreturn_t bh1745_interrupt_handler(int interrupt, void *p) 713 + { 714 + struct iio_dev *indio_dev = p; 715 + struct bh1745_data *data = iio_priv(indio_dev); 716 + int ret; 717 + int value; 718 + int int_src; 719 + 720 + ret = regmap_read(data->regmap, BH1745_INTR, &value); 721 + if (ret) 722 + return IRQ_NONE; 723 + 724 + int_src = FIELD_GET(BH1745_INTR_SOURCE_MASK, value); 725 + 726 + if (value & BH1745_INTR_STATUS) { 727 + iio_push_event(indio_dev, 728 + IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, int_src, 729 + IIO_EV_TYPE_THRESH, 730 + IIO_EV_DIR_EITHER), 731 + iio_get_time_ns(indio_dev)); 732 + 733 + return IRQ_HANDLED; 734 + } 735 + 736 + return IRQ_NONE; 737 + } 738 + 739 + static irqreturn_t bh1745_trigger_handler(int interrupt, void *p) 740 + { 741 + struct iio_poll_func *pf = p; 742 + struct iio_dev *indio_dev = pf->indio_dev; 743 + struct bh1745_data *data = iio_priv(indio_dev); 744 + struct { 745 + u16 chans[4]; 746 + s64 timestamp __aligned(8); 747 + } scan; 748 + u16 value; 749 + int ret; 750 + int i; 751 + int j = 0; 752 + 753 + iio_for_each_active_channel(indio_dev, i) { 754 + ret = regmap_bulk_read(data->regmap, BH1745_RED_LSB + 2 * i, 755 + &value, 2); 756 + if (ret) 757 + goto err; 758 + 759 + scan.chans[j++] = value; 760 + } 761 + 762 + iio_push_to_buffers_with_timestamp(indio_dev, &scan, 763 + iio_get_time_ns(indio_dev)); 764 + 765 + err: 766 + iio_trigger_notify_done(indio_dev->trig); 767 + 768 + return IRQ_HANDLED; 769 + } 770 + 771 + static int bh1745_setup_triggered_buffer(struct iio_dev *indio_dev, 772 + struct device *parent, 773 + int irq) 774 + { 775 + struct bh1745_data *data = iio_priv(indio_dev); 776 + struct device *dev = data->dev; 777 + int ret; 778 + 779 + ret = devm_iio_triggered_buffer_setup(parent, indio_dev, NULL, 780 + bh1745_trigger_handler, NULL); 781 + if (ret) 782 + return dev_err_probe(dev, ret, 783 + "Triggered buffer setup failed\n"); 784 + 785 + if (irq) { 786 + ret = devm_request_threaded_irq(dev, irq, NULL, 787 + bh1745_interrupt_handler, 788 + IRQF_ONESHOT, 789 + "bh1745_interrupt", indio_dev); 790 + if (ret) 791 + return dev_err_probe(dev, ret, 792 + "Request for IRQ failed\n"); 793 + } 794 + 795 + return 0; 796 + } 797 + 798 + static int bh1745_init(struct bh1745_data *data) 799 + { 800 + int ret; 801 + struct device *dev = data->dev; 802 + 803 + mutex_init(&data->lock); 804 + 805 + ret = devm_iio_init_iio_gts(dev, BH1745_MAX_GAIN, 0, bh1745_gain, 806 + ARRAY_SIZE(bh1745_gain), bh1745_itimes, 807 + ARRAY_SIZE(bh1745_itimes), &data->gts); 808 + if (ret) 809 + return ret; 810 + 811 + ret = bh1745_reset(data); 812 + if (ret) 813 + return dev_err_probe(dev, ret, "Failed to reset sensor\n"); 814 + 815 + ret = bh1745_power_on(data); 816 + if (ret) 817 + return dev_err_probe(dev, ret, "Failed to turn on sensor\n"); 818 + 819 + ret = devm_add_action_or_reset(dev, bh1745_power_off, data); 820 + if (ret) 821 + return dev_err_probe(dev, ret, 822 + "Failed to add action or reset\n"); 823 + 824 + return 0; 825 + } 826 + 827 + static int bh1745_probe(struct i2c_client *client) 828 + { 829 + int ret; 830 + int value; 831 + int part_id; 832 + struct bh1745_data *data; 833 + struct iio_dev *indio_dev; 834 + struct device *dev = &client->dev; 835 + 836 + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 837 + if (!indio_dev) 838 + return -ENOMEM; 839 + 840 + indio_dev->info = &bh1745_info; 841 + indio_dev->name = "bh1745"; 842 + indio_dev->channels = bh1745_channels; 843 + indio_dev->modes = INDIO_DIRECT_MODE; 844 + indio_dev->num_channels = ARRAY_SIZE(bh1745_channels); 845 + data = iio_priv(indio_dev); 846 + data->dev = &client->dev; 847 + data->regmap = devm_regmap_init_i2c(client, &bh1745_regmap); 848 + if (IS_ERR(data->regmap)) 849 + return dev_err_probe(dev, PTR_ERR(data->regmap), 850 + "Failed to initialize Regmap\n"); 851 + 852 + ret = regmap_read(data->regmap, BH1745_SYS_CTRL, &value); 853 + if (ret) 854 + return ret; 855 + 856 + part_id = FIELD_GET(BH1745_SYS_CTRL_PART_ID_MASK, value); 857 + if (part_id != BH1745_PART_ID) 858 + dev_warn(dev, "Unknown part ID 0x%x\n", part_id); 859 + 860 + ret = devm_regulator_get_enable(dev, "vdd"); 861 + if (ret) 862 + return dev_err_probe(dev, ret, 863 + "Failed to get and enable regulator\n"); 864 + 865 + ret = bh1745_init(data); 866 + if (ret) 867 + return ret; 868 + 869 + ret = bh1745_setup_triggered_buffer(indio_dev, indio_dev->dev.parent, 870 + client->irq); 871 + if (ret) 872 + return ret; 873 + 874 + ret = devm_iio_device_register(dev, indio_dev); 875 + if (ret) 876 + return dev_err_probe(dev, ret, "Failed to register device\n"); 877 + 878 + return 0; 879 + } 880 + 881 + static const struct i2c_device_id bh1745_idtable[] = { 882 + { "bh1745" }, 883 + { } 884 + }; 885 + MODULE_DEVICE_TABLE(i2c, bh1745_idtable); 886 + 887 + static const struct of_device_id bh1745_of_match[] = { 888 + { .compatible = "rohm,bh1745" }, 889 + { } 890 + }; 891 + MODULE_DEVICE_TABLE(of, bh1745_of_match); 892 + 893 + static struct i2c_driver bh1745_driver = { 894 + .driver = { 895 + .name = "bh1745", 896 + .of_match_table = bh1745_of_match, 897 + }, 898 + .probe = bh1745_probe, 899 + .id_table = bh1745_idtable, 900 + }; 901 + module_i2c_driver(bh1745_driver); 902 + 903 + MODULE_LICENSE("GPL"); 904 + MODULE_AUTHOR("Mudit Sharma <muditsharma.info@gmail.com>"); 905 + MODULE_DESCRIPTION("BH1745 colour sensor driver"); 906 + MODULE_IMPORT_NS(IIO_GTS_HELPER);