]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/staging/iio/light/tsl2583.c
staging: iio: tsl2583: convert illuminance0_calibscale sysfs attr to use iio_chan_spec
[karo-tx-linux.git] / drivers / staging / iio / light / tsl2583.c
index 08f1583ee34e92a79e3cbda3fbb5c46abfd84af9..bfff6ca54fe5b9b6562bad35d22b2040d9eaeb93 100644 (file)
@@ -124,14 +124,15 @@ static struct taos_lux taos_device_lux[11] = {
 struct gainadj {
        s16 ch0;
        s16 ch1;
+       s16 mean;
 };
 
 /* Index = (0 - 3) Used to validate the gain selection index */
 static const struct gainadj gainadj[] = {
-       { 1, 1 },
-       { 8, 8 },
-       { 16, 16 },
-       { 107, 115 }
+       { 1, 1, 1 },
+       { 8, 8, 8 },
+       { 16, 16, 16 },
+       { 107, 115, 111 }
 };
 
 /*
@@ -171,7 +172,14 @@ taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, unsigned int len)
                        return ret;
                }
                /* read the data */
-               *val = i2c_smbus_read_byte(client);
+               ret = i2c_smbus_read_byte(client);
+               if (ret < 0) {
+                       dev_err(&client->dev,
+                               "%s failed to read byte after writing to register %x\n",
+                               __func__, reg);
+                       return ret;
+               }
+               *val = ret;
                val++;
                reg++;
        }
@@ -204,28 +212,23 @@ static int taos_get_lux(struct iio_dev *indio_dev)
        u32 ch0lux = 0;
        u32 ch1lux = 0;
 
-       if (mutex_trylock(&chip->als_mutex) == 0) {
-               dev_info(&chip->client->dev, "taos_get_lux device is busy\n");
-               return chip->als_cur_info.lux; /* busy, so return LAST VALUE */
-       }
-
        if (chip->taos_chip_status != TSL258X_CHIP_WORKING) {
                /* device is not enabled */
                dev_err(&chip->client->dev, "taos_get_lux device is not enabled\n");
                ret = -EBUSY;
-               goto out_unlock;
+               goto done;
        }
 
        ret = taos_i2c_read(chip->client, (TSL258X_CMD_REG), &buf[0], 1);
        if (ret < 0) {
                dev_err(&chip->client->dev, "taos_get_lux failed to read CMD_REG\n");
-               goto out_unlock;
+               goto done;
        }
        /* is data new & valid */
        if (!(buf[0] & TSL258X_STA_ADC_INTR)) {
                dev_err(&chip->client->dev, "taos_get_lux data not valid\n");
                ret = chip->als_cur_info.lux; /* return LAST VALUE */
-               goto out_unlock;
+               goto done;
        }
 
        for (i = 0; i < 4; i++) {
@@ -236,7 +239,7 @@ static int taos_get_lux(struct iio_dev *indio_dev)
                        dev_err(&chip->client->dev,
                                "taos_get_lux failed to read register %x\n",
                                reg);
-                       goto out_unlock;
+                       goto done;
                }
        }
 
@@ -252,7 +255,7 @@ static int taos_get_lux(struct iio_dev *indio_dev)
                dev_err(&chip->client->dev,
                        "taos_i2c_write_command failed in taos_get_lux, err = %d\n",
                        ret);
-               goto out_unlock; /* have no data, so return failure */
+               goto done; /* have no data, so return failure */
        }
 
        /* extract ALS/lux data */
@@ -269,7 +272,7 @@ static int taos_get_lux(struct iio_dev *indio_dev)
                /* have no data, so return LAST VALUE */
                ret = 0;
                chip->als_cur_info.lux = 0;
-               goto out_unlock;
+               goto done;
        }
        /* calculate ratio */
        ratio = (ch1 << 15) / ch0;
@@ -295,7 +298,7 @@ static int taos_get_lux(struct iio_dev *indio_dev)
                dev_dbg(&chip->client->dev, "No Data - Return last value\n");
                ret = 0;
                chip->als_cur_info.lux = 0;
