#define ISL29035_BOUT_SHIFT            0x07
 #define ISL29035_BOUT_MASK             (0x01 << ISL29035_BOUT_SHIFT)
 
+#define ISL29018_INT_TIME_AVAIL                "0.090000 0.005630 0.000351 0.000021"
+#define ISL29023_INT_TIME_AVAIL                "0.090000 0.005600 0.000352 0.000022"
+#define ISL29035_INT_TIME_AVAIL                "0.105000 0.006500 0.000410 0.000025"
+
+static const char * const int_time_avail[] = {
+       ISL29018_INT_TIME_AVAIL,
+       ISL29023_INT_TIME_AVAIL,
+       ISL29035_INT_TIME_AVAIL,
+};
+
+enum isl29018_int_time {
+       ISL29018_INT_TIME_16,
+       ISL29018_INT_TIME_12,
+       ISL29018_INT_TIME_8,
+       ISL29018_INT_TIME_4,
+};
+
+static const unsigned int isl29018_int_utimes[3][4] = {
+       {90000, 5630, 351, 21},
+       {90000, 5600, 352, 22},
+       {105000, 6500, 410, 25},
+};
+
+static const struct isl29018_scale {
+       unsigned int scale;
+       unsigned int uscale;
+} isl29018_scales[4][4] = {
+       { {0, 15258}, {0, 61035}, {0, 244140}, {0, 976562} },
+       { {0, 244140}, {0, 976562}, {3, 906250}, {15, 625000} },
+       { {3, 906250}, {15, 625000}, {62, 500000}, {250, 0} },
+       { {62, 500000}, {250, 0}, {1000, 0}, {4000, 0} }
+};
+
 struct isl29018_chip {
        struct device           *dev;
        struct regmap           *regmap;
        int                     type;
        unsigned int            calibscale;
        unsigned int            ucalibscale;
-       unsigned int            range;
-       unsigned int            adc_bit;
+       unsigned int            int_time;
+       struct isl29018_scale   scale;
        int                     prox_scheme;
        bool                    suspended;
 };
 
-static int isl29018_set_range(struct isl29018_chip *chip, unsigned long range,
-               unsigned int *new_range)
+static int isl29018_set_integration_time(struct isl29018_chip *chip,
+                                        unsigned int utime)
 {
-       static const unsigned long supp_ranges[] = {1000, 4000, 16000, 64000};
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(supp_ranges); ++i) {
-               if (range <= supp_ranges[i]) {
-                       *new_range = (unsigned int)supp_ranges[i];
+       int i, ret;
+       unsigned int int_time, new_int_time;
+       struct isl29018_scale new_scale;
+
+       for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) {
+               if (utime == isl29018_int_utimes[chip->type][i]) {
+                       new_int_time = i;
+                       new_scale = isl29018_scales[new_int_time][0];
                        break;
                }
        }
 
-       if (i >= ARRAY_SIZE(supp_ranges))
+       if (i >= ARRAY_SIZE(isl29018_int_utimes[chip->type]))
                return -EINVAL;
 
-       return regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
-                       COMMANDII_RANGE_MASK, i << COMMANDII_RANGE_SHIFT);
+       ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+                                COMMANDII_RESOLUTION_MASK,
+                                i << COMMANDII_RESOLUTION_SHIFT);
+       if (ret < 0)
+               return ret;
+
+       /* keep the same range when integration time changes */
+       int_time = chip->int_time;
+       for (i = 0; i < ARRAY_SIZE(isl29018_scales[int_time]); ++i) {
+               if (chip->scale.scale == isl29018_scales[int_time][i].scale &&
+                   chip->scale.uscale == isl29018_scales[int_time][i].uscale) {
+                       chip->scale = isl29018_scales[new_int_time][i];
+                       break;
+               }
+       }
+       chip->int_time = new_int_time;
+
+       return 0;
 }
 
