for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) { if (utime == isl29018_int_utimes[chip->type][i]) {
new_int_time = i; break;
}
}
if (i >= ARRAY_SIZE(isl29018_int_utimes[chip->type])) return -EINVAL;
ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2,
ISL29018_CMD2_RESOLUTION_MASK,
i << ISL29018_CMD2_RESOLUTION_SHIFT); if (ret < 0) return ret;
/* Keep the same range when integration time changes */
int_time = chip->int_time; for (i = 0; i < ARRAY_SIZE(isl29018_scales[int_time]); ++i) { if (chip->scale.scale == isl29018_scales[int_time][i].scale &&
chip->scale.uscale == isl29018_scales[int_time][i].uscale) {
chip->scale = isl29018_scales[new_int_time][i]; break;
}
}
chip->int_time = new_int_time;
return 0;
}
staticint isl29018_set_scale(struct isl29018_chip *chip, int scale, int uscale)
{ unsignedint i; int ret; struct isl29018_scale new_scale;
for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) { if (scale == isl29018_scales[chip->int_time][i].scale &&
uscale == isl29018_scales[chip->int_time][i].uscale) {
new_scale = isl29018_scales[chip->int_time][i]; break;
}
}
if (i >= ARRAY_SIZE(isl29018_scales[chip->int_time])) return -EINVAL;
ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2,
ISL29018_CMD2_RANGE_MASK,
i << ISL29018_CMD2_RANGE_SHIFT); if (ret < 0) return ret;
chip->scale = new_scale;
return 0;
}
staticint isl29018_read_sensor_input(struct isl29018_chip *chip, int mode)
{ int status; unsignedint lsb; unsignedint msb; struct device *dev = regmap_get_device(chip->regmap);
/* Set mode */
status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1,
mode << ISL29018_CMD1_OPMODE_SHIFT); if (status) {
dev_err(dev, "Error in setting operating mode err %d\n", status); return status;
}
msleep(ISL29018_CONV_TIME_MS);
status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb); if (status < 0) {
dev_err(dev, "Error in reading LSB DATA with err %d\n", status); return status;
}
status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb); if (status < 0) {
dev_err(dev, "Error in reading MSB DATA with error %d\n", status); return status;
}
dev_vdbg(dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
return (msb << 8) | lsb;
}
staticint isl29018_read_lux(struct isl29018_chip *chip, int *lux)
{ int lux_data; unsignedint data_x_range;
lux_data = isl29018_read_sensor_input(chip,
ISL29018_CMD1_OPMODE_ALS_ONCE); if (lux_data < 0) return lux_data;
staticint isl29018_read_ir(struct isl29018_chip *chip, int *ir)
{ int ir_data;
ir_data = isl29018_read_sensor_input(chip,
ISL29018_CMD1_OPMODE_IR_ONCE); if (ir_data < 0) return ir_data;
*ir = ir_data;
return 0;
}
staticint isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme, int *near_ir)
{ int status; int prox_data = -1; int ir_data = -1; struct device *dev = regmap_get_device(chip->regmap);
/* Do proximity sensing with required scheme */
status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2,
ISL29018_CMD2_SCHEME_MASK,
scheme << ISL29018_CMD2_SCHEME_SHIFT); if (status) {
dev_err(dev, "Error in setting operating mode\n"); return status;
}
prox_data = isl29018_read_sensor_input(chip,
ISL29018_CMD1_OPMODE_PROX_ONCE); if (prox_data < 0) return prox_data;
mutex_lock(&chip->lock); for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i)
len += sprintf(buf + len, "%d.%06d ",
isl29018_scales[chip->int_time][i].scale,
isl29018_scales[chip->int_time][i].uscale);
mutex_unlock(&chip->lock);
for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i)
len += sprintf(buf + len, "0.%06d ",
isl29018_int_utimes[chip->type][i]);
buf[len - 1] = '\n';
return len;
}
/* * From ISL29018 Data Sheet (FN6619.4, Oct 8, 2012) regarding the * infrared suppression: * * Proximity Sensing Scheme: Bit 7. This bit programs the function * of the proximity detection. Logic 0 of this bit, Scheme 0, makes * full n (4, 8, 12, 16) bits (unsigned) proximity detection. The range * of Scheme 0 proximity count is from 0 to 2^n. Logic 1 of this bit, * Scheme 1, makes n-1 (3, 7, 11, 15) bits (2's complementary) * proximity_less_ambient detection. The range of Scheme 1 * proximity count is from -2^(n-1) to 2^(n-1) . The sign bit is extended * for resolutions less than 16. While Scheme 0 has wider dynamic * range, Scheme 1 proximity detection is less affected by the * ambient IR noise variation. * * 0 Sensing IR from LED and ambient * 1 Sensing IR from LED with ambient IR rejection
*/ static ssize_t proximity_on_chip_ambient_infrared_suppression_show
(struct device *dev, struct device_attribute *attr, char *buf)
{ struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev);
/* * Return the "proximity scheme" i.e. if the chip does on chip * infrared suppression (1 means perform on chip suppression)
*/ return sprintf(buf, "%d\n", chip->prox_scheme);
}
if (kstrtoint(buf, 10, &val)) return -EINVAL; if (!(val == 0 || val == 1)) return -EINVAL;
/* * Get the "proximity scheme" i.e. if the chip does on chip * infrared suppression (1 means perform on chip suppression)
*/
mutex_lock(&chip->lock);
chip->prox_scheme = val;
mutex_unlock(&chip->lock);
return count;
}
staticint isl29018_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ struct isl29018_chip *chip = iio_priv(indio_dev); int ret = -EINVAL;
mutex_lock(&chip->lock); if (chip->suspended) {
ret = -EBUSY; goto write_done;
} switch (mask) { case IIO_CHAN_INFO_CALIBSCALE: if (chan->type == IIO_LIGHT) {
chip->calibscale = val;
chip->ucalibscale = val2;
ret = 0;
} break; case IIO_CHAN_INFO_INT_TIME: if (chan->type == IIO_LIGHT && !val)
ret = isl29018_set_integration_time(chip, val2); break; case IIO_CHAN_INFO_SCALE: if (chan->type == IIO_LIGHT)
ret = isl29018_set_scale(chip, val, val2); break; default: break;
}
write_done:
mutex_unlock(&chip->lock);
return ret;
}
staticint isl29018_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ int ret = -EINVAL; struct isl29018_chip *chip = iio_priv(indio_dev);
mutex_lock(&chip->lock); if (chip->suspended) {
ret = -EBUSY; goto read_done;
} switch (mask) { case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_LIGHT:
ret = isl29018_read_lux(chip, val); break; case IIO_INTENSITY:
ret = isl29018_read_ir(chip, val); break; case IIO_PROXIMITY:
ret = isl29018_read_proximity_ir(chip,
chip->prox_scheme,
val); break; default: break;
} if (!ret)
ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_INT_TIME: if (chan->type == IIO_LIGHT) {
*val = 0;
*val2 = isl29018_int_utimes[chip->type][chip->int_time];
ret = IIO_VAL_INT_PLUS_MICRO;
} break; case IIO_CHAN_INFO_SCALE: if (chan->type == IIO_LIGHT) {
*val = chip->scale.scale;
*val2 = chip->scale.uscale;
ret = IIO_VAL_INT_PLUS_MICRO;
} break; case IIO_CHAN_INFO_CALIBSCALE: if (chan->type == IIO_LIGHT) {
*val = chip->calibscale;
*val2 = chip->ucalibscale;
ret = IIO_VAL_INT_PLUS_MICRO;
} break; default: break;
}
status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); if (status < 0) {
dev_err(dev, "Error reading ID register with error %d\n",
status); return status;
}
id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT;
if (id != ISL29035_DEVICE_ID) return -ENODEV;
/* Clear brownout bit */
status = regmap_clear_bits(chip->regmap,
ISL29035_REG_DEVICE_ID,
ISL29035_BOUT_MASK); if (status < 0) return status;
}
/* * 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 = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0); if (status < 0) {
dev_err(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 = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0); if (status < 0) {
dev_err(dev, "Failed to clear isl29018 CMD1 reg.(%d)\n",
status); return status;
}
usleep_range(1000, 2000); /* per data sheet, page 10 */
/* Set defaults */
status = isl29018_set_scale(chip, chip->scale.scale,
chip->scale.uscale); if (status < 0) {
dev_err(dev, "Init of isl29018 fails\n"); return status;
}
status = isl29018_set_integration_time(chip,
isl29018_int_utimes[chip->type][chip->int_time]); if (status < 0)
dev_err(dev, "Init of isl29018 fails\n");
staticbool isl29018_is_volatile_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case ISL29018_REG_ADD_DATA_LSB: case ISL29018_REG_ADD_DATA_MSB: case ISL29018_REG_ADD_COMMAND1: case ISL29018_REG_TEST: case ISL29035_REG_DEVICE_ID: returntrue; default: returnfalse;
}
}
chip->vcc_reg = devm_regulator_get(&client->dev, "vcc"); if (IS_ERR(chip->vcc_reg)) return dev_err_probe(&client->dev, PTR_ERR(chip->vcc_reg), "failed to get VCC regulator!\n");
err = regulator_enable(chip->vcc_reg); if (err) {
dev_err(&client->dev, "failed to enable VCC regulator!\n"); return err;
}
err = devm_add_action_or_reset(&client->dev, isl29018_disable_regulator_action,
chip); if (err) {
dev_err(&client->dev, "failed to setup regulator cleanup action!\n"); return err;
}
/* * Since this driver uses only polling commands, we are by default in * auto shutdown (ie, power-down) mode. * So we do not have much to do here.
*/
chip->suspended = true;
ret = regulator_disable(chip->vcc_reg); if (ret)
dev_err(dev, "failed to disable VCC regulator\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.