-               goto out_unlock;
+               goto done;
        }
 
        /* adjust for active time scale */
@@ -327,8 +330,7 @@ return_max:
        chip->als_cur_info.lux = lux;
        ret = lux;
 
-out_unlock:
-       mutex_unlock(&chip->als_mutex);
+done:
        return ret;
 }
 
@@ -355,11 +357,18 @@ static int taos_als_calibrate(struct iio_dev *indio_dev)
        }
 
        reg_val = i2c_smbus_read_byte(chip->client);
+       if (reg_val < 0) {
+               dev_err(&chip->client->dev,
+                       "%s failed to read after writing to the CNTRL register\n",
+                       __func__);
+               return ret;
+       }
+
        if ((reg_val & (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWR_ON))
                        != (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWR_ON)) {
                dev_err(&chip->client->dev,
                        "taos_als_calibrate failed: device not powered on with ADC enabled\n");
-               return -1;
+               return -EINVAL;
        }
 
        ret = i2c_smbus_write_byte(chip->client,
@@ -371,6 +380,12 @@ static int taos_als_calibrate(struct iio_dev *indio_dev)
                return ret;
        }
        reg_val = i2c_smbus_read_byte(chip->client);
+       if (reg_val < 0) {
+               dev_err(&chip->client->dev,
+                       "%s failed to read after writing to the STATUS register\n",
+                       __func__);
+               return ret;
+       }
 
        if ((reg_val & TSL258X_STA_ADC_VALID) != TSL258X_STA_ADC_VALID) {
                dev_err(&chip->client->dev,
@@ -491,90 +506,6 @@ static int taos_chip_off(struct iio_dev *indio_dev)
 
 /* Sysfs Interface Functions */
 
-static ssize_t taos_power_state_show(struct device *dev,
-                                    struct device_attribute *attr, char *buf)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2583_chip *chip = iio_priv(indio_dev);
-
-       return sprintf(buf, "%d\n", chip->taos_chip_status);
-}
-
-static ssize_t taos_power_state_store(struct device *dev,
-                                     struct device_attribute *attr,
-                                     const char *buf, size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       int value;
-
-       if (kstrtoint(buf, 0, &value))
-               return -EINVAL;
-
-       if (!value)
-               taos_chip_off(indio_dev);
-       else
-               taos_chip_on(indio_dev);
-
-       return len;
-}
-
-static ssize_t taos_gain_show(struct device *dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2583_chip *chip = iio_priv(indio_dev);
-       char gain[4] = {0};
-
-       switch (chip->taos_settings.als_gain) {
-       case 0:
-               strcpy(gain, "001");
-               break;
-       case 1:
-               strcpy(gain, "008");
-               break;
-       case 2:
-               strcpy(gain, "016");
-               break;
-       case 3:
-               strcpy(gain, "111");
-               break;
-       }
-
-       return sprintf(buf, "%s\n", gain);
-}
-
-static ssize_t taos_gain_store(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2583_chip *chip = iio_priv(indio_dev);
-       int value;
-
-       if (kstrtoint(buf, 0, &value))
-               return -EINVAL;
-
-       switch (value) {
-       case 1:
-               chip->taos_settings.als_gain = 0;
-               break;
-       case 8:
-               chip->taos_settings.als_gain = 1;
-               break;
-       case 16:
-               chip->taos_settings.als_gain = 2;
-               break;
-       case 111:
-               chip->taos_settings.als_gain = 3;
-               break;
-       default:
-               dev_err(dev, "Invalid Gain Index (must be 1,8,16,111)\n");
-               return -1;
-       }
-
-       return len;
-}
-
 static ssize_t taos_gain_available_show(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
@@ -582,69 +513,12 @@ static ssize_t taos_gain_available_show(struct device *dev,
        return sprintf(buf, "%s\n", "1 8 16 111");
 }
 
-static ssize_t taos_als_time_show(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2583_chip *chip = iio_priv(indio_dev);
-
-       return sprintf(buf, "%d\n", chip->taos_settings.als_time);
-}
-
-static ssize_t taos_als_time_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2583_chip *chip = iio_priv(indio_dev);
-       int value;
-
-       if (kstrtoint(buf, 0, &value))
-               return -EINVAL;
-
-       if ((value < 50) || (value > 650))
-               return -EINVAL;
-
-       if (value % 50)
-               return -EINVAL;
-
-       chip->taos_settings.als_time = value;
-
-       return len;
-}
-
 static ssize_t taos_als_time_available_show(struct device *dev,
                                            struct device_attribute *attr,
                                            char *buf)
 {
        return sprintf(buf, "%s\n",
-               "50 100 150 200 250 300 350 400 450 500 550 600 650");
-}
-
-static ssize_t taos_als_trim_show(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2583_chip *chip = iio_priv(indio_dev);
-
-       return sprintf(buf, "%d\n", chip->taos_settings.als_gain_trim);
-}
-
-static ssize_t taos_als_trim_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2583_chip *chip = iio_priv(indio_dev);
-       int value;
-
-       if (kstrtoint(buf, 0, &value))
-               return -EINVAL;
-
-       if (value)
-               chip->taos_settings.als_gain_trim = value;
-
-       return len;
+               "0.000050 0.000100 0.000150 0.000200 0.000250 0.000300 0.000350 0.000400 0.000450 0.000500 0.000550 0.000600 0.000650");
 }
 
 static ssize_t taos_als_cal_target_show(struct device *dev,
@@ -674,18 +548,6 @@ static ssize_t taos_als_cal_target_store(struct device *dev,
        return len;
 }
 
-static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr,
-                            char *buf)
-{
-       int ret;
-
-       ret = taos_get_lux(dev_to_iio_dev(dev));
-       if (ret < 0)
-               return ret;
-
-       return sprintf(buf, "%d\n", ret);
-}
-
 static ssize_t taos_do_calibrate(struct device *dev,
                                 struct device_attribute *attr,
                                 const char *buf, size_t len)
