/* sensor measures reliably up to 3000 ug / m3 */ #define SPS30_MAX_PM 3000 /* minimum and maximum self cleaning periods in seconds */ #define SPS30_AUTO_CLEANING_PERIOD_MIN 0 #define SPS30_AUTO_CLEANING_PERIOD_MAX 604800
enum {
PM1,
PM2P5,
PM4,
PM10,
};
enum {
RESET,
MEASURING,
};
static s32 sps30_float_to_int_clamped(__be32 *fp)
{ int val = be32_to_cpup(fp); int mantissa = val & GENMASK(22, 0); /* this is fine since passed float is always non-negative */ int exp = val >> 23; int fraction, shift;
/* special case 0 */ if (!exp && !mantissa) return 0;
exp -= 127; if (exp < 0) { /* return values ranging from 1 to 99 */ return ((((1 << 23) + mantissa) * 100) >> 23) >> (-exp);
}
/* return values ranging from 100 to 300000 */
shift = 23 - exp;
val = (1 << exp) + (mantissa >> shift); if (val >= SPS30_MAX_PM) return SPS30_MAX_PM * 100;
fraction = mantissa & GENMASK(shift - 1, 0);
return val * 100 + ((fraction * 100) >> shift);
}
staticint sps30_do_meas(struct sps30_state *state, s32 *data, int size)
{ int i, ret;
if (state->state == RESET) {
ret = state->ops->start_meas(state); if (ret) return ret;
state->state = MEASURING;
}
ret = state->ops->read_meas(state, (__be32 *)data, size); if (ret) return ret;
for (i = 0; i < size; i++)
data[i] = sps30_float_to_int_clamped((__be32 *)&data[i]);
return 0;
}
staticint sps30_do_reset(struct sps30_state *state)
{ int ret;
ret = state->ops->reset(state); if (ret) return ret;
staticint sps30_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct sps30_state *state = iio_priv(indio_dev); int data[4], ret = -EINVAL;
switch (mask) { case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_MASSCONCENTRATION:
mutex_lock(&state->lock); /* read up to the number of bytes actually needed */ switch (chan->channel2) { case IIO_MOD_PM1:
ret = sps30_do_meas(state, data, 1); break; case IIO_MOD_PM2P5:
ret = sps30_do_meas(state, data, 2); break; case IIO_MOD_PM4:
ret = sps30_do_meas(state, data, 3); break; case IIO_MOD_PM10:
ret = sps30_do_meas(state, data, 4); break;
}
mutex_unlock(&state->lock); if (ret) return ret;
return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL;
} case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_MASSCONCENTRATION: switch (chan->channel2) { case IIO_MOD_PM1: case IIO_MOD_PM2P5: case IIO_MOD_PM4: case IIO_MOD_PM10:
*val = 0;
*val2 = 10000;
if ((val < SPS30_AUTO_CLEANING_PERIOD_MIN) ||
(val > SPS30_AUTO_CLEANING_PERIOD_MAX)) return -EINVAL;
mutex_lock(&state->lock);
ret = state->ops->write_cleaning_period(state, cpu_to_be32(val)); if (ret) {
mutex_unlock(&state->lock); return ret;
}
msleep(20);
/* * sensor requires reset in order to return up to date self cleaning * period
*/
ret = sps30_do_reset(state); if (ret)
dev_warn(dev, "period changed but reads will return the old value\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.