Lines Matching +full:voc +full:- +full:sensor

1 // SPDX-License-Identifier: GPL-2.0+
3 * sgp40.c - Support for Sensirion SGP40 Gas Sensor
5 * Copyright (C) 2021 Andreas Klinger <ak@it-klinger.de>
14 * 1) read raw logarithmic resistance value from sensor
15 * --> useful to pass it to the algorithm of the sensor vendor for
19 * 2) calculate an estimated absolute voc index (in_concentration_input)
20 * with 0 - 500 index points) for measuring the air quality.
21 * For this purpose the value of the resistance for which the voc index
24 * The voc index is calculated as:
25 * x = (in_resistance_raw - in_resistance_calibbias) * 0.65
40 * floating point calculation of voc is done as integer
116 sign = -1; in sgp40_exp()
117 exp *= -1; in sgp40_exp()
135 divider -= power; in sgp40_exp()
139 if (sign == -1) in sgp40_exp()
145 static int sgp40_calc_voc(struct sgp40_data *data, u16 resistance_raw, int *voc) in sgp40_calc_voc() argument
151 mutex_lock(&data->lock); in sgp40_calc_voc()
152 x = ((int)resistance_raw - data->res_calibbias) * 106; in sgp40_calc_voc()
153 mutex_unlock(&data->lock); in sgp40_calc_voc()
155 /* voc = 500 / (1 + e^x) */ in sgp40_calc_voc()
157 *voc = 500 * ((1 << (SGP40_CALC_POWER * 2)) / ((1<<SGP40_CALC_POWER) + exp)); in sgp40_calc_voc()
159 dev_dbg(data->dev, "raw: %d res_calibbias: %d x: %d exp: %d voc: %d\n", in sgp40_calc_voc()
160 resistance_raw, data->res_calibbias, x, exp, *voc); in sgp40_calc_voc()
168 struct i2c_client *client = data->client; in sgp40_measure_resistance_raw()
175 mutex_lock(&data->lock); in sgp40_measure_resistance_raw()
177 ticks = (data->rht / 10) * 65535 / 10000; in sgp40_measure_resistance_raw()
182 ticks = ((data->temp + 45000) / 10 ) * 65535 / 17500; in sgp40_measure_resistance_raw()
183 ticks16 = (u16)clamp(ticks, 0u, 65535u); /* clamp between -45 .. +130 °C */ in sgp40_measure_resistance_raw()
187 mutex_unlock(&data->lock); in sgp40_measure_resistance_raw()
191 dev_warn(data->dev, "i2c_master_send ret: %d sizeof: %zu\n", ret, sizeof(tg)); in sgp40_measure_resistance_raw()
192 return -EIO; in sgp40_measure_resistance_raw()
200 dev_warn(data->dev, "i2c_master_recv ret: %d sizeof: %zu\n", ret, sizeof(tgres)); in sgp40_measure_resistance_raw()
201 return -EIO; in sgp40_measure_resistance_raw()
206 dev_err(data->dev, "CRC error while measure-raw\n"); in sgp40_measure_resistance_raw()
207 return -EIO; in sgp40_measure_resistance_raw()
220 int ret, voc; in sgp40_read_raw() local
225 switch (chan->type) { in sgp40_read_raw()
234 mutex_lock(&data->lock); in sgp40_read_raw()
235 *val = data->temp; in sgp40_read_raw()
236 mutex_unlock(&data->lock); in sgp40_read_raw()
239 mutex_lock(&data->lock); in sgp40_read_raw()
240 *val = data->rht; in sgp40_read_raw()
241 mutex_unlock(&data->lock); in sgp40_read_raw()
244 return -EINVAL; in sgp40_read_raw()
251 ret = sgp40_calc_voc(data, resistance_raw, &voc); in sgp40_read_raw()
255 *val = voc / (1 << SGP40_CALC_POWER); in sgp40_read_raw()
258 * voc <= (500 * 2^SGP40_CALC_POWER) = 8192000 in sgp40_read_raw()
261 *val2 = ((voc % (1 << SGP40_CALC_POWER)) * 244) / (1 << (SGP40_CALC_POWER - 12)); in sgp40_read_raw()
262 dev_dbg(data->dev, "voc: %d val: %d.%06d\n", voc, *val, *val2); in sgp40_read_raw()
265 mutex_lock(&data->lock); in sgp40_read_raw()
266 *val = data->res_calibbias; in sgp40_read_raw()
267 mutex_unlock(&data->lock); in sgp40_read_raw()
270 return -EINVAL; in sgp40_read_raw()
282 switch (chan->type) { in sgp40_write_raw()
284 if ((val < -45000) || (val > 130000)) in sgp40_write_raw()
285 return -EINVAL; in sgp40_write_raw()
287 mutex_lock(&data->lock); in sgp40_write_raw()
288 data->temp = val; in sgp40_write_raw()
289 mutex_unlock(&data->lock); in sgp40_write_raw()
293 return -EINVAL; in sgp40_write_raw()
295 mutex_lock(&data->lock); in sgp40_write_raw()
296 data->rht = val; in sgp40_write_raw()
297 mutex_unlock(&data->lock); in sgp40_write_raw()
300 return -EINVAL; in sgp40_write_raw()
304 return -EINVAL; in sgp40_write_raw()
306 mutex_lock(&data->lock); in sgp40_write_raw()
307 data->res_calibbias = val; in sgp40_write_raw()
308 mutex_unlock(&data->lock); in sgp40_write_raw()
311 return -EINVAL; in sgp40_write_raw()
322 struct device *dev = &client->dev; in sgp40_probe()
329 return -ENOMEM; in sgp40_probe()
332 data->client = client; in sgp40_probe()
333 data->dev = dev; in sgp40_probe()
337 mutex_init(&data->lock); in sgp40_probe()
340 data->rht = 50000; /* 50 % */ in sgp40_probe()
341 data->temp = 25000; /* 25 °C */ in sgp40_probe()
342 data->res_calibbias = 30000; /* resistance raw value for voc index of 250 */ in sgp40_probe()
344 indio_dev->info = &sgp40_info; in sgp40_probe()
345 indio_dev->name = id->name; in sgp40_probe()
346 indio_dev->modes = INDIO_DIRECT_MODE; in sgp40_probe()
347 indio_dev->channels = sgp40_channels; in sgp40_probe()
348 indio_dev->num_channels = ARRAY_SIZE(sgp40_channels); in sgp40_probe()
381 MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
382 MODULE_DESCRIPTION("Sensirion SGP40 gas sensor");