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 <linux/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 if (!iio_device_claim_direct(indio_dev)) 151 return -EBUSY; 152 153 ret = dlh_read_direct(st, &pressure, &temperature); 154 iio_device_release_direct(indio_dev); 155 if (ret) 156 return ret; 157 158 switch (channel->type) { 159 case IIO_PRESSURE: 160 *value = pressure; 161 return IIO_VAL_INT; 162 163 case IIO_TEMP: 164 *value = temperature; 165 return IIO_VAL_INT; 166 167 default: 168 return -EINVAL; 169 } 170 case IIO_CHAN_INFO_SCALE: 171 switch (channel->type) { 172 case IIO_PRESSURE: 173 tmp = div_s64(125LL * st->info.fss * 24909 * 100, 174 1 << DLH_NUM_PR_BITS); 175 tmp = div_s64_rem(tmp, 1000000000LL, &rem); 176 *value = tmp; 177 *value2 = rem; 178 return IIO_VAL_INT_PLUS_NANO; 179 180 case IIO_TEMP: 181 *value = 125 * 1000; 182 *value2 = DLH_NUM_TEMP_BITS; 183 return IIO_VAL_FRACTIONAL_LOG2; 184 185 default: 186 return -EINVAL; 187 } 188 case IIO_CHAN_INFO_OFFSET: 189 switch (channel->type) { 190 case IIO_PRESSURE: 191 *value = -125 * st->info.fss * 24909; 192 *value2 = 100 * st->info.osdig * 100000; 193 return IIO_VAL_FRACTIONAL; 194 195 case IIO_TEMP: 196 *value = -40 * 1000; 197 return IIO_VAL_INT; 198 199 default: 200 return -EINVAL; 201 } 202 } 203 204 return -EINVAL; 205 } 206 207 static const struct iio_info dlh_info = { 208 .read_raw = dlh_read_raw, 209 }; 210 211 static const struct iio_chan_spec dlh_channels[] = { 212 { 213 .type = IIO_PRESSURE, 214 .indexed = 1, 215 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 216 .info_mask_shared_by_type = 217 BIT(IIO_CHAN_INFO_SCALE) | 218 BIT(IIO_CHAN_INFO_OFFSET), 219 .scan_index = 0, 220 .scan_type = { 221 .sign = 'u', 222 .realbits = DLH_NUM_PR_BITS, 223 .storagebits = 32, 224 .shift = 8, 225 .endianness = IIO_BE, 226 }, 227 }, { 228 .type = IIO_TEMP, 229 .indexed = 1, 230 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 231 .info_mask_shared_by_type = 232 BIT(IIO_CHAN_INFO_SCALE) | 233 BIT(IIO_CHAN_INFO_OFFSET), 234 .scan_index = 1, 235 .scan_type = { 236 .sign = 'u', 237 .realbits = DLH_NUM_TEMP_BITS, 238 .storagebits = 32, 239 .shift = 8, 240 .endianness = IIO_BE, 241 }, 242 } 243 }; 244 245 static irqreturn_t dlh_trigger_handler(int irq, void *private) 246 { 247 struct iio_poll_func *pf = private; 248 struct iio_dev *indio_dev = pf->indio_dev; 249 struct dlh_state *st = iio_priv(indio_dev); 250 int ret; 251 unsigned int chn, i = 0; 252 __be32 tmp_buf[2] = { }; 253 254 ret = dlh_start_capture_and_read(st); 255 if (ret) 256 goto out; 257 258 iio_for_each_active_channel(indio_dev, chn) { 259 memcpy(&tmp_buf[i++], 260 &st->rx_buf[1] + chn * DLH_NUM_DATA_BYTES, 261 DLH_NUM_DATA_BYTES); 262 } 263 264 iio_push_to_buffers(indio_dev, tmp_buf); 265 266 out: 267 iio_trigger_notify_done(indio_dev->trig); 268 269 return IRQ_HANDLED; 270 } 271 272 static irqreturn_t dlh_interrupt(int irq, void *private) 273 { 274 struct iio_dev *indio_dev = private; 275 struct dlh_state *st = iio_priv(indio_dev); 276 277 complete(&st->completion); 278 279 return IRQ_HANDLED; 280 }; 281 282 static int dlh_probe(struct i2c_client *client) 283 { 284 const struct i2c_device_id *id = i2c_client_get_device_id(client); 285 struct dlh_state *st; 286 struct iio_dev *indio_dev; 287 int ret; 288 289 if (!i2c_check_functionality(client->adapter, 290 I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE)) { 291 dev_err(&client->dev, 292 "adapter doesn't support required i2c functionality\n"); 293 return -EOPNOTSUPP; 294 } 295 296 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); 297 if (!indio_dev) { 298 dev_err(&client->dev, "failed to allocate iio device\n"); 299 return -ENOMEM; 300 } 301 302 i2c_set_clientdata(client, indio_dev); 303 304 st = iio_priv(indio_dev); 305 st->info = dlh_info_tbl[id->driver_data]; 306 st->client = client; 307 st->use_interrupt = false; 308 309 indio_dev->name = id->name; 310 indio_dev->info = &dlh_info; 311 indio_dev->modes = INDIO_DIRECT_MODE; 312 indio_dev->channels = dlh_channels; 313 indio_dev->num_channels = ARRAY_SIZE(dlh_channels); 314 315 if (client->irq > 0) { 316 ret = devm_request_threaded_irq(&client->dev, client->irq, 317 dlh_interrupt, NULL, 318 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 319 id->name, indio_dev); 320 if (ret) { 321 dev_err(&client->dev, "failed to allocate threaded irq"); 322 return ret; 323 } 324 325 st->use_interrupt = true; 326 init_completion(&st->completion); 327 } 328 329 ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, 330 NULL, &dlh_trigger_handler, NULL); 331 if (ret) { 332 dev_err(&client->dev, "failed to setup iio buffer\n"); 333 return ret; 334 } 335 336 ret = devm_iio_device_register(&client->dev, indio_dev); 337 if (ret) 338 dev_err(&client->dev, "failed to register iio device\n"); 339 340 return ret; 341 } 342 343 static const struct of_device_id dlh_of_match[] = { 344 { .compatible = "asc,dlhl60d" }, 345 { .compatible = "asc,dlhl60g" }, 346 { } 347 }; 348 MODULE_DEVICE_TABLE(of, dlh_of_match); 349 350 static const struct i2c_device_id dlh_id[] = { 351 { "dlhl60d", dlhl60d }, 352 { "dlhl60g", dlhl60g }, 353 { } 354 }; 355 MODULE_DEVICE_TABLE(i2c, dlh_id); 356 357 static struct i2c_driver dlh_driver = { 358 .driver = { 359 .name = "dlhl60d", 360 .of_match_table = dlh_of_match, 361 }, 362 .probe = dlh_probe, 363 .id_table = dlh_id, 364 }; 365 module_i2c_driver(dlh_driver); 366 367 MODULE_AUTHOR("Tomislav Denis <tomislav.denis@avl.com>"); 368 MODULE_DESCRIPTION("Driver for All Sensors DLH series pressure sensors"); 369 MODULE_LICENSE("GPL v2"); 370