-static int isl29018_set_resolution(struct isl29018_chip *chip,
-                       unsigned long adcbit, unsigned int *conf_adc_bit)
+static int isl29018_set_scale(struct isl29018_chip *chip, int scale, int uscale)
 {
-       static const unsigned long supp_adcbit[] = {16, 12, 8, 4};
-       int i;
+       int i, ret;
+       struct isl29018_scale new_scale;
 
-       for (i = 0; i < ARRAY_SIZE(supp_adcbit); ++i) {
-               if (adcbit >= supp_adcbit[i]) {
-                       *conf_adc_bit = (unsigned int)supp_adcbit[i];
+       for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) {
+               if (scale == isl29018_scales[chip->int_time][i].scale &&
+                   uscale == isl29018_scales[chip->int_time][i].uscale) {
+                       new_scale = isl29018_scales[chip->int_time][i];
                        break;
                }
        }
 
-       if (i >= ARRAY_SIZE(supp_adcbit))
+       if (i >= ARRAY_SIZE(isl29018_scales[chip->int_time]))
                return -EINVAL;
 
-       return regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
-                       COMMANDII_RESOLUTION_MASK,
-                       i << COMMANDII_RESOLUTION_SHIFT);
+       ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+                                COMMANDII_RANGE_MASK,
+                                i << COMMANDII_RANGE_SHIFT);
+       if (ret < 0)
+               return ret;
+
+       chip->scale = new_scale;
+
+       return 0;
 }
 
 static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode)
 static int isl29018_read_lux(struct isl29018_chip *chip, int *lux)
 {
        int lux_data;
-       unsigned int data_x_range, lux_unshifted;
+       unsigned int data_x_range;
 
        lux_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_ALS_ONCE);
 
        if (lux_data < 0)
                return lux_data;
 
-       /* To support fractional scaling, separate the unshifted lux
-        * into two calculations: int scaling and micro-scaling.
-        * ucalibscale ranges from 0-999999, so about 20 bits.  Split
-        * the /1,000,000 in two to reduce the risk of over/underflow.
-        */
-       data_x_range = lux_data * chip->range;
-       lux_unshifted = data_x_range * chip->calibscale;
-       lux_unshifted += data_x_range / 1000 * chip->ucalibscale / 1000;
-       *lux = lux_unshifted >> chip->adc_bit;
+       data_x_range = lux_data * chip->scale.scale +
+                      lux_data * chip->scale.uscale / 1000000;
+       *lux = data_x_range * chip->calibscale +
+              data_x_range * chip->ucalibscale / 1000000;
 
        return 0;
 }
        return 0;
 }
 
-/* Sysfs interface */
+static ssize_t show_scale_available(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct isl29018_chip *chip = iio_priv(indio_dev);
+       int i, len = 0;
+
+       for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i)
+               len += sprintf(buf + len, "%d.%06d ",
+                              isl29018_scales[chip->int_time][i].scale,
+                              isl29018_scales[chip->int_time][i].uscale);
+
+       buf[len - 1] = '\n';
+
+       return len;
+}
+
+static ssize_t show_int_time_available(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct isl29018_chip *chip = iio_priv(indio_dev);
+       int i, len = 0;
+
+       for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i)
+               len += sprintf(buf + len, "0.%06d ",
+                              isl29018_int_utimes[chip->type][i]);
+
+       buf[len - 1] = '\n';
+
+       return len;
+}
+
 /* proximity scheme */
 static ssize_t show_prox_infrared_suppression(struct device *dev,
                        struct device_attribute *attr, char *buf)
        int ret = -EINVAL;
 
        mutex_lock(&chip->lock);
