xref: /openbmc/linux/drivers/iio/pressure/dps310.c (revision 08f5bd20)
1ba6ec48eSJoel Stanley // SPDX-License-Identifier: GPL-2.0+
2ba6ec48eSJoel Stanley // Copyright IBM Corp 2019
3ba6ec48eSJoel Stanley /*
4ba6ec48eSJoel Stanley  * The DPS310 is a barometric pressure and temperature sensor.
5ba6ec48eSJoel Stanley  * Currently only reading a single temperature is supported by
6ba6ec48eSJoel Stanley  * this driver.
7ba6ec48eSJoel Stanley  *
8ba6ec48eSJoel Stanley  * https://www.infineon.com/dgdl/?fileId=5546d462576f34750157750826c42242
9ba6ec48eSJoel Stanley  *
10ba6ec48eSJoel Stanley  * Temperature calculation:
11ba6ec48eSJoel Stanley  *   c0 * 0.5 + c1 * T_raw / kT °C
12ba6ec48eSJoel Stanley  *
13ba6ec48eSJoel Stanley  * TODO:
14ba6ec48eSJoel Stanley  *  - Optionally support the FIFO
15ba6ec48eSJoel Stanley  */
16ba6ec48eSJoel Stanley 
17ba6ec48eSJoel Stanley #include <linux/i2c.h>
18d711a3c7SEddie James #include <linux/limits.h>
19d711a3c7SEddie James #include <linux/math64.h>
20ba6ec48eSJoel Stanley #include <linux/module.h>
21ba6ec48eSJoel Stanley #include <linux/regmap.h>
22ba6ec48eSJoel Stanley 
23ba6ec48eSJoel Stanley #include <linux/iio/iio.h>
24ba6ec48eSJoel Stanley #include <linux/iio/sysfs.h>
25ba6ec48eSJoel Stanley 
26ba6ec48eSJoel Stanley #define DPS310_DEV_NAME		"dps310"
27ba6ec48eSJoel Stanley 
28ba6ec48eSJoel Stanley #define DPS310_PRS_B0		0x00
29ba6ec48eSJoel Stanley #define DPS310_PRS_B1		0x01
30ba6ec48eSJoel Stanley #define DPS310_PRS_B2		0x02
31ba6ec48eSJoel Stanley #define DPS310_TMP_B0		0x03
32ba6ec48eSJoel Stanley #define DPS310_TMP_B1		0x04
33ba6ec48eSJoel Stanley #define DPS310_TMP_B2		0x05
34ba6ec48eSJoel Stanley #define DPS310_PRS_CFG		0x06
35d711a3c7SEddie James #define  DPS310_PRS_RATE_BITS	GENMASK(6, 4)
36d711a3c7SEddie James #define  DPS310_PRS_PRC_BITS	GENMASK(3, 0)
37ba6ec48eSJoel Stanley #define DPS310_TMP_CFG		0x07
38ba6ec48eSJoel Stanley #define  DPS310_TMP_RATE_BITS	GENMASK(6, 4)
39ba6ec48eSJoel Stanley #define  DPS310_TMP_PRC_BITS	GENMASK(3, 0)
40ba6ec48eSJoel Stanley #define  DPS310_TMP_EXT		BIT(7)
41ba6ec48eSJoel Stanley #define DPS310_MEAS_CFG		0x08
42ba6ec48eSJoel Stanley #define  DPS310_MEAS_CTRL_BITS	GENMASK(2, 0)
43ba6ec48eSJoel Stanley #define   DPS310_PRS_EN		BIT(0)
44ba6ec48eSJoel Stanley #define   DPS310_TEMP_EN	BIT(1)
45ba6ec48eSJoel Stanley #define   DPS310_BACKGROUND	BIT(2)
46ba6ec48eSJoel Stanley #define  DPS310_PRS_RDY		BIT(4)
47ba6ec48eSJoel Stanley #define  DPS310_TMP_RDY		BIT(5)
48ba6ec48eSJoel Stanley #define  DPS310_SENSOR_RDY	BIT(6)
49ba6ec48eSJoel Stanley #define  DPS310_COEF_RDY	BIT(7)
50ba6ec48eSJoel Stanley #define DPS310_CFG_REG		0x09
51ba6ec48eSJoel Stanley #define  DPS310_INT_HL		BIT(7)
52ba6ec48eSJoel Stanley #define  DPS310_TMP_SHIFT_EN	BIT(3)
53ba6ec48eSJoel Stanley #define  DPS310_PRS_SHIFT_EN	BIT(4)
54ba6ec48eSJoel Stanley #define  DPS310_FIFO_EN		BIT(5)
55ba6ec48eSJoel Stanley #define  DPS310_SPI_EN		BIT(6)
56ba6ec48eSJoel Stanley #define DPS310_RESET		0x0c
57ba6ec48eSJoel Stanley #define  DPS310_RESET_MAGIC	0x09
58ba6ec48eSJoel Stanley #define DPS310_COEF_BASE	0x10
59ba6ec48eSJoel Stanley 
60901a293fSLakshmi Yadlapati /* Make sure sleep time is <= 30ms for usleep_range */
61901a293fSLakshmi Yadlapati #define DPS310_POLL_SLEEP_US(t)		min(30000, (t) / 8)
62ba6ec48eSJoel Stanley /* Silently handle error in rate value here */
63ba6ec48eSJoel Stanley #define DPS310_POLL_TIMEOUT_US(rc)	((rc) <= 0 ? 1000000 : 1000000 / (rc))
64ba6ec48eSJoel Stanley 
65ba6ec48eSJoel Stanley #define DPS310_PRS_BASE		DPS310_PRS_B0
66ba6ec48eSJoel Stanley #define DPS310_TMP_BASE		DPS310_TMP_B0
67ba6ec48eSJoel Stanley 
68ba6ec48eSJoel Stanley /*
69ba6ec48eSJoel Stanley  * These values (defined in the spec) indicate how to scale the raw register
70ba6ec48eSJoel Stanley  * values for each level of precision available.
71ba6ec48eSJoel Stanley  */
72ba6ec48eSJoel Stanley static const int scale_factors[] = {
73ba6ec48eSJoel Stanley 	 524288,
74ba6ec48eSJoel Stanley 	1572864,
75ba6ec48eSJoel Stanley 	3670016,
76ba6ec48eSJoel Stanley 	7864320,
77ba6ec48eSJoel Stanley 	 253952,
78ba6ec48eSJoel Stanley 	 516096,
79ba6ec48eSJoel Stanley 	1040384,
80ba6ec48eSJoel Stanley 	2088960,
81ba6ec48eSJoel Stanley };
82ba6ec48eSJoel Stanley 
83ba6ec48eSJoel Stanley struct dps310_data {
84ba6ec48eSJoel Stanley 	struct i2c_client *client;
85ba6ec48eSJoel Stanley 	struct regmap *regmap;
86ba6ec48eSJoel Stanley 	struct mutex lock;	/* Lock for sequential HW access functions */
87ba6ec48eSJoel Stanley 
88ba6ec48eSJoel Stanley 	s32 c0, c1;
89d711a3c7SEddie James 	s32 c00, c10, c20, c30, c01, c11, c21;
90d711a3c7SEddie James 	s32 pressure_raw;
91ba6ec48eSJoel Stanley 	s32 temp_raw;
927b4ab4abSEddie James 	bool timeout_recovery_failed;
93ba6ec48eSJoel Stanley };
94ba6ec48eSJoel Stanley 
95ba6ec48eSJoel Stanley static const struct iio_chan_spec dps310_channels[] = {
96ba6ec48eSJoel Stanley 	{
97ba6ec48eSJoel Stanley 		.type = IIO_TEMP,
98ba6ec48eSJoel Stanley 		.info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
99ba6ec48eSJoel Stanley 			BIT(IIO_CHAN_INFO_SAMP_FREQ) |
100ba6ec48eSJoel Stanley 			BIT(IIO_CHAN_INFO_PROCESSED),
101ba6ec48eSJoel Stanley 	},
102d711a3c7SEddie James 	{
103d711a3c7SEddie James 		.type = IIO_PRESSURE,
104d711a3c7SEddie James 		.info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
105d711a3c7SEddie James 			BIT(IIO_CHAN_INFO_SAMP_FREQ) |
106d711a3c7SEddie James 			BIT(IIO_CHAN_INFO_PROCESSED),
107d711a3c7SEddie James 	},
108ba6ec48eSJoel Stanley };
109ba6ec48eSJoel Stanley 
110ba6ec48eSJoel Stanley /* To be called after checking the COEF_RDY bit in MEAS_CFG */
dps310_get_coefs(struct dps310_data * data)111d711a3c7SEddie James static int dps310_get_coefs(struct dps310_data *data)
112ba6ec48eSJoel Stanley {
113ba6ec48eSJoel Stanley 	int rc;
114d711a3c7SEddie James 	u8 coef[18];
115ba6ec48eSJoel Stanley 	u32 c0, c1;
116d711a3c7SEddie James 	u32 c00, c10, c20, c30, c01, c11, c21;
117ba6ec48eSJoel Stanley 
118d711a3c7SEddie James 	/* Read all sensor calibration coefficients from the COEF registers. */
119ba6ec48eSJoel Stanley 	rc = regmap_bulk_read(data->regmap, DPS310_COEF_BASE, coef,
120ba6ec48eSJoel Stanley 			      sizeof(coef));
121ba6ec48eSJoel Stanley 	if (rc < 0)
122ba6ec48eSJoel Stanley 		return rc;
123ba6ec48eSJoel Stanley 
124d711a3c7SEddie James 	/*
125d711a3c7SEddie James 	 * Calculate temperature calibration coefficients c0 and c1. The
126d711a3c7SEddie James 	 * numbers are 12-bit 2's complement numbers.
127d711a3c7SEddie James 	 */
128ba6ec48eSJoel Stanley 	c0 = (coef[0] << 4) | (coef[1] >> 4);
129ba6ec48eSJoel Stanley 	data->c0 = sign_extend32(c0, 11);
130ba6ec48eSJoel Stanley 
131ba6ec48eSJoel Stanley 	c1 = ((coef[1] & GENMASK(3, 0)) << 8) | coef[2];
132ba6ec48eSJoel Stanley 	data->c1 = sign_extend32(c1, 11);
133ba6ec48eSJoel Stanley 
134d711a3c7SEddie James 	/*
135d711a3c7SEddie James 	 * Calculate pressure calibration coefficients. c00 and c10 are 20 bit
136d711a3c7SEddie James 	 * 2's complement numbers, while the rest are 16 bit 2's complement
137d711a3c7SEddie James 	 * numbers.
138d711a3c7SEddie James 	 */
139d711a3c7SEddie James 	c00 = (coef[3] << 12) | (coef[4] << 4) | (coef[5] >> 4);
140d711a3c7SEddie James 	data->c00 = sign_extend32(c00, 19);
141d711a3c7SEddie James 
142d711a3c7SEddie James 	c10 = ((coef[5] & GENMASK(3, 0)) << 16) | (coef[6] << 8) | coef[7];
143d711a3c7SEddie James 	data->c10 = sign_extend32(c10, 19);
144d711a3c7SEddie James 
145d711a3c7SEddie James 	c01 = (coef[8] << 8) | coef[9];
146d711a3c7SEddie James 	data->c01 = sign_extend32(c01, 15);
147d711a3c7SEddie James 
148d711a3c7SEddie James 	c11 = (coef[10] << 8) | coef[11];
149d711a3c7SEddie James 	data->c11 = sign_extend32(c11, 15);
150d711a3c7SEddie James 
151d711a3c7SEddie James 	c20 = (coef[12] << 8) | coef[13];
152d711a3c7SEddie James 	data->c20 = sign_extend32(c20, 15);
153d711a3c7SEddie James 
154d711a3c7SEddie James 	c21 = (coef[14] << 8) | coef[15];
155d711a3c7SEddie James 	data->c21 = sign_extend32(c21, 15);
156d711a3c7SEddie James 
157d711a3c7SEddie James 	c30 = (coef[16] << 8) | coef[17];
158d711a3c7SEddie James 	data->c30 = sign_extend32(c30, 15);
159d711a3c7SEddie James 
160ba6ec48eSJoel Stanley 	return 0;
161ba6ec48eSJoel Stanley }
162ba6ec48eSJoel Stanley 
163c2329717SEddie James /*
164c2329717SEddie James  * Some versions of the chip will read temperatures in the ~60C range when
165c2329717SEddie James  * it's actually ~20C. This is the manufacturer recommended workaround
166c2329717SEddie James  * to correct the issue. The registers used below are undocumented.
167c2329717SEddie James  */
dps310_temp_workaround(struct dps310_data * data)168c2329717SEddie James static int dps310_temp_workaround(struct dps310_data *data)
169c2329717SEddie James {
170c2329717SEddie James 	int rc;
171c2329717SEddie James 	int reg;
172c2329717SEddie James 
173c2329717SEddie James 	rc = regmap_read(data->regmap, 0x32, &reg);
174c2329717SEddie James 	if (rc)
175c2329717SEddie James 		return rc;
176c2329717SEddie James 
177c2329717SEddie James 	/*
178c2329717SEddie James 	 * If bit 1 is set then the device is okay, and the workaround does not
179c2329717SEddie James 	 * need to be applied
180c2329717SEddie James 	 */
181c2329717SEddie James 	if (reg & BIT(1))
182c2329717SEddie James 		return 0;
183c2329717SEddie James 
184c2329717SEddie James 	rc = regmap_write(data->regmap, 0x0e, 0xA5);
185c2329717SEddie James 	if (rc)
186c2329717SEddie James 		return rc;
187c2329717SEddie James 
188c2329717SEddie James 	rc = regmap_write(data->regmap, 0x0f, 0x96);
189c2329717SEddie James 	if (rc)
190c2329717SEddie James 		return rc;
191c2329717SEddie James 
192c2329717SEddie James 	rc = regmap_write(data->regmap, 0x62, 0x02);
193c2329717SEddie James 	if (rc)
194c2329717SEddie James 		return rc;
195c2329717SEddie James 
196c2329717SEddie James 	rc = regmap_write(data->regmap, 0x0e, 0x00);
197c2329717SEddie James 	if (rc)
198c2329717SEddie James 		return rc;
199c2329717SEddie James 
200c2329717SEddie James 	return regmap_write(data->regmap, 0x0f, 0x00);
201c2329717SEddie James }
202c2329717SEddie James 
dps310_startup(struct dps310_data * data)203c2329717SEddie James static int dps310_startup(struct dps310_data *data)
204c2329717SEddie James {
205c2329717SEddie James 	int rc;
206c2329717SEddie James 	int ready;
207c2329717SEddie James 
208c2329717SEddie James 	/*
209c2329717SEddie James 	 * Set up pressure sensor in single sample, one measurement per second
210c2329717SEddie James 	 * mode
211c2329717SEddie James 	 */
212c2329717SEddie James 	rc = regmap_write(data->regmap, DPS310_PRS_CFG, 0);
213c2329717SEddie James 	if (rc)
214c2329717SEddie James 		return rc;
215c2329717SEddie James 
216c2329717SEddie James 	/*
217c2329717SEddie James 	 * Set up external (MEMS) temperature sensor in single sample, one
218c2329717SEddie James 	 * measurement per second mode
219c2329717SEddie James 	 */
220c2329717SEddie James 	rc = regmap_write(data->regmap, DPS310_TMP_CFG, DPS310_TMP_EXT);
221c2329717SEddie James 	if (rc)
222c2329717SEddie James 		return rc;
223c2329717SEddie James 
224c2329717SEddie James 	/* Temp and pressure shifts are disabled when PRC <= 8 */
225c2329717SEddie James 	rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
226c2329717SEddie James 			       DPS310_PRS_SHIFT_EN | DPS310_TMP_SHIFT_EN, 0);
227c2329717SEddie James 	if (rc)
228c2329717SEddie James 		return rc;
229c2329717SEddie James 
230c2329717SEddie James 	/* MEAS_CFG doesn't update correctly unless first written with 0 */
231c2329717SEddie James 	rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
232c2329717SEddie James 			       DPS310_MEAS_CTRL_BITS, 0);
233c2329717SEddie James 	if (rc)
234c2329717SEddie James 		return rc;
235c2329717SEddie James 
236c2329717SEddie James 	/* Turn on temperature and pressure measurement in the background */
237c2329717SEddie James 	rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
238c2329717SEddie James 			       DPS310_MEAS_CTRL_BITS, DPS310_PRS_EN |
239c2329717SEddie James 			       DPS310_TEMP_EN | DPS310_BACKGROUND);
240c2329717SEddie James 	if (rc)
241c2329717SEddie James 		return rc;
242c2329717SEddie James 
243c2329717SEddie James 	/*
244c2329717SEddie James 	 * Calibration coefficients required for reporting temperature.
245c2329717SEddie James 	 * They are available 40ms after the device has started
246c2329717SEddie James 	 */
247c2329717SEddie James 	rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
248c2329717SEddie James 				      ready & DPS310_COEF_RDY, 10000, 40000);
249c2329717SEddie James 	if (rc)
250c2329717SEddie James 		return rc;
251c2329717SEddie James 
252c2329717SEddie James 	rc = dps310_get_coefs(data);
253c2329717SEddie James 	if (rc)
254c2329717SEddie James 		return rc;
255c2329717SEddie James 
256c2329717SEddie James 	return dps310_temp_workaround(data);
257c2329717SEddie James }
258c2329717SEddie James 
dps310_get_pres_precision(struct dps310_data * data)259d711a3c7SEddie James static int dps310_get_pres_precision(struct dps310_data *data)
260d711a3c7SEddie James {
261d711a3c7SEddie James 	int rc;
262d711a3c7SEddie James 	int val;
263d711a3c7SEddie James 
264d711a3c7SEddie James 	rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val);
265d711a3c7SEddie James 	if (rc < 0)
266d711a3c7SEddie James 		return rc;
267d711a3c7SEddie James 
268d711a3c7SEddie James 	return BIT(val & GENMASK(2, 0));
269d711a3c7SEddie James }
270d711a3c7SEddie James 
dps310_get_temp_precision(struct dps310_data * data)271ba6ec48eSJoel Stanley static int dps310_get_temp_precision(struct dps310_data *data)
272ba6ec48eSJoel Stanley {
273ba6ec48eSJoel Stanley 	int rc;
274ba6ec48eSJoel Stanley 	int val;
275ba6ec48eSJoel Stanley 
276ba6ec48eSJoel Stanley 	rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val);
277ba6ec48eSJoel Stanley 	if (rc < 0)
278ba6ec48eSJoel Stanley 		return rc;
279ba6ec48eSJoel Stanley 
280ba6ec48eSJoel Stanley 	/*
281ba6ec48eSJoel Stanley 	 * Scale factor is bottom 4 bits of the register, but 1111 is
282ba6ec48eSJoel Stanley 	 * reserved so just grab bottom three
283ba6ec48eSJoel Stanley 	 */
284ba6ec48eSJoel Stanley 	return BIT(val & GENMASK(2, 0));
285ba6ec48eSJoel Stanley }
286ba6ec48eSJoel Stanley 
287ba6ec48eSJoel Stanley /* Called with lock held */
dps310_set_pres_precision(struct dps310_data * data,int val)288d711a3c7SEddie James static int dps310_set_pres_precision(struct dps310_data *data, int val)
289d711a3c7SEddie James {
290d711a3c7SEddie James 	int rc;
291d711a3c7SEddie James 	u8 shift_en;
292d711a3c7SEddie James 
293d711a3c7SEddie James 	if (val < 0 || val > 128)
294d711a3c7SEddie James 		return -EINVAL;
295d711a3c7SEddie James 
296d711a3c7SEddie James 	shift_en = val >= 16 ? DPS310_PRS_SHIFT_EN : 0;
297d711a3c7SEddie James 	rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
298d711a3c7SEddie James 			       DPS310_PRS_SHIFT_EN, shift_en);
299d711a3c7SEddie James 	if (rc)
300d711a3c7SEddie James 		return rc;
301d711a3c7SEddie James 
302d711a3c7SEddie James 	return regmap_update_bits(data->regmap, DPS310_PRS_CFG,
303d711a3c7SEddie James 				  DPS310_PRS_PRC_BITS, ilog2(val));
304d711a3c7SEddie James }
305d711a3c7SEddie James 
306d711a3c7SEddie James /* Called with lock held */
dps310_set_temp_precision(struct dps310_data * data,int val)307ba6ec48eSJoel Stanley static int dps310_set_temp_precision(struct dps310_data *data, int val)
308ba6ec48eSJoel Stanley {
309ba6ec48eSJoel Stanley 	int rc;
310ba6ec48eSJoel Stanley 	u8 shift_en;
311ba6ec48eSJoel Stanley 
312ba6ec48eSJoel Stanley 	if (val < 0 || val > 128)
313ba6ec48eSJoel Stanley 		return -EINVAL;
314ba6ec48eSJoel Stanley 
315ba6ec48eSJoel Stanley 	shift_en = val >= 16 ? DPS310_TMP_SHIFT_EN : 0;
316ba6ec48eSJoel Stanley 	rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
317ba6ec48eSJoel Stanley 			       DPS310_TMP_SHIFT_EN, shift_en);
318ba6ec48eSJoel Stanley 	if (rc)
319ba6ec48eSJoel Stanley 		return rc;
320ba6ec48eSJoel Stanley 
321ba6ec48eSJoel Stanley 	return regmap_update_bits(data->regmap, DPS310_TMP_CFG,
322ba6ec48eSJoel Stanley 				  DPS310_TMP_PRC_BITS, ilog2(val));
323ba6ec48eSJoel Stanley }
324ba6ec48eSJoel Stanley 
325ba6ec48eSJoel Stanley /* Called with lock held */
dps310_set_pres_samp_freq(struct dps310_data * data,int freq)326d711a3c7SEddie James static int dps310_set_pres_samp_freq(struct dps310_data *data, int freq)
327d711a3c7SEddie James {
328d711a3c7SEddie James 	u8 val;
329d711a3c7SEddie James 
330d711a3c7SEddie James 	if (freq < 0 || freq > 128)
331d711a3c7SEddie James 		return -EINVAL;
332d711a3c7SEddie James 
333d711a3c7SEddie James 	val = ilog2(freq) << 4;
334d711a3c7SEddie James 
335d711a3c7SEddie James 	return regmap_update_bits(data->regmap, DPS310_PRS_CFG,
336d711a3c7SEddie James 				  DPS310_PRS_RATE_BITS, val);
337d711a3c7SEddie James }
338d711a3c7SEddie James 
339d711a3c7SEddie James /* Called with lock held */
dps310_set_temp_samp_freq(struct dps310_data * data,int freq)340ba6ec48eSJoel Stanley static int dps310_set_temp_samp_freq(struct dps310_data *data, int freq)
341ba6ec48eSJoel Stanley {
342ba6ec48eSJoel Stanley 	u8 val;
343ba6ec48eSJoel Stanley 
344ba6ec48eSJoel Stanley 	if (freq < 0 || freq > 128)
345ba6ec48eSJoel Stanley 		return -EINVAL;
346ba6ec48eSJoel Stanley 
347ba6ec48eSJoel Stanley 	val = ilog2(freq) << 4;
348ba6ec48eSJoel Stanley 
349ba6ec48eSJoel Stanley 	return regmap_update_bits(data->regmap, DPS310_TMP_CFG,
350ba6ec48eSJoel Stanley 				  DPS310_TMP_RATE_BITS, val);
351ba6ec48eSJoel Stanley }
352ba6ec48eSJoel Stanley 
dps310_get_pres_samp_freq(struct dps310_data * data)353d711a3c7SEddie James static int dps310_get_pres_samp_freq(struct dps310_data *data)
354d711a3c7SEddie James {
355d711a3c7SEddie James 	int rc;
356d711a3c7SEddie James 	int val;
357d711a3c7SEddie James 
358d711a3c7SEddie James 	rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val);
359d711a3c7SEddie James 	if (rc < 0)
360d711a3c7SEddie James 		return rc;
361d711a3c7SEddie James 
362d711a3c7SEddie James 	return BIT((val & DPS310_PRS_RATE_BITS) >> 4);
363d711a3c7SEddie James }
364d711a3c7SEddie James 
dps310_get_temp_samp_freq(struct dps310_data * data)365ba6ec48eSJoel Stanley static int dps310_get_temp_samp_freq(struct dps310_data *data)
366ba6ec48eSJoel Stanley {
367ba6ec48eSJoel Stanley 	int rc;
368ba6ec48eSJoel Stanley 	int val;
369ba6ec48eSJoel Stanley 
370ba6ec48eSJoel Stanley 	rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val);
371ba6ec48eSJoel Stanley 	if (rc < 0)
372ba6ec48eSJoel Stanley 		return rc;
373ba6ec48eSJoel Stanley 
374ba6ec48eSJoel Stanley 	return BIT((val & DPS310_TMP_RATE_BITS) >> 4);
375ba6ec48eSJoel Stanley }
376ba6ec48eSJoel Stanley 
dps310_get_pres_k(struct dps310_data * data)377d711a3c7SEddie James static int dps310_get_pres_k(struct dps310_data *data)
378d711a3c7SEddie James {
379d711a3c7SEddie James 	int rc = dps310_get_pres_precision(data);
380d711a3c7SEddie James 
381d711a3c7SEddie James 	if (rc < 0)
382d711a3c7SEddie James 		return rc;
383d711a3c7SEddie James 
384d711a3c7SEddie James 	return scale_factors[ilog2(rc)];
385d711a3c7SEddie James }
386d711a3c7SEddie James 
dps310_get_temp_k(struct dps310_data * data)387ba6ec48eSJoel Stanley static int dps310_get_temp_k(struct dps310_data *data)
388ba6ec48eSJoel Stanley {
389ba6ec48eSJoel Stanley 	int rc = dps310_get_temp_precision(data);
390ba6ec48eSJoel Stanley 
391ba6ec48eSJoel Stanley 	if (rc < 0)
392ba6ec48eSJoel Stanley 		return rc;
393ba6ec48eSJoel Stanley 
394ba6ec48eSJoel Stanley 	return scale_factors[ilog2(rc)];
395ba6ec48eSJoel Stanley }
396ba6ec48eSJoel Stanley 
dps310_reset_wait(struct dps310_data * data)3977b4ab4abSEddie James static int dps310_reset_wait(struct dps310_data *data)
3987b4ab4abSEddie James {
3997b4ab4abSEddie James 	int rc;
4007b4ab4abSEddie James 
4017b4ab4abSEddie James 	rc = regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC);
4027b4ab4abSEddie James 	if (rc)
4037b4ab4abSEddie James 		return rc;
4047b4ab4abSEddie James 
405901a293fSLakshmi Yadlapati 	/* Wait for device chip access: 15ms in specification */
406901a293fSLakshmi Yadlapati 	usleep_range(15000, 55000);
4077b4ab4abSEddie James 	return 0;
4087b4ab4abSEddie James }
4097b4ab4abSEddie James 
dps310_reset_reinit(struct dps310_data * data)4107b4ab4abSEddie James static int dps310_reset_reinit(struct dps310_data *data)
4117b4ab4abSEddie James {
4127b4ab4abSEddie James 	int rc;
4137b4ab4abSEddie James 
4147b4ab4abSEddie James 	rc = dps310_reset_wait(data);
4157b4ab4abSEddie James 	if (rc)
4167b4ab4abSEddie James 		return rc;
4177b4ab4abSEddie James 
4187b4ab4abSEddie James 	return dps310_startup(data);
4197b4ab4abSEddie James }
4207b4ab4abSEddie James 
dps310_ready_status(struct dps310_data * data,int ready_bit,int timeout)4217b4ab4abSEddie James static int dps310_ready_status(struct dps310_data *data, int ready_bit, int timeout)
4227b4ab4abSEddie James {
4237b4ab4abSEddie James 	int sleep = DPS310_POLL_SLEEP_US(timeout);
4247b4ab4abSEddie James 	int ready;
4257b4ab4abSEddie James 
4267b4ab4abSEddie James 	return regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, ready & ready_bit,
4277b4ab4abSEddie James 					sleep, timeout);
4287b4ab4abSEddie James }
4297b4ab4abSEddie James 
dps310_ready(struct dps310_data * data,int ready_bit,int timeout)4307b4ab4abSEddie James static int dps310_ready(struct dps310_data *data, int ready_bit, int timeout)
4317b4ab4abSEddie James {
4327b4ab4abSEddie James 	int rc;
4337b4ab4abSEddie James 
4347b4ab4abSEddie James 	rc = dps310_ready_status(data, ready_bit, timeout);
4357b4ab4abSEddie James 	if (rc) {
4367b4ab4abSEddie James 		if (rc == -ETIMEDOUT && !data->timeout_recovery_failed) {
4377b4ab4abSEddie James 			/* Reset and reinitialize the chip. */
4387b4ab4abSEddie James 			if (dps310_reset_reinit(data)) {
4397b4ab4abSEddie James 				data->timeout_recovery_failed = true;
4407b4ab4abSEddie James 			} else {
4417b4ab4abSEddie James 				/* Try again to get sensor ready status. */
4427b4ab4abSEddie James 				if (dps310_ready_status(data, ready_bit, timeout))
4437b4ab4abSEddie James 					data->timeout_recovery_failed = true;
4447b4ab4abSEddie James 				else
4457b4ab4abSEddie James 					return 0;
4467b4ab4abSEddie James 			}
4477b4ab4abSEddie James 		}
4487b4ab4abSEddie James 
4497b4ab4abSEddie James 		return rc;
4507b4ab4abSEddie James 	}
4517b4ab4abSEddie James 
4527b4ab4abSEddie James 	data->timeout_recovery_failed = false;
4537b4ab4abSEddie James 	return 0;
4547b4ab4abSEddie James }
4557b4ab4abSEddie James 
dps310_read_pres_raw(struct dps310_data * data)456d711a3c7SEddie James static int dps310_read_pres_raw(struct dps310_data *data)
457ba6ec48eSJoel Stanley {
458ba6ec48eSJoel Stanley 	int rc;
459ba6ec48eSJoel Stanley 	int rate;
460ba6ec48eSJoel Stanley 	int timeout;
461ba6ec48eSJoel Stanley 	s32 raw;
462ba6ec48eSJoel Stanley 	u8 val[3];
463ba6ec48eSJoel Stanley 
464ba6ec48eSJoel Stanley 	if (mutex_lock_interruptible(&data->lock))
465ba6ec48eSJoel Stanley 		return -EINTR;
466ba6ec48eSJoel Stanley 
467d711a3c7SEddie James 	rate = dps310_get_pres_samp_freq(data);
468d711a3c7SEddie James 	timeout = DPS310_POLL_TIMEOUT_US(rate);
469d711a3c7SEddie James 
470d711a3c7SEddie James 	/* Poll for sensor readiness; base the timeout upon the sample rate. */
4717b4ab4abSEddie James 	rc = dps310_ready(data, DPS310_PRS_RDY, timeout);
472d711a3c7SEddie James 	if (rc)
473d711a3c7SEddie James 		goto done;
474d711a3c7SEddie James 
475d711a3c7SEddie James 	rc = regmap_bulk_read(data->regmap, DPS310_PRS_BASE, val, sizeof(val));
476d711a3c7SEddie James 	if (rc < 0)
477d711a3c7SEddie James 		goto done;
478d711a3c7SEddie James 
479d711a3c7SEddie James 	raw = (val[0] << 16) | (val[1] << 8) | val[2];
480d711a3c7SEddie James 	data->pressure_raw = sign_extend32(raw, 23);
481d711a3c7SEddie James 
482d711a3c7SEddie James done:
483d711a3c7SEddie James 	mutex_unlock(&data->lock);
484d711a3c7SEddie James 	return rc;
485d711a3c7SEddie James }
486d711a3c7SEddie James 
487d711a3c7SEddie James /* Called with lock held */
dps310_read_temp_ready(struct dps310_data * data)488d711a3c7SEddie James static int dps310_read_temp_ready(struct dps310_data *data)
489d711a3c7SEddie James {
490d711a3c7SEddie James 	int rc;
491d711a3c7SEddie James 	u8 val[3];
492d711a3c7SEddie James 	s32 raw;
493d711a3c7SEddie James 
494d711a3c7SEddie James 	rc = regmap_bulk_read(data->regmap, DPS310_TMP_BASE, val, sizeof(val));
495d711a3c7SEddie James 	if (rc < 0)
496d711a3c7SEddie James 		return rc;
497d711a3c7SEddie James 
498d711a3c7SEddie James 	raw = (val[0] << 16) | (val[1] << 8) | val[2];
499d711a3c7SEddie James 	data->temp_raw = sign_extend32(raw, 23);
500d711a3c7SEddie James 
501d711a3c7SEddie James 	return 0;
502d711a3c7SEddie James }
503d711a3c7SEddie James 
dps310_read_temp_raw(struct dps310_data * data)504d711a3c7SEddie James static int dps310_read_temp_raw(struct dps310_data *data)
505d711a3c7SEddie James {
506d711a3c7SEddie James 	int rc;
507d711a3c7SEddie James 	int rate;
508d711a3c7SEddie James 	int timeout;
509d711a3c7SEddie James 
510d711a3c7SEddie James 	if (mutex_lock_interruptible(&data->lock))
511d711a3c7SEddie James 		return -EINTR;
512d711a3c7SEddie James 
513ba6ec48eSJoel Stanley 	rate = dps310_get_temp_samp_freq(data);
514ba6ec48eSJoel Stanley 	timeout = DPS310_POLL_TIMEOUT_US(rate);
515ba6ec48eSJoel Stanley 
516ba6ec48eSJoel Stanley 	/* Poll for sensor readiness; base the timeout upon the sample rate. */
5177b4ab4abSEddie James 	rc = dps310_ready(data, DPS310_TMP_RDY, timeout);
5187b4ab4abSEddie James 	if (rc)
519ba6ec48eSJoel Stanley 		goto done;
520ba6ec48eSJoel Stanley 
521d711a3c7SEddie James 	rc = dps310_read_temp_ready(data);
522ba6ec48eSJoel Stanley 
523ba6ec48eSJoel Stanley done:
524ba6ec48eSJoel Stanley 	mutex_unlock(&data->lock);
525ba6ec48eSJoel Stanley 	return rc;
526ba6ec48eSJoel Stanley }
527ba6ec48eSJoel Stanley 
dps310_is_writeable_reg(struct device * dev,unsigned int reg)528ba6ec48eSJoel Stanley static bool dps310_is_writeable_reg(struct device *dev, unsigned int reg)
529ba6ec48eSJoel Stanley {
530ba6ec48eSJoel Stanley 	switch (reg) {
531ba6ec48eSJoel Stanley 	case DPS310_PRS_CFG:
532ba6ec48eSJoel Stanley 	case DPS310_TMP_CFG:
533ba6ec48eSJoel Stanley 	case DPS310_MEAS_CFG:
534ba6ec48eSJoel Stanley 	case DPS310_CFG_REG:
535ba6ec48eSJoel Stanley 	case DPS310_RESET:
536cc8baffeSChristopher Bostic 	/* No documentation available on the registers below */
537cc8baffeSChristopher Bostic 	case 0x0e:
538cc8baffeSChristopher Bostic 	case 0x0f:
539cc8baffeSChristopher Bostic 	case 0x62:
540ba6ec48eSJoel Stanley 		return true;
541ba6ec48eSJoel Stanley 	default:
542ba6ec48eSJoel Stanley 		return false;
543ba6ec48eSJoel Stanley 	}
544ba6ec48eSJoel Stanley }
545ba6ec48eSJoel Stanley 
dps310_is_volatile_reg(struct device * dev,unsigned int reg)546ba6ec48eSJoel Stanley static bool dps310_is_volatile_reg(struct device *dev, unsigned int reg)
547ba6ec48eSJoel Stanley {
548ba6ec48eSJoel Stanley 	switch (reg) {
549ba6ec48eSJoel Stanley 	case DPS310_PRS_B0:
550ba6ec48eSJoel Stanley 	case DPS310_PRS_B1:
551ba6ec48eSJoel Stanley 	case DPS310_PRS_B2:
552ba6ec48eSJoel Stanley 	case DPS310_TMP_B0:
553ba6ec48eSJoel Stanley 	case DPS310_TMP_B1:
554ba6ec48eSJoel Stanley 	case DPS310_TMP_B2:
555ba6ec48eSJoel Stanley 	case DPS310_MEAS_CFG:
556cc8baffeSChristopher Bostic 	case 0x32:	/* No documentation available on this register */
557ba6ec48eSJoel Stanley 		return true;
558ba6ec48eSJoel Stanley 	default:
559ba6ec48eSJoel Stanley 		return false;
560ba6ec48eSJoel Stanley 	}
561ba6ec48eSJoel Stanley }
562ba6ec48eSJoel Stanley 
dps310_write_raw(struct iio_dev * iio,struct iio_chan_spec const * chan,int val,int val2,long mask)563ba6ec48eSJoel Stanley static int dps310_write_raw(struct iio_dev *iio,
564ba6ec48eSJoel Stanley 			    struct iio_chan_spec const *chan, int val,
565ba6ec48eSJoel Stanley 			    int val2, long mask)
566ba6ec48eSJoel Stanley {
567ba6ec48eSJoel Stanley 	int rc;
568ba6ec48eSJoel Stanley 	struct dps310_data *data = iio_priv(iio);
569ba6ec48eSJoel Stanley 
570ba6ec48eSJoel Stanley 	if (mutex_lock_interruptible(&data->lock))
571ba6ec48eSJoel Stanley 		return -EINTR;
572ba6ec48eSJoel Stanley 
573ba6ec48eSJoel Stanley 	switch (mask) {
574ba6ec48eSJoel Stanley 	case IIO_CHAN_INFO_SAMP_FREQ:
575d711a3c7SEddie James 		switch (chan->type) {
576d711a3c7SEddie James 		case IIO_PRESSURE:
577d711a3c7SEddie James 			rc = dps310_set_pres_samp_freq(data, val);
578d711a3c7SEddie James 			break;
579d711a3c7SEddie James 
580d711a3c7SEddie James 		case IIO_TEMP:
581ba6ec48eSJoel Stanley 			rc = dps310_set_temp_samp_freq(data, val);
582ba6ec48eSJoel Stanley 			break;
583ba6ec48eSJoel Stanley 
584d711a3c7SEddie James 		default:
585d711a3c7SEddie James 			rc = -EINVAL;
586d711a3c7SEddie James 			break;
587d711a3c7SEddie James 		}
588d711a3c7SEddie James 		break;
589d711a3c7SEddie James 
590ba6ec48eSJoel Stanley 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
591d711a3c7SEddie James 		switch (chan->type) {
592d711a3c7SEddie James 		case IIO_PRESSURE:
593d711a3c7SEddie James 			rc = dps310_set_pres_precision(data, val);
594d711a3c7SEddie James 			break;
595d711a3c7SEddie James 
596d711a3c7SEddie James 		case IIO_TEMP:
597ba6ec48eSJoel Stanley 			rc = dps310_set_temp_precision(data, val);
598ba6ec48eSJoel Stanley 			break;
599ba6ec48eSJoel Stanley 
600ba6ec48eSJoel Stanley 		default:
601ba6ec48eSJoel Stanley 			rc = -EINVAL;
602ba6ec48eSJoel Stanley 			break;
603ba6ec48eSJoel Stanley 		}
604d711a3c7SEddie James 		break;
605d711a3c7SEddie James 
606d711a3c7SEddie James 	default:
607d711a3c7SEddie James 		rc = -EINVAL;
608d711a3c7SEddie James 		break;
609d711a3c7SEddie James 	}
610ba6ec48eSJoel Stanley 
611ba6ec48eSJoel Stanley 	mutex_unlock(&data->lock);
612ba6ec48eSJoel Stanley 	return rc;
613ba6ec48eSJoel Stanley }
614ba6ec48eSJoel Stanley 
dps310_calculate_pressure(struct dps310_data * data)615d711a3c7SEddie James static int dps310_calculate_pressure(struct dps310_data *data)
616d711a3c7SEddie James {
617d711a3c7SEddie James 	int i;
618d711a3c7SEddie James 	int rc;
619d711a3c7SEddie James 	int t_ready;
620d711a3c7SEddie James 	int kpi = dps310_get_pres_k(data);
621d711a3c7SEddie James 	int kti = dps310_get_temp_k(data);
622d711a3c7SEddie James 	s64 rem = 0ULL;
623d711a3c7SEddie James 	s64 pressure = 0ULL;
624d711a3c7SEddie James 	s64 p;
625d711a3c7SEddie James 	s64 t;
626d711a3c7SEddie James 	s64 denoms[7];
627d711a3c7SEddie James 	s64 nums[7];
628d711a3c7SEddie James 	s64 rems[7];
629d711a3c7SEddie James 	s64 kp;
630d711a3c7SEddie James 	s64 kt;
631d711a3c7SEddie James 
632d711a3c7SEddie James 	if (kpi < 0)
633d711a3c7SEddie James 		return kpi;
634d711a3c7SEddie James 
635d711a3c7SEddie James 	if (kti < 0)
636d711a3c7SEddie James 		return kti;
637d711a3c7SEddie James 
638d711a3c7SEddie James 	kp = (s64)kpi;
639d711a3c7SEddie James 	kt = (s64)kti;
640d711a3c7SEddie James 
641d711a3c7SEddie James 	/* Refresh temp if it's ready, otherwise just use the latest value */
642d711a3c7SEddie James 	if (mutex_trylock(&data->lock)) {
643d711a3c7SEddie James 		rc = regmap_read(data->regmap, DPS310_MEAS_CFG, &t_ready);
644d711a3c7SEddie James 		if (rc >= 0 && t_ready & DPS310_TMP_RDY)
645d711a3c7SEddie James 			dps310_read_temp_ready(data);
646d711a3c7SEddie James 
647d711a3c7SEddie James 		mutex_unlock(&data->lock);
648d711a3c7SEddie James 	}
649d711a3c7SEddie James 
650d711a3c7SEddie James 	p = (s64)data->pressure_raw;
651d711a3c7SEddie James 	t = (s64)data->temp_raw;
652d711a3c7SEddie James 
653d711a3c7SEddie James 	/* Section 4.9.1 of the DPS310 spec; algebra'd to avoid underflow */
654d711a3c7SEddie James 	nums[0] = (s64)data->c00;
655d711a3c7SEddie James 	denoms[0] = 1LL;
656d711a3c7SEddie James 	nums[1] = p * (s64)data->c10;
657d711a3c7SEddie James 	denoms[1] = kp;
658d711a3c7SEddie James 	nums[2] = p * p * (s64)data->c20;
659d711a3c7SEddie James 	denoms[2] = kp * kp;
660d711a3c7SEddie James 	nums[3] = p * p * p * (s64)data->c30;
661d711a3c7SEddie James 	denoms[3] = kp * kp * kp;
662d711a3c7SEddie James 	nums[4] = t * (s64)data->c01;
663d711a3c7SEddie James 	denoms[4] = kt;
664d711a3c7SEddie James 	nums[5] = t * p * (s64)data->c11;
665d711a3c7SEddie James 	denoms[5] = kp * kt;
666d711a3c7SEddie James 	nums[6] = t * p * p * (s64)data->c21;
667d711a3c7SEddie James 	denoms[6] = kp * kp * kt;
668d711a3c7SEddie James 
669d711a3c7SEddie James 	/* Kernel lacks a div64_s64_rem function; denoms are all positive */
670d711a3c7SEddie James 	for (i = 0; i < 7; ++i) {
671d711a3c7SEddie James 		u64 irem;
672d711a3c7SEddie James 
673d711a3c7SEddie James 		if (nums[i] < 0LL) {
674d711a3c7SEddie James 			pressure -= div64_u64_rem(-nums[i], denoms[i], &irem);
675d711a3c7SEddie James 			rems[i] = -irem;
676d711a3c7SEddie James 		} else {
677d711a3c7SEddie James 			pressure += div64_u64_rem(nums[i], denoms[i], &irem);
678d711a3c7SEddie James 			rems[i] = (s64)irem;
679d711a3c7SEddie James 		}
680d711a3c7SEddie James 	}
681d711a3c7SEddie James 
682d711a3c7SEddie James 	/* Increase precision and calculate the remainder sum */
683d711a3c7SEddie James 	for (i = 0; i < 7; ++i)
684d711a3c7SEddie James 		rem += div64_s64((s64)rems[i] * 1000000000LL, denoms[i]);
685d711a3c7SEddie James 
686d711a3c7SEddie James 	pressure += div_s64(rem, 1000000000LL);
687d711a3c7SEddie James 	if (pressure < 0LL)
688d711a3c7SEddie James 		return -ERANGE;
689d711a3c7SEddie James 
690d711a3c7SEddie James 	return (int)min_t(s64, pressure, INT_MAX);
691d711a3c7SEddie James }
692d711a3c7SEddie James 
dps310_read_pressure(struct dps310_data * data,int * val,int * val2,long mask)693d711a3c7SEddie James static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2,
694d711a3c7SEddie James 				long mask)
695d711a3c7SEddie James {
696d711a3c7SEddie James 	int rc;
697d711a3c7SEddie James 
698d711a3c7SEddie James 	switch (mask) {
699d711a3c7SEddie James 	case IIO_CHAN_INFO_SAMP_FREQ:
700d711a3c7SEddie James 		rc = dps310_get_pres_samp_freq(data);
701d711a3c7SEddie James 		if (rc < 0)
702d711a3c7SEddie James 			return rc;
703d711a3c7SEddie James 
704d711a3c7SEddie James 		*val = rc;
705d711a3c7SEddie James 		return IIO_VAL_INT;
706d711a3c7SEddie James 
707d711a3c7SEddie James 	case IIO_CHAN_INFO_PROCESSED:
708d711a3c7SEddie James 		rc = dps310_read_pres_raw(data);
709d711a3c7SEddie James 		if (rc)
710d711a3c7SEddie James 			return rc;
711d711a3c7SEddie James 
712d711a3c7SEddie James 		rc = dps310_calculate_pressure(data);
713d711a3c7SEddie James 		if (rc < 0)
714d711a3c7SEddie James 			return rc;
715d711a3c7SEddie James 
716d711a3c7SEddie James 		*val = rc;
717d711a3c7SEddie James 		*val2 = 1000; /* Convert Pa to KPa per IIO ABI */
718d711a3c7SEddie James 		return IIO_VAL_FRACTIONAL;
719d711a3c7SEddie James 
720d711a3c7SEddie James 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
721d711a3c7SEddie James 		rc = dps310_get_pres_precision(data);
722d711a3c7SEddie James 		if (rc < 0)
723d711a3c7SEddie James 			return rc;
724d711a3c7SEddie James 
725d711a3c7SEddie James 		*val = rc;
726d711a3c7SEddie James 		return IIO_VAL_INT;
727d711a3c7SEddie James 
728d711a3c7SEddie James 	default:
729d711a3c7SEddie James 		return -EINVAL;
730d711a3c7SEddie James 	}
731d711a3c7SEddie James }
732d711a3c7SEddie James 
dps310_calculate_temp(struct dps310_data * data,int * val)73308f5bd20SThomas Haemmerle static int dps310_calculate_temp(struct dps310_data *data, int *val)
734ba6ec48eSJoel Stanley {
735ba6ec48eSJoel Stanley 	s64 c0;
736ba6ec48eSJoel Stanley 	s64 t;
737ba6ec48eSJoel Stanley 	int kt = dps310_get_temp_k(data);
738ba6ec48eSJoel Stanley 
739ba6ec48eSJoel Stanley 	if (kt < 0)
740ba6ec48eSJoel Stanley 		return kt;
741ba6ec48eSJoel Stanley 
742ba6ec48eSJoel Stanley 	/* Obtain inverse-scaled offset */
743ba6ec48eSJoel Stanley 	c0 = div_s64((s64)kt * (s64)data->c0, 2);
744ba6ec48eSJoel Stanley 
745ba6ec48eSJoel Stanley 	/* Add the offset to the unscaled temperature */
746ba6ec48eSJoel Stanley 	t = c0 + ((s64)data->temp_raw * (s64)data->c1);
747ba6ec48eSJoel Stanley 
748ba6ec48eSJoel Stanley 	/* Convert to milliCelsius and scale the temperature */
74908f5bd20SThomas Haemmerle 	*val = (int)div_s64(t * 1000LL, kt);
75008f5bd20SThomas Haemmerle 
75108f5bd20SThomas Haemmerle 	return 0;
752ba6ec48eSJoel Stanley }
753ba6ec48eSJoel Stanley 
dps310_read_temp(struct dps310_data * data,int * val,int * val2,long mask)754d711a3c7SEddie James static int dps310_read_temp(struct dps310_data *data, int *val, int *val2,
755d711a3c7SEddie James 			    long mask)
756ba6ec48eSJoel Stanley {
757ba6ec48eSJoel Stanley 	int rc;
758ba6ec48eSJoel Stanley 
759ba6ec48eSJoel Stanley 	switch (mask) {
760ba6ec48eSJoel Stanley 	case IIO_CHAN_INFO_SAMP_FREQ:
761ba6ec48eSJoel Stanley 		rc = dps310_get_temp_samp_freq(data);
762ba6ec48eSJoel Stanley 		if (rc < 0)
763ba6ec48eSJoel Stanley 			return rc;
764ba6ec48eSJoel Stanley 
765ba6ec48eSJoel Stanley 		*val = rc;
766ba6ec48eSJoel Stanley 		return IIO_VAL_INT;
767ba6ec48eSJoel Stanley 
768ba6ec48eSJoel Stanley 	case IIO_CHAN_INFO_PROCESSED:
769d711a3c7SEddie James 		rc = dps310_read_temp_raw(data);
770ba6ec48eSJoel Stanley 		if (rc)
771ba6ec48eSJoel Stanley 			return rc;
772ba6ec48eSJoel Stanley 
77308f5bd20SThomas Haemmerle 		rc = dps310_calculate_temp(data, val);
77408f5bd20SThomas Haemmerle 		if (rc)
775ba6ec48eSJoel Stanley 			return rc;
776ba6ec48eSJoel Stanley 
777ba6ec48eSJoel Stanley 		return IIO_VAL_INT;
778ba6ec48eSJoel Stanley 
779ba6ec48eSJoel Stanley 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
780ba6ec48eSJoel Stanley 		rc = dps310_get_temp_precision(data);
781ba6ec48eSJoel Stanley 		if (rc < 0)
782ba6ec48eSJoel Stanley 			return rc;
783ba6ec48eSJoel Stanley 
784ba6ec48eSJoel Stanley 		*val = rc;
785ba6ec48eSJoel Stanley 		return IIO_VAL_INT;
786ba6ec48eSJoel Stanley 
787ba6ec48eSJoel Stanley 	default:
788ba6ec48eSJoel Stanley 		return -EINVAL;
789ba6ec48eSJoel Stanley 	}
790ba6ec48eSJoel Stanley }
791ba6ec48eSJoel Stanley 
dps310_read_raw(struct iio_dev * iio,struct iio_chan_spec const * chan,int * val,int * val2,long mask)792d711a3c7SEddie James static int dps310_read_raw(struct iio_dev *iio,
793d711a3c7SEddie James 			   struct iio_chan_spec const *chan,
794d711a3c7SEddie James 			   int *val, int *val2, long mask)
795d711a3c7SEddie James {
796d711a3c7SEddie James 	struct dps310_data *data = iio_priv(iio);
797d711a3c7SEddie James 
798d711a3c7SEddie James 	switch (chan->type) {
799d711a3c7SEddie James 	case IIO_PRESSURE:
800d711a3c7SEddie James 		return dps310_read_pressure(data, val, val2, mask);
801d711a3c7SEddie James 
802d711a3c7SEddie James 	case IIO_TEMP:
803d711a3c7SEddie James 		return dps310_read_temp(data, val, val2, mask);
804d711a3c7SEddie James 
805d711a3c7SEddie James 	default:
806d711a3c7SEddie James 		return -EINVAL;
807d711a3c7SEddie James 	}
808d711a3c7SEddie James }
809d711a3c7SEddie James 
dps310_reset(void * action_data)810ba6ec48eSJoel Stanley static void dps310_reset(void *action_data)
811ba6ec48eSJoel Stanley {
812ba6ec48eSJoel Stanley 	struct dps310_data *data = action_data;
813ba6ec48eSJoel Stanley 
8147b4ab4abSEddie James 	dps310_reset_wait(data);
815ba6ec48eSJoel Stanley }
816ba6ec48eSJoel Stanley 
817ba6ec48eSJoel Stanley static const struct regmap_config dps310_regmap_config = {
818ba6ec48eSJoel Stanley 	.reg_bits = 8,
819ba6ec48eSJoel Stanley 	.val_bits = 8,
820ba6ec48eSJoel Stanley 	.writeable_reg = dps310_is_writeable_reg,
821ba6ec48eSJoel Stanley 	.volatile_reg = dps310_is_volatile_reg,
822ba6ec48eSJoel Stanley 	.cache_type = REGCACHE_RBTREE,
823cc8baffeSChristopher Bostic 	.max_register = 0x62, /* No documentation available on this register */
824ba6ec48eSJoel Stanley };
825ba6ec48eSJoel Stanley 
826ba6ec48eSJoel Stanley static const struct iio_info dps310_info = {
827ba6ec48eSJoel Stanley 	.read_raw = dps310_read_raw,
828ba6ec48eSJoel Stanley 	.write_raw = dps310_write_raw,
829ba6ec48eSJoel Stanley };
830ba6ec48eSJoel Stanley 
dps310_probe(struct i2c_client * client)83192a54a29SUwe Kleine-König static int dps310_probe(struct i2c_client *client)
832ba6ec48eSJoel Stanley {
83392a54a29SUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
834ba6ec48eSJoel Stanley 	struct dps310_data *data;
835ba6ec48eSJoel Stanley 	struct iio_dev *iio;
836c2329717SEddie James 	int rc;
837ba6ec48eSJoel Stanley 
838ba6ec48eSJoel Stanley 	iio = devm_iio_device_alloc(&client->dev,  sizeof(*data));
839ba6ec48eSJoel Stanley 	if (!iio)
840ba6ec48eSJoel Stanley 		return -ENOMEM;
841ba6ec48eSJoel Stanley 
842ba6ec48eSJoel Stanley 	data = iio_priv(iio);
843ba6ec48eSJoel Stanley 	data->client = client;
844ba6ec48eSJoel Stanley 	mutex_init(&data->lock);
845ba6ec48eSJoel Stanley 
846ba6ec48eSJoel Stanley 	iio->name = id->name;
847ba6ec48eSJoel Stanley 	iio->channels = dps310_channels;
848ba6ec48eSJoel Stanley 	iio->num_channels = ARRAY_SIZE(dps310_channels);
849ba6ec48eSJoel Stanley 	iio->info = &dps310_info;
850ba6ec48eSJoel Stanley 	iio->modes = INDIO_DIRECT_MODE;
851ba6ec48eSJoel Stanley 
852ba6ec48eSJoel Stanley 	data->regmap = devm_regmap_init_i2c(client, &dps310_regmap_config);
853ba6ec48eSJoel Stanley 	if (IS_ERR(data->regmap))
854ba6ec48eSJoel Stanley 		return PTR_ERR(data->regmap);
855ba6ec48eSJoel Stanley 
856ba6ec48eSJoel Stanley 	/* Register to run the device reset when the device is removed */
857ba6ec48eSJoel Stanley 	rc = devm_add_action_or_reset(&client->dev, dps310_reset, data);
858ba6ec48eSJoel Stanley 	if (rc)
859ba6ec48eSJoel Stanley 		return rc;
860ba6ec48eSJoel Stanley 
861c2329717SEddie James 	rc = dps310_startup(data);
862c2329717SEddie James 	if (rc)
863cc8baffeSChristopher Bostic 		return rc;
864cc8baffeSChristopher Bostic 
865ba6ec48eSJoel Stanley 	rc = devm_iio_device_register(&client->dev, iio);
866ba6ec48eSJoel Stanley 	if (rc)
867ba6ec48eSJoel Stanley 		return rc;
868ba6ec48eSJoel Stanley 
869ba6ec48eSJoel Stanley 	i2c_set_clientdata(client, iio);
870ba6ec48eSJoel Stanley 
871ba6ec48eSJoel Stanley 	return 0;
872ba6ec48eSJoel Stanley }
873ba6ec48eSJoel Stanley 
874ba6ec48eSJoel Stanley static const struct i2c_device_id dps310_id[] = {
875ba6ec48eSJoel Stanley 	{ DPS310_DEV_NAME, 0 },
876ba6ec48eSJoel Stanley 	{}
877ba6ec48eSJoel Stanley };
878ba6ec48eSJoel Stanley MODULE_DEVICE_TABLE(i2c, dps310_id);
879ba6ec48eSJoel Stanley 
88072ff2828SKai-Heng Feng static const struct acpi_device_id dps310_acpi_match[] = {
88172ff2828SKai-Heng Feng 	{ "IFX3100" },
88272ff2828SKai-Heng Feng 	{}
88372ff2828SKai-Heng Feng };
88472ff2828SKai-Heng Feng MODULE_DEVICE_TABLE(acpi, dps310_acpi_match);
88572ff2828SKai-Heng Feng 
886ba6ec48eSJoel Stanley static struct i2c_driver dps310_driver = {
887ba6ec48eSJoel Stanley 	.driver = {
888ba6ec48eSJoel Stanley 		.name = DPS310_DEV_NAME,
88972ff2828SKai-Heng Feng 		.acpi_match_table = dps310_acpi_match,
890ba6ec48eSJoel Stanley 	},
8917cf15f42SUwe Kleine-König 	.probe = dps310_probe,
892ba6ec48eSJoel Stanley 	.id_table = dps310_id,
893ba6ec48eSJoel Stanley };
894ba6ec48eSJoel Stanley module_i2c_driver(dps310_driver);
895ba6ec48eSJoel Stanley 
896ba6ec48eSJoel Stanley MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>");
897ba6ec48eSJoel Stanley MODULE_DESCRIPTION("Infineon DPS310 pressure and temperature sensor");
898ba6ec48eSJoel Stanley MODULE_LICENSE("GPL v2");
899