Skip to content

Commit d524b3e

Browse files
g0mb4jic23
authored andcommitted
iio: chemical: Add driver for SEN0322
Add support for the DFRobot SEN0322 oxygen sensor. To instantiate (assuming device is connected to I2C-2): echo 'sen0322 0x73' > /sys/class/i2c-dev/i2c-2/device/new_device To get the oxygen concentration (assuming device is iio:device0) multiply the values read from: /sys/bus/iio/devices/iio:device0/in_concentration_raw /sys/bus/iio/devices/iio:device0/in_concentration_scale Datasheet: https://wiki.dfrobot.com/Gravity_I2C_Oxygen_Sensor_SKU_SEN0322 Signed-off-by: Tóth János <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 844ca96 commit d524b3e

File tree

4 files changed

+178
-0
lines changed

4 files changed

+178
-0
lines changed

MAINTAINERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6863,6 +6863,12 @@ L: [email protected]
68636863
S: Maintained
68646864
F: drivers/rtc/rtc-sd2405al.c
68656865

6866+
DFROBOT SEN0322 DRIVER
6867+
M: Tóth János <[email protected]>
6868+
6869+
S: Maintained
6870+
F: drivers/iio/chemical/sen0322.c
6871+
68666872
DH ELECTRONICS DHSOM SOM AND BOARD SUPPORT
68676873
M: Christoph Niedermaier <[email protected]>
68686874
M: Marek Vasut <[email protected]>

drivers/iio/chemical/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,16 @@ config SCD4X
176176
To compile this driver as a module, choose M here: the module will
177177
be called scd4x.
178178

179+
config SEN0322
180+
tristate "SEN0322 oxygen sensor"
181+
depends on I2C
182+
select REGMAP_I2C
183+
help
184+
Say Y here to build support for the DFRobot SEN0322 oxygen sensor.
185+
186+
To compile this driver as a module, choose M here: the module will
187+
be called sen0322.
188+
179189
config SENSIRION_SGP30
180190
tristate "Sensirion SGPxx gas sensors"
181191
depends on I2C

drivers/iio/chemical/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ obj-$(CONFIG_SCD30_CORE) += scd30_core.o
2121
obj-$(CONFIG_SCD30_I2C) += scd30_i2c.o
2222
obj-$(CONFIG_SCD30_SERIAL) += scd30_serial.o
2323
obj-$(CONFIG_SCD4X) += scd4x.o
24+
obj-$(CONFIG_SEN0322) += sen0322.o
2425
obj-$(CONFIG_SENSEAIR_SUNRISE_CO2) += sunrise_co2.o
2526
obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o
2627
obj-$(CONFIG_SENSIRION_SGP40) += sgp40.o

drivers/iio/chemical/sen0322.c

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
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 <[email protected]>
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+
25+
struct sen0322 {
26+
struct regmap *regmap;
27+
};
28+
29+
static 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+
48+
static 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+
71+
static 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+
102+
static const struct iio_info sen0322_info = {
103+
.read_raw = sen0322_read_raw,
104+
};
105+
106+
static const struct regmap_config sen0322_regmap_conf = {
107+
.reg_bits = 8,
108+
.val_bits = 8,
109+
};
110+
111+
static 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+
117+
static 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+
144+
static const struct of_device_id sen0322_of_match[] = {
145+
{ .compatible = "dfrobot,sen0322" },
146+
{ }
147+
};
148+
MODULE_DEVICE_TABLE(of, sen0322_of_match);
149+
150+
static struct i2c_driver sen0322_driver = {
151+
.driver = {
152+
.name = "sen0322",
153+
.of_match_table = sen0322_of_match,
154+
},
155+
.probe = sen0322_probe,
156+
};
157+
module_i2c_driver(sen0322_driver);
158+
159+
MODULE_AUTHOR("Tóth János <[email protected]>");
160+
MODULE_LICENSE("GPL");
161+
MODULE_DESCRIPTION("SEN0322 oxygen sensor driver");

0 commit comments

Comments
 (0)