1 // SPDX-License-Identifier: GPL-2.0
3 * All Sensors DLH series low voltage digital pressure sensors
5 * Copyright (c) 2019 AVL DiTEST GmbH
6 * Tomislav Denis <tomislav.denis@avl.com>
8 * Datasheet: https://www.allsensors.com/cad/DS-0355_Rev_B.PDF
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>
21 #define DLH_START_SINGLE 0xAA
24 #define DLH_STATUS_OK 0x40
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
33 #define DLH_SINGLE_DUT_MS 5
41 u8 osdig
; /* digital offset factor */
42 unsigned int fss
; /* full scale span (inch H2O) */
46 struct i2c_client
*client
;
49 struct completion completion
;
50 u8 rx_buf
[DLH_NUM_READ_BYTES
] ____cacheline_aligned
;
53 static struct dlh_info dlh_info_tbl
[] = {
65 static int dlh_cmd_start_single(struct dlh_state
*st
)
69 ret
= i2c_smbus_write_byte(st
->client
, DLH_START_SINGLE
);
71 dev_err(&st
->client
->dev
,
72 "%s: I2C write byte failed\n", __func__
);
77 static int dlh_cmd_read_data(struct dlh_state
*st
)
81 ret
= i2c_master_recv(st
->client
, st
->rx_buf
, DLH_NUM_READ_BYTES
);
83 dev_err(&st
->client
->dev
,
84 "%s: I2C read block failed\n", __func__
);
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]);
97 static int dlh_start_capture_and_read(struct dlh_state
*st
)
101 if (st
->use_interrupt
)
102 reinit_completion(&st
->completion
);
104 ret
= dlh_cmd_start_single(st
);
108 if (st
->use_interrupt
) {
109 ret
= wait_for_completion_timeout(&st
->completion
,
110 msecs_to_jiffies(DLH_SINGLE_DUT_MS
));
112 dev_err(&st
->client
->dev
,
113 "%s: conversion timed out\n", __func__
);
117 mdelay(DLH_SINGLE_DUT_MS
);
120 return dlh_cmd_read_data(st
);
123 static int dlh_read_direct(struct dlh_state
*st
,
124 unsigned int *pressure
, unsigned int *temperature
)
128 ret
= dlh_start_capture_and_read(st
);
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);
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
)
143 struct dlh_state
*st
= iio_priv(indio_dev
);
144 unsigned int pressure
, temperature
;
150 case IIO_CHAN_INFO_RAW
:
151 ret
= iio_device_claim_direct_mode(indio_dev
);
155 ret
= dlh_read_direct(st
, &pressure
, &temperature
);
156 iio_device_release_direct_mode(indio_dev
);
160 switch (channel
->type
) {
166 *value
= temperature
;
172 case IIO_CHAN_INFO_SCALE
:
173 switch (channel
->type
) {
175 tmp
= div_s64(125LL * st
->info
.fss
* 24909 * 100,
176 1 << DLH_NUM_PR_BITS
);
177 tmp
= div_s64_rem(tmp
, 1000000000LL, &rem
);
180 return IIO_VAL_INT_PLUS_NANO
;
184 *value2
= DLH_NUM_TEMP_BITS
;
185 return IIO_VAL_FRACTIONAL_LOG2
;
190 case IIO_CHAN_INFO_OFFSET
:
191 switch (channel
->type
) {
193 *value
= -125 * st
->info
.fss
* 24909;
194 *value2
= 100 * st
->info
.osdig
* 100000;
195 return IIO_VAL_FRACTIONAL
;
209 static const struct iio_info dlh_info
= {
210 .read_raw
= dlh_read_raw
,
213 static const struct iio_chan_spec dlh_channels
[] = {
215 .type
= IIO_PRESSURE
,
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
),
224 .realbits
= DLH_NUM_PR_BITS
,
227 .endianness
= IIO_BE
,
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
),
239 .realbits
= DLH_NUM_TEMP_BITS
,
242 .endianness
= IIO_BE
,
247 static irqreturn_t
dlh_trigger_handler(int irq
, void *private)
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
);
253 unsigned int chn
, i
= 0;
256 ret
= dlh_start_capture_and_read(st
);
260 for_each_set_bit(chn
, indio_dev
->active_scan_mask
,
261 indio_dev
->masklength
) {
263 &st
->rx_buf
[1] + chn
* DLH_NUM_DATA_BYTES
,
268 iio_push_to_buffers(indio_dev
, tmp_buf
);
271 iio_trigger_notify_done(indio_dev
->trig
);
276 static irqreturn_t
dlh_interrupt(int irq
, void *private)
278 struct iio_dev
*indio_dev
= private;
279 struct dlh_state
*st
= iio_priv(indio_dev
);
281 complete(&st
->completion
);
286 static int dlh_probe(struct i2c_client
*client
,
287 const struct i2c_device_id
*id
)
289 struct dlh_state
*st
;
290 struct iio_dev
*indio_dev
;
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");
300 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*st
));
302 dev_err(&client
->dev
, "failed to allocate iio device\n");
306 i2c_set_clientdata(client
, indio_dev
);
308 st
= iio_priv(indio_dev
);
309 st
->info
= dlh_info_tbl
[id
->driver_data
];
311 st
->use_interrupt
= false;
313 indio_dev
->name
= id
->name
;
314 indio_dev
->info
= &dlh_info
;
315 indio_dev
->modes
= INDIO_DIRECT_MODE
;
316 indio_dev
->channels
= dlh_channels
;
317 indio_dev
->num_channels
= ARRAY_SIZE(dlh_channels
);
319 if (client
->irq
> 0) {
320 ret
= devm_request_threaded_irq(&client
->dev
, client
->irq
,
322 IRQF_TRIGGER_RISING
| IRQF_ONESHOT
,
323 id
->name
, indio_dev
);
325 dev_err(&client
->dev
, "failed to allocate threaded irq");
329 st
->use_interrupt
= true;
330 init_completion(&st
->completion
);
333 ret
= devm_iio_triggered_buffer_setup(&client
->dev
, indio_dev
,
334 NULL
, &dlh_trigger_handler
, NULL
);
336 dev_err(&client
->dev
, "failed to setup iio buffer\n");
340 ret
= devm_iio_device_register(&client
->dev
, indio_dev
);
342 dev_err(&client
->dev
, "failed to register iio device\n");
347 static const struct of_device_id dlh_of_match
[] = {
348 { .compatible
= "asc,dlhl60d" },
349 { .compatible
= "asc,dlhl60g" },
352 MODULE_DEVICE_TABLE(of
, dlh_of_match
);
354 static const struct i2c_device_id dlh_id
[] = {
355 { "dlhl60d", dlhl60d
},
356 { "dlhl60g", dlhl60g
},
359 MODULE_DEVICE_TABLE(i2c
, dlh_id
);
361 static struct i2c_driver dlh_driver
= {
364 .of_match_table
= dlh_of_match
,
369 module_i2c_driver(dlh_driver
);
371 MODULE_AUTHOR("Tomislav Denis <tomislav.denis@avl.com>");
372 MODULE_DESCRIPTION("Driver for All Sensors DLH series pressure sensors");
373 MODULE_LICENSE("GPL v2");