xref: /linux/drivers/iio/pressure/dlhl60d.c (revision 0d5ec7919f3747193f051036b2301734a4b5e1d6)
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 
dlh_cmd_start_single(struct dlh_state * st)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 
dlh_cmd_read_data(struct dlh_state * st)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 
dlh_start_capture_and_read(struct dlh_state * st)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 
dlh_read_direct(struct dlh_state * st,unsigned int * pressure,unsigned int * temperature)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 
dlh_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * channel,int * value,int * value2,long mask)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 
dlh_trigger_handler(int irq,void * private)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 
dlh_interrupt(int irq,void * private)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 
dlh_probe(struct i2c_client * client)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