staticint opt3001_find_scale(conststruct opt3001 *opt, int val, int val2, u8 *exponent)
{ int i; for (i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) { conststruct opt3001_scale *scale = &(*opt->chip_info->scales)[i]; /* *Comparetheintegerandmicropartstodeterminevaluescale.
*/ if (val < scale->val ||
(val == scale->val && val2 <= scale->val2)) {
*exponent = i; return0;
}
}
return -EINVAL;
}
staticvoid opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent,
u16 mantissa, int *val, int *val2)
{ int ret; int whole = opt->chip_info->factor_whole; int integer = opt->chip_info->factor_integer; int decimal = opt->chip_info->factor_decimal;
staticint opt3001_get_processed(struct opt3001 *opt, int *val, int *val2)
{ int ret;
u16 mantissa;
u16 reg;
u8 exponent;
u16 value; long timeout;
if (opt->use_irq) { /* *Enabletheend-of-conversioninterruptmechanism.Notethat *doingsowilloverwritethelow-levellimitvaluehoweverwe *willrestorethisvaluelateron.
*/
ret = i2c_smbus_write_word_swapped(opt->client,
OPT3001_LOW_LIMIT,
OPT3001_LOW_LIMIT_EOC_ENABLE); if (ret < 0) {
dev_err(opt->dev, "failed to write register %02x\n",
OPT3001_LOW_LIMIT); return ret;
}
/* Allow IRQ to access the device despite lock being set */
opt->ok_to_ignore_lock = true;
}
/* Reset data-ready indicator flag */
opt->result_ready = false;
/* Configure for single-conversion mode and start a new conversion */
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_CONFIGURATION); goto err;
}
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
reg); if (ret < 0) {
dev_err(opt->dev, "failed to write register %02x\n",
OPT3001_CONFIGURATION); goto err;
}
if (opt->use_irq) { /* Wait for the IRQ to indicate the conversion is complete */
ret = wait_event_timeout(opt->result_ready_queue,
opt->result_ready,
msecs_to_jiffies(OPT3001_RESULT_READY_LONG)); if (ret == 0) return -ETIMEDOUT;
} else { /* Sleep for result ready time */
timeout = (opt->int_time == OPT3001_INT_TIME_SHORT) ?
OPT3001_RESULT_READY_SHORT : OPT3001_RESULT_READY_LONG;
msleep(timeout);
/* Check result ready flag */
ret = i2c_smbus_read_word_swapped(opt->client,
OPT3001_CONFIGURATION); if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_CONFIGURATION); goto err;
}
if (!(ret & OPT3001_CONFIGURATION_CRF)) {
ret = -ETIMEDOUT; goto err;
}
/* Obtain value */
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT); if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_RESULT); goto err;
}
opt->result = ret;
opt->result_ready = true;
}
err: if (opt->use_irq) /* Disallow IRQ to access the device while lock is active */
opt->ok_to_ignore_lock = false;
if (ret < 0) return ret;
if (opt->use_irq) { /* *Disabletheend-of-conversioninterruptmechanismby *restoringthelow-levellimitvalue(clearing *OPT3001_LOW_LIMIT_EOC_ENABLE).Notethatselectivelyclearing *thoseenablebitswouldaffecttheactuallimitvaluedueto *bit-overlapandthereforecan'tbedone.
*/
value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa;
ret = i2c_smbus_write_word_swapped(opt->client,
OPT3001_LOW_LIMIT,
value); if (ret < 0) {
dev_err(opt->dev, "failed to write register %02x\n",
OPT3001_LOW_LIMIT); return ret;
}
}
staticint opt3001_read_raw(struct iio_dev *iio, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct opt3001 *opt = iio_priv(iio); int ret;
if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) return -EBUSY;
if (chan->type != opt->chip_info->chan_type) return -EINVAL;
mutex_lock(&opt->lock);
switch (mask) { case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED:
ret = opt3001_get_processed(opt, val, val2); break; case IIO_CHAN_INFO_INT_TIME:
ret = opt3001_get_int_time(opt, val, val2); break; default:
ret = -EINVAL;
}
mutex_unlock(&opt->lock);
return ret;
}
staticint opt3001_write_raw(struct iio_dev *iio, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ struct opt3001 *opt = iio_priv(iio); int ret;
if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) return -EBUSY;
if (chan->type != opt->chip_info->chan_type) return -EINVAL;
if (mask != IIO_CHAN_INFO_INT_TIME) return -EINVAL;
if (val != 0) return -EINVAL;
mutex_lock(&opt->lock);
ret = opt3001_set_int_time(opt, val2);
mutex_unlock(&opt->lock);
return ret;
}
staticint opt3001_read_event_value(struct iio_dev *iio, conststruct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, enum iio_event_info info, int *val, int *val2)
{ struct opt3001 *opt = iio_priv(iio); int ret = IIO_VAL_INT_PLUS_MICRO;
mutex_lock(&opt->lock);
switch (dir) { case IIO_EV_DIR_RISING:
opt3001_to_iio_ret(opt, opt->high_thresh_exp,
opt->high_thresh_mantissa, val, val2); break; case IIO_EV_DIR_FALLING:
opt3001_to_iio_ret(opt, opt->low_thresh_exp,
opt->low_thresh_mantissa, val, val2); break; default:
ret = -EINVAL;
}
mutex_unlock(&opt->lock);
return ret;
}
staticint opt3001_write_event_value(struct iio_dev *iio, conststruct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, enum iio_event_info info, int val, int val2)
{ struct opt3001 *opt = iio_priv(iio); int ret; int whole; int integer; int decimal;
u16 mantissa;
u16 value;
u16 reg;
u8 exponent;
if (val < 0) return -EINVAL;
mutex_lock(&opt->lock);
ret = opt3001_find_scale(opt, val, val2, &exponent); if (ret < 0) {
dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2); goto err;
}
/* Reflect status of the device's integration time setting */ if (reg & OPT3001_CONFIGURATION_CT)
opt->int_time = OPT3001_INT_TIME_LONG; else
opt->int_time = OPT3001_INT_TIME_SHORT;
/* Ensure device is in shutdown initially */
opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN);
ret = devm_iio_device_register(dev, iio); if (ret) {
dev_err(dev, "failed to register IIO device\n"); return ret;
}
/* Make use of INT pin only if valid IRQ no. is given */ if (irq > 0) {
ret = request_threaded_irq(irq, NULL, opt3001_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "opt3001", iio); if (ret) {
dev_err(dev, "failed to request IRQ #%d\n", irq); return ret;
}
opt->use_irq = true;
} else {
dev_dbg(opt->dev, "enabling interrupt-less operation\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.