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