ret = state->command(state, cmd, 0, &tmp, sizeof(tmp));
*val = be16_to_cpup(&tmp);
return ret;
}
staticint scd30_reset(struct scd30_state *state)
{ int ret;
u16 val;
ret = scd30_command_write(state, CMD_RESET, 0); if (ret) return ret;
/* sensor boots up within 2 secs */
msleep(2000); /* * Power-on-reset causes sensor to produce some glitch on i2c bus and * some controllers end up in error state. Try to recover by placing * any data on the bus.
*/
scd30_command_read(state, CMD_MEAS_READY, &val);
return 0;
}
/* simplified float to fixed point conversion with a scaling factor of 0.01 */ staticint scd30_float_to_fp(int float32)
{ int fraction, shift,
mantissa = float32 & GENMASK(22, 0),
sign = (float32 & BIT(31)) ? -1 : 1,
exp = (float32 & ~BIT(31)) >> 23;
/* special case 0 */ if (!exp && !mantissa) return 0;
for (i = 0; i < ARRAY_SIZE(state->meas); i++)
state->meas[i] = scd30_float_to_fp(state->meas[i]);
/* * co2 is left unprocessed while temperature and humidity are scaled * to milli deg C and milli percent respectively.
*/
state->meas[SCD30_TEMP] *= 10;
state->meas[SCD30_HR] *= 10;
return 0;
}
staticint scd30_wait_meas_irq(struct scd30_state *state)
{ int ret, timeout;
reinit_completion(&state->meas_ready);
enable_irq(state->irq);
timeout = msecs_to_jiffies(state->meas_interval * (1000 + SCD30_EXTRA_TIMEOUT_PER_S));
ret = wait_for_completion_interruptible_timeout(&state->meas_ready, timeout); if (ret > 0)
ret = 0; elseif (!ret)
ret = -ETIMEDOUT;
staticint scd30_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, constint **vals, int *type, int *length, long mask)
{ switch (mask) { case IIO_CHAN_INFO_RAW:
*vals = scd30_pressure_raw_available;
*type = IIO_VAL_INT;
return IIO_AVAIL_RANGE; case IIO_CHAN_INFO_CALIBBIAS:
*vals = scd30_temp_calibbias_available;
*type = IIO_VAL_INT;
return IIO_AVAIL_RANGE;
}
return -EINVAL;
}
static ssize_t sampling_frequency_available_show(struct device *dev, struct device_attribute *attr, char *buf)
{ int i = SCD30_MEAS_INTERVAL_MIN_S;
ssize_t len = 0;
do {
len += sysfs_emit_at(buf, len, "0.%09u ", 1000000000 / i); /* * Not all values fit PAGE_SIZE buffer hence print every 6th * (each frequency differs by 6s in time domain from the * adjacent). Unlisted but valid ones are still accepted.
*/
i += 6;
} while (i <= SCD30_MEAS_INTERVAL_MAX_S);
staticconststruct iio_chan_spec scd30_channels[] = {
{ /* * this channel is special in a sense we are pretending that * sensor is able to change measurement chamber pressure but in * fact we're just setting pressure compensation value
*/
.type = IIO_PRESSURE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
.output = 1,
.scan_index = -1,
},
{
.type = IIO_CONCENTRATION,
.channel2 = IIO_MOD_CO2,
.address = SCD30_CONC,
.scan_index = SCD30_CONC,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.modified = 1,
mutex_lock(&state->lock); if (!iio_trigger_using_own(indio_dev))
ret = scd30_read_poll(state); else
ret = scd30_read_meas(state);
memcpy(scan.data, state->meas, sizeof(state->meas));
mutex_unlock(&state->lock); if (ret) goto out;
ret = devm_iio_trigger_register(dev, trig); if (ret) return ret;
indio_dev->trig = iio_trigger_get(trig);
/* * Interrupt is enabled just before taking a fresh measurement * and disabled afterwards. This means we need to ensure it is not * enabled here to keep calls to enable/disable balanced.
*/
ret = devm_request_threaded_irq(dev, state->irq, scd30_irq_handler,
scd30_irq_thread_handler,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT |
IRQF_NO_AUTOEN,
indio_dev->name, indio_dev); if (ret) return dev_err_probe(dev, ret, "failed to request irq\n");
return 0;
}
int scd30_probe(struct device *dev, int irq, constchar *name, void *priv,
scd30_command_t command)
{ staticconstunsignedlong scd30_scan_masks[] = { 0x07, 0x00 }; struct scd30_state *state; struct iio_dev *indio_dev; int ret;
u16 val;
indio_dev = devm_iio_device_alloc(dev, sizeof(*state)); if (!indio_dev) return -ENOMEM;
state->vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(state->vdd)) return dev_err_probe(dev, PTR_ERR(state->vdd), "failed to get regulator\n");
ret = regulator_enable(state->vdd); if (ret) return ret;
ret = devm_add_action_or_reset(dev, scd30_disable_regulator, state); if (ret) return ret;
ret = scd30_reset(state); if (ret) return dev_err_probe(dev, ret, "failed to reset device\n");
if (state->irq > 0) {
ret = scd30_setup_trigger(indio_dev); if (ret) return dev_err_probe(dev, ret, "failed to setup trigger\n");
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, scd30_trigger_handler, NULL); if (ret) return ret;
ret = scd30_command_read(state, CMD_FW_VERSION, &val); if (ret) return dev_err_probe(dev, ret, "failed to read firmware version\n");
dev_info(dev, "firmware version: %d.%d\n", val >> 8, (char)val);
ret = scd30_command_write(state, CMD_MEAS_INTERVAL, state->meas_interval); if (ret) return dev_err_probe(dev, ret, "failed to set measurement interval\n");
ret = scd30_command_write(state, CMD_START_MEAS, state->pressure_comp); if (ret) return dev_err_probe(dev, ret, "failed to start measurement\n");
ret = devm_add_action_or_reset(dev, scd30_stop_meas, state); if (ret) return ret;
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.