diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2010-09-03 22:29:07 +0530 |
---|---|---|
committer | Bharat Nihalani <bnihalani@nvidia.com> | 2010-09-23 02:05:46 -0700 |
commit | 9a08e1184b5ab025a5d46a0c5c86630265ab51d9 (patch) | |
tree | 597f608e4be84100c773110808adbb3f48249e2c | |
parent | cc8ecb06787b3a5e5456e616a0ccef668fcaa844 (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-x | drivers/hwmon/isl29018.c | 589 |
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); } |