1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * atlas-ezo-sensor.c - Support for Atlas Scientific EZO sensors 4 * 5 * Copyright (C) 2020 Konsulko Group 6 * Author: Matt Ranostay <matt.ranostay@konsulko.com> 7 */ 8 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> 17 18 #define ATLAS_EZO_DRV_NAME "atlas-ezo-sensor" 19 #define ATLAS_CO2_INT_TIME_IN_MS 950 20 21 enum { 22 ATLAS_CO2_EZO, 23 }; 24 25 struct atlas_ezo_device { 26 const struct iio_chan_spec *channels; 27 int num_channels; 28 int delay; 29 }; 30 31 struct atlas_ezo_data { 32 struct i2c_client *client; 33 struct atlas_ezo_device *chip; 34 35 /* lock to avoid multiple concurrent read calls */ 36 struct mutex lock; 37 38 u8 buffer[8]; 39 }; 40 41 static const struct iio_chan_spec atlas_co2_ezo_channels[] = { 42 { 43 .type = IIO_CONCENTRATION, 44 .modified = 1, 45 .channel2 = IIO_MOD_CO2, 46 .info_mask_separate = 47 BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), 48 .scan_index = 0, 49 .scan_type = { 50 .sign = 'u', 51 .realbits = 32, 52 .storagebits = 32, 53 .endianness = IIO_CPU, 54 }, 55 }, 56 }; 57 58 static struct atlas_ezo_device atlas_ezo_devices[] = { 59 [ATLAS_CO2_EZO] = { 60 .channels = atlas_co2_ezo_channels, 61 .num_channels = 1, 62 .delay = ATLAS_CO2_INT_TIME_IN_MS, 63 }, 64 }; 65 66 static int atlas_ezo_read_raw(struct iio_dev *indio_dev, 67 struct iio_chan_spec const *chan, 68 int *val, int *val2, long mask) 69 { 70 struct atlas_ezo_data *data = iio_priv(indio_dev); 71 struct i2c_client *client = data->client; 72 int ret = 0; 73 74 if (chan->type != IIO_CONCENTRATION) 75 return -EINVAL; 76 77 switch (mask) { 78 case IIO_CHAN_INFO_RAW: { 79 long tmp; 80 81 mutex_lock(&data->lock); 82 83 tmp = i2c_smbus_write_byte(client, 'R'); 84 85 if (tmp < 0) { 86 mutex_unlock(&data->lock); 87 return tmp; 88 } 89 90 msleep(data->chip->delay); 91 92 tmp = i2c_master_recv(client, data->buffer, sizeof(data->buffer)); 93 94 if (tmp < 0 || data->buffer[0] != 1) { 95 mutex_unlock(&data->lock); 96 return -EBUSY; 97 } 98 99 ret = kstrtol(data->buffer + 1, 10, &tmp); 100 101 *val = tmp; 102 103 mutex_unlock(&data->lock); 104 105 return ret ? ret : IIO_VAL_INT; 106 } 107 case IIO_CHAN_INFO_SCALE: 108 *val = 0; 109 *val2 = 100; /* 0.0001 */ 110 return IIO_VAL_INT_PLUS_MICRO; 111 } 112 113 return ret; 114 } 115 116 static const struct iio_info atlas_info = { 117 .read_raw = atlas_ezo_read_raw, 118 }; 119 120 static const struct i2c_device_id atlas_ezo_id[] = { 121 { "atlas-co2-ezo", ATLAS_CO2_EZO }, 122 {} 123 }; 124 MODULE_DEVICE_TABLE(i2c, atlas_ezo_id); 125 126 static const struct of_device_id atlas_ezo_dt_ids[] = { 127 { .compatible = "atlas,co2-ezo", .data = (void *)ATLAS_CO2_EZO, }, 128 {} 129 }; 130 MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids); 131 132 static int atlas_ezo_probe(struct i2c_client *client, 133 const struct i2c_device_id *id) 134 { 135 struct atlas_ezo_data *data; 136 struct atlas_ezo_device *chip; 137 const struct of_device_id *of_id; 138 struct iio_dev *indio_dev; 139 140 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 141 if (!indio_dev) 142 return -ENOMEM; 143 144 of_id = of_match_device(atlas_ezo_dt_ids, &client->dev); 145 if (!of_id) 146 chip = &atlas_ezo_devices[id->driver_data]; 147 else 148 chip = &atlas_ezo_devices[(unsigned long)of_id->data]; 149 150 indio_dev->info = &atlas_info; 151 indio_dev->name = ATLAS_EZO_DRV_NAME; 152 indio_dev->channels = chip->channels; 153 indio_dev->num_channels = chip->num_channels; 154 indio_dev->modes = INDIO_DIRECT_MODE; 155 indio_dev->dev.parent = &client->dev; 156 157 data = iio_priv(indio_dev); 158 data->client = client; 159 data->chip = chip; 160 mutex_init(&data->lock); 161 162 return devm_iio_device_register(&client->dev, indio_dev); 163 }; 164 165 static struct i2c_driver atlas_ezo_driver = { 166 .driver = { 167 .name = ATLAS_EZO_DRV_NAME, 168 .of_match_table = atlas_ezo_dt_ids, 169 }, 170 .probe = atlas_ezo_probe, 171 .id_table = atlas_ezo_id, 172 }; 173 module_i2c_driver(atlas_ezo_driver); 174 175 MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); 176 MODULE_DESCRIPTION("Atlas Scientific EZO sensors"); 177 MODULE_LICENSE("GPL"); 178