@@ -734,7 +596,7 @@ static ssize_t taos_luxtable_store(struct device *dev,
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct tsl2583_chip *chip = iio_priv(indio_dev);
        int value[ARRAY_SIZE(taos_device_lux) * 3 + 1];
-       int n;
+       int n, ret = -EINVAL;
 
        get_options(buf, ARRAY_SIZE(value), value);
 
@@ -746,58 +608,50 @@ static ssize_t taos_luxtable_store(struct device *dev,
        n = value[0];
        if ((n % 3) || n < 6 || n > ((ARRAY_SIZE(taos_device_lux) - 1) * 3)) {
                dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
-               return -EINVAL;
+               goto done;
        }
        if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) {
                dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n);
-               return -EINVAL;
+               goto done;
        }
 
-       if (chip->taos_chip_status == TSL258X_CHIP_WORKING)
-               taos_chip_off(indio_dev);
+       if (chip->taos_chip_status == TSL258X_CHIP_WORKING) {
+               ret = taos_chip_off(indio_dev);
+               if (ret < 0)
+                       goto done;
+       }
 
        /* Zero out the table */
        memset(taos_device_lux, 0, sizeof(taos_device_lux));
        memcpy(taos_device_lux, &value[1], (value[0] * 4));
 
-       taos_chip_on(indio_dev);
+       ret = taos_chip_on(indio_dev);
+       if (ret < 0)
+               goto done;
 
-       return len;
-}
+       ret = len;
 
-static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
-               taos_power_state_show, taos_power_state_store);
+done:
+       return ret;
+}
 
-static DEVICE_ATTR(illuminance0_calibscale, S_IRUGO | S_IWUSR,
-               taos_gain_show, taos_gain_store);
 static DEVICE_ATTR(illuminance0_calibscale_available, S_IRUGO,
                taos_gain_available_show, NULL);
 
-static DEVICE_ATTR(illuminance0_integration_time, S_IRUGO | S_IWUSR,
-               taos_als_time_show, taos_als_time_store);
 static DEVICE_ATTR(illuminance0_integration_time_available, S_IRUGO,
                taos_als_time_available_show, NULL);
 