-       if (mask == IIO_CHAN_INFO_CALIBSCALE && chan->type == IIO_LIGHT) {
-               chip->calibscale = val;
-               /* With no write_raw_get_fmt(), val2 is a MICRO fraction. */
-               chip->ucalibscale = val2;
-               ret = 0;
+       switch (mask) {
+       case IIO_CHAN_INFO_CALIBSCALE:
+               if (chan->type == IIO_LIGHT) {
+                       chip->calibscale = val;
+                       chip->ucalibscale = val2;
+                       ret = 0;
+               }
+               break;
+       case IIO_CHAN_INFO_INT_TIME:
+               if (chan->type == IIO_LIGHT)
+                       if (val != 0) {
+                               mutex_unlock(&chip->lock);
+                               return -EINVAL;
+                       }
+                       ret = isl29018_set_integration_time(chip, val2);
+               break;
+       case IIO_CHAN_INFO_SCALE:
+               if (chan->type == IIO_LIGHT)
+                       ret = isl29018_set_scale(chip, val, val2);
+               break;
+       default:
+               break;
        }
        mutex_unlock(&chip->lock);
 
                if (!ret)
                        ret = IIO_VAL_INT;
                break;
+       case IIO_CHAN_INFO_INT_TIME:
+               if (chan->type == IIO_LIGHT) {
+                       *val = 0;
+                       *val2 = isl29018_int_utimes[chip->type][chip->int_time];
+                       ret = IIO_VAL_INT_PLUS_MICRO;
+               }
+               break;
+       case IIO_CHAN_INFO_SCALE:
+               if (chan->type == IIO_LIGHT) {
+                       *val = chip->scale.scale;
+                       *val2 = chip->scale.uscale;
+                       ret = IIO_VAL_INT_PLUS_MICRO;
+               }
+               break;
        case IIO_CHAN_INFO_CALIBSCALE:
                if (chan->type == IIO_LIGHT) {
                        *val = chip->calibscale;
        .indexed = 1,                                                   \
        .channel = 0,                                                   \
        .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |            \
-       BIT(IIO_CHAN_INFO_CALIBSCALE),                                  \
+       BIT(IIO_CHAN_INFO_CALIBSCALE) |                                 \
+       BIT(IIO_CHAN_INFO_SCALE) |                                      \
+       BIT(IIO_CHAN_INFO_INT_TIME),                                    \
 }
 
 #define ISL29018_IR_CHANNEL {                                          \
        ISL29018_IR_CHANNEL,
 };
 
+static IIO_DEVICE_ATTR(in_illuminance_integration_time_available, S_IRUGO,
+                      show_int_time_available, NULL, 0);
+static IIO_DEVICE_ATTR(in_illuminance_scale_available, S_IRUGO,
+                     show_scale_available, NULL, 0);
 static IIO_DEVICE_ATTR(proximity_on_chip_ambient_infrared_suppression,
                                        S_IRUGO | S_IWUSR,
                                        show_prox_infrared_suppression,
                                        store_prox_infrared_suppression, 0);
 
 #define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
-#define ISL29018_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
+
 static struct attribute *isl29018_attributes[] = {
+       ISL29018_DEV_ATTR(in_illuminance_scale_available),
+       ISL29018_DEV_ATTR(in_illuminance_integration_time_available),
        ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_suppression),
        NULL
 };
 
 static struct attribute *isl29023_attributes[] = {
+       ISL29018_DEV_ATTR(in_illuminance_scale_available),
+       ISL29018_DEV_ATTR(in_illuminance_integration_time_available),
        NULL
 };
 
 static int isl29018_chip_init(struct isl29018_chip *chip)
 {
        int status;
-       unsigned int new_adc_bit;
-       unsigned int new_range;
 
        if (chip->type == isl29035) {
                status = isl29035_detect(chip);
        usleep_range(1000, 2000);       /* per data sheet, page 10 */
 
        /* set defaults */
-       status = isl29018_set_range(chip, chip->range, &new_range);
+       status = isl29018_set_scale(chip, chip->scale.scale,
+                                   chip->scale.uscale);
        if (status < 0) {
                dev_err(chip->dev, "Init of isl29018 fails\n");
                return status;
        }
 
-       status = isl29018_set_resolution(chip, chip->adc_bit,
-                                               &new_adc_bit);
+       status = isl29018_set_integration_time(chip,
+                       isl29018_int_utimes[chip->type][chip->int_time]);
+       if (status < 0) {
+               dev_err(chip->dev, "Init of isl29018 fails\n");
+               return status;
+       }
 
        return 0;
 }
        chip->type = dev_id;
        chip->calibscale = 1;
        chip->ucalibscale = 0;
-       chip->range = 1000;
-       chip->adc_bit = 16;
+       chip->int_time = ISL29018_INT_TIME_16;
+       chip->scale = isl29018_scales[chip->int_time][0];
        chip->suspended = false;
 
        chip->regmap = devm_regmap_init_i2c(client,