brintos

brintos / linux-shallow public Read only

0
0
Text · 17.9 KiB · 7be5a45 Raw
755 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Sensirion SCD30 carbon dioxide sensor core driver4 *5 * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com>6 */7#include <linux/bits.h>8#include <linux/completion.h>9#include <linux/delay.h>10#include <linux/device.h>11#include <linux/errno.h>12#include <linux/export.h>13#include <linux/iio/buffer.h>14#include <linux/iio/iio.h>15#include <linux/iio/sysfs.h>16#include <linux/iio/trigger.h>17#include <linux/iio/trigger_consumer.h>18#include <linux/iio/triggered_buffer.h>19#include <linux/iio/types.h>20#include <linux/interrupt.h>21#include <linux/irqreturn.h>22#include <linux/jiffies.h>23#include <linux/kernel.h>24#include <linux/module.h>25#include <linux/mutex.h>26#include <linux/regulator/consumer.h>27#include <linux/string.h>28#include <linux/sysfs.h>29#include <linux/types.h>30#include <asm/byteorder.h>31 32#include "scd30.h"33 34#define SCD30_PRESSURE_COMP_MIN_MBAR 70035#define SCD30_PRESSURE_COMP_MAX_MBAR 140036#define SCD30_PRESSURE_COMP_DEFAULT 101337#define SCD30_MEAS_INTERVAL_MIN_S 238#define SCD30_MEAS_INTERVAL_MAX_S 180039#define SCD30_MEAS_INTERVAL_DEFAULT SCD30_MEAS_INTERVAL_MIN_S40#define SCD30_FRC_MIN_PPM 40041#define SCD30_FRC_MAX_PPM 200042#define SCD30_TEMP_OFFSET_MAX 65536043#define SCD30_EXTRA_TIMEOUT_PER_S 25044 45enum {46	SCD30_CONC,47	SCD30_TEMP,48	SCD30_HR,49};50 51static int scd30_command_write(struct scd30_state *state, enum scd30_cmd cmd, u16 arg)52{53	return state->command(state, cmd, arg, NULL, 0);54}55 56static int scd30_command_read(struct scd30_state *state, enum scd30_cmd cmd, u16 *val)57{58	__be16 tmp;59	int ret;60 61	ret = state->command(state, cmd, 0, &tmp, sizeof(tmp));62	*val = be16_to_cpup(&tmp);63 64	return ret;65}66 67static int scd30_reset(struct scd30_state *state)68{69	int ret;70	u16 val;71 72	ret = scd30_command_write(state, CMD_RESET, 0);73	if (ret)74		return ret;75 76	/* sensor boots up within 2 secs */77	msleep(2000);78	/*79	 * Power-on-reset causes sensor to produce some glitch on i2c bus and80	 * some controllers end up in error state. Try to recover by placing81	 * any data on the bus.82	 */83	scd30_command_read(state, CMD_MEAS_READY, &val);84 85	return 0;86}87 88/* simplified float to fixed point conversion with a scaling factor of 0.01 */89static int scd30_float_to_fp(int float32)90{91	int fraction, shift,92	    mantissa = float32 & GENMASK(22, 0),93	    sign = (float32 & BIT(31)) ? -1 : 1,94	    exp = (float32 & ~BIT(31)) >> 23;95 96	/* special case 0 */97	if (!exp && !mantissa)98		return 0;99 100	exp -= 127;101	if (exp < 0) {102		exp = -exp;103		/* return values ranging from 1 to 99 */104		return sign * ((((BIT(23) + mantissa) * 100) >> 23) >> exp);105	}106 107	/* return values starting at 100 */108	shift = 23 - exp;109	float32 = BIT(exp) + (mantissa >> shift);110	fraction = mantissa & GENMASK(shift - 1, 0);111 112	return sign * (float32 * 100 + ((fraction * 100) >> shift));113}114 115static int scd30_read_meas(struct scd30_state *state)116{117	int i, ret;118 119	ret = state->command(state, CMD_READ_MEAS, 0, state->meas, sizeof(state->meas));120	if (ret)121		return ret;122 123	be32_to_cpu_array(state->meas, (__be32 *)state->meas, ARRAY_SIZE(state->meas));124 125	for (i = 0; i < ARRAY_SIZE(state->meas); i++)126		state->meas[i] = scd30_float_to_fp(state->meas[i]);127 128	/*129	 * co2 is left unprocessed while temperature and humidity are scaled130	 * to milli deg C and milli percent respectively.131	 */132	state->meas[SCD30_TEMP] *= 10;133	state->meas[SCD30_HR] *= 10;134 135	return 0;136}137 138static int scd30_wait_meas_irq(struct scd30_state *state)139{140	int ret, timeout;141 142	reinit_completion(&state->meas_ready);143	enable_irq(state->irq);144	timeout = msecs_to_jiffies(state->meas_interval * (1000 + SCD30_EXTRA_TIMEOUT_PER_S));145	ret = wait_for_completion_interruptible_timeout(&state->meas_ready, timeout);146	if (ret > 0)147		ret = 0;148	else if (!ret)149		ret = -ETIMEDOUT;150 151	disable_irq(state->irq);152 153	return ret;154}155 156static int scd30_wait_meas_poll(struct scd30_state *state)157{158	int timeout = state->meas_interval * SCD30_EXTRA_TIMEOUT_PER_S, tries = 5;159 160	do {161		int ret;162		u16 val;163 164		ret = scd30_command_read(state, CMD_MEAS_READY, &val);165		if (ret)166			return -EIO;167 168		/* new measurement available */169		if (val)170			break;171 172		msleep_interruptible(timeout);173	} while (--tries);174 175	return tries ? 0 : -ETIMEDOUT;176}177 178static int scd30_read_poll(struct scd30_state *state)179{180	int ret;181 182	ret = scd30_wait_meas_poll(state);183	if (ret)184		return ret;185 186	return scd30_read_meas(state);187}188 189static int scd30_read(struct scd30_state *state)190{191	if (state->irq > 0)192		return scd30_wait_meas_irq(state);193 194	return scd30_read_poll(state);195}196 197static int scd30_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,198			  int *val, int *val2, long mask)199{200	struct scd30_state *state = iio_priv(indio_dev);201	int ret = -EINVAL;202	u16 tmp;203 204	mutex_lock(&state->lock);205	switch (mask) {206	case IIO_CHAN_INFO_RAW:207	case IIO_CHAN_INFO_PROCESSED:208		if (chan->output) {209			*val = state->pressure_comp;210			ret = IIO_VAL_INT;211			break;212		}213 214		ret = iio_device_claim_direct_mode(indio_dev);215		if (ret)216			break;217 218		ret = scd30_read(state);219		if (ret) {220			iio_device_release_direct_mode(indio_dev);221			break;222		}223 224		*val = state->meas[chan->address];225		iio_device_release_direct_mode(indio_dev);226		ret = IIO_VAL_INT;227		break;228	case IIO_CHAN_INFO_SCALE:229		*val = 0;230		*val2 = 1;231		ret = IIO_VAL_INT_PLUS_MICRO;232		break;233	case IIO_CHAN_INFO_SAMP_FREQ:234		ret = scd30_command_read(state, CMD_MEAS_INTERVAL, &tmp);235		if (ret)236			break;237 238		*val = 0;239		*val2 = 1000000000 / tmp;240		ret = IIO_VAL_INT_PLUS_NANO;241		break;242	case IIO_CHAN_INFO_CALIBBIAS:243		ret = scd30_command_read(state, CMD_TEMP_OFFSET, &tmp);244		if (ret)245			break;246 247		*val = tmp;248		ret = IIO_VAL_INT;249		break;250	}251	mutex_unlock(&state->lock);252 253	return ret;254}255 256static int scd30_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,257			   int val, int val2, long mask)258{259	struct scd30_state *state = iio_priv(indio_dev);260	int ret = -EINVAL;261 262	mutex_lock(&state->lock);263	switch (mask) {264	case IIO_CHAN_INFO_SAMP_FREQ:265		if (val)266			break;267 268		val = 1000000000 / val2;269		if (val < SCD30_MEAS_INTERVAL_MIN_S || val > SCD30_MEAS_INTERVAL_MAX_S)270			break;271 272		ret = scd30_command_write(state, CMD_MEAS_INTERVAL, val);273		if (ret)274			break;275 276		state->meas_interval = val;277		break;278	case IIO_CHAN_INFO_RAW:279		switch (chan->type) {280		case IIO_PRESSURE:281			if (val < SCD30_PRESSURE_COMP_MIN_MBAR ||282			    val > SCD30_PRESSURE_COMP_MAX_MBAR)283				break;284 285			ret = scd30_command_write(state, CMD_START_MEAS, val);286			if (ret)287				break;288 289			state->pressure_comp = val;290			break;291		default:292			break;293		}294		break;295	case IIO_CHAN_INFO_CALIBBIAS:296		if (val < 0 || val > SCD30_TEMP_OFFSET_MAX)297			break;298		/*299		 * Manufacturer does not explicitly specify min/max sensible300		 * values hence check is omitted for simplicity.301		 */302		ret = scd30_command_write(state, CMD_TEMP_OFFSET / 10, val);303	}304	mutex_unlock(&state->lock);305 306	return ret;307}308 309static int scd30_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,310				   long mask)311{312	switch (mask) {313	case IIO_CHAN_INFO_SAMP_FREQ:314		return IIO_VAL_INT_PLUS_NANO;315	case IIO_CHAN_INFO_RAW:316	case IIO_CHAN_INFO_CALIBBIAS:317		return IIO_VAL_INT;318	}319 320	return -EINVAL;321}322 323static const int scd30_pressure_raw_available[] = {324	SCD30_PRESSURE_COMP_MIN_MBAR, 1, SCD30_PRESSURE_COMP_MAX_MBAR,325};326 327static const int scd30_temp_calibbias_available[] = {328	0, 10, SCD30_TEMP_OFFSET_MAX,329};330 331static int scd30_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,332			    const int **vals, int *type, int *length, long mask)333{334	switch (mask) {335	case IIO_CHAN_INFO_RAW:336		*vals = scd30_pressure_raw_available;337		*type = IIO_VAL_INT;338 339		return IIO_AVAIL_RANGE;340	case IIO_CHAN_INFO_CALIBBIAS:341		*vals = scd30_temp_calibbias_available;342		*type = IIO_VAL_INT;343 344		return IIO_AVAIL_RANGE;345	}346 347	return -EINVAL;348}349 350static ssize_t sampling_frequency_available_show(struct device *dev, struct device_attribute *attr,351						 char *buf)352{353	int i = SCD30_MEAS_INTERVAL_MIN_S;354	ssize_t len = 0;355 356	do {357		len += sysfs_emit_at(buf, len, "0.%09u ", 1000000000 / i);358		/*359		 * Not all values fit PAGE_SIZE buffer hence print every 6th360		 * (each frequency differs by 6s in time domain from the361		 * adjacent). Unlisted but valid ones are still accepted.362		 */363		i += 6;364	} while (i <= SCD30_MEAS_INTERVAL_MAX_S);365 366	buf[len - 1] = '\n';367 368	return len;369}370 371static ssize_t calibration_auto_enable_show(struct device *dev, struct device_attribute *attr,372					    char *buf)373{374	struct iio_dev *indio_dev = dev_to_iio_dev(dev);375	struct scd30_state *state = iio_priv(indio_dev);376	int ret;377	u16 val;378 379	mutex_lock(&state->lock);380	ret = scd30_command_read(state, CMD_ASC, &val);381	mutex_unlock(&state->lock);382 383	return ret ?: sysfs_emit(buf, "%d\n", val);384}385 386static ssize_t calibration_auto_enable_store(struct device *dev, struct device_attribute *attr,387					     const char *buf, size_t len)388{389	struct iio_dev *indio_dev = dev_to_iio_dev(dev);390	struct scd30_state *state = iio_priv(indio_dev);391	bool val;392	int ret;393 394	ret = kstrtobool(buf, &val);395	if (ret)396		return ret;397 398	mutex_lock(&state->lock);399	ret = scd30_command_write(state, CMD_ASC, val);400	mutex_unlock(&state->lock);401 402	return ret ?: len;403}404 405static ssize_t calibration_forced_value_show(struct device *dev, struct device_attribute *attr,406					     char *buf)407{408	struct iio_dev *indio_dev = dev_to_iio_dev(dev);409	struct scd30_state *state = iio_priv(indio_dev);410	int ret;411	u16 val;412 413	mutex_lock(&state->lock);414	ret = scd30_command_read(state, CMD_FRC, &val);415	mutex_unlock(&state->lock);416 417	return ret ?: sysfs_emit(buf, "%d\n", val);418}419 420static ssize_t calibration_forced_value_store(struct device *dev, struct device_attribute *attr,421					      const char *buf, size_t len)422{423	struct iio_dev *indio_dev = dev_to_iio_dev(dev);424	struct scd30_state *state = iio_priv(indio_dev);425	int ret;426	u16 val;427 428	ret = kstrtou16(buf, 0, &val);429	if (ret)430		return ret;431 432	if (val < SCD30_FRC_MIN_PPM || val > SCD30_FRC_MAX_PPM)433		return -EINVAL;434 435	mutex_lock(&state->lock);436	ret = scd30_command_write(state, CMD_FRC, val);437	mutex_unlock(&state->lock);438 439	return ret ?: len;440}441 442static IIO_DEVICE_ATTR_RO(sampling_frequency_available, 0);443static IIO_DEVICE_ATTR_RW(calibration_auto_enable, 0);444static IIO_DEVICE_ATTR_RW(calibration_forced_value, 0);445 446static struct attribute *scd30_attrs[] = {447	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,448	&iio_dev_attr_calibration_auto_enable.dev_attr.attr,449	&iio_dev_attr_calibration_forced_value.dev_attr.attr,450	NULL451};452 453static const struct attribute_group scd30_attr_group = {454	.attrs = scd30_attrs,455};456 457static const struct iio_info scd30_info = {458	.attrs = &scd30_attr_group,459	.read_raw = scd30_read_raw,460	.write_raw = scd30_write_raw,461	.write_raw_get_fmt = scd30_write_raw_get_fmt,462	.read_avail = scd30_read_avail,463};464 465#define SCD30_CHAN_SCAN_TYPE(_sign, _realbits) .scan_type = { \466	.sign = _sign, \467	.realbits = _realbits, \468	.storagebits = 32, \469	.endianness = IIO_CPU, \470}471 472static const struct iio_chan_spec scd30_channels[] = {473	{474		/*475		 * this channel is special in a sense we are pretending that476		 * sensor is able to change measurement chamber pressure but in477		 * fact we're just setting pressure compensation value478		 */479		.type = IIO_PRESSURE,480		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),481		.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),482		.output = 1,483		.scan_index = -1,484	},485	{486		.type = IIO_CONCENTRATION,487		.channel2 = IIO_MOD_CO2,488		.address = SCD30_CONC,489		.scan_index = SCD30_CONC,490		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |491				      BIT(IIO_CHAN_INFO_SCALE),492		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),493		.modified = 1,494 495		SCD30_CHAN_SCAN_TYPE('u', 20),496	},497	{498		.type = IIO_TEMP,499		.address = SCD30_TEMP,500		.scan_index = SCD30_TEMP,501		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |502				      BIT(IIO_CHAN_INFO_CALIBBIAS),503		.info_mask_separate_available = BIT(IIO_CHAN_INFO_CALIBBIAS),504		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),505 506		SCD30_CHAN_SCAN_TYPE('s', 18),507	},508	{509		.type = IIO_HUMIDITYRELATIVE,510		.address = SCD30_HR,511		.scan_index = SCD30_HR,512		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),513		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),514 515		SCD30_CHAN_SCAN_TYPE('u', 17),516	},517	IIO_CHAN_SOFT_TIMESTAMP(3),518};519 520static int scd30_suspend(struct device *dev)521{522	struct iio_dev *indio_dev = dev_get_drvdata(dev);523	struct scd30_state *state  = iio_priv(indio_dev);524	int ret;525 526	ret = scd30_command_write(state, CMD_STOP_MEAS, 0);527	if (ret)528		return ret;529 530	return regulator_disable(state->vdd);531}532 533static int scd30_resume(struct device *dev)534{535	struct iio_dev *indio_dev = dev_get_drvdata(dev);536	struct scd30_state *state = iio_priv(indio_dev);537	int ret;538 539	ret = regulator_enable(state->vdd);540	if (ret)541		return ret;542 543	return scd30_command_write(state, CMD_START_MEAS, state->pressure_comp);544}545 546EXPORT_NS_SIMPLE_DEV_PM_OPS(scd30_pm_ops, scd30_suspend, scd30_resume, IIO_SCD30);547 548static void scd30_stop_meas(void *data)549{550	struct scd30_state *state = data;551 552	scd30_command_write(state, CMD_STOP_MEAS, 0);553}554 555static void scd30_disable_regulator(void *data)556{557	struct scd30_state *state = data;558 559	regulator_disable(state->vdd);560}561 562static irqreturn_t scd30_irq_handler(int irq, void *priv)563{564	struct iio_dev *indio_dev = priv;565 566	if (iio_buffer_enabled(indio_dev)) {567		iio_trigger_poll(indio_dev->trig);568 569		return IRQ_HANDLED;570	}571 572	return IRQ_WAKE_THREAD;573}574 575static irqreturn_t scd30_irq_thread_handler(int irq, void *priv)576{577	struct iio_dev *indio_dev = priv;578	struct scd30_state *state = iio_priv(indio_dev);579	int ret;580 581	ret = scd30_read_meas(state);582	if (ret)583		goto out;584 585	complete_all(&state->meas_ready);586out:587	return IRQ_HANDLED;588}589 590static irqreturn_t scd30_trigger_handler(int irq, void *p)591{592	struct iio_poll_func *pf = p;593	struct iio_dev *indio_dev = pf->indio_dev;594	struct scd30_state *state = iio_priv(indio_dev);595	struct {596		int data[SCD30_MEAS_COUNT];597		s64 ts __aligned(8);598	} scan;599	int ret;600 601	mutex_lock(&state->lock);602	if (!iio_trigger_using_own(indio_dev))603		ret = scd30_read_poll(state);604	else605		ret = scd30_read_meas(state);606	memset(&scan, 0, sizeof(scan));607	memcpy(scan.data, state->meas, sizeof(state->meas));608	mutex_unlock(&state->lock);609	if (ret)610		goto out;611 612	iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev));613out:614	iio_trigger_notify_done(indio_dev->trig);615	return IRQ_HANDLED;616}617 618static int scd30_set_trigger_state(struct iio_trigger *trig, bool state)619{620	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);621	struct scd30_state *st = iio_priv(indio_dev);622 623	if (state)624		enable_irq(st->irq);625	else626		disable_irq(st->irq);627 628	return 0;629}630 631static const struct iio_trigger_ops scd30_trigger_ops = {632	.set_trigger_state = scd30_set_trigger_state,633	.validate_device = iio_trigger_validate_own_device,634};635 636static int scd30_setup_trigger(struct iio_dev *indio_dev)637{638	struct scd30_state *state = iio_priv(indio_dev);639	struct device *dev = indio_dev->dev.parent;640	struct iio_trigger *trig;641	int ret;642 643	trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,644				      iio_device_id(indio_dev));645	if (!trig)646		return dev_err_probe(dev, -ENOMEM, "failed to allocate trigger\n");647 648	trig->ops = &scd30_trigger_ops;649	iio_trigger_set_drvdata(trig, indio_dev);650 651	ret = devm_iio_trigger_register(dev, trig);652	if (ret)653		return ret;654 655	indio_dev->trig = iio_trigger_get(trig);656 657	/*658	 * Interrupt is enabled just before taking a fresh measurement659	 * and disabled afterwards. This means we need to ensure it is not660	 * enabled here to keep calls to enable/disable balanced.661	 */662	ret = devm_request_threaded_irq(dev, state->irq, scd30_irq_handler,663					scd30_irq_thread_handler,664					IRQF_TRIGGER_HIGH | IRQF_ONESHOT |665					IRQF_NO_AUTOEN,666					indio_dev->name, indio_dev);667	if (ret)668		return dev_err_probe(dev, ret, "failed to request irq\n");669 670	return 0;671}672 673int scd30_probe(struct device *dev, int irq, const char *name, void *priv,674		scd30_command_t command)675{676	static const unsigned long scd30_scan_masks[] = { 0x07, 0x00 };677	struct scd30_state *state;678	struct iio_dev *indio_dev;679	int ret;680	u16 val;681 682	indio_dev = devm_iio_device_alloc(dev, sizeof(*state));683	if (!indio_dev)684		return -ENOMEM;685 686	state = iio_priv(indio_dev);687	state->dev = dev;688	state->priv = priv;689	state->irq = irq;690	state->pressure_comp = SCD30_PRESSURE_COMP_DEFAULT;691	state->meas_interval = SCD30_MEAS_INTERVAL_DEFAULT;692	state->command = command;693	mutex_init(&state->lock);694	init_completion(&state->meas_ready);695 696	dev_set_drvdata(dev, indio_dev);697 698	indio_dev->info = &scd30_info;699	indio_dev->name = name;700	indio_dev->channels = scd30_channels;701	indio_dev->num_channels = ARRAY_SIZE(scd30_channels);702	indio_dev->modes = INDIO_DIRECT_MODE;703	indio_dev->available_scan_masks = scd30_scan_masks;704 705	state->vdd = devm_regulator_get(dev, "vdd");706	if (IS_ERR(state->vdd))707		return dev_err_probe(dev, PTR_ERR(state->vdd), "failed to get regulator\n");708 709	ret = regulator_enable(state->vdd);710	if (ret)711		return ret;712 713	ret = devm_add_action_or_reset(dev, scd30_disable_regulator, state);714	if (ret)715		return ret;716 717	ret = scd30_reset(state);718	if (ret)719		return dev_err_probe(dev, ret, "failed to reset device\n");720 721	if (state->irq > 0) {722		ret = scd30_setup_trigger(indio_dev);723		if (ret)724			return dev_err_probe(dev, ret, "failed to setup trigger\n");725	}726 727	ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, scd30_trigger_handler, NULL);728	if (ret)729		return ret;730 731	ret = scd30_command_read(state, CMD_FW_VERSION, &val);732	if (ret)733		return dev_err_probe(dev, ret, "failed to read firmware version\n");734	dev_info(dev, "firmware version: %d.%d\n", val >> 8, (char)val);735 736	ret = scd30_command_write(state, CMD_MEAS_INTERVAL, state->meas_interval);737	if (ret)738		return dev_err_probe(dev, ret, "failed to set measurement interval\n");739 740	ret = scd30_command_write(state, CMD_START_MEAS, state->pressure_comp);741	if (ret)742		return dev_err_probe(dev, ret, "failed to start measurement\n");743 744	ret = devm_add_action_or_reset(dev, scd30_stop_meas, state);745	if (ret)746		return ret;747 748	return devm_iio_device_register(dev, indio_dev);749}750EXPORT_SYMBOL_NS(scd30_probe, IIO_SCD30);751 752MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>");753MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor core driver");754MODULE_LICENSE("GPL v2");755