These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / iio / light / isl29018.c
index a348918..bbf7e35 100644 (file)
 #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;
        struct mutex            lock;
        int                     type;
-       unsigned int            lux_scale;
-       unsigned int            lux_uscale;
-       unsigned int            range;
-       unsigned int            adc_bit;
+       unsigned int            calibscale;
+       unsigned int            ucalibscale;
+       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;
+       int i, ret;
+       unsigned int int_time, new_int_time;
 
-       for (i = 0; i < ARRAY_SIZE(supp_ranges); ++i) {
-               if (range <= supp_ranges[i]) {
-                       *new_range = (unsigned int)supp_ranges[i];
+       for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) {
+               if (utime == isl29018_int_utimes[chip->type][i]) {
+                       new_int_time = i;
                        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)
@@ -156,22 +211,17 @@ 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.
-        * lux_uscale 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->lux_scale;
-       lux_unshifted += data_x_range / 1000 * chip->lux_uscale / 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;
 }
@@ -229,86 +279,37 @@ static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme,
        return 0;
 }
 
-/* Sysfs interface */
-/* range */
-static ssize_t show_range(struct device *dev,
+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;
 
-       return sprintf(buf, "%u\n", chip->range);
-}
+       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);
 
-static ssize_t store_range(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct isl29018_chip *chip = iio_priv(indio_dev);
-       int status;
-       unsigned long lval;
-       unsigned int new_range;
-
-       if (kstrtoul(buf, 10, &lval))
-               return -EINVAL;
+       buf[len - 1] = '\n';
 
-       if (!(lval == 1000UL || lval == 4000UL ||
-                       lval == 16000UL || lval == 64000UL)) {
-               dev_err(dev, "The range is not supported\n");
-               return -EINVAL;
-       }
-
-       mutex_lock(&chip->lock);
-       status = isl29018_set_range(chip, lval, &new_range);
-       if (status < 0) {
-               mutex_unlock(&chip->lock);
-               dev_err(dev,
-                       "Error in setting max range with err %d\n", status);
-               return status;
-       }
-       chip->range = new_range;
-       mutex_unlock(&chip->lock);
-
-       return count;
+       return len;
 }
 
-/* resolution */
-static ssize_t show_resolution(struct device *dev,
+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;
 
-       return sprintf(buf, "%u\n", chip->adc_bit);
-}
-
-static ssize_t store_resolution(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct isl29018_chip *chip = iio_priv(indio_dev);
-       int status;
-       unsigned int val;
-       unsigned int new_adc_bit;
-
-       if (kstrtouint(buf, 10, &val))
-               return -EINVAL;
-       if (!(val == 4 || val == 8 || val == 12 || val == 16)) {
-               dev_err(dev, "The resolution is not supported\n");
-               return -EINVAL;
-       }
+       for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i)
+               len += sprintf(buf + len, "0.%06d ",
+                              isl29018_int_utimes[chip->type][i]);
 
-       mutex_lock(&chip->lock);
-       status = isl29018_set_resolution(chip, val, &new_adc_bit);
-       if (status < 0) {
-               mutex_unlock(&chip->lock);
-               dev_err(dev, "Error in setting resolution\n");
-               return status;
-       }
-       chip->adc_bit = new_adc_bit;
-       mutex_unlock(&chip->lock);
+       buf[len - 1] = '\n';
 
-       return count;
+       return len;
 }
 
 /* proximity scheme */
@@ -357,11 +358,29 @@ static int isl29018_write_raw(struct iio_dev *indio_dev,
        int ret = -EINVAL;
 
        mutex_lock(&chip->lock);
-       if (mask == IIO_CHAN_INFO_CALIBSCALE && chan->type == IIO_LIGHT) {
-               chip->lux_scale = val;
-               /* With no write_raw_get_fmt(), val2 is a MICRO fraction. */
-               chip->lux_uscale = 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) {
+                               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);
 
@@ -402,10 +421,24 @@ static int isl29018_read_raw(struct iio_dev *indio_dev,
                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->lux_scale;
-                       *val2 = chip->lux_uscale;
+                       *val = chip->calibscale;
+                       *val2 = chip->ucalibscale;
                        ret = IIO_VAL_INT_PLUS_MICRO;
                }
                break;
@@ -421,7 +454,9 @@ static int isl29018_read_raw(struct iio_dev *indio_dev,
        .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 {                                          \
@@ -447,32 +482,27 @@ static const struct iio_chan_spec isl29023_channels[] = {
        ISL29018_IR_CHANNEL,
 };
 
-static IIO_DEVICE_ATTR(range, S_IRUGO | S_IWUSR, show_range, store_range, 0);
-static IIO_CONST_ATTR(range_available, "1000 4000 16000 64000");
-static IIO_CONST_ATTR(adc_resolution_available, "4 8 12 16");
-static IIO_DEVICE_ATTR(adc_resolution, S_IRUGO | S_IWUSR,
-                                       show_resolution, store_resolution, 0);
+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(range),
-       ISL29018_CONST_ATTR(range_available),
-       ISL29018_DEV_ATTR(adc_resolution),
-       ISL29018_CONST_ATTR(adc_resolution_available),
+       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(range),
-       ISL29018_CONST_ATTR(range_available),
-       ISL29018_DEV_ATTR(adc_resolution),
-       ISL29018_CONST_ATTR(adc_resolution_available),
+       ISL29018_DEV_ATTR(in_illuminance_scale_available),
+       ISL29018_DEV_ATTR(in_illuminance_integration_time_available),
        NULL
 };
 
@@ -516,8 +546,6 @@ enum {
 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);
@@ -566,14 +594,19 @@ static int isl29018_chip_init(struct isl29018_chip *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;
 }
@@ -681,7 +714,7 @@ static int isl29018_probe(struct i2c_client *client,
        int dev_id = 0;
 
        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
-       if (indio_dev == NULL) {
+       if (!indio_dev) {
                dev_err(&client->dev, "iio allocation fails\n");
                return -ENOMEM;
        }
@@ -701,10 +734,10 @@ static int isl29018_probe(struct i2c_client *client,
        mutex_init(&chip->lock);
 
        chip->type = dev_id;
-       chip->lux_scale = 1;
-       chip->lux_uscale = 0;
-       chip->range = 1000;
-       chip->adc_bit = 16;
+       chip->calibscale = 1;
+       chip->ucalibscale = 0;
+       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,
@@ -803,7 +836,6 @@ static struct i2c_driver isl29018_driver = {
                        .name = "isl29018",
                        .acpi_match_table = ACPI_PTR(isl29018_acpi_match),
                        .pm = ISL29018_PM_OPS,
-                       .owner = THIS_MODULE,
                        .of_match_table = isl29018_of_match,
                    },
        .probe   = isl29018_probe,