staticint opt4060_set_state_common(struct opt4060_chip *chip, bool continuous_sampling, bool continuous_irq)
{ int ret = 0;
/* It is important to setup irq before sampling to avoid missing samples. */ if (continuous_irq)
ret = opt4060_set_int_state(chip, OPT4060_INT_CTRL_ALL_CH); else
ret = opt4060_set_int_state(chip, OPT4060_INT_CTRL_THRESHOLD); if (ret) {
dev_err(chip->dev, "Failed to set irq state.\n"); return ret;
}
if (continuous_sampling || opt4060_event_active(chip))
ret = opt4060_set_sampling_mode(chip, true); else
ret = opt4060_set_sampling_mode(chip, false); if (ret)
dev_err(chip->dev, "Failed to set sampling state.\n"); return ret;
}
/* *Functionforsettingthedriverstateforsamplingandirq.Eitherdirect *modeofbuffermodewillbeclaimedduringthetransitiontopreventraces *betweensysfsread,bufferorevents.
*/ staticint opt4060_set_driver_state(struct iio_dev *indio_dev, bool continuous_sampling, bool continuous_irq)
{ struct opt4060_chip *chip = iio_priv(indio_dev); int ret = 0;
any_mode_retry: if (iio_device_claim_buffer_mode(indio_dev)) { /* *Thisoneisa*bit*hacky.Ifwecannotclaimbuffermode, *thentrydirectmodesothatwemakesurethingscannot *concurrentlychange.Andwejustkeeptryinguntilwegetone *ofthemodes...
*/ if (!iio_device_claim_direct(indio_dev)) goto any_mode_retry; /* *Thispathmeansthatwemanagedtoclaimdirectmode.In *thiscasethebufferisn'tenabledandit'sokaytoleave *continuousmodeforsamplingand/orirq.
*/
ret = opt4060_set_state_common(chip, continuous_sampling,
continuous_irq);
iio_device_release_direct(indio_dev); return ret;
} else { /* *Thispathmeansthatwemanagedtoclaimbuffermode.In *thiscasethebufferisenabledandirqandsamplingmustgo *toorremaincontinuous,butonlyifthetriggerisfromthis *device.
*/ if (!iio_trigger_validate_own_device(indio_dev->trig, indio_dev))
ret = opt4060_set_state_common(chip, true, true); else
ret = opt4060_set_state_common(chip, continuous_sampling,
continuous_irq);
iio_device_release_buffer_mode(indio_dev);
} return ret;
}
ret = regmap_read_poll_timeout(chip->regmap, OPT4060_RES_CTRL,
ready, (ready & OPT4060_RES_CTRL_CONV_READY), 1000, timeout_us); if (ret)
dev_err(chip->dev, "Conversion ready did not finish within timeout.\n");
} /* Setting the state in one shot mode with irq on thresholds. */ return opt4060_set_driver_state(indio_dev, false, false);
}
staticint opt4060_read_chan_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val)
{ struct opt4060_chip *chip = iio_priv(indio_dev);
u32 adc_raw; int ret;
ret = opt4060_trigger_new_samples(indio_dev); if (ret) {
dev_err(chip->dev, "Failed to trigger new samples.\n"); return ret;
}
ret = opt4060_read_raw_value(chip, chan->address, &adc_raw); if (ret) {
dev_err(chip->dev, "Reading raw channel data failed.\n"); return ret;
}
*val = adc_raw; return IIO_VAL_INT;
}
staticint opt4060_calc_illuminance(struct opt4060_chip *chip, int *val)
{
u32 lux_raw; int ret;
/* The green wide spectral channel is used for illuminance. */
ret = opt4060_read_raw_value(chip, OPT4060_GREEN_MSB, &lux_raw); if (ret) {
dev_err(chip->dev, "Reading raw channel data failed\n"); return ret;
}
/* Illuminance is calculated by ADC_RAW * 2.15e-3. */
*val = DIV_U64_ROUND_CLOSEST((u64)(lux_raw * 215), 1000); return ret;
}
staticint opt4060_read_illuminance(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val)
{ struct opt4060_chip *chip = iio_priv(indio_dev); int ret;
ret = opt4060_trigger_new_samples(indio_dev); if (ret) {
dev_err(chip->dev, "Failed to trigger new samples.\n"); return ret;
}
ret = opt4060_calc_illuminance(chip, val); if (ret) {
dev_err(chip->dev, "Failed to calculate illuminance.\n"); return ret;
}
return IIO_VAL_INT;
}
staticint opt4060_set_int_time(struct opt4060_chip *chip)
{ unsignedint regval; int ret;
regval = FIELD_PREP(OPT4060_CTRL_CONV_TIME_MASK, chip->int_time);
ret = regmap_update_bits(chip->regmap, OPT4060_CTRL,
OPT4060_CTRL_CONV_TIME_MASK, regval); if (ret)
dev_err(chip->dev, "Failed to set integration time.\n");
return ret;
}
staticint opt4060_power_down(struct opt4060_chip *chip)
{ int ret;
ret = regmap_clear_bits(chip->regmap, OPT4060_CTRL, OPT4060_CTRL_OPER_MODE_MASK); if (ret)
dev_err(chip->dev, "Failed to power down\n");
ret = regmap_write(chip->regmap, OPT4060_THRESHOLD_LOW, opt4060_calc_th_reg(th_lo)); if (ret) {
dev_err(chip->dev, "Failed to write THRESHOLD_LOW.\n"); return ret;
}
ret = regmap_write(chip->regmap, OPT4060_THRESHOLD_HIGH, opt4060_calc_th_reg(th_hi)); if (ret)
dev_err(chip->dev, "Failed to write THRESHOLD_HIGH.\n");
if (chan->type != IIO_INTENSITY) return -EINVAL; if (type != IIO_EV_TYPE_THRESH) return -EINVAL;
ret = opt4060_get_channel_sel(chip, &ch_sel); if (ret) return ret;
if (state) { /* Only one channel can be active at the same time */ if ((chip->thresh_event_lo_active || chip->thresh_event_hi_active) &&
(ch_idx != ch_sel)) return -EBUSY; if (dir == IIO_EV_DIR_FALLING)
chip->thresh_event_lo_active = true; elseif (dir == IIO_EV_DIR_RISING)
chip->thresh_event_hi_active = true;
ret = opt4060_set_channel_sel(chip, ch_idx); if (ret) return ret;
} else { if (ch_idx == ch_sel) { if (dir == IIO_EV_DIR_FALLING)
chip->thresh_event_lo_active = false; elseif (dir == IIO_EV_DIR_RISING)
chip->thresh_event_hi_active = false;
}
}
static irqreturn_t opt4060_trigger_handler(int irq, void *p)
{ struct iio_poll_func *pf = p; struct iio_dev *idev = pf->indio_dev; struct opt4060_chip *chip = iio_priv(idev); struct {
u32 chan[OPT4060_NUM_CHANS];
aligned_s64 ts;
} raw = { }; int i = 0; int chan, ret;
/* If the trigger is not from this driver, a new sample is needed.*/ if (iio_trigger_validate_own_device(idev->trig, idev))
opt4060_trigger_new_samples(idev);
iio_for_each_active_channel(idev, chan) { if (chan == OPT4060_ILLUM)
ret = opt4060_calc_illuminance(chip, &raw.chan[i++]); else
ret = opt4060_read_raw_value(chip,
idev->channels[chan].address,
&raw.chan[i++]); if (ret) {
dev_err(chip->dev, "Reading channel data failed\n"); goto err_read;
}
}
ret = regmap_read(chip->regmap, OPT4060_RES_CTRL, &int_res); if (ret < 0) {
dev_err(chip->dev, "Failed to read interrupt reasons.\n"); return IRQ_NONE;
}
/* Read OPT4060_CTRL to clear interrupt */
ret = regmap_read(chip->regmap, OPT4060_CTRL, &dummy); if (ret < 0) {
dev_err(chip->dev, "Failed to clear interrupt\n"); return IRQ_NONE;
}
/* Handle events */ if (int_res & (OPT4060_RES_CTRL_FLAG_H | OPT4060_RES_CTRL_FLAG_L)) {
u64 code; int chan = 0;
ret = opt4060_get_channel_sel(chip, &chan); if (ret) {
dev_err(chip->dev, "Failed to read threshold channel.\n"); return IRQ_NONE;
}
/* Check if the interrupt is from the lower threshold */ if (int_res & OPT4060_RES_CTRL_FLAG_L) {
code = IIO_MOD_EVENT_CODE(IIO_INTENSITY,
chan,
idev->channels[chan].channel2,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING);
iio_push_event(idev, code, iio_get_time_ns(idev));
} /* Check if the interrupt is from the upper threshold */ if (int_res & OPT4060_RES_CTRL_FLAG_H) {
code = IIO_MOD_EVENT_CODE(IIO_INTENSITY,
chan,
idev->channels[chan].channel2,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING);
iio_push_event(idev, code, iio_get_time_ns(idev));
}
}
/* Handle conversion ready */ if (int_res & OPT4060_RES_CTRL_CONV_READY) { /* Signal completion for potentially waiting reads */
complete(&chip->completion);
/* Handle data ready triggers */ if (iio_buffer_enabled(idev))
iio_trigger_poll_nested(chip->trig);
} return IRQ_HANDLED;
}
staticint opt4060_setup_buffer(struct opt4060_chip *chip, struct iio_dev *idev)
{ int ret;
ret = devm_iio_triggered_buffer_setup(chip->dev, idev,
&iio_pollfunc_store_time,
opt4060_trigger_handler, NULL); if (ret) return dev_err_probe(chip->dev, ret, "Buffer setup failed.\n"); return ret;
}
name = devm_kasprintf(chip->dev, GFP_KERNEL, "%s-opt4060",
dev_name(chip->dev)); if (!name) return dev_err_probe(chip->dev, -ENOMEM, "Failed to alloc chip name\n");
ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL, opt4060_irq_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
name, idev); if (ret) return dev_err_probe(chip->dev, ret, "Could not request IRQ\n");
init_completion(&chip->completion);
ret = devm_mutex_init(chip->dev, &chip->irq_setting_lock); if (ret) return ret;
ret = devm_mutex_init(chip->dev, &chip->event_enabling_lock); if (ret) return ret;
ret = regmap_write_bits(chip->regmap, OPT4060_INT_CTRL,
OPT4060_INT_CTRL_OUTPUT,
OPT4060_INT_CTRL_OUTPUT); if (ret) return dev_err_probe(chip->dev, ret, "Failed to set interrupt as output\n");
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.17Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-28)
¤
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.