#include <linux/slab.h>
#include "../iio.h"
#include "../sysfs.h"
-#define CONVERSION_TIME_MS 100
#define ISL29018_REG_ADD_COMMAND1 0x00
#define COMMMAND1_OPMODE_SHIFT 5
#define ISL29018_TEST_SHIFT 0
#define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT)
+#define ISL29018_REG_TEST 0x08
+#define ISL29018_TEST_SHIFT 0
+#define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT)
+
struct isl29018_chip {
struct i2c_client *client;
struct mutex lock;
COMMANDII_RESOLUTION_SHIFT);
}
+static void integration_wait(struct isl29018_chip *chip)
+{
+ int wait_time;
+
+ /* Integration and conversion time is described in the data sheet
+ * as 2^n x (constant), and for 16 bits it's 90ms. So calculate
+ * from there.
+ *
+ * Since the time taken depends on a resistor value, leave some
+ * margin above the 90ms timeout, otherwise we risk reading a
+ * stale value.
+ */
+ wait_time = DIV_ROUND_UP(100, 1 << (16 - chip->adc_bit));
+ msleep(wait_time);
+}
+
static int isl29018_read_sensor_input(struct i2c_client *client, int mode)
{
int status;
- int lsb;
- int msb;
+ int lux;
/* Set mode */
status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1,
dev_err(&client->dev, "Error in setting operating mode\n");
return status;
}
- msleep(CONVERSION_TIME_MS);
- lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB);
- if (lsb < 0) {
- dev_err(&client->dev, "Error in reading LSB DATA\n");
- return lsb;
+ integration_wait(iio_priv(i2c_get_clientdata(client)));
+ status = i2c_smbus_read_word_data(client, ISL29018_REG_ADD_DATA_LSB);
+ if (status < 0) {
+ dev_err(&client->dev, "Error in reading Lux DATA\n");
+ return status;
}
- msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB);
- if (msb < 0) {
- dev_err(&client->dev, "Error in reading MSB DATA\n");
- return msb;
- }
- dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
+ lux = le16_to_cpu(status);
+ dev_vdbg(&client->dev, "lux = %u\n", lux);
- return (msb << 8) | lsb;
+ return lux;
}
static int isl29018_read_lux(struct i2c_client *client, int *lux)
}
/* Sysfs interface */
+/* lux_scale */
+static ssize_t show_lux_scale(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct isl29018_chip *chip = iio_priv(indio_dev);
+
+ return sprintf(buf, "%d\n", chip->lux_scale);
+}
+
+static ssize_t store_lux_scale(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct isl29018_chip *chip = iio_priv(indio_dev);
+ unsigned long lval;
+
+ lval = simple_strtoul(buf, NULL, 10);
+ if (lval == 0)
+ return -EINVAL;
+
+ mutex_lock(&chip->lock);
+ chip->lux_scale = lval;
+ mutex_unlock(&chip->lock);
+
+ return count;
+}
+
+static ssize_t get_sensor_data(struct device *dev, char *buf, int mode)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct isl29018_chip *chip = iio_priv(indio_dev);
+ struct i2c_client *client = chip->client;
+ int value = 0;
+ int status;
+
+ mutex_lock(&chip->lock);
+ switch (mode) {
+ case COMMMAND1_OPMODE_PROX_ONCE:
+ status = isl29018_read_proximity_ir(client,
+ chip->prox_scheme, &value);
+ break;
+
+ case COMMMAND1_OPMODE_ALS_ONCE:
+ status = isl29018_read_lux(client, &value);
+ break;
+
+ case COMMMAND1_OPMODE_IR_ONCE:
+ status = isl29018_read_ir(client, &value);
+ break;
+
+ default:
+ dev_err(&client->dev, "Mode %d is not supported\n", mode);
+ mutex_unlock(&chip->lock);
+ return -EBUSY;
+ }
+
+ if (status < 0) {
+ dev_err(&client->dev, "Error in Reading data");
+ mutex_unlock(&chip->lock);
+ return status;
+ }
+
+ mutex_unlock(&chip->lock);
+
+ return sprintf(buf, "%d\n", value);
+}
+
+
+/* Read lux */
+static ssize_t show_lux(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return get_sensor_data(dev, buf, COMMMAND1_OPMODE_ALS_ONCE);
+}
+
+/* Read ir */
+static ssize_t show_ir(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return get_sensor_data(dev, buf, COMMMAND1_OPMODE_IR_ONCE);
+}
+
+/* Read nearest ir */
+static ssize_t show_proxim_ir(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return get_sensor_data(dev, buf, COMMMAND1_OPMODE_PROX_ONCE);
+}
+
/* range */
static ssize_t show_range(struct device *dev,
struct device_attribute *attr, char *buf)
S_IRUGO | S_IWUSR,
show_prox_infrared_supression,
store_prox_infrared_supression, 0);
+static IIO_DEVICE_ATTR(illuminance0_input, S_IRUGO, show_lux, NULL, 0);
+static IIO_DEVICE_ATTR(illuminance0_calibscale, S_IRUGO | S_IWUSR,
+ show_lux_scale, store_lux_scale, 0);
+static IIO_DEVICE_ATTR(intensity_infrared_raw, S_IRUGO, show_ir, NULL, 0);
+static IIO_DEVICE_ATTR(proximity_raw, S_IRUGO, show_proxim_ir, NULL, 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)
ISL29018_DEV_ATTR(adc_resolution),
ISL29018_CONST_ATTR(adc_resolution_available),
ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_supression),
+ ISL29018_DEV_ATTR(illuminance0_input),
+ ISL29018_DEV_ATTR(illuminance0_calibscale),
+ ISL29018_DEV_ATTR(intensity_infrared_raw),
+ ISL29018_DEV_ATTR(proximity_raw),
NULL
};