File Index
Files and directories
Sign in
FILE

sen0322.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/chemical/sen0322.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Driver for the DFRobot SEN0322 oxygen sensor.
  4 *
  5 * Datasheet:
  6 *	https://wiki.dfrobot.com/Gravity_I2C_Oxygen_Sensor_SKU_SEN0322
  7 *
  8 * Possible I2C slave addresses:
  9 *	0x70
 10 *	0x71
 11 *	0x72
 12 *	0x73
 13 *
 14 * Copyright (C) 2025 Tóth János <gomba007@gmail.com>
 15 */
 16
 17#include <linux/i2c.h>
 18#include <linux/regmap.h>
 19
 20#include <linux/iio/iio.h>
 21
 22#define SEN0322_REG_DATA	0x03
 23#define SEN0322_REG_COEFF	0x0A
 24
 25struct sen0322 {
 26	struct regmap	*regmap;
 27};
 28
 29static int sen0322_read_data(struct sen0322 *sen0322)
 30{
 31	u8 data[3] = { };
 32	int ret;
 33
 34	ret = regmap_bulk_read(sen0322->regmap, SEN0322_REG_DATA, data,
 35			       sizeof(data));
 36	if (ret < 0)
 37		return ret;
 38
 39	/*
 40	 * The actual value in the registers is:
 41	 *	val = data[0] + data[1] / 10 + data[2] / 100
 42	 * but it is multiplied by 100 here to avoid floating-point math
 43	 * and the scale is divided by 100 to compensate this.
 44	 */
 45	return data[0] * 100 + data[1] * 10 + data[2];
 46}
 47
 48static int sen0322_read_scale(struct sen0322 *sen0322, int *num, int *den)
 49{
 50	u32 val;
 51	int ret;
 52
 53	ret = regmap_read(sen0322->regmap, SEN0322_REG_COEFF, &val);
 54	if (ret < 0)
 55		return ret;
 56
 57	if (val) {
 58		*num = val;
 59		*den = 100000;	/* Coeff is scaled by 1000 at calibration. */
 60	} else { /* The device is not calibrated, using the factory-defaults. */
 61		*num = 209;	/* Oxygen content in the atmosphere is 20.9%. */
 62		*den = 120000;	/* Output of the sensor at 20.9% is 120 uA. */
 63	}
 64
 65	dev_dbg(regmap_get_device(sen0322->regmap), "scale: %d/%d\n",
 66		*num, *den);
 67
 68	return 0;
 69}
 70
 71static int sen0322_read_raw(struct iio_dev *iio_dev,
 72			    const struct iio_chan_spec *chan,
 73			    int *val, int *val2, long mask)
 74{
 75	struct sen0322 *sen0322 = iio_priv(iio_dev);
 76	int ret;
 77
 78	if (chan->type != IIO_CONCENTRATION)
 79		return -EINVAL;
 80
 81	switch (mask) {
 82	case IIO_CHAN_INFO_RAW:
 83		ret = sen0322_read_data(sen0322);
 84		if (ret < 0)
 85			return ret;
 86
 87		*val = ret;
 88		return IIO_VAL_INT;
 89
 90	case IIO_CHAN_INFO_SCALE:
 91		ret = sen0322_read_scale(sen0322, val, val2);
 92		if (ret < 0)
 93			return ret;
 94
 95		return IIO_VAL_FRACTIONAL;
 96
 97	default:
 98		return -EINVAL;
 99	}
100}
101
102static const struct iio_info sen0322_info = {
103	.read_raw = sen0322_read_raw,
104};
105
106static const struct regmap_config sen0322_regmap_conf = {
107	.reg_bits = 8,
108	.val_bits = 8,
109};
110
111static const struct iio_chan_spec sen0322_channel = {
112	.type = IIO_CONCENTRATION,
113	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
114			      BIT(IIO_CHAN_INFO_SCALE),
115};
116
117static int sen0322_probe(struct i2c_client *client)
118{
119	struct sen0322 *sen0322;
120	struct iio_dev *iio_dev;
121
122	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
123		return -ENODEV;
124
125	iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*sen0322));
126	if (!iio_dev)
127		return -ENOMEM;
128
129	sen0322 = iio_priv(iio_dev);
130
131	sen0322->regmap = devm_regmap_init_i2c(client, &sen0322_regmap_conf);
132	if (IS_ERR(sen0322->regmap))
133		return PTR_ERR(sen0322->regmap);
134
135	iio_dev->info = &sen0322_info;
136	iio_dev->name = "sen0322";
137	iio_dev->channels = &sen0322_channel;
138	iio_dev->num_channels = 1;
139	iio_dev->modes = INDIO_DIRECT_MODE;
140
141	return devm_iio_device_register(&client->dev, iio_dev);
142}
143
144static const struct of_device_id sen0322_of_match[] = {
145	{ .compatible = "dfrobot,sen0322" },
146	{ }
147};
148MODULE_DEVICE_TABLE(of, sen0322_of_match);
149
150static struct i2c_driver sen0322_driver = {
151	.driver = {
152		.name = "sen0322",
153		.of_match_table = sen0322_of_match,
154	},
155	.probe = sen0322_probe,
156};
157module_i2c_driver(sen0322_driver);
158
159MODULE_AUTHOR("Tóth János <gomba007@gmail.com>");
160MODULE_LICENSE("GPL");
161MODULE_DESCRIPTION("SEN0322 oxygen sensor driver");
~/ Read-only file preview.