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