brintos

brintos / linux-shallow public Read only

0
0
Text · 3.9 KiB · 8fcd809 Raw
166 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2023 Anshul Dalal <anshulusr@gmail.com>4 *5 * Driver for Aosong AGS02MA6 *7 * Datasheet:8 *   https://asairsensors.com/wp-content/uploads/2021/09/AGS02MA.pdf9 * Product Page:10 *   http://www.aosong.com/m/en/products-33.html11 */12 13#include <linux/crc8.h>14#include <linux/delay.h>15#include <linux/i2c.h>16#include <linux/module.h>17 18#include <linux/iio/iio.h>19 20#define AGS02MA_TVOC_READ_REG		   0x0021#define AGS02MA_VERSION_REG		   0x1122 23#define AGS02MA_VERSION_PROCESSING_DELAY   3024#define AGS02MA_TVOC_READ_PROCESSING_DELAY 150025 26#define AGS02MA_CRC8_INIT		   0xff27#define AGS02MA_CRC8_POLYNOMIAL		   0x3128 29DECLARE_CRC8_TABLE(ags02ma_crc8_table);30 31struct ags02ma_data {32	struct i2c_client *client;33};34 35struct ags02ma_reading {36	__be32 data;37	u8 crc;38} __packed;39 40static int ags02ma_register_read(struct i2c_client *client, u8 reg, u16 delay,41				 u32 *val)42{43	int ret;44	u8 crc;45	struct ags02ma_reading read_buffer;46 47	ret = i2c_master_send(client, &reg, sizeof(reg));48	if (ret < 0) {49		dev_err(&client->dev,50			"Failed to send data to register 0x%x: %d", reg, ret);51		return ret;52	}53 54	/* Processing Delay, Check Table 7.7 in the datasheet */55	msleep_interruptible(delay);56 57	ret = i2c_master_recv(client, (u8 *)&read_buffer, sizeof(read_buffer));58	if (ret < 0) {59		dev_err(&client->dev,60			"Failed to receive from register 0x%x: %d", reg, ret);61		return ret;62	}63 64	crc = crc8(ags02ma_crc8_table, (u8 *)&read_buffer.data,65		   sizeof(read_buffer.data), AGS02MA_CRC8_INIT);66	if (crc != read_buffer.crc) {67		dev_err(&client->dev, "CRC error\n");68		return -EIO;69	}70 71	*val = be32_to_cpu(read_buffer.data);72	return 0;73}74 75static int ags02ma_read_raw(struct iio_dev *iio_device,76			    struct iio_chan_spec const *chan, int *val,77			    int *val2, long mask)78{79	int ret;80	struct ags02ma_data *data = iio_priv(iio_device);81 82	switch (mask) {83	case IIO_CHAN_INFO_RAW:84		ret = ags02ma_register_read(data->client, AGS02MA_TVOC_READ_REG,85					    AGS02MA_TVOC_READ_PROCESSING_DELAY,86					    val);87		if (ret < 0)88			return ret;89		return IIO_VAL_INT;90	case IIO_CHAN_INFO_SCALE:91		/* The sensor reads data as ppb */92		*val = 0;93		*val2 = 100;94		return IIO_VAL_INT_PLUS_NANO;95	default:96		return -EINVAL;97	}98}99 100static const struct iio_info ags02ma_info = {101	.read_raw = ags02ma_read_raw,102};103 104static const struct iio_chan_spec ags02ma_channel = {105	.type = IIO_CONCENTRATION,106	.channel2 = IIO_MOD_VOC,107	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |108		BIT(IIO_CHAN_INFO_SCALE),109};110 111static int ags02ma_probe(struct i2c_client *client)112{113	int ret;114	struct ags02ma_data *data;115	struct iio_dev *indio_dev;116	u32 version;117 118	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));119	if (!indio_dev)120		return -ENOMEM;121 122	crc8_populate_msb(ags02ma_crc8_table, AGS02MA_CRC8_POLYNOMIAL);123 124	ret = ags02ma_register_read(client, AGS02MA_VERSION_REG,125				    AGS02MA_VERSION_PROCESSING_DELAY, &version);126	if (ret < 0)127		return dev_err_probe(&client->dev, ret,128			      "Failed to read device version\n");129	dev_dbg(&client->dev, "Aosong AGS02MA, Version: 0x%x", version);130 131	data = iio_priv(indio_dev);132	data->client = client;133	indio_dev->info = &ags02ma_info;134	indio_dev->channels = &ags02ma_channel;135	indio_dev->num_channels = 1;136	indio_dev->name = "ags02ma";137 138	return devm_iio_device_register(&client->dev, indio_dev);139}140 141static const struct i2c_device_id ags02ma_id_table[] = {142	{ "ags02ma" },143	{ /* Sentinel */ }144};145MODULE_DEVICE_TABLE(i2c, ags02ma_id_table);146 147static const struct of_device_id ags02ma_of_table[] = {148	{ .compatible = "aosong,ags02ma" },149	{ /* Sentinel */ }150};151MODULE_DEVICE_TABLE(of, ags02ma_of_table);152 153static struct i2c_driver ags02ma_driver = {154	.driver = {155		.name = "ags02ma",156		.of_match_table = ags02ma_of_table,157	},158	.id_table = ags02ma_id_table,159	.probe = ags02ma_probe,160};161module_i2c_driver(ags02ma_driver);162 163MODULE_AUTHOR("Anshul Dalal <anshulusr@gmail.com>");164MODULE_DESCRIPTION("Aosong AGS02MA TVOC Driver");165MODULE_LICENSE("GPL");166