-static DEVICE_ATTR(illuminance0_calibbias, S_IRUGO | S_IWUSR,
-               taos_als_trim_show, taos_als_trim_store);
-
 static DEVICE_ATTR(illuminance0_input_target, S_IRUGO | S_IWUSR,
                taos_als_cal_target_show, taos_als_cal_target_store);
 
-static DEVICE_ATTR(illuminance0_input, S_IRUGO, taos_lux_show, NULL);
 static DEVICE_ATTR(illuminance0_calibrate, S_IWUSR, NULL, taos_do_calibrate);
 static DEVICE_ATTR(illuminance0_lux_table, S_IRUGO | S_IWUSR,
                taos_luxtable_show, taos_luxtable_store);
 
 static struct attribute *sysfs_attrs_ctrl[] = {
-       &dev_attr_power_state.attr,
-       &dev_attr_illuminance0_calibscale.attr,                 /* Gain  */
        &dev_attr_illuminance0_calibscale_available.attr,
-       &dev_attr_illuminance0_integration_time.attr,   /* I time*/
        &dev_attr_illuminance0_integration_time_available.attr,
-       &dev_attr_illuminance0_calibbias.attr,                  /* trim  */
        &dev_attr_illuminance0_input_target.attr,
-       &dev_attr_illuminance0_input.attr,
        &dev_attr_illuminance0_calibrate.attr,
        &dev_attr_illuminance0_lux_table.attr,
        NULL
@@ -813,9 +667,161 @@ static int taos_tsl258x_device(unsigned char *bufp)
        return ((bufp[TSL258X_CHIPID] & 0xf0) == 0x90);
 }
 
