brintos

brintos / linux-shallow public Read only

0
0
Text · 8.6 KiB · c1aa3b4 Raw
368 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * ScioSense ENS160 multi-gas sensor driver4 *5 * Copyright (c) 2024 Gustavo Silva <gustavograzs@gmail.com>6 *7 * Datasheet:8 *  https://www.sciosense.com/wp-content/uploads/2023/12/ENS160-Datasheet.pdf9 */10 11#include <linux/bitfield.h>12#include <linux/iio/iio.h>13#include <linux/iio/trigger.h>14#include <linux/iio/trigger_consumer.h>15#include <linux/iio/triggered_buffer.h>16#include <linux/module.h>17#include <linux/regmap.h>18 19#include "ens160.h"20 21#define ENS160_PART_ID 0x16022 23#define ENS160_BOOTING_TIME_MS 10U24 25#define ENS160_REG_PART_ID		0x0026 27#define ENS160_REG_OPMODE		0x1028 29#define ENS160_REG_CONFIG		0x1130#define ENS160_REG_CONFIG_INTEN		BIT(0)31#define ENS160_REG_CONFIG_INTDAT	BIT(1)32#define ENS160_REG_CONFIG_INT_CFG	BIT(5)33 34#define ENS160_REG_MODE_DEEP_SLEEP	0x0035#define ENS160_REG_MODE_IDLE		0x0136#define ENS160_REG_MODE_STANDARD	0x0237#define ENS160_REG_MODE_RESET		0xF038 39#define ENS160_REG_COMMAND		0x1240#define ENS160_REG_COMMAND_GET_APPVER	0x0E41#define ENS160_REG_COMMAND_CLRGPR	0xCC42 43#define ENS160_REG_TEMP_IN		0x1344#define ENS160_REG_RH_IN		0x1545#define ENS160_REG_DEVICE_STATUS	0x2046#define ENS160_REG_DATA_AQI		0x2147#define ENS160_REG_DATA_TVOC		0x2248#define ENS160_REG_DATA_ECO2		0x2449#define ENS160_REG_DATA_T		0x3050#define ENS160_REG_DATA_RH		0x3251#define ENS160_REG_GPR_READ4		0x4C52 53#define ENS160_STATUS_VALIDITY_FLAG	GENMASK(3, 2)54 55#define ENS160_STATUS_NORMAL		0x0056 57struct ens160_data {58	struct regmap *regmap;59	/* Protect reads from the sensor */60	struct mutex mutex;61	struct {62		__le16 chans[2];63		s64 timestamp __aligned(8);64	} scan __aligned(IIO_DMA_MINALIGN);65	u8 fw_version[3];66	__le16 buf;67};68 69static const struct iio_chan_spec ens160_channels[] = {70	{71		.type = IIO_CONCENTRATION,72		.channel2 = IIO_MOD_VOC,73		.modified = 1,74		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |75				      BIT(IIO_CHAN_INFO_SCALE),76		.address = ENS160_REG_DATA_TVOC,77		.scan_index = 0,78		.scan_type = {79			.sign = 'u',80			.realbits = 16,81			.storagebits = 16,82			.endianness = IIO_LE,83		},84	},85	{86		.type = IIO_CONCENTRATION,87		.channel2 = IIO_MOD_CO2,88		.modified = 1,89		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |90				      BIT(IIO_CHAN_INFO_SCALE),91		.address = ENS160_REG_DATA_ECO2,92		.scan_index = 1,93		.scan_type = {94			.sign = 'u',95			.realbits = 16,96			.storagebits = 16,97			.endianness = IIO_LE,98		},99	},100	IIO_CHAN_SOFT_TIMESTAMP(2),101};102 103static int ens160_read_raw(struct iio_dev *indio_dev,104			   struct iio_chan_spec const *chan,105			   int *val, int *val2, long mask)106{107	struct ens160_data *data = iio_priv(indio_dev);108	int ret;109 110	switch (mask) {111	case IIO_CHAN_INFO_RAW:112		iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {113			guard(mutex)(&data->mutex);114			ret = regmap_bulk_read(data->regmap, chan->address,115					       &data->buf, sizeof(data->buf));116			if (ret)117				return ret;118			*val = le16_to_cpu(data->buf);119			return IIO_VAL_INT;120		}121		unreachable();122	case IIO_CHAN_INFO_SCALE:123		switch (chan->channel2) {124		case IIO_MOD_CO2:125			/* The sensor reads CO2 data as ppm */126			*val = 0;127			*val2 = 100;128			return IIO_VAL_INT_PLUS_MICRO;129		case IIO_MOD_VOC:130			/* The sensor reads VOC data as ppb */131			*val = 0;132			*val2 = 100;133			return IIO_VAL_INT_PLUS_NANO;134		default:135			return -EINVAL;136		}137	default:138		return -EINVAL;139	}140}141 142static int ens160_set_mode(struct ens160_data *data, u8 mode)143{144	int ret;145 146	ret = regmap_write(data->regmap, ENS160_REG_OPMODE, mode);147	if (ret)148		return ret;149 150	msleep(ENS160_BOOTING_TIME_MS);151 152	return 0;153}154 155static void ens160_set_idle(void *data)156{157	ens160_set_mode(data, ENS160_REG_MODE_IDLE);158}159 160static int ens160_chip_init(struct ens160_data *data)161{162	struct device *dev = regmap_get_device(data->regmap);163	unsigned int status;164	int ret;165 166	ret = ens160_set_mode(data, ENS160_REG_MODE_RESET);167	if (ret)168		return ret;169 170	ret = regmap_bulk_read(data->regmap, ENS160_REG_PART_ID, &data->buf,171			       sizeof(data->buf));172	if (ret)173		return ret;174 175	if (le16_to_cpu(data->buf) != ENS160_PART_ID)176		return -ENODEV;177 178	ret = ens160_set_mode(data, ENS160_REG_MODE_IDLE);179	if (ret)180		return ret;181 182	ret = regmap_write(data->regmap, ENS160_REG_COMMAND,183			   ENS160_REG_COMMAND_CLRGPR);184	if (ret)185		return ret;186 187	ret = regmap_write(data->regmap, ENS160_REG_COMMAND,188			   ENS160_REG_COMMAND_GET_APPVER);189	if (ret)190		return ret;191 192	ret = regmap_bulk_read(data->regmap, ENS160_REG_GPR_READ4,193			       data->fw_version, sizeof(data->fw_version));194	if (ret)195		return ret;196 197	dev_info(dev, "firmware version: %u.%u.%u\n", data->fw_version[2],198		 data->fw_version[1], data->fw_version[0]);199 200	ret = ens160_set_mode(data, ENS160_REG_MODE_STANDARD);201	if (ret)202		return ret;203 204	ret = devm_add_action_or_reset(dev, ens160_set_idle, data);205	if (ret)206		return ret;207 208	ret = regmap_read(data->regmap, ENS160_REG_DEVICE_STATUS, &status);209	if (ret)210		return ret;211 212	if (FIELD_GET(ENS160_STATUS_VALIDITY_FLAG, status)213	    != ENS160_STATUS_NORMAL)214		return -EINVAL;215 216	return 0;217}218 219static const struct iio_info ens160_info = {220	.read_raw = ens160_read_raw,221};222 223static int ens160_suspend(struct device *dev)224{225	struct iio_dev *indio_dev = dev_get_drvdata(dev);226	struct ens160_data *data = iio_priv(indio_dev);227 228	return ens160_set_mode(data, ENS160_REG_MODE_DEEP_SLEEP);229}230 231static int ens160_resume(struct device *dev)232{233	struct iio_dev *indio_dev = dev_get_drvdata(dev);234	struct ens160_data *data = iio_priv(indio_dev);235	int ret;236 237	ret = ens160_set_mode(data, ENS160_REG_MODE_IDLE);238	if (ret)239		return ret;240 241	return ens160_set_mode(data, ENS160_REG_MODE_STANDARD);242}243EXPORT_NS_SIMPLE_DEV_PM_OPS(ens160_pm_ops, ens160_suspend, ens160_resume,244			    IIO_ENS160);245 246static irqreturn_t ens160_trigger_handler(int irq, void *p)247{248	struct iio_poll_func *pf = p;249	struct iio_dev *indio_dev = pf->indio_dev;250	struct ens160_data *data = iio_priv(indio_dev);251	int ret;252 253	guard(mutex)(&data->mutex);254 255	ret = regmap_bulk_read(data->regmap, ENS160_REG_DATA_TVOC,256			       data->scan.chans, sizeof(data->scan.chans));257	if (ret)258		goto err;259 260	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,261					   pf->timestamp);262err:263	iio_trigger_notify_done(indio_dev->trig);264 265	return IRQ_HANDLED;266}267 268static int ens160_set_trigger_state(struct iio_trigger *trig, bool state)269{270	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);271	struct ens160_data *data = iio_priv(indio_dev);272	unsigned int int_bits = ENS160_REG_CONFIG_INTEN |273				ENS160_REG_CONFIG_INTDAT |274				ENS160_REG_CONFIG_INT_CFG;275 276	if (state)277		return regmap_set_bits(data->regmap, ENS160_REG_CONFIG,278				       int_bits);279	else280		return regmap_clear_bits(data->regmap, ENS160_REG_CONFIG,281					 int_bits);282}283 284static const struct iio_trigger_ops ens160_trigger_ops = {285	.set_trigger_state = ens160_set_trigger_state,286	.validate_device = iio_trigger_validate_own_device,287};288 289static int ens160_setup_trigger(struct iio_dev *indio_dev, int irq)290{291	struct device *dev = indio_dev->dev.parent;292	struct iio_trigger *trig;293	int ret;294 295	trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,296				      iio_device_id(indio_dev));297	if (!trig)298		return dev_err_probe(dev, -ENOMEM,299				     "failed to allocate trigger\n");300 301	trig->ops = &ens160_trigger_ops;302	iio_trigger_set_drvdata(trig, indio_dev);303 304	ret = devm_iio_trigger_register(dev, trig);305	if (ret)306		return ret;307 308	indio_dev->trig = iio_trigger_get(trig);309 310	ret = devm_request_threaded_irq(dev, irq,311					iio_trigger_generic_data_rdy_poll,312					NULL,313					IRQF_ONESHOT,314					indio_dev->name,315					indio_dev->trig);316	if (ret)317		return dev_err_probe(dev, ret, "failed to request irq\n");318 319	return 0;320}321 322int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq,323			   const char *name)324{325	struct ens160_data *data;326	struct iio_dev *indio_dev;327	int ret;328 329	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));330	if (!indio_dev)331		return -ENOMEM;332 333	data = iio_priv(indio_dev);334	data->regmap = regmap;335 336	indio_dev->name = name;337	indio_dev->info = &ens160_info;338	indio_dev->modes = INDIO_DIRECT_MODE;339	indio_dev->channels = ens160_channels;340	indio_dev->num_channels = ARRAY_SIZE(ens160_channels);341 342	if (irq > 0) {343		ret = ens160_setup_trigger(indio_dev, irq);344		if (ret)345			return dev_err_probe(dev, ret,346					     "failed to setup trigger\n");347	}348 349	ret = ens160_chip_init(data);350	if (ret)351		return dev_err_probe(dev, ret, "chip initialization failed\n");352 353	mutex_init(&data->mutex);354 355	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,356					      iio_pollfunc_store_time,357					      ens160_trigger_handler, NULL);358	if (ret)359		return ret;360 361	return devm_iio_device_register(dev, indio_dev);362}363EXPORT_SYMBOL_NS(devm_ens160_core_probe, IIO_ENS160);364 365MODULE_AUTHOR("Gustavo Silva <gustavograzs@gmail.com>");366MODULE_DESCRIPTION("ScioSense ENS160 driver");367MODULE_LICENSE("GPL v2");368