On 10/06/10 22:25, rklein@xxxxxxxxxx wrote: > From: Rhyland Klein <rklein@xxxxxxxxxx> > > Adding support for the ISL 29018 ambient light and proximity sensor. > > Addressed comments from reviews by Jonathan Cameron and Joe Perches > * Removed some excess dbg prints that only printed function name > * Renamed some properties to make them more descriptive > * Added a property to list available adc resolutions > * Defined arrays for resolutions/ranges as static const > * Change loops initialization to memset for extensibility. > * used sizeof() instead of ARRAY_SIZE() to be safer > * Added a property to list available adc ranges One typo in the documentation you will want to fix. Otherwise, I'm happy. > > Signed-off-by: Rhyland Klein <rklein@xxxxxxxxxx> Acked-by: Jonathan Cameron <jic23@xxxxxxxxx> Please send a copy to Greg KH <greg@xxxxxxxxx> for merging > --- > .../staging/iio/Documentation/sysfs-bus-iio-light | 64 +++ > drivers/staging/iio/light/Kconfig | 11 + > drivers/staging/iio/light/Makefile | 1 + > drivers/staging/iio/light/isl29018.c | 563 ++++++++++++++++++++ > 4 files changed, 639 insertions(+), 0 deletions(-) > create mode 100644 drivers/staging/iio/Documentation/sysfs-bus-iio-light > create mode 100755 drivers/staging/iio/light/isl29018.c > > diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/drivers/staging/iio/Documentation/sysfs-bus-iio-light > new file mode 100644 > index 0000000..2f7d9c5 > --- /dev/null > +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light > @@ -0,0 +1,64 @@ > + > +What: /sys/bus/iio/devices/device[n]/range > +KernelVersion: 2.6.37 > +Contact: linux-iio@xxxxxxxxxxxxxxx > +Description: > + Hardware dependent ADC Full Scale Range used for some ambient > + light sensors in calculating lux. > + > +What: /sys/bus/iio/devices/device[n]/range_available > +KernelVersion: 2.6.37 > +Contact: linux-iio@xxxxxxxxxxxxxxx > +Description: > + Hardware dependent supported vales for ADC Full Scale Range. > + > +What: /sys/bus/iio/devices/device[n]/adc_resolution > +KernelVersion: 2.6.37 > +Contact: linux-iio@xxxxxxxxxxxxxxx > +Description: > + Hardware dependent ADC resolution of the ambient light sensor > + used in calculating the lux. > + > +What: /sys/bus/iio/devices/device[n]/adc_resolution_available > +KernelVersion: 2.6.37 > +Contact: linux-iio@xxxxxxxxxxxxxxx > +Description: > + Hardware dependent list of possible values supported for the > + adc_resolution of the given sensor. > + > +What: /sys/bus/iio/devices/device[n]/illuminance0[_input|_raw] > +KernelVersion: 2.6.35 > +Contact: linux-iio@xxxxxxxxxxxxxxx > +Description: > + This should return the calculated lux from the light sensor. If > + it comes back in SI units, it should also inclue _input else it typo inclue -> include. > + should include _raw to signify it is not in SI units. > + > +What: /sys/.../device[n]/proximity_on_chip_ambient_infrared_supression > +KernelVersion: 2.6.37 > +Contact: linux-iio@xxxxxxxxxxxxxxx > +Description: > + Hardware dependent mode for an ALS device to calculate the value > + in proximity mode. When this is enabled, then the device should > + use a infrared sensor reading to remove infrared noise from the > + proximity reading. If this is not enabled, the driver can still > + do this calculation manually by reading the infrared sensor > + value and doing the negation in sw. > + > +What: /sys/bus/iio/devices/device[n]/proximity[_input|_raw] > +KernelVersion: 2.6.37 > +Contact: linux-iio@xxxxxxxxxxxxxxx > +Description: > + This property is supported by proximity sensors and should be > + used to return the value of a reading by the sensor. If this > + value is returned in SI units, it should also include _input > + but if it is not, then it should include _raw. > + > +What: /sys/bus/iio/devices/device[n]/intensity_infrared[_input|_raw] > +KernelVersion: 2.6.37 > +Contact: linux-iio@xxxxxxxxxxxxxxx > +Description: > + This property is supported by sensors that have an infrared > + sensing mode. This value should be the output from a reading > + and if expressed in SI units, should include _input. If this > + value is not in SI units, then it should include _raw. > diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig > index 80cb6e5..36d8bbe 100644 > --- a/drivers/staging/iio/light/Kconfig > +++ b/drivers/staging/iio/light/Kconfig > @@ -13,3 +13,14 @@ config SENSORS_TSL2563 > This driver can also be built as a module. If so, the module > will be called tsl2563. > > +config SENSORS_ISL29018 > + tristate "ISL 29018 light and proximity sensor" > + depends on I2C > + default n > + help > + If you say yes here you get support for ambient light sensing and > + proximity infrared sensing from Intersil ISL29018. > + This driver will provide the measurements of ambient light intensity > + in lux, proximity infrared sensing and normal infrared sensing. > + Data from sensor is accessible via sysfs. > + > diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile > index 30f3300..9142c0e 100644 > --- a/drivers/staging/iio/light/Makefile > +++ b/drivers/staging/iio/light/Makefile > @@ -3,3 +3,4 @@ > # > > obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o > +obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o > diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c > new file mode 100755 > index 0000000..c83f39f > --- /dev/null > +++ b/drivers/staging/iio/light/isl29018.c > @@ -0,0 +1,563 @@ > +/* > + * A iio driver for the light sensor ISL 29018. > + * > + * IIO driver for monitoring ambient light intensity in luxi, proximity > + * sensing and infrared sensing. > + * > + * Copyright (c) 2010, NVIDIA Corporation. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, write to the Free Software Foundation, Inc., > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + */ > + > +#include <linux/module.h> > +#include <linux/i2c.h> > +#include <linux/err.h> > +#include <linux/mutex.h> > +#include <linux/delay.h> > +#include <linux/slab.h> > +#include "../iio.h" > + > +#define CONVERSION_TIME_MS 100 > + > +#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 > + > +#define ISL29018_REG_ADD_COMMANDII 0x01 > +#define COMMANDII_RESOLUTION_SHIFT 2 > +#define COMMANDII_RESOLUTION_MASK (0x3 << COMMANDII_RESOLUTION_SHIFT) > + > +#define COMMANDII_RANGE_SHIFT 0 > +#define COMMANDII_RANGE_MASK (0x3 << COMMANDII_RANGE_SHIFT) > + > +#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_chip { > + struct iio_dev *indio_dev; > + struct i2c_client *client; > + struct mutex lock; > + unsigned int range; > + unsigned int adc_bit; > + int prox_scheme; > + u8 reg_cache[ISL29018_MAX_REGS]; > +}; > + > +static int isl29018_write_data(struct i2c_client *client, u8 reg, > + u8 val, u8 mask, u8 shift) > +{ > + u8 regval; > + int ret = 0; > + struct isl29018_chip *chip = i2c_get_clientdata(client); > + > + regval = chip->reg_cache[reg]; > + regval &= ~mask; > + regval |= val << shift; > + > + ret = i2c_smbus_write_byte_data(client, reg, regval); > + if (ret) { > + dev_err(&client->dev, "Write to device fails status %x\n", ret); > + return ret; > + } > + chip->reg_cache[reg] = regval; > + > + return 0; > +} > + > +static int isl29018_set_range(struct i2c_client *client, unsigned long range, > + unsigned int *new_range) > +{ > + static const unsigned long supp_ranges[] = {1000, 4000, 16000, 64000}; > + int i; > + > + for (i = 0; i < ARRAY_SIZE(supp_ranges); ++i) { > + if (range <= supp_ranges[i]) { > + *new_range = (unsigned int)supp_ranges[i]; > + break; > + } > + } > + > + if (i >= ARRAY_SIZE(supp_ranges)) > + return -EINVAL; > + > + return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, > + i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT); > +} > + > +static int isl29018_set_resolution(struct i2c_client *client, > + unsigned long adcbit, unsigned int *conf_adc_bit) > +{ > + static const unsigned long supp_adcbit[] = {16, 12, 8, 4}; > + int i; > + > + for (i = 0; i < ARRAY_SIZE(supp_adcbit); ++i) { > + if (adcbit >= supp_adcbit[i]) { > + *conf_adc_bit = (unsigned int)supp_adcbit[i]; > + break; > + } > + } > + > + if (i >= ARRAY_SIZE(supp_adcbit)) > + return -EINVAL; > + > + return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, > + i, COMMANDII_RESOLUTION_MASK, > + COMMANDII_RESOLUTION_SHIFT); > +} > + > +static int isl29018_read_sensor_input(struct i2c_client *client, int mode) > +{ > + int status; > + 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 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; > + } > + > + 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); > + > + return (msb << 8) | lsb; > +} > + > +static int isl29018_read_lux(struct i2c_client *client, int *lux) > +{ > + int lux_data; > + struct isl29018_chip *chip = i2c_get_clientdata(client); > + > + lux_data = isl29018_read_sensor_input(client, > + COMMMAND1_OPMODE_ALS_ONCE); > + > + if (lux_data < 0) > + return lux_data; > + > + *lux = (lux_data * chip->range) >> chip->adc_bit; > + > + return 0; > +} > + > +static int 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) > + return ir_data; > + > + *ir = ir_data; > + > + return 0; > +} > + > +static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme, > + int *near_ir) > +{ > + int 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 status; > + } > + > + prox_data = isl29018_read_sensor_input(client, > + COMMMAND1_OPMODE_PROX_ONCE); > + if (prox_data < 0) > + return prox_data; > + > + if (scheme == 1) { > + *near_ir = prox_data; > + return 0; > + } > + > + ir_data = isl29018_read_sensor_input(client, > + COMMMAND1_OPMODE_IR_ONCE); > + > + if (ir_data < 0) > + return ir_data; > + > + if (prox_data >= ir_data) > + *near_ir = prox_data - ir_data; > + else > + *near_ir = 0; > + > + return 0; > +} > + > +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 = indio_dev->dev_data; > + 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); > +} > + > +/* Sysfs interface */ > +/* range */ > +static ssize_t show_range(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct isl29018_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%u\n", chip->range); > +} > + > +static ssize_t store_range(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 = indio_dev->dev_data; > + struct i2c_client *client = chip->client; > + int status; > + unsigned long lval; > + unsigned int new_range; > + > + 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(&chip->lock); > + status = isl29018_set_range(client, lval, &new_range); > + if (status < 0) { > + mutex_unlock(&chip->lock); > + dev_err(dev, "Error in setting max range\n"); > + return status; > + } > + chip->range = new_range; > + mutex_unlock(&chip->lock); > + > + return count; > +} > + > +/* resolution */ > +static ssize_t show_resolution(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct isl29018_chip *chip = indio_dev->dev_data; > + > + 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_get_drvdata(dev); > + struct isl29018_chip *chip = indio_dev->dev_data; > + struct i2c_client *client = chip->client; > + int status; > + unsigned long lval; > + unsigned int new_adc_bit; > + > + 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(&chip->lock); > + status = isl29018_set_resolution(client, lval, &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); > + > + return count; > +} > + > +/* proximity scheme */ > +static ssize_t show_prox_infrared_supression(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct isl29018_chip *chip = indio_dev->dev_data; > + > + /* return the "proximity scheme" i.e. if the chip does on chip > + infrared supression (1 means perform on chip supression) */ > + return sprintf(buf, "%d\n", chip->prox_scheme); > +} > + > +static ssize_t store_prox_infrared_supression(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 = indio_dev->dev_data; > + unsigned long lval; > + > + if (strict_strtoul(buf, 10, &lval)) > + return -EINVAL; > + if (!(lval == 0UL || lval == 1UL)) { > + dev_err(dev, "The mode is not supported\n"); > + return -EINVAL; > + } > + > + /* get the "proximity scheme" i.e. if the chip does on chip > + infrared supression (1 means perform on chip supression) */ > + mutex_lock(&chip->lock); > + chip->prox_scheme = (int)lval; > + mutex_unlock(&chip->lock); > + > + return count; > +} > + > +/* 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); > +} > + > +/* Read name */ > +static ssize_t show_name(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct isl29018_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%s\n", chip->client->name); > +} > + > +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(proximity_on_chip_ambient_infrared_supression, > + S_IRUGO | S_IWUSR, > + show_prox_infrared_suppression, > + store_prox_infrared_supression, 0); > +static IIO_DEVICE_ATTR(illuminance0_input, S_IRUGO, show_lux, NULL, 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); > +static IIO_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); > + > +#define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) > +static struct attribute *isl29018_attributes[] = { > + ISL29018_DEV_ATTR(name), > + ISL29018_DEV_ATTR(range), > + ISL29018_DEV_ATTR(range_available), > + ISL29018_DEV_ATTR(adc_resolution), > + ISL29018_DEV_ATTR(adc_resolution_available), > + ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_supression), > + ISL29018_DEV_ATTR(illuminance0_input), > + ISL29018_DEV_ATTR(intensity_infrared_raw), > + ISL29018_DEV_ATTR(proximity_raw), > + NULL > +}; > + > +static const struct attribute_group isl29108_group = { > + .attrs = isl29018_attributes, > +}; > + > +static int isl29018_chip_init(struct i2c_client *client) > +{ > + struct isl29018_chip *chip = i2c_get_clientdata(client); > + int status; > + int i; > + int new_adc_bit; > + unsigned int new_range; > + > + memset(chip->reg_cache, 0, sizeof(chip->reg_cache)); > + > + /* set defaults */ > + status = isl29018_set_range(client, chip->range, &new_range); > + if (status < 0) { > + dev_err(&client->dev, "Init of isl29018 fails\n"); > + return status; > + } > + > + status = isl29018_set_resolution(client, chip->adc_bit, > + &new_adc_bit); > + > + return 0; > +} > + > +static int __devinit isl29018_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct isl29018_chip *chip; > + int err; > + > + chip = kzalloc(sizeof(struct isl29018_chip), GFP_KERNEL); > + if (!chip) { > + dev_err(&client->dev, "Memory allocation fails\n"); > + err = -ENOMEM; > + goto exit; > + } > + > + i2c_set_clientdata(client, chip); > + chip->client = client; > + > + mutex_init(&chip->lock); > + > + chip->range = 1000; > + chip->adc_bit = 16; > + > + err = isl29018_chip_init(client); > + if (err) > + goto exit_free; > + > + chip->indio_dev = iio_allocate_device(); > + if (!chip->indio_dev) { > + dev_err(&client->dev, "iio allocation fails\n"); > + goto exit_free; > + } > + chip->indio_dev->attrs = &isl29108_group; > + chip->indio_dev->dev.parent = &client->dev; > + chip->indio_dev->dev_data = (void *)(chip); > + chip->indio_dev->driver_module = THIS_MODULE; > + chip->indio_dev->modes = INDIO_DIRECT_MODE; > + err = iio_device_register(chip->indio_dev); > + if (err) { > + dev_err(&client->dev, "iio registration fails\n"); > + goto exit_iio_free; > + } > + > + return 0; > +exit_iio_free: > + iio_free_device(chip->indio_dev); > +exit_free: > + kfree(chip); > +exit: > + return err; > +} > + > +static int __devexit isl29018_remove(struct i2c_client *client) > +{ > + struct isl29018_chip *chip = i2c_get_clientdata(client); > + > + dev_dbg(&client->dev, "%s()\n", __func__); > + iio_device_unregister(chip->indio_dev); > + kfree(chip); > + > + 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) > +{ > + return i2c_add_driver(&isl29018_driver); > +} > + > +static void __exit isl29018_exit(void) > +{ > + i2c_del_driver(&isl29018_driver); > +} > + > +module_init(isl29018_init); > +module_exit(isl29018_exit); > + > +MODULE_DESCRIPTION("ISL29018 Ambient Light Sensor driver"); > +MODULE_LICENSE("GPL"); -- To unsubscribe from this list: send the line "unsubscribe linux-i2c" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html