+static const struct iio_chan_spec tsl2583_channels[] = {
+       {
+               .type = IIO_LIGHT,
+               .modified = 1,
+               .channel2 = IIO_MOD_LIGHT_IR,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+       },
+       {
+               .type = IIO_LIGHT,
+               .modified = 1,
+               .channel2 = IIO_MOD_LIGHT_BOTH,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+       },
+       {
+               .type = IIO_LIGHT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+                                     BIT(IIO_CHAN_INFO_CALIBBIAS) |
+                                     BIT(IIO_CHAN_INFO_CALIBSCALE) |
+                                     BIT(IIO_CHAN_INFO_INT_TIME),
+       },
+};
+
+static int tsl2583_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long mask)
+{
+       struct tsl2583_chip *chip = iio_priv(indio_dev);
+       int ret = -EINVAL;
+
+       mutex_lock(&chip->als_mutex);
+
+       if (chip->taos_chip_status != TSL258X_CHIP_WORKING) {
+               ret = -EBUSY;
+               goto read_done;
+       }
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               if (chan->type == IIO_LIGHT) {
+                       ret = taos_get_lux(indio_dev);
+                       if (ret < 0)
+                               goto read_done;
+
+                       /*
+                        * From page 20 of the TSL2581, TSL2583 data
+                        * sheet (TAOS134 − MARCH 2011):
+                        *
+                        * One of the photodiodes (channel 0) is
+                        * sensitive to both visible and infrared light,
+                        * while the second photodiode (channel 1) is
+                        * sensitive primarily to infrared light.
+                        */
+                       if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
+                               *val = chip->als_cur_info.als_ch0;
+                       else
+                               *val = chip->als_cur_info.als_ch1;
+
+                       ret = IIO_VAL_INT;
+               }
+               break;
+       case IIO_CHAN_INFO_PROCESSED:
+               if (chan->type == IIO_LIGHT) {
+                       ret = taos_get_lux(indio_dev);
+                       if (ret < 0)
+                               goto read_done;
+
+                       *val = ret;
+                       ret = IIO_VAL_INT;
+               }
+               break;
+       case IIO_CHAN_INFO_CALIBBIAS:
+               if (chan->type == IIO_LIGHT) {
+                       *val = chip->taos_settings.als_gain_trim;
+                       ret = IIO_VAL_INT;
+               }
+               break;
+       case IIO_CHAN_INFO_CALIBSCALE:
+               if (chan->type == IIO_LIGHT) {
+                       *val = gainadj[chip->taos_settings.als_gain].mean;
+                       ret = IIO_VAL_INT;
+               }
+               break;
+       case IIO_CHAN_INFO_INT_TIME:
+               if (chan->type == IIO_LIGHT) {
+                       *val = 0;
+                       *val2 = chip->taos_settings.als_time;
+                       ret = IIO_VAL_INT_PLUS_MICRO;
+               }
+               break;
+       default:
+               break;
+       }
+
+read_done:
+       mutex_unlock(&chip->als_mutex);
+
+       return ret;
+}
+
+static int tsl2583_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2, long mask)
+{
+       struct tsl2583_chip *chip = iio_priv(indio_dev);
+       int ret = -EINVAL;
+
+       mutex_lock(&chip->als_mutex);
+
+       if (chip->taos_chip_status != TSL258X_CHIP_WORKING) {
+               ret = -EBUSY;
+               goto write_done;
+       }
+
+       switch (mask) {
+       case IIO_CHAN_INFO_CALIBBIAS:
+               if (chan->type == IIO_LIGHT) {
+                       chip->taos_settings.als_gain_trim = val;
+                       ret = 0;
+               }
+               break;
+       case IIO_CHAN_INFO_CALIBSCALE:
+               if (chan->type == IIO_LIGHT) {
+                       int i;
+
+                       for (i = 0; i < ARRAY_SIZE(gainadj); i++) {
+                               if (gainadj[i].mean == val) {
+                                       chip->taos_settings.als_gain = i;
+                                       ret = 0;
+                                       break;
+                               }
+                       }
+               }
+               break;
+       case IIO_CHAN_INFO_INT_TIME:
+               if (chan->type == IIO_LIGHT && !val && val2 >= 50 &&
+                   val2 <= 650 && !(val2 % 50)) {
+                       chip->taos_settings.als_time = val2;
+                       ret = 0;
+               }
+               break;
+       default:
+               break;
+       }
+
+write_done:
+       mutex_unlock(&chip->als_mutex);
+
+       return ret;
+}
+
 static const struct iio_info tsl2583_info = {
        .attrs = &tsl2583_attribute_group,
        .driver_module = THIS_MODULE,
+       .read_raw = tsl2583_read_raw,
+       .write_raw = tsl2583_write_raw,
 };
 
 /*
@@ -881,6 +887,8 @@ static int taos_probe(struct i2c_client *clientp,
        }
 
        indio_dev->info = &tsl2583_info;
+       indio_dev->channels = tsl2583_channels;
+       indio_dev->num_channels = ARRAY_SIZE(tsl2583_channels);
        indio_dev->dev.parent = &clientp->dev;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->name = chip->client->name;
@@ -894,7 +902,9 @@ static int taos_probe(struct i2c_client *clientp,
        taos_defaults(chip);
 
        /* Make sure the chip is on */
-       taos_chip_on(indio_dev);
+       ret = taos_chip_on(indio_dev);
+       if (ret < 0)
+               return ret;
 
        dev_info(&clientp->dev, "Light sensor found.\n");
        return 0;
@@ -947,11 +957,24 @@ static struct i2c_device_id taos_idtable[] = {
 };
 MODULE_DEVICE_TABLE(i2c, taos_idtable);
 
+#ifdef CONFIG_OF
+static const struct of_device_id taos2583_of_match[] = {
+       { .compatible = "amstaos,tsl2580", },
+       { .compatible = "amstaos,tsl2581", },
+       { .compatible = "amstaos,tsl2583", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, taos2583_of_match);
+#else
+#define taos2583_of_match NULL
+#endif
+
 /* Driver definition */
 static struct i2c_driver taos_driver = {
        .driver = {
                .name = "tsl2583",
                .pm = TAOS_PM_OPS,
+               .of_match_table = taos2583_of_match,
        },
        .id_table = taos_idtable,
        .probe = taos_probe,