1 // SPDX-License-Identifier: GPL-2.0+
3 * atlas-ezo-sensor.c - Support for Atlas Scientific EZO sensors
5 * Copyright (C) 2020 Konsulko Group
6 * Author: Matt Ranostay <matt.ranostay@konsulko.com>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/delay.h>
12 #include <linux/mutex.h>
13 #include <linux/err.h>
14 #include <linux/i2c.h>
15 #include <linux/of_device.h>
16 #include <linux/iio/iio.h>
18 #define ATLAS_EZO_DRV_NAME "atlas-ezo-sensor"
19 #define ATLAS_INT_TIME_IN_MS 950
20 #define ATLAS_INT_HUM_TIME_IN_MS 350
28 struct atlas_ezo_device
{
29 const struct iio_chan_spec
*channels
;
34 struct atlas_ezo_data
{
35 struct i2c_client
*client
;
36 struct atlas_ezo_device
*chip
;
38 /* lock to avoid multiple concurrent read calls */
44 #define ATLAS_CONCENTRATION_CHANNEL(_modifier) \
46 .type = IIO_CONCENTRATION, \
48 .channel2 = _modifier, \
49 .info_mask_separate = \
50 BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
56 .endianness = IIO_CPU, \
60 static const struct iio_chan_spec atlas_co2_ezo_channels
[] = {
61 ATLAS_CONCENTRATION_CHANNEL(IIO_MOD_CO2
),
64 static const struct iio_chan_spec atlas_o2_ezo_channels
[] = {
65 ATLAS_CONCENTRATION_CHANNEL(IIO_MOD_O2
),
68 static const struct iio_chan_spec atlas_hum_ezo_channels
[] = {
70 .type
= IIO_HUMIDITYRELATIVE
,
72 BIT(IIO_CHAN_INFO_RAW
) | BIT(IIO_CHAN_INFO_SCALE
),
78 .endianness
= IIO_CPU
,
83 static struct atlas_ezo_device atlas_ezo_devices
[] = {
85 .channels
= atlas_co2_ezo_channels
,
87 .delay
= ATLAS_INT_TIME_IN_MS
,
90 .channels
= atlas_o2_ezo_channels
,
92 .delay
= ATLAS_INT_TIME_IN_MS
,
95 .channels
= atlas_hum_ezo_channels
,
97 .delay
= ATLAS_INT_HUM_TIME_IN_MS
,
101 static void atlas_ezo_sanitize(char *buf
)
103 char *ptr
= strchr(buf
, '.');
108 memmove(ptr
, ptr
+ 1, strlen(ptr
));
111 static int atlas_ezo_read_raw(struct iio_dev
*indio_dev
,
112 struct iio_chan_spec
const *chan
,
113 int *val
, int *val2
, long mask
)
115 struct atlas_ezo_data
*data
= iio_priv(indio_dev
);
116 struct i2c_client
*client
= data
->client
;
118 if (chan
->type
!= IIO_CONCENTRATION
)
122 case IIO_CHAN_INFO_RAW
: {
126 mutex_lock(&data
->lock
);
128 tmp
= i2c_smbus_write_byte(client
, 'R');
131 mutex_unlock(&data
->lock
);
135 msleep(data
->chip
->delay
);
137 tmp
= i2c_master_recv(client
, data
->buffer
, sizeof(data
->buffer
));
139 if (tmp
< 0 || data
->buffer
[0] != 1) {
140 mutex_unlock(&data
->lock
);
144 /* removing floating point for fixed number representation */
145 atlas_ezo_sanitize(data
->buffer
+ 2);
147 ret
= kstrtol(data
->buffer
+ 1, 10, &tmp
);
151 mutex_unlock(&data
->lock
);
153 return ret
? ret
: IIO_VAL_INT
;
155 case IIO_CHAN_INFO_SCALE
:
156 switch (chan
->type
) {
157 case IIO_HUMIDITYRELATIVE
:
160 case IIO_CONCENTRATION
:
166 /* IIO_CONCENTRATION modifiers */
167 switch (chan
->channel2
) {
170 *val2
= 100; /* 0.0001 */
171 return IIO_VAL_INT_PLUS_MICRO
;
182 static const struct iio_info atlas_info
= {
183 .read_raw
= atlas_ezo_read_raw
,
186 static const struct i2c_device_id atlas_ezo_id
[] = {
187 { "atlas-co2-ezo", ATLAS_CO2_EZO
},
188 { "atlas-o2-ezo", ATLAS_O2_EZO
},
189 { "atlas-hum-ezo", ATLAS_HUM_EZO
},
192 MODULE_DEVICE_TABLE(i2c
, atlas_ezo_id
);
194 static const struct of_device_id atlas_ezo_dt_ids
[] = {
195 { .compatible
= "atlas,co2-ezo", .data
= (void *)ATLAS_CO2_EZO
, },
196 { .compatible
= "atlas,o2-ezo", .data
= (void *)ATLAS_O2_EZO
, },
197 { .compatible
= "atlas,hum-ezo", .data
= (void *)ATLAS_HUM_EZO
, },
200 MODULE_DEVICE_TABLE(of
, atlas_ezo_dt_ids
);
202 static int atlas_ezo_probe(struct i2c_client
*client
,
203 const struct i2c_device_id
*id
)
205 struct atlas_ezo_data
*data
;
206 struct atlas_ezo_device
*chip
;
207 const struct of_device_id
*of_id
;
208 struct iio_dev
*indio_dev
;
210 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*data
));
214 of_id
= of_match_device(atlas_ezo_dt_ids
, &client
->dev
);
216 chip
= &atlas_ezo_devices
[id
->driver_data
];
218 chip
= &atlas_ezo_devices
[(unsigned long)of_id
->data
];
220 indio_dev
->info
= &atlas_info
;
221 indio_dev
->name
= ATLAS_EZO_DRV_NAME
;
222 indio_dev
->channels
= chip
->channels
;
223 indio_dev
->num_channels
= chip
->num_channels
;
224 indio_dev
->modes
= INDIO_DIRECT_MODE
;
226 data
= iio_priv(indio_dev
);
227 data
->client
= client
;
229 mutex_init(&data
->lock
);
231 return devm_iio_device_register(&client
->dev
, indio_dev
);
234 static struct i2c_driver atlas_ezo_driver
= {
236 .name
= ATLAS_EZO_DRV_NAME
,
237 .of_match_table
= atlas_ezo_dt_ids
,
239 .probe
= atlas_ezo_probe
,
240 .id_table
= atlas_ezo_id
,
242 module_i2c_driver(atlas_ezo_driver
);
244 MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
245 MODULE_DESCRIPTION("Atlas Scientific EZO sensors");
246 MODULE_LICENSE("GPL");