1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * All Sensors DLH series low voltage digital pressure sensors 4 * 5 * Copyright (c) 2019 AVL DiTEST GmbH 6 * Tomislav Denis <tomislav.denis@avl.com> 7 * 8 * Datasheet: https://www.allsensors.com/cad/DS-0355_Rev_B.PDF 9 */ 10 11 #include <linux/module.h> 12 #include <linux/delay.h> 13 #include <linux/i2c.h> 14 #include <linux/iio/iio.h> 15 #include <linux/iio/buffer.h> 16 #include <linux/iio/trigger_consumer.h> 17 #include <linux/iio/triggered_buffer.h> 18 #include <asm/unaligned.h> 19 20 /* Commands */ 21 #define DLH_START_SINGLE 0xAA 22 23 /* Status bits */ 24 #define DLH_STATUS_OK 0x40 25 26 /* DLH data format */ 27 #define DLH_NUM_READ_BYTES 7 28 #define DLH_NUM_DATA_BYTES 3 29 #define DLH_NUM_PR_BITS 24 30 #define DLH_NUM_TEMP_BITS 24 31 32 /* DLH timings */ 33 #define DLH_SINGLE_DUT_MS 5 34 35 enum dhl_ids { 36 dlhl60d, 37 dlhl60g, 38 }; 39 40 struct dlh_info { 41 u8 osdig; /* digital offset factor */ 42 unsigned int fss; /* full scale span (inch H2O) */ 43 }; 44 45 struct dlh_state { 46 struct i2c_client *client; 47 struct dlh_info info; 48 bool use_interrupt; 49 struct completion completion; 50 u8 rx_buf[DLH_NUM_READ_BYTES]; 51 }; 52 53 static struct dlh_info dlh_info_tbl[] = { 54 [dlhl60d] = { 55 .osdig = 2, 56 .fss = 120, 57 }, 58 [dlhl60g] = { 59 .osdig = 10, 60 .fss = 60, 61 }, 62 }; 63 64 65 static int dlh_cmd_start_single(struct dlh_state *st) 66 { 67 int ret; 68 69 ret = i2c_smbus_write_byte(st->client, DLH_START_SINGLE); 70 if (ret) 71 dev_err(&st->client->dev, 72 "%s: I2C write byte failed\n", __func__); 73 74 return ret; 75 } 76 77 static int dlh_cmd_read_data(struct dlh_state *st) 78 { 79 int ret; 80 81 ret = i2c_master_recv(st->client, st->rx_buf, DLH_NUM_READ_BYTES); 82 if (ret < 0) { 83 dev_err(&st->client->dev, 84 "%s: I2C read block failed\n", __func__); 85 return ret; 86 } 87 88 if (st->rx_buf[0] != DLH_STATUS_OK) { 89 dev_err(&st->client->dev, 90 "%s: invalid status 0x%02x\n", __func__, st->rx_buf[0]); 91 return -EBUSY; 92 } 93 94 return 0; 95 } 96 97 static int dlh_start_capture_and_read(struct dlh_state *st) 98 { 99 int ret; 100 101 if (st->use_interrupt) 102 reinit_completion(&st->completion); 103 104 ret = dlh_cmd_start_single(st); 105 if (ret) 106 return ret; 107 108 if (st->use_interrupt) { 109 ret = wait_for_completion_timeout(&st->completion, 110 msecs_to_jiffies(DLH_SINGLE_DUT_MS)); 111 if (!ret) { 112 dev_err(&st->client->dev, 113 "%s: conversion timed out\n", __func__); 114 return -ETIMEDOUT; 115 } 116 } else { 117 mdelay(DLH_SINGLE_DUT_MS); 118 } 119 120 return dlh_cmd_read_data(st); 121 } 122 123 static int dlh_read_direct(struct dlh_state *st, 124 unsigned int *pressure, unsigned int *temperature) 125 { 126 int ret; 127 128 ret = dlh_start_capture_and_read(st); 129 if (ret) 130 return ret; 131 132 *pressure = get_unaligned_be24(&st->rx_buf[1]); 133 *temperature = get_unaligned_be24(&st->rx_buf[4]); 134 135 return 0; 136 } 137 138 static int dlh_read_raw(struct iio_dev *indio_dev, 139 struct iio_chan_spec const *channel, int *value, 140 int *value2, long mask) 141 { 142 struct dlh_state *st = iio_priv(indio_dev); 143 unsigned int pressure, temperature; 144 int ret; 145 s64 tmp; 146 s32 rem; 147 148 switch (mask) { 149 case IIO_CHAN_INFO_RAW: 150 ret = iio_device_claim_direct_mode(indio_dev); 151 if (ret) 152 return ret; 153 154 ret = dlh_read_direct(st, &pressure, &temperature); 155 iio_device_release_direct_mode(indio_dev); 156 if (ret) 157 return ret; 158 159 switch (channel->type) { 160 case IIO_PRESSURE: 161 *value = pressure; 162 return IIO_VAL_INT; 163 164 case IIO_TEMP: 165 *value = temperature; 166 return IIO_VAL_INT; 167 168 default: 169 return -EINVAL; 170 } 171 case IIO_CHAN_INFO_SCALE: 172 switch (channel->type) { 173 case IIO_PRESSURE: 174 tmp = div_s64(125LL * st->info.fss * 24909 * 100, 175 1 << DLH_NUM_PR_BITS); 176 tmp = div_s64_rem(tmp, 1000000000LL, &rem); 177 *value = tmp; 178 *value2 = rem; 179 return IIO_VAL_INT_PLUS_NANO; 180 181 case IIO_TEMP: 182 *value = 125 * 1000; 183 *value2 = DLH_NUM_TEMP_BITS; 184 return IIO_VAL_FRACTIONAL_LOG2; 185 186 default: 187 return -EINVAL; 188 } 189 case IIO_CHAN_INFO_OFFSET: 190 switch (channel->type) { 191 case IIO_PRESSURE: 192 *value = -125 * st->info.fss * 24909; 193 *value2 = 100 * st->info.osdig * 100000; 194 return IIO_VAL_FRACTIONAL; 195 196 case IIO_TEMP: 197 *value = -40 * 1000; 198 return IIO_VAL_INT; 199 200 default: 201 return -EINVAL; 202 } 203 } 204 205 return -EINVAL; 206 } 207 208 static const struct iio_info dlh_info = { 209 .read_raw = dlh_read_raw, 210 }; 211 212 static const struct iio_chan_spec dlh_channels[] = { 213 { 214 .type = IIO_PRESSURE, 215 .indexed = 1, 216 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 217 .info_mask_shared_by_type = 218 BIT(IIO_CHAN_INFO_SCALE) | 219 BIT(IIO_CHAN_INFO_OFFSET), 220 .scan_index = 0, 221 .scan_type = { 222 .sign = 'u', 223 .realbits = DLH_NUM_PR_BITS, 224 .storagebits = 32, 225 .shift = 8, 226 .endianness = IIO_BE, 227 }, 228 }, { 229 .type = IIO_TEMP, 230 .indexed = 1, 231 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 232 .info_mask_shared_by_type = 233 BIT(IIO_CHAN_INFO_SCALE) | 234 BIT(IIO_CHAN_INFO_OFFSET), 235 .scan_index = 1, 236 .scan_type = { 237 .sign = 'u', 238 .realbits = DLH_NUM_TEMP_BITS, 239 .storagebits = 32, 240 .shift = 8, 241 .endianness = IIO_BE, 242 }, 243 } 244 }; 245 246 static irqreturn_t dlh_trigger_handler(int irq, void *private) 247 { 248 struct iio_poll_func *pf = private; 249 struct iio_dev *indio_dev = pf->indio_dev; 250 struct dlh_state *st = iio_priv(indio_dev); 251 int ret; 252 unsigned int chn, i = 0; 253 __be32 tmp_buf[2] = { }; 254 255 ret = dlh_start_capture_and_read(st); 256 if (ret) 257 goto out; 258 259 iio_for_each_active_channel(indio_dev, chn) { 260 memcpy(&tmp_buf[i++], 261 &st->rx_buf[1] + chn * DLH_NUM_DATA_BYTES, 262 DLH_NUM_DATA_BYTES); 263 } 264 265 iio_push_to_buffers(indio_dev, tmp_buf); 266 267 out: 268 iio_trigger_notify_done(indio_dev->trig); 269 270 return IRQ_HANDLED; 271 } 272 273 static irqreturn_t dlh_interrupt(int irq, void *private) 274 { 275 struct iio_dev *indio_dev = private; 276 struct dlh_state *st = iio_priv(indio_dev); 277 278 complete(&st->completion); 279 280 return IRQ_HANDLED; 281 }; 282 283 static int dlh_probe(struct i2c_client *client) 284 { 285 const struct i2c_device_id *id = i2c_client_get_device_id(client); 286 struct dlh_state *st; 287 struct iio_dev *indio_dev; 288 int ret; 289 290 if (!i2c_check_functionality(client->adapter, 291 I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE)) { 292 dev_err(&client->dev, 293 "adapter doesn't support required i2c functionality\n"); 294 return -EOPNOTSUPP; 295 } 296 297 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); 298 if (!indio_dev) { 299 dev_err(&client->dev, "failed to allocate iio device\n"); 300 return -ENOMEM; 301 } 302 303 i2c_set_clientdata(client, indio_dev); 304 305 st = iio_priv(indio_dev); 306 st->info = dlh_info_tbl[id->driver_data]; 307 st->client = client; 308 st->use_interrupt = false; 309 310 indio_dev->name = id->name; 311 indio_dev->info = &dlh_info; 312 indio_dev->modes = INDIO_DIRECT_MODE; 313 indio_dev->channels = dlh_channels; 314 indio_dev->num_channels = ARRAY_SIZE(dlh_channels); 315 316 if (client->irq > 0) { 317 ret = devm_request_threaded_irq(&client->dev, client->irq, 318 dlh_interrupt, NULL, 319 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 320 id->name, indio_dev); 321 if (ret) { 322 dev_err(&client->dev, "failed to allocate threaded irq"); 323 return ret; 324 } 325 326 st->use_interrupt = true; 327 init_completion(&st->completion); 328 } 329 330 ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, 331 NULL, &dlh_trigger_handler, NULL); 332 if (ret) { 333 dev_err(&client->dev, "failed to setup iio buffer\n"); 334 return ret; 335 } 336 337 ret = devm_iio_device_register(&client->dev, indio_dev); 338 if (ret) 339 dev_err(&client->dev, "failed to register iio device\n"); 340 341 return ret; 342 } 343 344 static const struct of_device_id dlh_of_match[] = { 345 { .compatible = "asc,dlhl60d" }, 346 { .compatible = "asc,dlhl60g" }, 347 {} 348 }; 349 MODULE_DEVICE_TABLE(of, dlh_of_match); 350 351 static const struct i2c_device_id dlh_id[] = { 352 { "dlhl60d", dlhl60d }, 353 { "dlhl60g", dlhl60g }, 354 {} 355 }; 356 MODULE_DEVICE_TABLE(i2c, dlh_id); 357 358 static struct i2c_driver dlh_driver = { 359 .driver = { 360 .name = "dlhl60d", 361 .of_match_table = dlh_of_match, 362 }, 363 .probe = dlh_probe, 364 .id_table = dlh_id, 365 }; 366 module_i2c_driver(dlh_driver); 367 368 MODULE_AUTHOR("Tomislav Denis <tomislav.denis@avl.com>"); 369 MODULE_DESCRIPTION("Driver for All Sensors DLH series pressure sensors"); 370 MODULE_LICENSE("GPL v2"); 371