diff options
Diffstat (limited to 'drivers/staging/iio/light/isl29018.c')
-rw-r--r-- | drivers/staging/iio/light/isl29018.c | 74 |
1 files changed, 63 insertions, 11 deletions
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 426b6af..9dc9e63 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -28,7 +28,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include "../iio.h" - +#include "../sysfs.h" #define CONVERSION_TIME_MS 100 #define ISL29018_REG_ADD_COMMAND1 0x00 @@ -51,7 +51,11 @@ #define ISL29018_REG_ADD_DATA_LSB 0x02 #define ISL29018_REG_ADD_DATA_MSB 0x03 -#define ISL29018_MAX_REGS ISL29018_REG_ADD_DATA_MSB +#define ISL29018_MAX_REGS (ISL29018_REG_ADD_DATA_MSB+1) + +#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; @@ -66,22 +70,27 @@ struct isl29018_chip { static int isl29018_write_data(struct i2c_client *client, u8 reg, u8 val, u8 mask, u8 shift) { - u8 regval; - int ret = 0; + u8 regval = val; + int ret; struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client)); - regval = chip->reg_cache[reg]; - regval &= ~mask; - regval |= val << shift; + /* don't cache or mask REG_TEST */ + if (reg < ISL29018_MAX_REGS) { + 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; + } else { + /* don't update cache on err */ + if (reg < ISL29018_MAX_REGS) + chip->reg_cache[reg] = regval; } - chip->reg_cache[reg] = regval; - return 0; + return ret; } static int isl29018_set_range(struct i2c_client *client, unsigned long range, @@ -411,7 +420,7 @@ static const struct iio_chan_spec isl29018_channels[] = { .type = IIO_LIGHT, .indexed = 1, .channel = 0, - .processed_val = 1, + .processed_val = IIO_PROCESSED, .info_mask = (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE), }, { .type = IIO_INTENSITY, @@ -457,6 +466,48 @@ static int isl29018_chip_init(struct i2c_client *client) memset(chip->reg_cache, 0, sizeof(chip->reg_cache)); + /* Code added per Intersil Application Note 1534: + * When VDD sinks to approximately 1.8V or below, some of + * the part's registers may change their state. When VDD + * recovers to 2.25V (or greater), the part may thus be in an + * unknown mode of operation. The user can return the part to + * a known mode of operation either by (a) setting VDD = 0V for + * 1 second or more and then powering back up with a slew rate + * of 0.5V/ms or greater, or (b) via I2C disable all ALS/PROX + * conversions, clear the test registers, and then rewrite all + * registers to the desired values. + * ... + * FOR ISL29011, ISL29018, ISL29021, ISL29023 + * 1. Write 0x00 to register 0x08 (TEST) + * 2. Write 0x00 to register 0x00 (CMD1) + * 3. Rewrite all registers to the desired values + * + * ISL29018 Data Sheet (FN6619.1, Feb 11, 2010) essentially says + * the same thing EXCEPT the data sheet asks for a 1ms delay after + * writing the CMD1 register. + */ + status = isl29018_write_data(client, ISL29018_REG_TEST, 0, + ISL29018_TEST_MASK, ISL29018_TEST_SHIFT); + if (status < 0) { + dev_err(&client->dev, "Failed to clear isl29018 TEST reg." + "(%d)\n", status); + return status; + } + + /* See Intersil AN1534 comments above. + * "Operating Mode" (COMMAND1) register is reprogrammed when + * data is read from the device. + */ + status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, 0, + 0xff, 0); + if (status < 0) { + dev_err(&client->dev, "Failed to clear isl29018 CMD1 reg." + "(%d)\n", status); + return status; + } + + msleep(1); /* per data sheet, page 10 */ + /* set defaults */ status = isl29018_set_range(client, chip->range, &new_range); if (status < 0) { @@ -530,6 +581,7 @@ static int __devexit isl29018_remove(struct i2c_client *client) dev_dbg(&client->dev, "%s()\n", __func__); iio_device_unregister(indio_dev); + iio_free_device(indio_dev); return 0; } |