summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2010-09-03 22:29:07 +0530
committerBharat Nihalani <bnihalani@nvidia.com>2010-09-23 02:05:46 -0700
commit9a08e1184b5ab025a5d46a0c5c86630265ab51d9 (patch)
tree597f608e4be84100c773110808adbb3f48249e2c
parentcc8ecb06787b3a5e5456e616a0ccef668fcaa844 (diff)
[sensor] isl29018: Adding proximity sensing functionality.
Following are changes: - using smbus api to read/write from/to device. - Adding proximitysensing with scheme 0 and 1. - Adding ir sensing. - Removing the undesired definition and code. - Remove gpio initialzation and usage. - Sysfs interface for setting range/resolution/proximity scheme. - sysfs interface for reading lux/proximity ir and ir. - General code cleaning. (cherry picked from commit 0a148f035c9284cfa0e60e875052d6768267d731) Change-Id: I0d84f534a14b85e5a6bcea3218ecd8d864c0a103 Reviewed-on: http://git-master.nvidia.com/r/7102 Reviewed-by: Suresh Mangipudi <smangipudi@nvidia.com> Tested-by: Suresh Mangipudi <smangipudi@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rwxr-xr-xdrivers/hwmon/isl29018.c589
1 files changed, 291 insertions, 298 deletions
diff --git a/drivers/hwmon/isl29018.c b/drivers/hwmon/isl29018.c
index 79bab1ccb252..3a0c5e177255 100755
--- a/drivers/hwmon/isl29018.c
+++ b/drivers/hwmon/isl29018.c
@@ -1,7 +1,8 @@
/*
- * A hwmon driver for the Ambient light sensor ISL 29018.
+ * A hwmon driver for the light sensor ISL 29018.
*
- * Ambient light sensor driver for monitoring ambient light intensity in lux.
+ * Hwmon driver for monitoring ambient light intensity in luxi, proximity
+ * sensing and infrared sensing.
*
* Copyright (c) 2010, NVIDIA Corporation.
*
@@ -28,117 +29,56 @@
#include <linux/mutex.h>
#include <linux/delay.h>
-#include <asm/gpio.h>
-
-/*#define DEBUG 1*/
-/*#define VERBOSE_DEBUG 1*/
-
-#define MAX_CONVERSION_TRIAL 5
-#define MAX_CONVERION_TIMEOUT 500
-#define CONVERSION_TIME 100
-#define RESOLUTION_ADC_BIT 16
-
-#define ISL_29018_REG_ADD_COMMAND1 0x00
-
-#define COMMMAND1_OPMODE_SHIFT 5
-#define COMMMAND1_OPMODE_MASK (7 << COMMMAND1_OPMODE_SHIFT)
-#define COMMMAND1_OPMODE_POWER_DOWN 0
-#define COMMMAND1_OPMODE_ALS_ONCE 1
-#define COMMMAND1_OPMODE_ALS_CONT 5
-
-#define COMMAND1_INT_FLAG_SHIFT 2
-#define COMMAND1_INT_FLAG_MASK (1 << COMMAND1_INT_FLAG_SHIFT)
-#define COMMAND1_INT_FLAG_ON 1
-#define COMMAND1_INT_FLAG_CLEAR 0
-
-#define COMMAND1_PERSISTANCE_SHIFT 0
-#define COMMAND1_PERSISTANCE_MASK (3 << COMMAND1_PERSISTANCE_SHIFT)
-#define COMMAND1_PERSISTANCE_1 0
-#define COMMAND1_PERSISTANCE_4 1
-#define COMMAND1_PERSISTANCE_8 2
-#define COMMAND1_PERSISTANCE_16 3
-
-#define ISL_29018_REG_ADD_COMMANDII 0x01
-#define COMMANDII_RESOLUTION_SHIFT 2
-#define COMMANDII_RESOLUTION_MASK (0x3 << COMMANDII_RESOLUTION_SHIFT)
-#define COMMANDII_RESOLUTION_ADC_16BIT 0
-#define COMMANDII_RESOLUTION_ADC_12BIT 1
-#define COMMANDII_RESOLUTION_ADC_8BIT 2
-#define COMMANDII_RESOLUTION_ADC_4BIT 3
-
-#define COMMANDII_RANGE_SHIFT 0
-#define COMMANDII_RANGE_MASK (0x3 << COMMANDII_RANGE_SHIFT)
-#define COMMANDII_RANGE_ALS_SENSING_1000 0
-#define COMMANDII_RANGE_ALS_SENSING_4000 1
-#define COMMANDII_RANGE_ALS_SENSING_16000 2
-#define COMMANDII_RANGE_ALS_SENSING_64000 3
-
-#define ISL_29018_REG_ADD_DATA_LSB 0x02
-#define ISL_29018_REG_ADD_DATA_MSB 0x03
-#define ISL_29018_REG_ADD_INT_LOW_THRES_LSB 0x04
-#define ISL_29018_REG_ADD_INT_LOW_THRES_MSB 0x05
-#define ISL_29018_REG_ADD_INT_HIGH_THRES_LSB 0x06
-#define ISL_29018_REG_ADD_INT_HIGH_THRES_MSB 0x07
-#define ISL_29018_REG_ADD_TEST 0x08
-#define ISL_29018_MAX_REGS ISL_29018_REG_ADD_TEST
+/*#define DEBUG 1*/
+/*#define VERBOSE_DEBUG 1*/
-struct isl29018_data {
- struct device *hwmon_dev;
- struct attribute_group attrs;
- struct mutex lock;
- unsigned int min_range;
- unsigned int max_range;
- int mode;
- int eoc_gpio;
- int eoc_irq;
- u32 adc_bit;
- u8 reg_cache[ISL_29018_MAX_REGS];
- u16 bits_per_unit;
-};
+#define CONVERSION_TIME_MS 100
-static int isl29018_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-static int isl29018_remove(struct i2c_client *client);
+#define ISL29018_REG_ADD_COMMAND1 0x00
+#define COMMMAND1_OPMODE_SHIFT 5
+#define COMMMAND1_OPMODE_MASK (7 << COMMMAND1_OPMODE_SHIFT)
+#define COMMMAND1_OPMODE_POWER_DOWN 0
+#define COMMMAND1_OPMODE_ALS_ONCE 1
+#define COMMMAND1_OPMODE_IR_ONCE 2
+#define COMMMAND1_OPMODE_PROX_ONCE 3
-static const struct i2c_device_id isl29018_id[] = {
- {"isl29018", 0},
- {}
-};
+#define ISL29018_REG_ADD_COMMANDII 0x01
+#define COMMANDII_RESOLUTION_SHIFT 2
+#define COMMANDII_RESOLUTION_MASK (0x3 << COMMANDII_RESOLUTION_SHIFT)
-MODULE_DEVICE_TABLE(i2c, isl29018_id);
+#define COMMANDII_RANGE_SHIFT 0
+#define COMMANDII_RANGE_MASK (0x3 << COMMANDII_RANGE_SHIFT)
-static struct i2c_driver isl29018_driver = {
- .class = I2C_CLASS_HWMON,
- .driver = {
- .name = "isl29018",
- },
- .probe = isl29018_probe,
- .remove = isl29018_remove,
- .id_table = isl29018_id,
+#define COMMANDII_SCHEME_SHIFT 7
+#define COMMANDII_SCHEME_MASK (0x1 << COMMANDII_SCHEME_SHIFT)
+
+#define ISL29018_REG_ADD_DATA_LSB 0x02
+#define ISL29018_REG_ADD_DATA_MSB 0x03
+#define ISL29018_MAX_REGS ISL29018_REG_ADD_DATA_MSB
+
+struct isl29018_data {
+ struct device *hwmon_dev;
+ struct attribute_group attrs;
+ struct mutex lock;
+ unsigned int range;
+ unsigned int adc_bit;
+ int prox_scheme;
+ u8 reg_cache[ISL29018_MAX_REGS];
};
static bool isl29018_write_data(struct i2c_client *client, u8 reg,
u8 val, u8 mask, u8 shift)
{
u8 regval;
- struct i2c_msg msg;
- u8 w_data[2];
int ret = 0;
-
struct isl29018_data *data = i2c_get_clientdata(client);
regval = data->reg_cache[reg];
regval &= ~mask;
regval |= val << shift;
- w_data[0] = reg;
- w_data[1] = regval;
-
- msg.addr = client->addr;
- msg.flags = 0;
- msg.len = 2;
- msg.buf = w_data;
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret < 0) {
+
+ ret = i2c_smbus_write_byte_data(client, reg, regval);
+ if (ret) {
dev_err(&client->dev, "Write to device fails status %x\n", ret);
return false;
}
@@ -146,281 +86,347 @@ static bool isl29018_write_data(struct i2c_client *client, u8 reg,
return true;
}
-static bool isl29018_read_data(struct i2c_client *client, u8 reg, u8 length,
- u8 * buffer)
+static bool isl29018_set_range(struct i2c_client *client, unsigned long range,
+ unsigned int *new_range)
{
- struct i2c_msg msg[2];
- u8 w_data[2];
- int ret = 0;
-
- w_data[0] = reg;
-
- msg[0].addr = client->addr;
- msg[0].flags = I2C_M_NOSTART; /* set repeated start and write */
- msg[0].len = 1;
- msg[0].buf = w_data;
-
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = length;
- msg[1].buf = buffer;
+ unsigned long supp_ranges[] = {1000, 4000, 16000, 64000};
+ int i;
- ret = i2c_transfer(client->adapter, msg, 2);
- if (ret < 0) {
- dev_err(&client->dev, "Read from device fails.\n");
- return false;
+ for (i = 0; i < (ARRAY_SIZE(supp_ranges) -1); ++i) {
+ if (range <= supp_ranges[i])
+ break;
}
- return true;
+ *new_range = (unsigned int)supp_ranges[i];
+ return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
+ i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT);
}
-static bool isl29018_set_range(struct i2c_client *client, u32 min, u32 max)
+static bool isl29018_set_resolution(struct i2c_client *client,
+ unsigned long adcbit, unsigned int *conf_adc_bit)
{
- u32 max_ranges[] = { 1000, 4000, 16000, 64000 };
+ unsigned long supp_adcbit[] = {16, 12, 8, 4};
int i;
- for (i = 0; i < (ARRAY_SIZE(max_ranges) -1); ++i) {
- if (max < max_ranges[i])
+
+ for (i = 0; i < (ARRAY_SIZE(supp_adcbit)); ++i) {
+ if (adcbit == supp_adcbit[i])
break;
}
-
- return isl29018_write_data(client, ISL_29018_REG_ADD_COMMANDII,
- i, COMMANDII_RANGE_MASK,
- COMMANDII_RANGE_SHIFT);
+ *conf_adc_bit = (unsigned int)supp_adcbit[i];
+ return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
+ i, COMMANDII_RESOLUTION_MASK, COMMANDII_RESOLUTION_SHIFT);
}
-static bool isl29018_read_lux(struct i2c_client *client, int *lux_val)
+static int isl29018_read_sensor_input(struct i2c_client *client, int mode)
{
bool status;
- u8 data_lsb;
- u8 data_msb;
-
- dev_vdbg(&client->dev, "%s()\n", __func__);
- /* Write once ALS */
- status = isl29018_write_data(client, ISL_29018_REG_ADD_COMMAND1,
- COMMMAND1_OPMODE_ALS_ONCE,
- COMMMAND1_OPMODE_MASK,
- COMMMAND1_OPMODE_SHIFT);
+ int lsb;
+ int msb;
+
+ /* Set mode */
+ status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1,
+ mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT);
if (!status) {
dev_err(&client->dev, "Error in setting operating mode\n");
- return -EINVAL;
+ return -EBUSY;
}
- msleep(CONVERSION_TIME);
- status = isl29018_read_data(client, ISL_29018_REG_ADD_DATA_LSB, 1,
- &data_lsb);
- if (!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 false;
+ return lsb;
}
- status = isl29018_read_data(client, ISL_29018_REG_ADD_DATA_MSB, 1,
- &data_msb);
- if (!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 false;
+ return msb;
}
- dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", data_msb, data_lsb);
- *lux_val = (int) (((data_msb << 8) & 0xFF00) | (data_lsb & 0xFF));
- return true;
+ dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
+ return ((msb << 8) | lsb);
}
-static ssize_t show_mode(struct device *dev,
- struct device_attribute *devattr, char *buf)
+static bool isl29018_read_lux(struct i2c_client *client, int *lux)
{
- struct i2c_client *client = to_i2c_client(dev);
+ int lux_data;
struct isl29018_data *data = i2c_get_clientdata(client);
- dev_vdbg(dev, "%s()\n", __func__);
- return sprintf(buf, "%d\n", data->mode);
+
+ lux_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_ALS_ONCE);
+ if (lux_data > 0) {
+ *lux = (lux_data * data->range) >> data->adc_bit;
+ return true;
+ }
+ return false;
}
-static ssize_t store_mode(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
+static bool isl29018_read_ir(struct i2c_client *client, int *ir)
+{
+ int ir_data;
+
+ ir_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_IR_ONCE);
+ if (ir_data > 0) {
+ *ir = ir_data;
+ return true;
+ }
+ return false;
+}
+
+static bool isl29018_read_proximity_ir(struct i2c_client *client, int scheme,
+ int *near_ir)
+{
+ bool status;
+ int prox_data = -1;
+ int ir_data = -1;
+
+ /* Do proximity sensing with required scheme */
+ status = isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
+ scheme, COMMANDII_SCHEME_MASK, COMMANDII_SCHEME_SHIFT);
+ if (!status) {
+ dev_err(&client->dev, "Error in setting operating mode\n");
+ return false;
+ }
+ prox_data = isl29018_read_sensor_input(client,
+ COMMMAND1_OPMODE_PROX_ONCE);
+ if (scheme == 1) {
+ if (prox_data >= 0) {
+ *near_ir = prox_data;
+ return true;
+ }
+ return false;
+ }
+ if (prox_data >= 0)
+ ir_data = isl29018_read_sensor_input(client,
+ COMMMAND1_OPMODE_IR_ONCE);
+ if (prox_data >= 0 && ir_data >= 0) {
+ if (prox_data >= ir_data) {
+ *near_ir = prox_data - ir_data;
+ return true;
+ }
+ }
+ return false;
+}
+
+static ssize_t get_sensor_data(struct device *dev, char *buf, int mode)
{
struct i2c_client *client = to_i2c_client(dev);
struct isl29018_data *data = i2c_get_clientdata(client);
- long oval;
- int mode;
+ int value = 0;
bool status;
- dev_vdbg(dev, "%s()\n", __func__);
- if (strict_strtol(buf, 10, &oval))
- return -EINVAL;
-
mutex_lock(&data->lock);
- mode = (int) oval;
- if ((mode < 0) || (mode > 1)) {
- dev_err(&client->dev,
- "Operating mode value is not supported\n");
- mutex_unlock(&data->lock);
- return -EINVAL;
- }
+ switch (mode) {
+ case COMMMAND1_OPMODE_PROX_ONCE:
+ status = isl29018_read_proximity_ir(client,
+ data->prox_scheme, &value);
+ break;
- if (data->mode != mode) {
- status = isl29018_write_data(client, ISL_29018_REG_ADD_COMMAND1,
- mode, COMMMAND1_OPMODE_MASK,
- COMMMAND1_OPMODE_SHIFT);
- if (status && !mode) {
- status = isl29018_write_data(client,
- ISL_29018_REG_ADD_COMMAND1,
- COMMAND1_PERSISTANCE_8,
- COMMAND1_PERSISTANCE_MASK,
- COMMAND1_PERSISTANCE_SHIFT);
- if (status)
- status = isl29018_set_range(client,
- data->min_range,
- data->max_range);
- }
+ case COMMMAND1_OPMODE_ALS_ONCE:
+ status = isl29018_read_lux(client, &value);
+ break;
+
+ case COMMMAND1_OPMODE_IR_ONCE:
+ status = isl29018_read_ir(client, &value);
+ break;
- if (!status) {
- dev_err(&client->dev,
- "Error in setting operating mode\n");
+ default:
+ dev_err(&client->dev,"Mode %d is not supported\n",mode);
mutex_unlock(&data->lock);
- return -EINVAL;
- }
- data->mode = mode;
+ return -EBUSY;
+ }
+ if (!status) {
+ dev_err(&client->dev, "Error in Reading data");
+ mutex_unlock(&data->lock);
+ return -EBUSY;
}
+
mutex_unlock(&data->lock);
- return count;
+ return sprintf(buf, "%d\n", value);
}
-static ssize_t show_min_range(struct device *dev,
+/* Sysfs interface */
+/* range */
+static ssize_t show_range(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct isl29018_data *data = i2c_get_clientdata(client);
dev_vdbg(dev, "%s()\n", __func__);
- return sprintf(buf, "%u\n", data->min_range);
+ return sprintf(buf, "%u\n", data->range);
}
-static ssize_t store_min_range(struct device *dev,
+static ssize_t store_range(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct isl29018_data *data = i2c_get_clientdata(client);
- unsigned long min_val;
+ bool status;
+ unsigned long lval;
+ unsigned int new_range;
dev_vdbg(dev, "%s()\n", __func__);
- if (strict_strtoul(buf, 10, &min_val))
+ if (strict_strtoul(buf, 10, &lval))
+ return -EINVAL;
+
+ if (!(lval == 1000UL || lval == 4000UL ||
+ lval == 16000UL || lval == 64000UL)) {
+ dev_err(dev, "The range is not supported\n");
return -EINVAL;
+ }
mutex_lock(&data->lock);
- /* There is no need to set min range */
- data->min_range = (unsigned int) min_val;
+ status = isl29018_set_range(client, lval, &new_range);
+ if (!status) {
+ mutex_unlock(&data->lock);
+ dev_err(dev, "Error in setting max range\n");
+ return -EINVAL;
+ }
+ data->range = new_range;
mutex_unlock(&data->lock);
return count;
}
-static ssize_t show_max_range(struct device *dev,
+/* resolution */
+static ssize_t show_resolution(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct isl29018_data *data = i2c_get_clientdata(client);
dev_vdbg(dev, "%s()\n", __func__);
- return sprintf(buf, "%u\n", data->max_range);
+ return sprintf(buf, "%u\n", data->adc_bit);
}
-static ssize_t store_max_range(struct device *dev,
+static ssize_t store_resolution(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct isl29018_data *data = i2c_get_clientdata(client);
bool status;
- unsigned long max_val;
+ unsigned long lval;
+ unsigned int new_adc_bit;
dev_vdbg(dev, "%s()\n", __func__);
- if (strict_strtoul(buf, 10, &max_val))
+ if (strict_strtoul(buf, 10, &lval))
+ return -EINVAL;
+ if (!(lval == 4 || lval == 8 || lval == 12 || lval == 16)) {
+ dev_err(dev, "The resolution is not supported\n");
return -EINVAL;
+ }
mutex_lock(&data->lock);
- status = isl29018_set_range(client, data->min_range, max_val);
+ status = isl29018_set_resolution(client, lval, &new_adc_bit);
if (!status) {
mutex_unlock(&data->lock);
- dev_err(dev, "Error in setting max range\n");
+ dev_err(dev, "Error in setting resolution\n");
return -EINVAL;
}
- data->max_range = (unsigned int) max_val;
- data->bits_per_unit = ((1 << data->adc_bit) + data->max_range - 1) /
- data->max_range;
+ data->adc_bit = new_adc_bit;
mutex_unlock(&data->lock);
return count;
}
-static ssize_t show_show_lux(struct device *dev,
- struct device_attribute *devattr, char *buf)
+/* proximity scheme */
+static ssize_t show_prox_scheme(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct isl29018_data *data = i2c_get_clientdata(client);
- int luxval = 0;
- bool status;
- int trial_count = MAX_CONVERSION_TRIAL;
dev_vdbg(dev, "%s()\n", __func__);
- if (!data) {
- dev_err(&client->dev, "No device found\n");
- return -ENODEV;
- }
+ return sprintf(buf, "%d\n", data->prox_scheme);
+}
- mutex_lock(&data->lock);
- if (data->mode == 0) {
- dev_err(&client->dev, "Operating mode is in power down mode\n");
- return -EBUSY;
- }
- while (trial_count--) {
- status = isl29018_read_lux(client, &luxval);
- if (!status) {
- dev_err(&client->dev, "Error Reading flux trial %d\n",
- trial_count);
- continue;
- }
- break;
- }
+static ssize_t store_prox_scheme(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct isl29018_data *data = i2c_get_clientdata(client);
+ unsigned long lval;
- if (!status) {
- dev_err(&client->dev, "Tried maximum trials %d\n",
- MAX_CONVERSION_TRIAL);
- mutex_unlock(&data->lock);
- return -EBUSY;
+ dev_vdbg(dev, "%s()\n", __func__);
+
+ if (strict_strtoul(buf, 10, &lval))
+ return -EINVAL;
+ if (!(lval == 0UL || lval == 1UL)) {
+ dev_err(dev, "The scheme is not supported\n");
+ return -EINVAL;
}
- luxval = (luxval / data->bits_per_unit);
+ mutex_lock(&data->lock);
+ data->prox_scheme = (int)lval;
mutex_unlock(&data->lock);
- return sprintf(buf, "%d\n", luxval);
+ return count;
}
-static SENSOR_DEVICE_ATTR(min_range, S_IRUGO | S_IWUSR,
- show_min_range, store_min_range, 1);
-static SENSOR_DEVICE_ATTR(max_range, S_IRUGO | S_IWUSR,
- show_max_range, store_max_range, 2);
-static SENSOR_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
- show_mode, store_mode, 3);
-static SENSOR_DEVICE_ATTR(show_lux, S_IRUGO, show_show_lux, NULL, 4);
+/* 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);
+}
+
+static SENSOR_DEVICE_ATTR(range, S_IRUGO | S_IWUSR,
+ show_range, store_range, 0);
+static SENSOR_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR,
+ show_resolution, store_resolution, 1);
+static SENSOR_DEVICE_ATTR(proximity_scheme, S_IRUGO | S_IWUSR,
+ show_prox_scheme, store_prox_scheme, 2);
+static SENSOR_DEVICE_ATTR(lux, S_IRUGO, show_lux, NULL, 3);
+static SENSOR_DEVICE_ATTR(ir, S_IRUGO, show_ir, NULL, 4);
+static SENSOR_DEVICE_ATTR(proxim_ir, S_IRUGO, show_proxim_ir, NULL, 5);
static struct attribute *isl29018_attr[] = {
- &sensor_dev_attr_min_range.dev_attr.attr,
- &sensor_dev_attr_max_range.dev_attr.attr,
- &sensor_dev_attr_mode.dev_attr.attr,
- &sensor_dev_attr_show_lux.dev_attr.attr,
+ &sensor_dev_attr_range.dev_attr.attr,
+ &sensor_dev_attr_resolution.dev_attr.attr,
+ &sensor_dev_attr_proximity_scheme.dev_attr.attr,
+ &sensor_dev_attr_lux.dev_attr.attr,
+ &sensor_dev_attr_ir.dev_attr.attr,
+ &sensor_dev_attr_proxim_ir.dev_attr.attr,
NULL
};
-static void init_adc_resolution(struct isl29018_data *data)
+static int isl29018_init_client(struct i2c_client *client)
{
- u8 adc_resol[] = {16, 12, 8, 4};
+ struct isl29018_data *data = i2c_get_clientdata(client);
+ bool status;
int i;
- for (i =0; i < ARRAY_SIZE(adc_resol); ++i) {
- if (adc_resol[i] != data->adc_bit)
- continue;
- data->reg_cache[ISL_29018_REG_ADD_COMMANDII] &=
- ~COMMANDII_RESOLUTION_MASK;
- data->reg_cache[ISL_29018_REG_ADD_COMMANDII] |=
- (i << COMMANDII_RESOLUTION_SHIFT);
+ int new_adc_bit;
+ unsigned int new_range;
+
+ for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) {
+ data->reg_cache[i] = 0;
}
+
+ /* set defaults */
+ status = isl29018_set_range(client, data->range, &new_range);
+ if (status)
+ status = isl29018_set_resolution(client, data->adc_bit,
+ &new_adc_bit);
+ if (!status) {
+ dev_err(&client->dev, "Init of isl29018 fails\n");
+ return -ENODEV;
+ }
+ return 0;
}
-static int isl29018_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+
+static int __devinit isl29018_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct isl29018_data *data;
int err;
@@ -435,33 +441,12 @@ static int isl29018_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
mutex_init(&data->lock);
- data->eoc_irq = client->irq;
- if (!data->eoc_irq) {
- data->eoc_gpio = irq_to_gpio(client->irq);
+ data->range = 1000;
+ data->adc_bit = 16;
- err = gpio_request(data->eoc_gpio, "isl29018");
- if (err < 0) {
- dev_err(&client->dev, "failed to request GPIO %d,"
- " error %d\n", data->eoc_gpio, err);
- goto exit_free;
- }
-
- err = gpio_direction_input(data->eoc_gpio);
- if (err < 0) {
- dev_err(&client->dev, "Failed to configure input"
- "direction for GPIO %d, error %d\n",
- data->eoc_gpio, err);
- gpio_free(data->eoc_gpio);
- goto exit_gpio;
- }
- }
- data->min_range = 1;
- data->max_range = 1000;
- data->mode = 0;
- data->adc_bit = RESOLUTION_ADC_BIT;
- data->bits_per_unit = ((1 << data->adc_bit) + data->max_range - 1) /
- data->max_range;
- init_adc_resolution(data);
+ err = isl29018_init_client(client);
+ if (err)
+ goto exit_free;
/* Register sysfs hooks */
data->attrs.attrs = isl29018_attr;
@@ -470,49 +455,57 @@ static int isl29018_probe(struct i2c_client *client,
dev_err(&client->dev, "Not able to create the sysfs\n");
goto exit_free;
}
-
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
dev_err(&client->dev, "hwmon registration fails\n");
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
-
return 0;
-
exit_remove:
sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_gpio:
- if (!data->eoc_irq)
- gpio_free(data->eoc_gpio);
exit_free:
kfree(data);
exit:
return err;
}
-static int isl29018_remove(struct i2c_client *client)
+static int __devexit isl29018_remove(struct i2c_client *client)
{
struct isl29018_data *data = i2c_get_clientdata(client);
dev_dbg(&client->dev, "%s()\n", __func__);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
- if (!data->eoc_irq)
- gpio_free(data->eoc_gpio);
kfree(data);
return 0;
}
+static const struct i2c_device_id isl29018_id[] = {
+ {"isl29018", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, isl29018_id);
+
+static struct i2c_driver isl29018_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "isl29018",
+ .owner = THIS_MODULE,
+ },
+ .probe = isl29018_probe,
+ .remove = __devexit_p(isl29018_remove),
+ .id_table = isl29018_id,
+};
+
static int __init isl29018_init(void)
{
- pr_info("%s()\n", __func__);
return i2c_add_driver(&isl29018_driver);
}
static void __exit isl29018_exit(void)
{
- pr_info("%s()\n", __func__);
i2c_del_driver(&isl29018_driver);
}