FILE
adp810.c
File preview with syntax highlighting.
linux-6.19.14/drivers/iio/pressure/adp810.c
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 33DECLARE_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 */ 40struct 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 49struct adp810_data { 50 struct i2c_client *client; 51 /* Use lock to synchronize access to device during read sequence */ 52 struct mutex lock; 53}; 54 55static 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 108static 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 153static const struct iio_info adp810_info = { 154 .read_raw = adp810_read_raw, 155}; 156 157static 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 170static 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 201static const struct i2c_device_id adp810_id_table[] = { 202 { "adp810" }, 203 { } 204}; 205MODULE_DEVICE_TABLE(i2c, adp810_id_table); 206 207static const struct of_device_id adp810_of_table[] = { 208 { .compatible = "aosong,adp810" }, 209 { } 210}; 211MODULE_DEVICE_TABLE(of, adp810_of_table); 212 213static 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}; 221module_i2c_driver(adp810_driver); 222 223MODULE_AUTHOR("Akhilesh Patil <akhilesh@ee.iitb.ac.in>"); 224MODULE_DESCRIPTION("Driver for Aosong ADP810 sensor"); 225MODULE_LICENSE("GPL");
~/
Read-only file preview.