1// SPDX-License-Identifier: GPL-2.0-only 2/** 3 * Aosong AM2315 relative humidity and temperature 4 * 5 * Copyright (c) 2016, Intel Corporation. 6 * 7 * 7-bit I2C address: 0x5C. 8 */ 9 10#include <linux/acpi.h> 11#include <linux/delay.h> 12#include <linux/i2c.h> 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/iio/buffer.h> 16#include <linux/iio/iio.h> 17#include <linux/iio/sysfs.h> 18#include <linux/iio/trigger_consumer.h> 19#include <linux/iio/triggered_buffer.h> 20 21#define AM2315_REG_HUM_MSB 0x00 22#define AM2315_REG_HUM_LSB 0x01 23#define AM2315_REG_TEMP_MSB 0x02 24#define AM2315_REG_TEMP_LSB 0x03 25 26#define AM2315_FUNCTION_READ 0x03 27#define AM2315_HUM_OFFSET 2 28#define AM2315_TEMP_OFFSET 4 29#define AM2315_ALL_CHANNEL_MASK GENMASK(1, 0) 30 31#define AM2315_DRIVER_NAME "am2315" 32 33struct am2315_data { 34 struct i2c_client *client; 35 struct mutex lock; 36 /* Ensure timestamp is naturally aligned */ 37 struct { 38 s16 chans[2]; 39 s64 timestamp __aligned(8); 40 } scan; 41}; 42 43struct am2315_sensor_data { 44 s16 hum_data; 45 s16 temp_data; 46}; 47 48static const struct iio_chan_spec am2315_channels[] = { 49 { 50 .type = IIO_HUMIDITYRELATIVE, 51 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 52 BIT(IIO_CHAN_INFO_SCALE), 53 .scan_index = 0, 54 .scan_type = { 55 .sign = 's', 56 .realbits = 16, 57 .storagebits = 16, 58 .endianness = IIO_CPU, 59 }, 60 }, 61 { 62 .type = IIO_TEMP, 63 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 64 BIT(IIO_CHAN_INFO_SCALE), 65 .scan_index = 1, 66 .scan_type = { 67 .sign = 's', 68 .realbits = 16, 69 .storagebits = 16, 70 .endianness = IIO_CPU, 71 }, 72 }, 73 IIO_CHAN_SOFT_TIMESTAMP(2), 74}; 75 76/* CRC calculation algorithm, as specified in the datasheet (page 13). */ 77static u16 am2315_crc(u8 *data, u8 nr_bytes) 78{ 79 int i; 80 u16 crc = 0xffff; 81 82 while (nr_bytes--) { 83 crc ^= *data++; 84 for (i = 0; i < 8; i++) { 85 if (crc & 0x01) { 86 crc >>= 1; 87 crc ^= 0xA001; 88 } else { 89 crc >>= 1; 90 } 91 } 92 } 93 94 return crc; 95} 96 97/* Simple function that sends a few bytes to the device to wake it up. */ 98static void am2315_ping(struct i2c_client *client) 99{ 100 i2c_smbus_read_byte_data(client, AM2315_REG_HUM_MSB); 101} 102 103static int am2315_read_data(struct am2315_data *data, 104 struct am2315_sensor_data *sensor_data) 105{ 106 int ret; 107 /* tx_buf format: <function code> <start addr> <nr of regs to read> */ 108 u8 tx_buf[3] = { AM2315_FUNCTION_READ, AM2315_REG_HUM_MSB, 4 }; 109 /* 110 * rx_buf format: 111 * <function code> <number of registers read> 112 * <humidity MSB> <humidity LSB> <temp MSB> <temp LSB> 113 * <CRC LSB> <CRC MSB> 114 */ 115 u8 rx_buf[8]; 116 u16 crc; 117 118 /* First wake up the device. */ 119 am2315_ping(data->client); 120 121 mutex_lock(&data->lock); 122 ret = i2c_master_send(data->client, tx_buf, sizeof(tx_buf)); 123 if (ret < 0) { 124 dev_err(&data->client->dev, "failed to send read request\n"); 125 goto exit_unlock; 126 } 127 /* Wait 2-3 ms, then read back the data sent by the device. */ 128 usleep_range(2000, 3000); 129 /* Do a bulk data read, then pick out what we need. */ 130 ret = i2c_master_recv(data->client, rx_buf, sizeof(rx_buf)); 131 if (ret < 0) { 132 dev_err(&data->client->dev, "failed to read sensor data\n"); 133 goto exit_unlock; 134 } 135 mutex_unlock(&data->lock); 136 /* 137 * Do a CRC check on the data and compare it to the value 138 * calculated by the device. 139 */ 140 crc = am2315_crc(rx_buf, sizeof(rx_buf) - 2); 141 if ((crc & 0xff) != rx_buf[6] || (crc >> 8) != rx_buf[7]) { 142 dev_err(&data->client->dev, "failed to verify sensor data\n"); 143 return -EIO; 144 } 145 146 sensor_data->hum_data = (rx_buf[AM2315_HUM_OFFSET] << 8) | 147 rx_buf[AM2315_HUM_OFFSET + 1]; 148 sensor_data->temp_data = (rx_buf[AM2315_TEMP_OFFSET] << 8) | 149 rx_buf[AM2315_TEMP_OFFSET + 1]; 150 151 return ret; 152 153exit_unlock: 154 mutex_unlock(&data->lock); 155 return ret; 156} 157 158static irqreturn_t am2315_trigger_handler(int irq, void *p) 159{ 160 int i; 161 int ret; 162 int bit; 163 struct iio_poll_func *pf = p; 164 struct iio_dev *indio_dev = pf->indio_dev; 165 struct am2315_data *data = iio_priv(indio_dev); 166 struct am2315_sensor_data sensor_data; 167 168 ret = am2315_read_data(data, &sensor_data); 169 if (ret < 0) 170 goto err; 171 172 mutex_lock(&data->lock); 173 if (*(indio_dev->active_scan_mask) == AM2315_ALL_CHANNEL_MASK) { 174 data->scan.chans[0] = sensor_data.hum_data; 175 data->scan.chans[1] = sensor_data.temp_data; 176 } else { 177 i = 0; 178 for_each_set_bit(bit, indio_dev->active_scan_mask, 179 indio_dev->masklength) { 180 data->scan.chans[i] = (bit ? sensor_data.temp_data : 181 sensor_data.hum_data); 182 i++; 183 } 184 } 185 mutex_unlock(&data->lock); 186 187 iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, 188 pf->timestamp); 189err: 190 iio_trigger_notify_done(indio_dev->trig); 191 return IRQ_HANDLED; 192} 193 194static int am2315_read_raw(struct iio_dev *indio_dev, 195 struct iio_chan_spec const *chan, 196 int *val, int *val2, long mask) 197{ 198 int ret; 199 struct am2315_sensor_data sensor_data; 200 struct am2315_data *data = iio_priv(indio_dev); 201 202 switch (mask) { 203 case IIO_CHAN_INFO_RAW: 204 ret = am2315_read_data(data, &sensor_data); 205 if (ret < 0) 206 return ret; 207 *val = (chan->type == IIO_HUMIDITYRELATIVE) ? 208 sensor_data.hum_data : sensor_data.temp_data; 209 return IIO_VAL_INT; 210 case IIO_CHAN_INFO_SCALE: 211 *val = 100; 212 return IIO_VAL_INT; 213 } 214 215 return -EINVAL; 216} 217 218static const struct iio_info am2315_info = { 219 .read_raw = am2315_read_raw, 220}; 221 222static int am2315_probe(struct i2c_client *client, 223 const struct i2c_device_id *id) 224{ 225 int ret; 226 struct iio_dev *indio_dev; 227 struct am2315_data *data; 228 229 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 230 if (!indio_dev) { 231 dev_err(&client->dev, "iio allocation failed!\n"); 232 return -ENOMEM; 233 } 234 235 data = iio_priv(indio_dev); 236 data->client = client; 237 i2c_set_clientdata(client, indio_dev); 238 mutex_init(&data->lock); 239 240 indio_dev->info = &am2315_info; 241 indio_dev->name = AM2315_DRIVER_NAME; 242 indio_dev->modes = INDIO_DIRECT_MODE; 243 indio_dev->channels = am2315_channels; 244 indio_dev->num_channels = ARRAY_SIZE(am2315_channels); 245 246 ret = devm_iio_triggered_buffer_setup(&client->dev, 247 indio_dev, iio_pollfunc_store_time, 248 am2315_trigger_handler, NULL); 249 if (ret < 0) { 250 dev_err(&client->dev, "iio triggered buffer setup failed\n"); 251 return ret; 252 } 253 254 return devm_iio_device_register(&client->dev, indio_dev); 255} 256 257static const struct i2c_device_id am2315_i2c_id[] = { 258 {"am2315", 0}, 259 {} 260}; 261MODULE_DEVICE_TABLE(i2c, am2315_i2c_id); 262 263static const struct acpi_device_id am2315_acpi_id[] = { 264 {"AOS2315", 0}, 265 {} 266}; 267 268MODULE_DEVICE_TABLE(acpi, am2315_acpi_id); 269 270static struct i2c_driver am2315_driver = { 271 .driver = { 272 .name = "am2315", 273 .acpi_match_table = ACPI_PTR(am2315_acpi_id), 274 }, 275 .probe = am2315_probe, 276 .id_table = am2315_i2c_id, 277}; 278 279module_i2c_driver(am2315_driver); 280 281MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>"); 282MODULE_DESCRIPTION("Aosong AM2315 relative humidity and temperature"); 283MODULE_LICENSE("GPL v2"); 284