1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2025 Akhilesh Patil <akhilesh@ee.iitb.ac.in> 4 * 5 * Driver for adp810 pressure and temperature sensor 6 * Datasheet: 7 * https://aosong.com/userfiles/files/media/Datasheet%20ADP810-Digital.pdf 8 */ 9 10 #include <linux/array_size.h> 11 #include <linux/cleanup.h> 12 #include <linux/crc8.h> 13 #include <linux/delay.h> 14 #include <linux/device.h> 15 #include <linux/dev_printk.h> 16 #include <linux/errno.h> 17 #include <linux/i2c.h> 18 #include <linux/module.h> 19 #include <linux/mod_devicetable.h> 20 #include <linux/mutex.h> 21 #include <linux/types.h> 22 #include <linux/unaligned.h> 23 24 #include <linux/iio/iio.h> 25 #include <linux/iio/types.h> 26 27 /* 28 * Refer section 5.4 checksum calculation from datasheet. 29 * This sensor uses CRC polynomial x^8 + x^5 + x^4 + 1 (0x31) 30 */ 31 #define ADP810_CRC8_POLYNOMIAL 0x31 32 33 DECLARE_CRC8_TABLE(crc_table); 34 35 /* 36 * Buffer declaration which holds 9 bytes of measurement data read 37 * from the sensor. Use __packed to avoid any paddings, as data sent 38 * from the sensor is strictly contiguous 9 bytes. 39 */ 40 struct adp810_read_buf { 41 __be16 dp; 42 u8 dp_crc; 43 __be16 tmp; 44 u8 tmp_crc; 45 __be16 sf; 46 u8 sf_crc; 47 } __packed; 48 49 struct adp810_data { 50 struct i2c_client *client; 51 /* Use lock to synchronize access to device during read sequence */ 52 struct mutex lock; 53 }; 54 55 static int adp810_measure(struct adp810_data *data, struct adp810_read_buf *buf) 56 { 57 struct i2c_client *client = data->client; 58 struct device *dev = &client->dev; 59 int ret; 60 u8 trig_cmd[2] = {0x37, 0x2d}; 61 62 /* Send trigger command to the sensor for measurement */ 63 ret = i2c_master_send(client, trig_cmd, sizeof(trig_cmd)); 64 if (ret < 0) { 65 dev_err(dev, "Error sending trigger command\n"); 66 return ret; 67 } 68 if (ret != sizeof(trig_cmd)) 69 return -EIO; 70 71 /* 72 * Wait for the sensor to acquire data. As per datasheet section 5.3.1, 73 * at least 10ms delay before reading from the sensor is recommended. 74 * Here, we wait for 20ms to have some safe margin on the top 75 * of recommendation and to compensate for any possible variations. 76 */ 77 msleep(20); 78 79 /* Read sensor values */ 80 ret = i2c_master_recv(client, (char *)buf, sizeof(*buf)); 81 if (ret < 0) { 82 dev_err(dev, "Error reading from sensor\n"); 83 return ret; 84 } 85 if (ret != sizeof(*buf)) 86 return -EIO; 87 88 /* CRC checks */ 89 crc8_populate_msb(crc_table, ADP810_CRC8_POLYNOMIAL); 90 if (buf->dp_crc != crc8(crc_table, (u8 *)&buf->dp, 0x2, CRC8_INIT_VALUE)) { 91 dev_err(dev, "CRC error for pressure\n"); 92 return -EIO; 93 } 94 95 if (buf->tmp_crc != crc8(crc_table, (u8 *)&buf->tmp, 0x2, CRC8_INIT_VALUE)) { 96 dev_err(dev, "CRC error for temperature\n"); 97 return -EIO; 98 } 99 100 if (buf->sf_crc != crc8(crc_table, (u8 *)&buf->sf, 0x2, CRC8_INIT_VALUE)) { 101 dev_err(dev, "CRC error for scale\n"); 102 return -EIO; 103 } 104 105 return 0; 106 } 107 108 static int adp810_read_raw(struct iio_dev *indio_dev, 109 struct iio_chan_spec const *chan, 110 int *val, int *val2, long mask) 111 { 112 struct adp810_data *data = iio_priv(indio_dev); 113 struct device *dev = &data->client->dev; 114 struct adp810_read_buf buf = { }; 115 int ret; 116 117 scoped_guard(mutex, &data->lock) { 118 ret = adp810_measure(data, &buf); 119 if (ret) { 120 dev_err(dev, "Failed to read from device\n"); 121 return ret; 122 } 123 } 124 125 switch (mask) { 126 case IIO_CHAN_INFO_RAW: 127 switch (chan->type) { 128 case IIO_PRESSURE: 129 *val = get_unaligned_be16(&buf.dp); 130 return IIO_VAL_INT; 131 case IIO_TEMP: 132 *val = get_unaligned_be16(&buf.tmp); 133 return IIO_VAL_INT; 134 default: 135 return -EINVAL; 136 } 137 case IIO_CHAN_INFO_SCALE: 138 switch (chan->type) { 139 case IIO_PRESSURE: 140 *val = get_unaligned_be16(&buf.sf); 141 return IIO_VAL_INT; 142 case IIO_TEMP: 143 *val = 200; 144 return IIO_VAL_INT; 145 default: 146 return -EINVAL; 147 } 148 default: 149 return -EINVAL; 150 } 151 } 152 153 static const struct iio_info adp810_info = { 154 .read_raw = adp810_read_raw, 155 }; 156 157 static const struct iio_chan_spec adp810_channels[] = { 158 { 159 .type = IIO_PRESSURE, 160 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 161 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), 162 }, 163 { 164 .type = IIO_TEMP, 165 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 166 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), 167 }, 168 }; 169 170 static int adp810_probe(struct i2c_client *client) 171 { 172 struct device *dev = &client->dev; 173 struct iio_dev *indio_dev; 174 struct adp810_data *data; 175 int ret; 176 177 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 178 if (!indio_dev) 179 return -ENOMEM; 180 181 data = iio_priv(indio_dev); 182 data->client = client; 183 184 ret = devm_mutex_init(dev, &data->lock); 185 if (ret) 186 return ret; 187 188 indio_dev->name = "adp810"; 189 indio_dev->channels = adp810_channels; 190 indio_dev->num_channels = ARRAY_SIZE(adp810_channels); 191 indio_dev->info = &adp810_info; 192 indio_dev->modes = INDIO_DIRECT_MODE; 193 194 ret = devm_iio_device_register(dev, indio_dev); 195 if (ret) 196 return dev_err_probe(dev, ret, "Failed to register IIO device\n"); 197 198 return 0; 199 } 200 201 static const struct i2c_device_id adp810_id_table[] = { 202 { "adp810" }, 203 { } 204 }; 205 MODULE_DEVICE_TABLE(i2c, adp810_id_table); 206 207 static const struct of_device_id adp810_of_table[] = { 208 { .compatible = "aosong,adp810" }, 209 { } 210 }; 211 MODULE_DEVICE_TABLE(of, adp810_of_table); 212 213 static struct i2c_driver adp810_driver = { 214 .driver = { 215 .name = "adp810", 216 .of_match_table = adp810_of_table, 217 }, 218 .probe = adp810_probe, 219 .id_table = adp810_id_table, 220 }; 221 module_i2c_driver(adp810_driver); 222 223 MODULE_AUTHOR("Akhilesh Patil <akhilesh@ee.iitb.ac.in>"); 224 MODULE_DESCRIPTION("Driver for Aosong ADP810 sensor"); 225 MODULE_LICENSE("GPL"); 226