--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ROHM BH1745 digital colour sensor driver
+ *
+ * Copyright (C) Mudit Sharma <muditsharma.info@gmail.com>
+ *
+ * 7-bit I2C slave addresses:
+ *  0x38 (ADDR pin low)
+ *  0x39 (ADDR pin high)
+ */
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/util_macros.h>
+#include <linux/iio/events.h>
+#include <linux/regmap.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/iio-gts-helper.h>
+
+/* BH1745 configuration registers */
+
+/* System control */
+#define BH1745_SYS_CTRL 0x40
+#define BH1745_SYS_CTRL_SW_RESET BIT(7)
+#define BH1745_SYS_CTRL_INTR_RESET BIT(6)
+#define BH1745_SYS_CTRL_PART_ID_MASK GENMASK(5, 0)
+#define BH1745_PART_ID 0x0B
+
+/* Mode control 1 */
+#define BH1745_MODE_CTRL1 0x41
+#define BH1745_CTRL1_MEASUREMENT_TIME_MASK GENMASK(2, 0)
+
+/* Mode control 2 */
+#define BH1745_MODE_CTRL2 0x42
+#define BH1745_CTRL2_RGBC_EN BIT(4)
+#define BH1745_CTRL2_ADC_GAIN_MASK GENMASK(1, 0)
+
+/* Interrupt */
+#define BH1745_INTR 0x60
+#define BH1745_INTR_STATUS BIT(7)
+#define BH1745_INTR_SOURCE_MASK GENMASK(3, 2)
+#define BH1745_INTR_ENABLE BIT(0)
+
+#define BH1745_PERSISTENCE 0x61
+
+/* Threshold high */
+#define BH1745_TH_LSB 0x62
+#define BH1745_TH_MSB 0x63
+
+/* Threshold low */
+#define BH1745_TL_LSB 0x64
+#define BH1745_TL_MSB 0x65
+
+/* BH1745 data output regs */
+#define BH1745_RED_LSB 0x50
+#define BH1745_RED_MSB 0x51
+#define BH1745_GREEN_LSB 0x52
+#define BH1745_GREEN_MSB 0x53
+#define BH1745_BLUE_LSB 0x54
+#define BH1745_BLUE_MSB 0x55
+#define BH1745_CLEAR_LSB 0x56
+#define BH1745_CLEAR_MSB 0x57
+
+#define BH1745_MANU_ID_REG 0x92
+
+/* From 16x max HW gain and 32x max integration time */
+#define BH1745_MAX_GAIN 512
+
+enum bh1745_int_source {
+       BH1745_INTR_SOURCE_RED,
+       BH1745_INTR_SOURCE_GREEN,
+       BH1745_INTR_SOURCE_BLUE,
+       BH1745_INTR_SOURCE_CLEAR,
+};
+
+enum bh1745_gain {
+       BH1745_ADC_GAIN_1X,
+       BH1745_ADC_GAIN_2X,
+       BH1745_ADC_GAIN_16X,
+};
+
+enum bh1745_measurement_time {
+       BH1745_MEASUREMENT_TIME_160MS,
+       BH1745_MEASUREMENT_TIME_320MS,
+       BH1745_MEASUREMENT_TIME_640MS,
+       BH1745_MEASUREMENT_TIME_1280MS,
+       BH1745_MEASUREMENT_TIME_2560MS,
+       BH1745_MEASUREMENT_TIME_5120MS,
+};
+
+enum bh1745_presistence_value {
+       BH1745_PRESISTENCE_UPDATE_TOGGLE,
+       BH1745_PRESISTENCE_UPDATE_EACH_MEASUREMENT,
+       BH1745_PRESISTENCE_UPDATE_FOUR_MEASUREMENT,
+       BH1745_PRESISTENCE_UPDATE_EIGHT_MEASUREMENT,
+};
+
+static const struct iio_gain_sel_pair bh1745_gain[] = {
+       GAIN_SCALE_GAIN(1, BH1745_ADC_GAIN_1X),
+       GAIN_SCALE_GAIN(2, BH1745_ADC_GAIN_2X),
+       GAIN_SCALE_GAIN(16, BH1745_ADC_GAIN_16X),
+};
+
+static const struct iio_itime_sel_mul bh1745_itimes[] = {
+       GAIN_SCALE_ITIME_US(5120000, BH1745_MEASUREMENT_TIME_5120MS, 32),
+       GAIN_SCALE_ITIME_US(2560000, BH1745_MEASUREMENT_TIME_2560MS, 16),
+       GAIN_SCALE_ITIME_US(1280000, BH1745_MEASUREMENT_TIME_1280MS, 8),
+       GAIN_SCALE_ITIME_US(640000, BH1745_MEASUREMENT_TIME_640MS, 4),
+       GAIN_SCALE_ITIME_US(320000, BH1745_MEASUREMENT_TIME_320MS, 2),
+       GAIN_SCALE_ITIME_US(160000, BH1745_MEASUREMENT_TIME_160MS, 1),
+};
+
+struct bh1745_data {
+       /*
+        * Lock to prevent device setting update or read before
+        * related calculations are completed
+        */
+       struct mutex lock;
+       struct regmap *regmap;
+       struct device *dev;
+       struct iio_trigger *trig;
+       struct iio_gts gts;
+};
+
+static const struct regmap_range bh1745_volatile_ranges[] = {
+       regmap_reg_range(BH1745_MODE_CTRL2, BH1745_MODE_CTRL2), /* VALID */
+       regmap_reg_range(BH1745_RED_LSB, BH1745_CLEAR_MSB), /* Data */
+       regmap_reg_range(BH1745_INTR, BH1745_INTR), /* Interrupt */
+};
+
+static const struct regmap_access_table bh1745_volatile_regs = {
+       .yes_ranges = bh1745_volatile_ranges,
+       .n_yes_ranges = ARRAY_SIZE(bh1745_volatile_ranges),
+};
+
+static const struct regmap_range bh1745_readable_ranges[] = {
+       regmap_reg_range(BH1745_SYS_CTRL, BH1745_MODE_CTRL2),
+       regmap_reg_range(BH1745_RED_LSB, BH1745_CLEAR_MSB),
+       regmap_reg_range(BH1745_INTR, BH1745_INTR),
+       regmap_reg_range(BH1745_PERSISTENCE, BH1745_TL_MSB),
+       regmap_reg_range(BH1745_MANU_ID_REG, BH1745_MANU_ID_REG),
+};
+
+static const struct regmap_access_table bh1745_readable_regs = {
+       .yes_ranges = bh1745_readable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(bh1745_readable_ranges),
+};
+
+static const struct regmap_range bh1745_writable_ranges[] = {
+       regmap_reg_range(BH1745_SYS_CTRL, BH1745_MODE_CTRL2),
+       regmap_reg_range(BH1745_INTR, BH1745_INTR),
+       regmap_reg_range(BH1745_PERSISTENCE, BH1745_TL_MSB),
+};
+
+static const struct regmap_access_table bh1745_writable_regs = {
+       .yes_ranges = bh1745_writable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(bh1745_writable_ranges),
+};
+
+static const struct regmap_config bh1745_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = BH1745_MANU_ID_REG,
+       .cache_type = REGCACHE_RBTREE,
+       .volatile_table = &bh1745_volatile_regs,
+       .wr_table = &bh1745_writable_regs,
+       .rd_table = &bh1745_readable_regs,
+};
+
+static const struct iio_event_spec bh1745_event_spec[] = {
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_RISING,
+               .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
+       },
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_FALLING,
+               .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
+       },
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_EITHER,
+               .mask_shared_by_type = BIT(IIO_EV_INFO_PERIOD),
+               .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+       },
+};
+
+#define BH1745_CHANNEL(_colour, _si, _addr)                             \
+       {                                                               \
+               .type = IIO_INTENSITY, .modified = 1,                   \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |   \
+                                          BIT(IIO_CHAN_INFO_INT_TIME), \
+               .info_mask_shared_by_all_available =                    \
+                       BIT(IIO_CHAN_INFO_SCALE) |                      \
+                       BIT(IIO_CHAN_INFO_INT_TIME),                    \
+               .event_spec = bh1745_event_spec,                        \
+               .num_event_specs = ARRAY_SIZE(bh1745_event_spec),       \
+               .channel2 = IIO_MOD_LIGHT_##_colour, .address = _addr,  \
+               .scan_index = _si,                                      \
+               .scan_type = {                                          \
+                       .sign = 'u',                                    \
+                       .realbits = 16,                                 \
+                       .storagebits = 16,                              \
+                       .endianness = IIO_CPU,                          \
+               },                                                      \
+       }
+
+static const struct iio_chan_spec bh1745_channels[] = {
+       BH1745_CHANNEL(RED, 0, BH1745_RED_LSB),
+       BH1745_CHANNEL(GREEN, 1, BH1745_GREEN_LSB),
+       BH1745_CHANNEL(BLUE, 2, BH1745_BLUE_LSB),
+       BH1745_CHANNEL(CLEAR, 3, BH1745_CLEAR_LSB),
+       IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static int bh1745_reset(struct bh1745_data *data)
+{
+       return regmap_set_bits(data->regmap, BH1745_SYS_CTRL,
+                              BH1745_SYS_CTRL_SW_RESET |
+                              BH1745_SYS_CTRL_INTR_RESET);
+}
+
+static int bh1745_power_on(struct bh1745_data *data)
+{
+       return regmap_set_bits(data->regmap, BH1745_MODE_CTRL2,
+                              BH1745_CTRL2_RGBC_EN);
+}
+
+static void bh1745_power_off(void *data_ptr)
+{
+       struct bh1745_data *data = data_ptr;
+       struct device *dev = data->dev;
+       int ret;
+
+       ret = regmap_clear_bits(data->regmap, BH1745_MODE_CTRL2,
+                               BH1745_CTRL2_RGBC_EN);
+       if (ret)
+               dev_err(dev, "Failed to turn off device\n");
+}
+
+static int bh1745_get_scale(struct bh1745_data *data, int *val, int *val2)
+{
+       int ret;
+       int value;
+       int gain_sel, int_time_sel;
+       int gain;
+       const struct iio_itime_sel_mul *int_time;
+
+       ret = regmap_read(data->regmap, BH1745_MODE_CTRL2, &value);
+       if (ret)
+               return ret;
+
+       gain_sel = FIELD_GET(BH1745_CTRL2_ADC_GAIN_MASK, value);
+       gain = iio_gts_find_gain_by_sel(&data->gts, gain_sel);
+
+       ret = regmap_read(data->regmap, BH1745_MODE_CTRL1, &value);
+       if (ret)
+               return ret;
+
+       int_time_sel = FIELD_GET(BH1745_CTRL1_MEASUREMENT_TIME_MASK, value);
+       int_time = iio_gts_find_itime_by_sel(&data->gts, int_time_sel);
+
+       return iio_gts_get_scale(&data->gts, gain, int_time->time_us, val,
+                                val2);
+}
+
+static int bh1745_set_scale(struct bh1745_data *data, int val)
+{
+       struct device *dev = data->dev;
+       int ret;
+       int value;
+       int hw_gain_sel, current_int_time_sel, new_int_time_sel;
+
+       ret = regmap_read(data->regmap, BH1745_MODE_CTRL1, &value);
+       if (ret)
+               return ret;
+
+       current_int_time_sel = FIELD_GET(BH1745_CTRL1_MEASUREMENT_TIME_MASK,
+                                        value);
+       ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts,
+                                                        current_int_time_sel,
+                                                        val, 0, &hw_gain_sel);
+       if (ret) {
+               for (int i = 0; i < data->gts.num_itime; i++) {
+                       new_int_time_sel = data->gts.itime_table[i].sel;
+
+                       if (new_int_time_sel == current_int_time_sel)
+                               continue;
+
+                       ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts,
+                                                                        new_int_time_sel,
+                                                                        val, 0,
+                                                                        &hw_gain_sel);
+                       if (!ret)
+                               break;
+               }
+
+               if (ret) {
+                       dev_dbg(dev, "Unsupported scale value requested: %d\n",
+                               val);
+                       return -EINVAL;
+               }
+
+               ret = regmap_write_bits(data->regmap, BH1745_MODE_CTRL1,
+                                       BH1745_CTRL1_MEASUREMENT_TIME_MASK,
+                                       new_int_time_sel);
+               if (ret)
+                       return ret;
+       }
+
+       return regmap_write_bits(data->regmap, BH1745_MODE_CTRL2,
+                                BH1745_CTRL2_ADC_GAIN_MASK, hw_gain_sel);
+}
+
+static int bh1745_get_int_time(struct bh1745_data *data, int *val)
+{
+       int ret;
+       int value;
+       int int_time, int_time_sel;
+
+       ret = regmap_read(data->regmap, BH1745_MODE_CTRL1, &value);
+       if (ret)
+               return ret;
+
+       int_time_sel = FIELD_GET(BH1745_CTRL1_MEASUREMENT_TIME_MASK, value);
+       int_time = iio_gts_find_int_time_by_sel(&data->gts, int_time_sel);
+       if (int_time < 0)
+               return int_time;
+
+       *val = int_time;
+
+       return 0;
+}
+
+static int bh1745_set_int_time(struct bh1745_data *data, int val, int val2)
+{
+       struct device *dev = data->dev;
+       int ret;
+       int value;
+       int current_int_time, current_hwgain_sel, current_hwgain;
+       int new_hwgain, new_hwgain_sel, new_int_time_sel;
+       int req_int_time = (1000000 * val) + val2;
+
+       if (!iio_gts_valid_time(&data->gts, req_int_time)) {
+               dev_dbg(dev, "Unsupported integration time requested: %d\n",
+                       req_int_time);
+               return -EINVAL;
+       }
+
+       ret = bh1745_get_int_time(data, ¤t_int_time);
+       if (ret)
+               return ret;
+
+       if (current_int_time == req_int_time)
+               return 0;
+
+       ret = regmap_read(data->regmap, BH1745_MODE_CTRL2, &value);
+       if (ret)
+               return ret;
+
+       current_hwgain_sel = FIELD_GET(BH1745_CTRL2_ADC_GAIN_MASK, value);
+       current_hwgain = iio_gts_find_gain_by_sel(&data->gts,
+                                                 current_hwgain_sel);
+       ret = iio_gts_find_new_gain_by_old_gain_time(&data->gts, current_hwgain,
+                                                    current_int_time,
+                                                    req_int_time,
+                                                    &new_hwgain);
+       if (new_hwgain < 0) {
+               dev_dbg(dev, "No corresponding gain for requested integration time\n");
+               return ret;
+       }
+
+       if (ret) {
+               bool in_range;
+
+               new_hwgain = iio_find_closest_gain_low(&data->gts, new_hwgain,
+                                                      &in_range);
+               if (new_hwgain < 0) {
+                       new_hwgain = iio_gts_get_min_gain(&data->gts);
+                       if (new_hwgain < 0)
+                               return ret;
+               }
+
+               if (!in_range)
+                       dev_dbg(dev, "Optimal gain out of range\n");
+
+               dev_dbg(dev, "Scale changed, new hw_gain %d\n", new_hwgain);
+       }
+
+       new_hwgain_sel = iio_gts_find_sel_by_gain(&data->gts, new_hwgain);
+       if (new_hwgain_sel < 0)
+               return new_hwgain_sel;
+
+       ret = regmap_write_bits(data->regmap, BH1745_MODE_CTRL2,
+                               BH1745_CTRL2_ADC_GAIN_MASK,
+                               new_hwgain_sel);
+       if (ret)
+               return ret;
+
+       new_int_time_sel = iio_gts_find_sel_by_int_time(&data->gts,
+                                                       req_int_time);
+       if (new_int_time_sel < 0)
+               return new_int_time_sel;
+
+       return regmap_write_bits(data->regmap, BH1745_MODE_CTRL1,
+                                BH1745_CTRL1_MEASUREMENT_TIME_MASK,
+                                new_int_time_sel);
+}
+
+static int bh1745_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct bh1745_data *data = iio_priv(indio_dev);
+       int ret;
+       int value;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+                       ret = regmap_bulk_read(data->regmap, chan->address,
+                                              &value, 2);
+                       if (ret)
+                               return ret;
+                       *val = value;
+
+                       return IIO_VAL_INT;
+               }
+               unreachable();
+
+       case IIO_CHAN_INFO_SCALE: {
+                       guard(mutex)(&data->lock);
+                       ret = bh1745_get_scale(data, val, val2);
+                       if (ret)
+                               return ret;
+
+                       return IIO_VAL_INT;
+               }
+
+       case IIO_CHAN_INFO_INT_TIME: {
+                       guard(mutex)(&data->lock);
+                       *val = 0;
+                       ret = bh1745_get_int_time(data, val2);
+                       if (ret)
+                               return 0;
+
+                       return IIO_VAL_INT_PLUS_MICRO;
+               }
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bh1745_write_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int val, int val2, long mask)
+{
+       struct bh1745_data *data = iio_priv(indio_dev);
+
+       guard(mutex)(&data->lock);
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               return bh1745_set_scale(data, val);
+
+       case IIO_CHAN_INFO_INT_TIME:
+               return bh1745_set_int_time(data, val, val2);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bh1745_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                   struct iio_chan_spec const *chan,
+                                   long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_INT_TIME:
+               return IIO_VAL_INT_PLUS_MICRO;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bh1745_read_thresh(struct iio_dev *indio_dev,
+                             const struct iio_chan_spec *chan,
+                             enum iio_event_type type,
+                             enum iio_event_direction dir,
+                             enum iio_event_info info, int *val, int *val2)
+{
+       struct bh1745_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       ret = regmap_bulk_read(data->regmap, BH1745_TH_LSB,
+                                              val, 2);
+                       if (ret)
+                               return ret;
+
+                       return IIO_VAL_INT;
+
+               case IIO_EV_DIR_FALLING:
+                       ret = regmap_bulk_read(data->regmap, BH1745_TL_LSB,
+                                              val, 2);
+                       if (ret)
+                               return ret;
+
+                       return IIO_VAL_INT;
+
+               default:
+                       return -EINVAL;
+               }
+
+       case IIO_EV_INFO_PERIOD:
+               ret = regmap_read(data->regmap, BH1745_PERSISTENCE, val);
+               if (ret)
+                       return ret;
+
+               return IIO_VAL_INT;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bh1745_write_thresh(struct iio_dev *indio_dev,
+                              const struct iio_chan_spec *chan,
+                              enum iio_event_type type,
+                              enum iio_event_direction dir,
+                              enum iio_event_info info, int val, int val2)
+{
+       struct bh1745_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               if (val < 0x0 || val > 0xFFFF)
+                       return -EINVAL;
+
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       ret = regmap_bulk_write(data->regmap, BH1745_TH_LSB,
+                                               &val, 2);
+                       if (ret)
+                               return ret;
+
+                       return IIO_VAL_INT;
+
+               case IIO_EV_DIR_FALLING:
+                       ret = regmap_bulk_write(data->regmap, BH1745_TL_LSB,
+                                               &val, 2);
+                       if (ret)
+                               return ret;
+
+                       return IIO_VAL_INT;
+
+               default:
+                       return -EINVAL;
+               }
+
+       case IIO_EV_INFO_PERIOD:
+               if (val < BH1745_PRESISTENCE_UPDATE_TOGGLE ||
+                   val > BH1745_PRESISTENCE_UPDATE_EIGHT_MEASUREMENT)
+                       return -EINVAL;
+               ret = regmap_write(data->regmap, BH1745_PERSISTENCE, val);
+               if (ret)
+                       return ret;
+
+               return IIO_VAL_INT;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bh1745_read_event_config(struct iio_dev *indio_dev,
+                                   const struct iio_chan_spec *chan,
+                                   enum iio_event_type type,
+                                   enum iio_event_direction dir)
+{
+       struct bh1745_data *data = iio_priv(indio_dev);
+       int ret;
+       int value;
+       int int_src;
+
+       ret = regmap_read(data->regmap, BH1745_INTR, &value);
+       if (ret)
+               return ret;
+
+       if (!FIELD_GET(BH1745_INTR_ENABLE, value))
+               return 0;
+
+       int_src = FIELD_GET(BH1745_INTR_SOURCE_MASK, value);
+
+       switch (chan->channel2) {
+       case IIO_MOD_LIGHT_RED:
+               if (int_src == BH1745_INTR_SOURCE_RED)
+                       return 1;
+               return 0;
+
+       case IIO_MOD_LIGHT_GREEN:
+               if (int_src == BH1745_INTR_SOURCE_GREEN)
+                       return 1;
+               return 0;
+
+       case IIO_MOD_LIGHT_BLUE:
+               if (int_src == BH1745_INTR_SOURCE_BLUE)
+                       return 1;
+               return 0;
+
+       case IIO_MOD_LIGHT_CLEAR:
+               if (int_src == BH1745_INTR_SOURCE_CLEAR)
+                       return 1;
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int bh1745_write_event_config(struct iio_dev *indio_dev,
+                                    const struct iio_chan_spec *chan,
+                                    enum iio_event_type type,
+                                    enum iio_event_direction dir, int state)
+{
+       struct bh1745_data *data = iio_priv(indio_dev);
+       int value;
+
+       if (state == 0)
+               return regmap_clear_bits(data->regmap,
+                                        BH1745_INTR, BH1745_INTR_ENABLE);
+
+       if (state == 1) {
+               /* Latch is always enabled when enabling interrupt */
+               value = BH1745_INTR_ENABLE;
+
+               switch (chan->channel2) {
+               case IIO_MOD_LIGHT_RED:
+                       return regmap_write(data->regmap, BH1745_INTR,
+                                           value | FIELD_PREP(BH1745_INTR_SOURCE_MASK,
+                                                              BH1745_INTR_SOURCE_RED));
+
+               case IIO_MOD_LIGHT_GREEN:
+                       return regmap_write(data->regmap, BH1745_INTR,
+                                           value | FIELD_PREP(BH1745_INTR_SOURCE_MASK,
+                                                              BH1745_INTR_SOURCE_GREEN));
+
+               case IIO_MOD_LIGHT_BLUE:
+                       return regmap_write(data->regmap, BH1745_INTR,
+                                           value | FIELD_PREP(BH1745_INTR_SOURCE_MASK,
+                                                              BH1745_INTR_SOURCE_BLUE));
+
+               case IIO_MOD_LIGHT_CLEAR:
+                       return regmap_write(data->regmap, BH1745_INTR,
+                                           value | FIELD_PREP(BH1745_INTR_SOURCE_MASK,
+                                                              BH1745_INTR_SOURCE_CLEAR));
+
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int bh1745_read_avail(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan, const int **vals,
+                            int *type, int *length, long mask)
+{
+       struct bh1745_data *data = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_INT_TIME:
+               return iio_gts_avail_times(&data->gts, vals, type, length);
+
+       case IIO_CHAN_INFO_SCALE:
+               return iio_gts_all_avail_scales(&data->gts, vals, type, length);
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info bh1745_info = {
+       .read_raw = bh1745_read_raw,
+       .write_raw = bh1745_write_raw,
+       .write_raw_get_fmt = bh1745_write_raw_get_fmt,
+       .read_event_value = bh1745_read_thresh,
+       .write_event_value = bh1745_write_thresh,
+       .read_event_config = bh1745_read_event_config,
+       .write_event_config = bh1745_write_event_config,
+       .read_avail = bh1745_read_avail,
+};
+
+static irqreturn_t bh1745_interrupt_handler(int interrupt, void *p)
+{
+       struct iio_dev *indio_dev = p;
+       struct bh1745_data *data = iio_priv(indio_dev);
+       int ret;
+       int value;
+       int int_src;
+
+       ret = regmap_read(data->regmap, BH1745_INTR, &value);
+       if (ret)
+               return IRQ_NONE;
+
+       int_src = FIELD_GET(BH1745_INTR_SOURCE_MASK, value);
+
+       if (value & BH1745_INTR_STATUS) {
+               iio_push_event(indio_dev,
+                              IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, int_src,
+                                                   IIO_EV_TYPE_THRESH,
+                                                   IIO_EV_DIR_EITHER),
+                              iio_get_time_ns(indio_dev));
+
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static irqreturn_t bh1745_trigger_handler(int interrupt, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct bh1745_data *data = iio_priv(indio_dev);
+       struct {
+               u16 chans[4];
+               s64 timestamp __aligned(8);
+       } scan;
+       u16 value;
+       int ret;
+       int i;
+       int j = 0;
+
+       iio_for_each_active_channel(indio_dev, i) {
+               ret = regmap_bulk_read(data->regmap, BH1745_RED_LSB + 2 * i,
+                                      &value, 2);
+               if (ret)
+                       goto err;
+
+               scan.chans[j++] = value;
+       }
+
+       iio_push_to_buffers_with_timestamp(indio_dev, &scan,
+                                          iio_get_time_ns(indio_dev));
+
+err:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int bh1745_setup_triggered_buffer(struct iio_dev *indio_dev,
+                                        struct device *parent,
+                                        int irq)
+{
+       struct bh1745_data *data = iio_priv(indio_dev);
+       struct device *dev = data->dev;
+       int ret;
+
+       ret = devm_iio_triggered_buffer_setup(parent, indio_dev, NULL,
+                                             bh1745_trigger_handler, NULL);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Triggered buffer setup failed\n");
+
+       if (irq) {
+               ret = devm_request_threaded_irq(dev, irq, NULL,
+                                               bh1745_interrupt_handler,
+                                               IRQF_ONESHOT,
+                                               "bh1745_interrupt", indio_dev);
+               if (ret)
+                       return dev_err_probe(dev, ret,
+                                            "Request for IRQ failed\n");
+       }
+
+       return 0;
+}
+
+static int bh1745_init(struct bh1745_data *data)
+{
+       int ret;
+       struct device *dev = data->dev;
+
+       mutex_init(&data->lock);
+
+       ret = devm_iio_init_iio_gts(dev, BH1745_MAX_GAIN, 0, bh1745_gain,
+                                   ARRAY_SIZE(bh1745_gain), bh1745_itimes,
+                                   ARRAY_SIZE(bh1745_itimes), &data->gts);
+       if (ret)
+               return ret;
+
+       ret = bh1745_reset(data);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to reset sensor\n");
+
+       ret = bh1745_power_on(data);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to turn on sensor\n");
+
+       ret = devm_add_action_or_reset(dev, bh1745_power_off, data);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Failed to add action or reset\n");
+
+       return 0;
+}
+
+static int bh1745_probe(struct i2c_client *client)
+{
+       int ret;
+       int value;
+       int part_id;
+       struct bh1745_data *data;
+       struct iio_dev *indio_dev;
+       struct device *dev = &client->dev;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       indio_dev->info = &bh1745_info;
+       indio_dev->name = "bh1745";
+       indio_dev->channels = bh1745_channels;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->num_channels = ARRAY_SIZE(bh1745_channels);
+       data = iio_priv(indio_dev);
+       data->dev = &client->dev;
+       data->regmap = devm_regmap_init_i2c(client, &bh1745_regmap);
+       if (IS_ERR(data->regmap))
+               return dev_err_probe(dev, PTR_ERR(data->regmap),
+                                    "Failed to initialize Regmap\n");
+
+       ret = regmap_read(data->regmap, BH1745_SYS_CTRL, &value);
+       if (ret)
+               return ret;
+
+       part_id = FIELD_GET(BH1745_SYS_CTRL_PART_ID_MASK, value);
+       if (part_id != BH1745_PART_ID)
+               dev_warn(dev, "Unknown part ID 0x%x\n", part_id);
+
+       ret = devm_regulator_get_enable(dev, "vdd");
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Failed to get and enable regulator\n");
+
+       ret = bh1745_init(data);
+       if (ret)
+               return ret;
+
+       ret = bh1745_setup_triggered_buffer(indio_dev, indio_dev->dev.parent,
+                                           client->irq);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_device_register(dev, indio_dev);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to register device\n");
+
+       return 0;
+}
+
+static const struct i2c_device_id bh1745_idtable[] = {
+       { "bh1745" },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, bh1745_idtable);
+
+static const struct of_device_id bh1745_of_match[] = {
+       { .compatible = "rohm,bh1745" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, bh1745_of_match);
+
+static struct i2c_driver bh1745_driver = {
+       .driver = {
+               .name = "bh1745",
+               .of_match_table = bh1745_of_match,
+       },
+       .probe = bh1745_probe,
+       .id_table = bh1745_idtable,
+};
+module_i2c_driver(bh1745_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mudit Sharma <muditsharma.info@gmail.com>");
+MODULE_DESCRIPTION("BH1745 colour sensor driver");
+MODULE_IMPORT_NS(IIO_GTS_HELPER);