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 <linux/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
];
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_be24(&st
->rx_buf
[1]);
133 *temperature
= get_unaligned_be24(&st
->rx_buf
[4]);
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
)
142 struct dlh_state
*st
= iio_priv(indio_dev
);
143 unsigned int pressure
, temperature
;
149 case IIO_CHAN_INFO_RAW
:
150 ret
= iio_device_claim_direct_mode(indio_dev
);
154 ret
= dlh_read_direct(st
, &pressure
, &temperature
);
155 iio_device_release_direct_mode(indio_dev
);
159 switch (channel
->type
) {
165 *value
= temperature
;
171 case IIO_CHAN_INFO_SCALE
:
172 switch (channel
->type
) {
174 tmp
= div_s64(125LL * st
->info
.fss
* 24909 * 100,
175 1 << DLH_NUM_PR_BITS
);
176 tmp
= div_s64_rem(tmp
, 1000000000LL, &rem
);
179 return IIO_VAL_INT_PLUS_NANO
;
183 *value2
= DLH_NUM_TEMP_BITS
;
184 return IIO_VAL_FRACTIONAL_LOG2
;
189 case IIO_CHAN_INFO_OFFSET
:
190 switch (channel
->type
) {
192 *value
= -125 * st
->info
.fss
* 24909;
193 *value2
= 100 * st
->info
.osdig
* 100000;
194 return IIO_VAL_FRACTIONAL
;
208 static const struct iio_info dlh_info
= {
209 .read_raw
= dlh_read_raw
,
212 static const struct iio_chan_spec dlh_channels
[] = {
214 .type
= IIO_PRESSURE
,
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
),
223 .realbits
= DLH_NUM_PR_BITS
,
226 .endianness
= IIO_BE
,
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
),
238 .realbits
= DLH_NUM_TEMP_BITS
,
241 .endianness
= IIO_BE
,
246 static irqreturn_t
dlh_trigger_handler(int irq
, void *private)
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
);
252 unsigned int chn
, i
= 0;
253 __be32 tmp_buf
[2] = { };
255 ret
= dlh_start_capture_and_read(st
);
259 iio_for_each_active_channel(indio_dev
, chn
) {
260 memcpy(&tmp_buf
[i
++],
261 &st
->rx_buf
[1] + chn
* DLH_NUM_DATA_BYTES
,
265 iio_push_to_buffers(indio_dev
, tmp_buf
);
268 iio_trigger_notify_done(indio_dev
->trig
);
273 static irqreturn_t
dlh_interrupt(int irq
, void *private)
275 struct iio_dev
*indio_dev
= private;
276 struct dlh_state
*st
= iio_priv(indio_dev
);
278 complete(&st
->completion
);
283 static int dlh_probe(struct i2c_client
*client
)
285 const struct i2c_device_id
*id
= i2c_client_get_device_id(client
);
286 struct dlh_state
*st
;
287 struct iio_dev
*indio_dev
;
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");
297 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*st
));
299 dev_err(&client
->dev
, "failed to allocate iio device\n");
303 i2c_set_clientdata(client
, indio_dev
);
305 st
= iio_priv(indio_dev
);
306 st
->info
= dlh_info_tbl
[id
->driver_data
];
308 st
->use_interrupt
= false;
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
);
316 if (client
->irq
> 0) {
317 ret
= devm_request_threaded_irq(&client
->dev
, client
->irq
,
319 IRQF_TRIGGER_RISING
| IRQF_ONESHOT
,
320 id
->name
, indio_dev
);
322 dev_err(&client
->dev
, "failed to allocate threaded irq");
326 st
->use_interrupt
= true;
327 init_completion(&st
->completion
);
330 ret
= devm_iio_triggered_buffer_setup(&client
->dev
, indio_dev
,
331 NULL
, &dlh_trigger_handler
, NULL
);
333 dev_err(&client
->dev
, "failed to setup iio buffer\n");
337 ret
= devm_iio_device_register(&client
->dev
, indio_dev
);
339 dev_err(&client
->dev
, "failed to register iio device\n");
344 static const struct of_device_id dlh_of_match
[] = {
345 { .compatible
= "asc,dlhl60d" },
346 { .compatible
= "asc,dlhl60g" },
349 MODULE_DEVICE_TABLE(of
, dlh_of_match
);
351 static const struct i2c_device_id dlh_id
[] = {
352 { "dlhl60d", dlhl60d
},
353 { "dlhl60g", dlhl60g
},
356 MODULE_DEVICE_TABLE(i2c
, dlh_id
);
358 static struct i2c_driver dlh_driver
= {
361 .of_match_table
= dlh_of_match
,
366 module_i2c_driver(dlh_driver
);
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");