1c87742abSCrt Mori // SPDX-License-Identifier: GPL-2.0
2c87742abSCrt Mori /*
3c87742abSCrt Mori  * mlx90632.c - Melexis MLX90632 contactless IR temperature sensor
4c87742abSCrt Mori  *
5c87742abSCrt Mori  * Copyright (c) 2017 Melexis <cmo@melexis.com>
6c87742abSCrt Mori  *
7c87742abSCrt Mori  * Driver for the Melexis MLX90632 I2C 16-bit IR thermopile sensor
8c87742abSCrt Mori  */
9c87742abSCrt Mori #include <linux/delay.h>
10c87742abSCrt Mori #include <linux/err.h>
11c87742abSCrt Mori #include <linux/gpio/consumer.h>
12c87742abSCrt Mori #include <linux/i2c.h>
13c87742abSCrt Mori #include <linux/kernel.h>
14c87742abSCrt Mori #include <linux/module.h>
15c87742abSCrt Mori #include <linux/math64.h>
16c87742abSCrt Mori #include <linux/of.h>
17c87742abSCrt Mori #include <linux/pm_runtime.h>
18c87742abSCrt Mori #include <linux/regmap.h>
19c87742abSCrt Mori 
20c87742abSCrt Mori #include <linux/iio/iio.h>
21c87742abSCrt Mori #include <linux/iio/sysfs.h>
22c87742abSCrt Mori 
23c87742abSCrt Mori /* Memory sections addresses */
24c87742abSCrt Mori #define MLX90632_ADDR_RAM	0x4000 /* Start address of ram */
25c87742abSCrt Mori #define MLX90632_ADDR_EEPROM	0x2480 /* Start address of user eeprom */
26c87742abSCrt Mori 
27c87742abSCrt Mori /* EEPROM addresses - used at startup */
28c87742abSCrt Mori #define MLX90632_EE_CTRL	0x24d4 /* Control register initial value */
29c87742abSCrt Mori #define MLX90632_EE_I2C_ADDR	0x24d5 /* I2C address register initial value */
30c87742abSCrt Mori #define MLX90632_EE_VERSION	0x240b /* EEPROM version reg address */
31c87742abSCrt Mori #define MLX90632_EE_P_R		0x240c /* P_R calibration register 32bit */
32c87742abSCrt Mori #define MLX90632_EE_P_G		0x240e /* P_G calibration register 32bit */
33c87742abSCrt Mori #define MLX90632_EE_P_T		0x2410 /* P_T calibration register 32bit */
34c87742abSCrt Mori #define MLX90632_EE_P_O		0x2412 /* P_O calibration register 32bit */
35c87742abSCrt Mori #define MLX90632_EE_Aa		0x2414 /* Aa calibration register 32bit */
36c87742abSCrt Mori #define MLX90632_EE_Ab		0x2416 /* Ab calibration register 32bit */
37c87742abSCrt Mori #define MLX90632_EE_Ba		0x2418 /* Ba calibration register 32bit */
38c87742abSCrt Mori #define MLX90632_EE_Bb		0x241a /* Bb calibration register 32bit */
39c87742abSCrt Mori #define MLX90632_EE_Ca		0x241c /* Ca calibration register 32bit */
40c87742abSCrt Mori #define MLX90632_EE_Cb		0x241e /* Cb calibration register 32bit */
41c87742abSCrt Mori #define MLX90632_EE_Da		0x2420 /* Da calibration register 32bit */
42c87742abSCrt Mori #define MLX90632_EE_Db		0x2422 /* Db calibration register 32bit */
43c87742abSCrt Mori #define MLX90632_EE_Ea		0x2424 /* Ea calibration register 32bit */
44c87742abSCrt Mori #define MLX90632_EE_Eb		0x2426 /* Eb calibration register 32bit */
45c87742abSCrt Mori #define MLX90632_EE_Fa		0x2428 /* Fa calibration register 32bit */
46c87742abSCrt Mori #define MLX90632_EE_Fb		0x242a /* Fb calibration register 32bit */
47c87742abSCrt Mori #define MLX90632_EE_Ga		0x242c /* Ga calibration register 32bit */
48c87742abSCrt Mori 
49c87742abSCrt Mori #define MLX90632_EE_Gb		0x242e /* Gb calibration register 16bit */
50c87742abSCrt Mori #define MLX90632_EE_Ka		0x242f /* Ka calibration register 16bit */
51c87742abSCrt Mori 
52c87742abSCrt Mori #define MLX90632_EE_Ha		0x2481 /* Ha customer calib value reg 16bit */
53c87742abSCrt Mori #define MLX90632_EE_Hb		0x2482 /* Hb customer calib value reg 16bit */
54c87742abSCrt Mori 
55c87742abSCrt Mori /* Register addresses - volatile */
56c87742abSCrt Mori #define MLX90632_REG_I2C_ADDR	0x3000 /* Chip I2C address register */
57c87742abSCrt Mori 
58c87742abSCrt Mori /* Control register address - volatile */
59c87742abSCrt Mori #define MLX90632_REG_CONTROL	0x3001 /* Control Register address */
60c87742abSCrt Mori #define   MLX90632_CFG_PWR_MASK		GENMASK(2, 1) /* PowerMode Mask */
61c87742abSCrt Mori /* PowerModes statuses */
62c87742abSCrt Mori #define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1)
63c87742abSCrt Mori #define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */
64c87742abSCrt Mori #define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /* sleep step*/
65c87742abSCrt Mori #define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */
66c87742abSCrt Mori #define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous*/
67c87742abSCrt Mori 
68c87742abSCrt Mori /* Device status register - volatile */
69c87742abSCrt Mori #define MLX90632_REG_STATUS	0x3fff /* Device status register */
70c87742abSCrt Mori #define   MLX90632_STAT_BUSY		BIT(10) /* Device busy indicator */
71c87742abSCrt Mori #define   MLX90632_STAT_EE_BUSY		BIT(9) /* EEPROM busy indicator */
72c87742abSCrt Mori #define   MLX90632_STAT_BRST		BIT(8) /* Brown out reset indicator */
73c87742abSCrt Mori #define   MLX90632_STAT_CYCLE_POS	GENMASK(6, 2) /* Data position */
74c87742abSCrt Mori #define   MLX90632_STAT_DATA_RDY	BIT(0) /* Data ready indicator */
75c87742abSCrt Mori 
76c87742abSCrt Mori /* RAM_MEAS address-es for each channel */
77c87742abSCrt Mori #define MLX90632_RAM_1(meas_num)	(MLX90632_ADDR_RAM + 3 * meas_num)
78c87742abSCrt Mori #define MLX90632_RAM_2(meas_num)	(MLX90632_ADDR_RAM + 3 * meas_num + 1)
79c87742abSCrt Mori #define MLX90632_RAM_3(meas_num)	(MLX90632_ADDR_RAM + 3 * meas_num + 2)
80c87742abSCrt Mori 
81c87742abSCrt Mori /* Magic constants */
82c87742abSCrt Mori #define MLX90632_ID_MEDICAL	0x0105 /* EEPROM DSPv5 Medical device id */
83c87742abSCrt Mori #define MLX90632_ID_CONSUMER	0x0205 /* EEPROM DSPv5 Consumer device id */
84389fc70bSCrt Mori #define MLX90632_DSP_VERSION	5 /* DSP version */
85389fc70bSCrt Mori #define MLX90632_DSP_MASK	GENMASK(7, 0) /* DSP version in EE_VERSION */
86c87742abSCrt Mori #define MLX90632_RESET_CMD	0x0006 /* Reset sensor (address or global) */
87c87742abSCrt Mori #define MLX90632_REF_12		12LL /**< ResCtrlRef value of Ch 1 or Ch 2 */
88c87742abSCrt Mori #define MLX90632_REF_3		12LL /**< ResCtrlRef value of Channel 3 */
89c87742abSCrt Mori #define MLX90632_MAX_MEAS_NUM	31 /**< Maximum measurements in list */
90c87742abSCrt Mori #define MLX90632_SLEEP_DELAY_MS 3000 /**< Autosleep delay */
91c87742abSCrt Mori 
92856437dbSCrt Mori /**
93856437dbSCrt Mori  * struct mlx90632_data - private data for the MLX90632 device
94856437dbSCrt Mori  * @client: I2C client of the device
95856437dbSCrt Mori  * @lock: Internal mutex for multiple reads for single measurement
96856437dbSCrt Mori  * @regmap: Regmap of the device
97856437dbSCrt Mori  * @emissivity: Object emissivity from 0 to 1000 where 1000 = 1.
98856437dbSCrt Mori  */
99c87742abSCrt Mori struct mlx90632_data {
100c87742abSCrt Mori 	struct i2c_client *client;
101856437dbSCrt Mori 	struct mutex lock;
102c87742abSCrt Mori 	struct regmap *regmap;
103c87742abSCrt Mori 	u16 emissivity;
104c87742abSCrt Mori };
105c87742abSCrt Mori 
106c87742abSCrt Mori static const struct regmap_range mlx90632_volatile_reg_range[] = {
107c87742abSCrt Mori 	regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
108c87742abSCrt Mori 	regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
109c87742abSCrt Mori 	regmap_reg_range(MLX90632_RAM_1(0),
110c87742abSCrt Mori 			 MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
111c87742abSCrt Mori };
112c87742abSCrt Mori 
113c87742abSCrt Mori static const struct regmap_access_table mlx90632_volatile_regs_tbl = {
114c87742abSCrt Mori 	.yes_ranges = mlx90632_volatile_reg_range,
115c87742abSCrt Mori 	.n_yes_ranges = ARRAY_SIZE(mlx90632_volatile_reg_range),
116c87742abSCrt Mori };
117c87742abSCrt Mori 
118c87742abSCrt Mori static const struct regmap_range mlx90632_read_reg_range[] = {
119c87742abSCrt Mori 	regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka),
120c87742abSCrt Mori 	regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR),
121c87742abSCrt Mori 	regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb),
122c87742abSCrt Mori 	regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
123c87742abSCrt Mori 	regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
124c87742abSCrt Mori 	regmap_reg_range(MLX90632_RAM_1(0),
125c87742abSCrt Mori 			 MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
126c87742abSCrt Mori };
127c87742abSCrt Mori 
128c87742abSCrt Mori static const struct regmap_access_table mlx90632_readable_regs_tbl = {
129c87742abSCrt Mori 	.yes_ranges = mlx90632_read_reg_range,
130c87742abSCrt Mori 	.n_yes_ranges = ARRAY_SIZE(mlx90632_read_reg_range),
131c87742abSCrt Mori };
132c87742abSCrt Mori 
133c87742abSCrt Mori static const struct regmap_range mlx90632_no_write_reg_range[] = {
134c87742abSCrt Mori 	regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka),
135c87742abSCrt Mori 	regmap_reg_range(MLX90632_RAM_1(0),
136c87742abSCrt Mori 			 MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
137c87742abSCrt Mori };
138c87742abSCrt Mori 
139c87742abSCrt Mori static const struct regmap_access_table mlx90632_writeable_regs_tbl = {
140c87742abSCrt Mori 	.no_ranges = mlx90632_no_write_reg_range,
141c87742abSCrt Mori 	.n_no_ranges = ARRAY_SIZE(mlx90632_no_write_reg_range),
142c87742abSCrt Mori };
143c87742abSCrt Mori 
144c87742abSCrt Mori static const struct regmap_config mlx90632_regmap = {
145c87742abSCrt Mori 	.reg_bits = 16,
146c87742abSCrt Mori 	.val_bits = 16,
147c87742abSCrt Mori 
148c87742abSCrt Mori 	.volatile_table = &mlx90632_volatile_regs_tbl,
149c87742abSCrt Mori 	.rd_table = &mlx90632_readable_regs_tbl,
150c87742abSCrt Mori 	.wr_table = &mlx90632_writeable_regs_tbl,
151c87742abSCrt Mori 
1521c96a2f6SDavid Frey 	.use_single_read = true,
1531c96a2f6SDavid Frey 	.use_single_write = true,
154c87742abSCrt Mori 	.reg_format_endian = REGMAP_ENDIAN_BIG,
155c87742abSCrt Mori 	.val_format_endian = REGMAP_ENDIAN_BIG,
156c87742abSCrt Mori 	.cache_type = REGCACHE_RBTREE,
157c87742abSCrt Mori };
158c87742abSCrt Mori 
159c87742abSCrt Mori static s32 mlx90632_pwr_set_sleep_step(struct regmap *regmap)
160c87742abSCrt Mori {
161c87742abSCrt Mori 	return regmap_update_bits(regmap, MLX90632_REG_CONTROL,
162c87742abSCrt Mori 				  MLX90632_CFG_PWR_MASK,
163c87742abSCrt Mori 				  MLX90632_PWR_STATUS_SLEEP_STEP);
164c87742abSCrt Mori }
165c87742abSCrt Mori 
166c87742abSCrt Mori static s32 mlx90632_pwr_continuous(struct regmap *regmap)
167c87742abSCrt Mori {
168c87742abSCrt Mori 	return regmap_update_bits(regmap, MLX90632_REG_CONTROL,
169c87742abSCrt Mori 				  MLX90632_CFG_PWR_MASK,
170c87742abSCrt Mori 				  MLX90632_PWR_STATUS_CONTINUOUS);
171c87742abSCrt Mori }
172c87742abSCrt Mori 
173c87742abSCrt Mori /**
1747390192bSLee Jones  * mlx90632_perform_measurement() - Trigger and retrieve current measurement cycle
1757390192bSLee Jones  * @data: pointer to mlx90632_data object containing regmap information
176c87742abSCrt Mori  *
177c87742abSCrt Mori  * Perform a measurement and return latest measurement cycle position reported
178c87742abSCrt Mori  * by sensor. This is a blocking function for 500ms, as that is default sensor
179c87742abSCrt Mori  * refresh rate.
180c87742abSCrt Mori  */
181c87742abSCrt Mori static int mlx90632_perform_measurement(struct mlx90632_data *data)
182c87742abSCrt Mori {
183c87742abSCrt Mori 	unsigned int reg_status;
184037697ddSCrt Mori 	int ret;
185c87742abSCrt Mori 
186c87742abSCrt Mori 	ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS,
187c87742abSCrt Mori 				 MLX90632_STAT_DATA_RDY, 0);
188c87742abSCrt Mori 	if (ret < 0)
189c87742abSCrt Mori 		return ret;
190c87742abSCrt Mori 
191037697ddSCrt Mori 	ret = regmap_read_poll_timeout(data->regmap, MLX90632_REG_STATUS, reg_status,
192037697ddSCrt Mori 				       !(reg_status & MLX90632_STAT_DATA_RDY), 10000,
193037697ddSCrt Mori 				       100 * 10000);
194c87742abSCrt Mori 
195037697ddSCrt Mori 	if (ret < 0) {
196c87742abSCrt Mori 		dev_err(&data->client->dev, "data not ready");
197c87742abSCrt Mori 		return -ETIMEDOUT;
198c87742abSCrt Mori 	}
199c87742abSCrt Mori 
200c87742abSCrt Mori 	return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2;
201c87742abSCrt Mori }
202c87742abSCrt Mori 
203c87742abSCrt Mori static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
204c87742abSCrt Mori 				       uint8_t *channel_old)
205c87742abSCrt Mori {
206c87742abSCrt Mori 	switch (perform_ret) {
207c87742abSCrt Mori 	case 1:
208c87742abSCrt Mori 		*channel_new = 1;
209c87742abSCrt Mori 		*channel_old = 2;
210c87742abSCrt Mori 		break;
211c87742abSCrt Mori 	case 2:
212c87742abSCrt Mori 		*channel_new = 2;
213c87742abSCrt Mori 		*channel_old = 1;
214c87742abSCrt Mori 		break;
215c87742abSCrt Mori 	default:
216c87742abSCrt Mori 		return -EINVAL;
217c87742abSCrt Mori 	}
218c87742abSCrt Mori 
219c87742abSCrt Mori 	return 0;
220c87742abSCrt Mori }
221c87742abSCrt Mori 
222c87742abSCrt Mori static int mlx90632_read_ambient_raw(struct regmap *regmap,
223c87742abSCrt Mori 				     s16 *ambient_new_raw, s16 *ambient_old_raw)
224c87742abSCrt Mori {
225c87742abSCrt Mori 	int ret;
226c87742abSCrt Mori 	unsigned int read_tmp;
227c87742abSCrt Mori 
228c87742abSCrt Mori 	ret = regmap_read(regmap, MLX90632_RAM_3(1), &read_tmp);
229c87742abSCrt Mori 	if (ret < 0)
230c87742abSCrt Mori 		return ret;
231c87742abSCrt Mori 	*ambient_new_raw = (s16)read_tmp;
232c87742abSCrt Mori 
233c87742abSCrt Mori 	ret = regmap_read(regmap, MLX90632_RAM_3(2), &read_tmp);
234c87742abSCrt Mori 	if (ret < 0)
235c87742abSCrt Mori 		return ret;
236c87742abSCrt Mori 	*ambient_old_raw = (s16)read_tmp;
237c87742abSCrt Mori 
238c87742abSCrt Mori 	return ret;
239c87742abSCrt Mori }
240c87742abSCrt Mori 
241c87742abSCrt Mori static int mlx90632_read_object_raw(struct regmap *regmap,
242c87742abSCrt Mori 				    int perform_measurement_ret,
243c87742abSCrt Mori 				    s16 *object_new_raw, s16 *object_old_raw)
244c87742abSCrt Mori {
245c87742abSCrt Mori 	int ret;
246c87742abSCrt Mori 	unsigned int read_tmp;
247c87742abSCrt Mori 	s16 read;
248c87742abSCrt Mori 	u8 channel = 0;
249c87742abSCrt Mori 	u8 channel_old = 0;
250c87742abSCrt Mori 
251c87742abSCrt Mori 	ret = mlx90632_channel_new_select(perform_measurement_ret, &channel,
252c87742abSCrt Mori 					  &channel_old);
253c87742abSCrt Mori 	if (ret != 0)
254c87742abSCrt Mori 		return ret;
255c87742abSCrt Mori 
256c87742abSCrt Mori 	ret = regmap_read(regmap, MLX90632_RAM_2(channel), &read_tmp);
257c87742abSCrt Mori 	if (ret < 0)
258c87742abSCrt Mori 		return ret;
259c87742abSCrt Mori 
260c87742abSCrt Mori 	read = (s16)read_tmp;
261c87742abSCrt Mori 
262c87742abSCrt Mori 	ret = regmap_read(regmap, MLX90632_RAM_1(channel), &read_tmp);
263c87742abSCrt Mori 	if (ret < 0)
264c87742abSCrt Mori 		return ret;
265c87742abSCrt Mori 	*object_new_raw = (read + (s16)read_tmp) / 2;
266c87742abSCrt Mori 
267c87742abSCrt Mori 	ret = regmap_read(regmap, MLX90632_RAM_2(channel_old), &read_tmp);
268c87742abSCrt Mori 	if (ret < 0)
269c87742abSCrt Mori 		return ret;
270c87742abSCrt Mori 	read = (s16)read_tmp;
271c87742abSCrt Mori 
272c87742abSCrt Mori 	ret = regmap_read(regmap, MLX90632_RAM_1(channel_old), &read_tmp);
273c87742abSCrt Mori 	if (ret < 0)
274c87742abSCrt Mori 		return ret;
275c87742abSCrt Mori 	*object_old_raw = (read + (s16)read_tmp) / 2;
276c87742abSCrt Mori 
277c87742abSCrt Mori 	return ret;
278c87742abSCrt Mori }
279c87742abSCrt Mori 
280c87742abSCrt Mori static int mlx90632_read_all_channel(struct mlx90632_data *data,
281c87742abSCrt Mori 				     s16 *ambient_new_raw, s16 *ambient_old_raw,
282c87742abSCrt Mori 				     s16 *object_new_raw, s16 *object_old_raw)
283c87742abSCrt Mori {
284c87742abSCrt Mori 	s32 ret, measurement;
285c87742abSCrt Mori 
286c87742abSCrt Mori 	mutex_lock(&data->lock);
287c87742abSCrt Mori 	measurement = mlx90632_perform_measurement(data);
288c87742abSCrt Mori 	if (measurement < 0) {
289c87742abSCrt Mori 		ret = measurement;
290c87742abSCrt Mori 		goto read_unlock;
291c87742abSCrt Mori 	}
292c87742abSCrt Mori 	ret = mlx90632_read_ambient_raw(data->regmap, ambient_new_raw,
293c87742abSCrt Mori 					ambient_old_raw);
294c87742abSCrt Mori 	if (ret < 0)
295c87742abSCrt Mori 		goto read_unlock;
296c87742abSCrt Mori 
297c87742abSCrt Mori 	ret = mlx90632_read_object_raw(data->regmap, measurement,
298c87742abSCrt Mori 				       object_new_raw, object_old_raw);
299c87742abSCrt Mori read_unlock:
300c87742abSCrt Mori 	mutex_unlock(&data->lock);
301c87742abSCrt Mori 	return ret;
302c87742abSCrt Mori }
303c87742abSCrt Mori 
304c87742abSCrt Mori static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb,
305c87742abSCrt Mori 				     s32 *reg_value)
306c87742abSCrt Mori {
307c87742abSCrt Mori 	s32 ret;
308c87742abSCrt Mori 	unsigned int read;
309c87742abSCrt Mori 	u32 value;
310c87742abSCrt Mori 
311c87742abSCrt Mori 	ret = regmap_read(regmap, reg_lsb, &read);
312c87742abSCrt Mori 	if (ret < 0)
313c87742abSCrt Mori 		return ret;
314c87742abSCrt Mori 
315c87742abSCrt Mori 	value = read;
316c87742abSCrt Mori 
317c87742abSCrt Mori 	ret = regmap_read(regmap, reg_lsb + 1, &read);
318c87742abSCrt Mori 	if (ret < 0)
319c87742abSCrt Mori 		return ret;
320c87742abSCrt Mori 
321c87742abSCrt Mori 	*reg_value = (read << 16) | (value & 0xffff);
322c87742abSCrt Mori 
323c87742abSCrt Mori 	return 0;
324c87742abSCrt Mori }
325c87742abSCrt Mori 
326c87742abSCrt Mori static s64 mlx90632_preprocess_temp_amb(s16 ambient_new_raw,
327c87742abSCrt Mori 					s16 ambient_old_raw, s16 Gb)
328c87742abSCrt Mori {
329c87742abSCrt Mori 	s64 VR_Ta, kGb, tmp;
330c87742abSCrt Mori 
331c87742abSCrt Mori 	kGb = ((s64)Gb * 1000LL) >> 10ULL;
332c87742abSCrt Mori 	VR_Ta = (s64)ambient_old_raw * 1000000LL +
333c87742abSCrt Mori 		kGb * div64_s64(((s64)ambient_new_raw * 1000LL),
334c87742abSCrt Mori 			(MLX90632_REF_3));
335c87742abSCrt Mori 	tmp = div64_s64(
336c87742abSCrt Mori 			 div64_s64(((s64)ambient_new_raw * 1000000000000LL),
337c87742abSCrt Mori 				   (MLX90632_REF_3)), VR_Ta);
338c87742abSCrt Mori 	return div64_s64(tmp << 19ULL, 1000LL);
339c87742abSCrt Mori }
340c87742abSCrt Mori 
341c87742abSCrt Mori static s64 mlx90632_preprocess_temp_obj(s16 object_new_raw, s16 object_old_raw,
342c87742abSCrt Mori 					s16 ambient_new_raw,
343c87742abSCrt Mori 					s16 ambient_old_raw, s16 Ka)
344c87742abSCrt Mori {
345c87742abSCrt Mori 	s64 VR_IR, kKa, tmp;
346c87742abSCrt Mori 
347c87742abSCrt Mori 	kKa = ((s64)Ka * 1000LL) >> 10ULL;
348c87742abSCrt Mori 	VR_IR = (s64)ambient_old_raw * 1000000LL +
349c87742abSCrt Mori 		kKa * div64_s64(((s64)ambient_new_raw * 1000LL),
350c87742abSCrt Mori 			(MLX90632_REF_3));
351c87742abSCrt Mori 	tmp = div64_s64(
352c87742abSCrt Mori 			div64_s64(((s64)((object_new_raw + object_old_raw) / 2)
353c87742abSCrt Mori 				   * 1000000000000LL), (MLX90632_REF_12)),
354c87742abSCrt Mori 			VR_IR);
355c87742abSCrt Mori 	return div64_s64((tmp << 19ULL), 1000LL);
356c87742abSCrt Mori }
357c87742abSCrt Mori 
358c87742abSCrt Mori static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw,
359c87742abSCrt Mori 				      s32 P_T, s32 P_R, s32 P_G, s32 P_O,
360c87742abSCrt Mori 				      s16 Gb)
361c87742abSCrt Mori {
362c87742abSCrt Mori 	s64 Asub, Bsub, Ablock, Bblock, Cblock, AMB, sum;
363c87742abSCrt Mori 
364c87742abSCrt Mori 	AMB = mlx90632_preprocess_temp_amb(ambient_new_raw, ambient_old_raw,
365c87742abSCrt Mori 					   Gb);
366c87742abSCrt Mori 	Asub = ((s64)P_T * 10000000000LL) >> 44ULL;
367c87742abSCrt Mori 	Bsub = AMB - (((s64)P_R * 1000LL) >> 8ULL);
368c87742abSCrt Mori 	Ablock = Asub * (Bsub * Bsub);
369c87742abSCrt Mori 	Bblock = (div64_s64(Bsub * 10000000LL, P_G)) << 20ULL;
370c87742abSCrt Mori 	Cblock = ((s64)P_O * 10000000000LL) >> 8ULL;
371c87742abSCrt Mori 
372c87742abSCrt Mori 	sum = div64_s64(Ablock, 1000000LL) + Bblock + Cblock;
373c87742abSCrt Mori 
374c87742abSCrt Mori 	return div64_s64(sum, 10000000LL);
375c87742abSCrt Mori }
376c87742abSCrt Mori 
377c87742abSCrt Mori static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object,
378b99095e5SCrt Mori 					       s64 TAdut, s64 TAdut4, s32 Fa, s32 Fb,
379c87742abSCrt Mori 					       s32 Ga, s16 Ha, s16 Hb,
380c87742abSCrt Mori 					       u16 emissivity)
381c87742abSCrt Mori {
382b99095e5SCrt Mori 	s64 calcedKsTO, calcedKsTA, ir_Alpha, Alpha_corr;
383c87742abSCrt Mori 	s64 Ha_customer, Hb_customer;
384c87742abSCrt Mori 
385c87742abSCrt Mori 	Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL;
386c87742abSCrt Mori 	Hb_customer = ((s64)Hb * 100) >> 10ULL;
387c87742abSCrt Mori 
388c87742abSCrt Mori 	calcedKsTO = ((s64)((s64)Ga * (prev_object_temp - 25 * 1000LL)
389c87742abSCrt Mori 			     * 1000LL)) >> 36LL;
390c87742abSCrt Mori 	calcedKsTA = ((s64)(Fb * (TAdut - 25 * 1000000LL))) >> 36LL;
391c87742abSCrt Mori 	Alpha_corr = div64_s64((((s64)(Fa * 10000000000LL) >> 46LL)
392c87742abSCrt Mori 				* Ha_customer), 1000LL);
393c87742abSCrt Mori 	Alpha_corr *= ((s64)(1 * 1000000LL + calcedKsTO + calcedKsTA));
394c87742abSCrt Mori 	Alpha_corr = emissivity * div64_s64(Alpha_corr, 100000LL);
395c87742abSCrt Mori 	Alpha_corr = div64_s64(Alpha_corr, 1000LL);
396c87742abSCrt Mori 	ir_Alpha = div64_s64((s64)object * 10000000LL, Alpha_corr);
397c87742abSCrt Mori 
398c87742abSCrt Mori 	return (int_sqrt64(int_sqrt64(ir_Alpha * 1000000000000LL + TAdut4))
399c87742abSCrt Mori 		- 27315 - Hb_customer) * 10;
400c87742abSCrt Mori }
401c87742abSCrt Mori 
402b99095e5SCrt Mori static s64 mlx90632_calc_ta4(s64 TAdut, s64 scale)
403b99095e5SCrt Mori {
404b99095e5SCrt Mori 	return (div64_s64(TAdut, scale) + 27315) *
405b99095e5SCrt Mori 		(div64_s64(TAdut, scale) + 27315) *
406b99095e5SCrt Mori 		(div64_s64(TAdut, scale) + 27315) *
407b99095e5SCrt Mori 		(div64_s64(TAdut, scale) + 27315);
408b99095e5SCrt Mori }
409b99095e5SCrt Mori 
410c87742abSCrt Mori static s32 mlx90632_calc_temp_object(s64 object, s64 ambient, s32 Ea, s32 Eb,
411c87742abSCrt Mori 				     s32 Fa, s32 Fb, s32 Ga, s16 Ha, s16 Hb,
412c87742abSCrt Mori 				     u16 tmp_emi)
413c87742abSCrt Mori {
414b99095e5SCrt Mori 	s64 kTA, kTA0, TAdut, TAdut4;
415c87742abSCrt Mori 	s64 temp = 25000;
416c87742abSCrt Mori 	s8 i;
417c87742abSCrt Mori 
418c87742abSCrt Mori 	kTA = (Ea * 1000LL) >> 16LL;
419c87742abSCrt Mori 	kTA0 = (Eb * 1000LL) >> 8LL;
420c87742abSCrt Mori 	TAdut = div64_s64(((ambient - kTA0) * 1000000LL), kTA) + 25 * 1000000LL;
421b99095e5SCrt Mori 	TAdut4 = mlx90632_calc_ta4(TAdut, 10000LL);
422c87742abSCrt Mori 
423c87742abSCrt Mori 	/* Iterations of calculation as described in datasheet */
424c87742abSCrt Mori 	for (i = 0; i < 5; ++i) {
425b99095e5SCrt Mori 		temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, TAdut4,
426c87742abSCrt Mori 							   Fa, Fb, Ga, Ha, Hb,
427c87742abSCrt Mori 							   tmp_emi);
428c87742abSCrt Mori 	}
429c87742abSCrt Mori 	return temp;
430c87742abSCrt Mori }
431c87742abSCrt Mori 
432c87742abSCrt Mori static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
433c87742abSCrt Mori {
434c87742abSCrt Mori 	s32 ret;
435c87742abSCrt Mori 	s32 Ea, Eb, Fa, Fb, Ga;
436c87742abSCrt Mori 	unsigned int read_tmp;
437c87742abSCrt Mori 	s16 Ha, Hb, Gb, Ka;
438c87742abSCrt Mori 	s16 ambient_new_raw, ambient_old_raw, object_new_raw, object_old_raw;
439c87742abSCrt Mori 	s64 object, ambient;
440c87742abSCrt Mori 
441c87742abSCrt Mori 	ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Ea, &Ea);
442c87742abSCrt Mori 	if (ret < 0)
443c87742abSCrt Mori 		return ret;
444c87742abSCrt Mori 	ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Eb, &Eb);
445c87742abSCrt Mori 	if (ret < 0)
446c87742abSCrt Mori 		return ret;
447c87742abSCrt Mori 	ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Fa, &Fa);
448c87742abSCrt Mori 	if (ret < 0)
449c87742abSCrt Mori 		return ret;
450c87742abSCrt Mori 	ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Fb, &Fb);
451c87742abSCrt Mori 	if (ret < 0)
452c87742abSCrt Mori 		return ret;
453c87742abSCrt Mori 	ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Ga, &Ga);
454c87742abSCrt Mori 	if (ret < 0)
455c87742abSCrt Mori 		return ret;
456c87742abSCrt Mori 	ret = regmap_read(data->regmap, MLX90632_EE_Ha, &read_tmp);
457c87742abSCrt Mori 	if (ret < 0)
458c87742abSCrt Mori 		return ret;
459c87742abSCrt Mori 	Ha = (s16)read_tmp;
460c87742abSCrt Mori 	ret = regmap_read(data->regmap, MLX90632_EE_Hb, &read_tmp);
461c87742abSCrt Mori 	if (ret < 0)
462c87742abSCrt Mori 		return ret;
463c87742abSCrt Mori 	Hb = (s16)read_tmp;
464c87742abSCrt Mori 	ret = regmap_read(data->regmap, MLX90632_EE_Gb, &read_tmp);
465c87742abSCrt Mori 	if (ret < 0)
466c87742abSCrt Mori 		return ret;
467c87742abSCrt Mori 	Gb = (s16)read_tmp;
468c87742abSCrt Mori 	ret = regmap_read(data->regmap, MLX90632_EE_Ka, &read_tmp);
469c87742abSCrt Mori 	if (ret < 0)
470c87742abSCrt Mori 		return ret;
471c87742abSCrt Mori 	Ka = (s16)read_tmp;
472c87742abSCrt Mori 
473c87742abSCrt Mori 	ret = mlx90632_read_all_channel(data,
474c87742abSCrt Mori 					&ambient_new_raw, &ambient_old_raw,
475c87742abSCrt Mori 					&object_new_raw, &object_old_raw);
476c87742abSCrt Mori 	if (ret < 0)
477c87742abSCrt Mori 		return ret;
478c87742abSCrt Mori 
479c87742abSCrt Mori 	ambient = mlx90632_preprocess_temp_amb(ambient_new_raw,
480c87742abSCrt Mori 					       ambient_old_raw, Gb);
481c87742abSCrt Mori 	object = mlx90632_preprocess_temp_obj(object_new_raw,
482c87742abSCrt Mori 					      object_old_raw,
483c87742abSCrt Mori 					      ambient_new_raw,
484c87742abSCrt Mori 					      ambient_old_raw, Ka);
485c87742abSCrt Mori 
486c87742abSCrt Mori 	*val = mlx90632_calc_temp_object(object, ambient, Ea, Eb, Fa, Fb, Ga,
487c87742abSCrt Mori 					 Ha, Hb, data->emissivity);
488c87742abSCrt Mori 	return 0;
489c87742abSCrt Mori }
490c87742abSCrt Mori 
491c87742abSCrt Mori static int mlx90632_calc_ambient_dsp105(struct mlx90632_data *data, int *val)
492c87742abSCrt Mori {
493c87742abSCrt Mori 	s32 ret;
494c87742abSCrt Mori 	unsigned int read_tmp;
495c87742abSCrt Mori 	s32 PT, PR, PG, PO;
496c87742abSCrt Mori 	s16 Gb;
497c87742abSCrt Mori 	s16 ambient_new_raw, ambient_old_raw;
498c87742abSCrt Mori 
499c87742abSCrt Mori 	ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_R, &PR);
500c87742abSCrt Mori 	if (ret < 0)
501c87742abSCrt Mori 		return ret;
502c87742abSCrt Mori 	ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_G, &PG);
503c87742abSCrt Mori 	if (ret < 0)
504c87742abSCrt Mori 		return ret;
505c87742abSCrt Mori 	ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_T, &PT);
506c87742abSCrt Mori 	if (ret < 0)
507c87742abSCrt Mori 		return ret;
508c87742abSCrt Mori 	ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_O, &PO);
509c87742abSCrt Mori 	if (ret < 0)
510c87742abSCrt Mori 		return ret;
511c87742abSCrt Mori 	ret = regmap_read(data->regmap, MLX90632_EE_Gb, &read_tmp);
512c87742abSCrt Mori 	if (ret < 0)
513c87742abSCrt Mori 		return ret;
514c87742abSCrt Mori 	Gb = (s16)read_tmp;
515c87742abSCrt Mori 
516c87742abSCrt Mori 	ret = mlx90632_read_ambient_raw(data->regmap, &ambient_new_raw,
517c87742abSCrt Mori 					&ambient_old_raw);
518c50fadefSDan Carpenter 	if (ret < 0)
519c50fadefSDan Carpenter 		return ret;
520c87742abSCrt Mori 	*val = mlx90632_calc_temp_ambient(ambient_new_raw, ambient_old_raw,
521c87742abSCrt Mori 					  PT, PR, PG, PO, Gb);
522c87742abSCrt Mori 	return ret;
523c87742abSCrt Mori }
524c87742abSCrt Mori 
525c87742abSCrt Mori static int mlx90632_read_raw(struct iio_dev *indio_dev,
526c87742abSCrt Mori 			     struct iio_chan_spec const *channel, int *val,
527c87742abSCrt Mori 			     int *val2, long mask)
528c87742abSCrt Mori {
529c87742abSCrt Mori 	struct mlx90632_data *data = iio_priv(indio_dev);
530c87742abSCrt Mori 	int ret;
531c87742abSCrt Mori 
532c87742abSCrt Mori 	switch (mask) {
533c87742abSCrt Mori 	case IIO_CHAN_INFO_PROCESSED:
534c87742abSCrt Mori 		switch (channel->channel2) {
535c87742abSCrt Mori 		case IIO_MOD_TEMP_AMBIENT:
536c87742abSCrt Mori 			ret = mlx90632_calc_ambient_dsp105(data, val);
537c87742abSCrt Mori 			if (ret < 0)
538c87742abSCrt Mori 				return ret;
539c87742abSCrt Mori 			return IIO_VAL_INT;
540c87742abSCrt Mori 		case IIO_MOD_TEMP_OBJECT:
541c87742abSCrt Mori 			ret = mlx90632_calc_object_dsp105(data, val);
542c87742abSCrt Mori 			if (ret < 0)
543c87742abSCrt Mori 				return ret;
544c87742abSCrt Mori 			return IIO_VAL_INT;
545c87742abSCrt Mori 		default:
546c87742abSCrt Mori 			return -EINVAL;
547c87742abSCrt Mori 		}
548c87742abSCrt Mori 	case IIO_CHAN_INFO_CALIBEMISSIVITY:
549c87742abSCrt Mori 		if (data->emissivity == 1000) {
550c87742abSCrt Mori 			*val = 1;
551c87742abSCrt Mori 			*val2 = 0;
552c87742abSCrt Mori 		} else {
553c87742abSCrt Mori 			*val = 0;
554c87742abSCrt Mori 			*val2 = data->emissivity * 1000;
555c87742abSCrt Mori 		}
556c87742abSCrt Mori 		return IIO_VAL_INT_PLUS_MICRO;
557c87742abSCrt Mori 
558c87742abSCrt Mori 	default:
559c87742abSCrt Mori 		return -EINVAL;
560c87742abSCrt Mori 	}
561c87742abSCrt Mori }
562c87742abSCrt Mori 
563c87742abSCrt Mori static int mlx90632_write_raw(struct iio_dev *indio_dev,
564c87742abSCrt Mori 			      struct iio_chan_spec const *channel, int val,
565c87742abSCrt Mori 			      int val2, long mask)
566c87742abSCrt Mori {
567c87742abSCrt Mori 	struct mlx90632_data *data = iio_priv(indio_dev);
568c87742abSCrt Mori 
569c87742abSCrt Mori 	switch (mask) {
570c87742abSCrt Mori 	case IIO_CHAN_INFO_CALIBEMISSIVITY:
571c87742abSCrt Mori 		/* Confirm we are within 0 and 1.0 */
572c87742abSCrt Mori 		if (val < 0 || val2 < 0 || val > 1 ||
573c87742abSCrt Mori 		    (val == 1 && val2 != 0))
574c87742abSCrt Mori 			return -EINVAL;
575c87742abSCrt Mori 		data->emissivity = val * 1000 + val2 / 1000;
576c87742abSCrt Mori 		return 0;
577c87742abSCrt Mori 	default:
578c87742abSCrt Mori 		return -EINVAL;
579c87742abSCrt Mori 	}
580c87742abSCrt Mori }
581c87742abSCrt Mori 
582c87742abSCrt Mori static const struct iio_chan_spec mlx90632_channels[] = {
583c87742abSCrt Mori 	{
584c87742abSCrt Mori 		.type = IIO_TEMP,
585c87742abSCrt Mori 		.modified = 1,
586c87742abSCrt Mori 		.channel2 = IIO_MOD_TEMP_AMBIENT,
587c87742abSCrt Mori 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
588c87742abSCrt Mori 	},
589c87742abSCrt Mori 	{
590c87742abSCrt Mori 		.type = IIO_TEMP,
591c87742abSCrt Mori 		.modified = 1,
592c87742abSCrt Mori 		.channel2 = IIO_MOD_TEMP_OBJECT,
593c87742abSCrt Mori 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
594c87742abSCrt Mori 			BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
595c87742abSCrt Mori 	},
596c87742abSCrt Mori };
597c87742abSCrt Mori 
598c87742abSCrt Mori static const struct iio_info mlx90632_info = {
599c87742abSCrt Mori 	.read_raw = mlx90632_read_raw,
600c87742abSCrt Mori 	.write_raw = mlx90632_write_raw,
601c87742abSCrt Mori };
602c87742abSCrt Mori 
603c87742abSCrt Mori static int mlx90632_sleep(struct mlx90632_data *data)
604c87742abSCrt Mori {
605c87742abSCrt Mori 	regcache_mark_dirty(data->regmap);
606c87742abSCrt Mori 
607c87742abSCrt Mori 	dev_dbg(&data->client->dev, "Requesting sleep");
608c87742abSCrt Mori 	return mlx90632_pwr_set_sleep_step(data->regmap);
609c87742abSCrt Mori }
610c87742abSCrt Mori 
611c87742abSCrt Mori static int mlx90632_wakeup(struct mlx90632_data *data)
612c87742abSCrt Mori {
613c87742abSCrt Mori 	int ret;
614c87742abSCrt Mori 
615c87742abSCrt Mori 	ret = regcache_sync(data->regmap);
616c87742abSCrt Mori 	if (ret < 0) {
617c87742abSCrt Mori 		dev_err(&data->client->dev,
618c87742abSCrt Mori 			"Failed to sync regmap registers: %d\n", ret);
619c87742abSCrt Mori 		return ret;
620c87742abSCrt Mori 	}
621c87742abSCrt Mori 
622c87742abSCrt Mori 	dev_dbg(&data->client->dev, "Requesting wake-up\n");
623c87742abSCrt Mori 	return mlx90632_pwr_continuous(data->regmap);
624c87742abSCrt Mori }
625c87742abSCrt Mori 
626c87742abSCrt Mori static int mlx90632_probe(struct i2c_client *client,
627c87742abSCrt Mori 			  const struct i2c_device_id *id)
628c87742abSCrt Mori {
629c87742abSCrt Mori 	struct iio_dev *indio_dev;
630c87742abSCrt Mori 	struct mlx90632_data *mlx90632;
631c87742abSCrt Mori 	struct regmap *regmap;
632c87742abSCrt Mori 	int ret;
633c87742abSCrt Mori 	unsigned int read;
634c87742abSCrt Mori 
635c87742abSCrt Mori 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mlx90632));
636c87742abSCrt Mori 	if (!indio_dev) {
637c87742abSCrt Mori 		dev_err(&client->dev, "Failed to allocate device\n");
638c87742abSCrt Mori 		return -ENOMEM;
639c87742abSCrt Mori 	}
640c87742abSCrt Mori 
641c87742abSCrt Mori 	regmap = devm_regmap_init_i2c(client, &mlx90632_regmap);
642c87742abSCrt Mori 	if (IS_ERR(regmap)) {
643c87742abSCrt Mori 		ret = PTR_ERR(regmap);
644c87742abSCrt Mori 		dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret);
645c87742abSCrt Mori 		return ret;
646c87742abSCrt Mori 	}
647c87742abSCrt Mori 
648c87742abSCrt Mori 	mlx90632 = iio_priv(indio_dev);
649c87742abSCrt Mori 	i2c_set_clientdata(client, indio_dev);
650c87742abSCrt Mori 	mlx90632->client = client;
651c87742abSCrt Mori 	mlx90632->regmap = regmap;
652c87742abSCrt Mori 
653c87742abSCrt Mori 	mutex_init(&mlx90632->lock);
654c87742abSCrt Mori 	indio_dev->name = id->name;
655c87742abSCrt Mori 	indio_dev->modes = INDIO_DIRECT_MODE;
656c87742abSCrt Mori 	indio_dev->info = &mlx90632_info;
657c87742abSCrt Mori 	indio_dev->channels = mlx90632_channels;
658c87742abSCrt Mori 	indio_dev->num_channels = ARRAY_SIZE(mlx90632_channels);
659c87742abSCrt Mori 
660c87742abSCrt Mori 	ret = mlx90632_wakeup(mlx90632);
661c87742abSCrt Mori 	if (ret < 0) {
662c87742abSCrt Mori 		dev_err(&client->dev, "Wakeup failed: %d\n", ret);
663c87742abSCrt Mori 		return ret;
664c87742abSCrt Mori 	}
665c87742abSCrt Mori 
666c87742abSCrt Mori 	ret = regmap_read(mlx90632->regmap, MLX90632_EE_VERSION, &read);
667c87742abSCrt Mori 	if (ret < 0) {
668c87742abSCrt Mori 		dev_err(&client->dev, "read of version failed: %d\n", ret);
669c87742abSCrt Mori 		return ret;
670c87742abSCrt Mori 	}
671c87742abSCrt Mori 	if (read == MLX90632_ID_MEDICAL) {
672c87742abSCrt Mori 		dev_dbg(&client->dev,
673c87742abSCrt Mori 			"Detected Medical EEPROM calibration %x\n", read);
674c87742abSCrt Mori 	} else if (read == MLX90632_ID_CONSUMER) {
675c87742abSCrt Mori 		dev_dbg(&client->dev,
676c87742abSCrt Mori 			"Detected Consumer EEPROM calibration %x\n", read);
677389fc70bSCrt Mori 	} else if ((read & MLX90632_DSP_MASK) == MLX90632_DSP_VERSION) {
678389fc70bSCrt Mori 		dev_dbg(&client->dev,
679389fc70bSCrt Mori 			"Detected Unknown EEPROM calibration %x\n", read);
680c87742abSCrt Mori 	} else {
681c87742abSCrt Mori 		dev_err(&client->dev,
682389fc70bSCrt Mori 			"Wrong DSP version %x (expected %x)\n",
683389fc70bSCrt Mori 			read, MLX90632_DSP_VERSION);
684c87742abSCrt Mori 		return -EPROTONOSUPPORT;
685c87742abSCrt Mori 	}
686c87742abSCrt Mori 
687c87742abSCrt Mori 	mlx90632->emissivity = 1000;
688c87742abSCrt Mori 
689c87742abSCrt Mori 	pm_runtime_disable(&client->dev);
690c87742abSCrt Mori 	ret = pm_runtime_set_active(&client->dev);
691c87742abSCrt Mori 	if (ret < 0) {
692c87742abSCrt Mori 		mlx90632_sleep(mlx90632);
693c87742abSCrt Mori 		return ret;
694c87742abSCrt Mori 	}
695c87742abSCrt Mori 	pm_runtime_enable(&client->dev);
696c87742abSCrt Mori 	pm_runtime_set_autosuspend_delay(&client->dev, MLX90632_SLEEP_DELAY_MS);
697c87742abSCrt Mori 	pm_runtime_use_autosuspend(&client->dev);
698c87742abSCrt Mori 
699c87742abSCrt Mori 	return iio_device_register(indio_dev);
700c87742abSCrt Mori }
701c87742abSCrt Mori 
702c87742abSCrt Mori static int mlx90632_remove(struct i2c_client *client)
703c87742abSCrt Mori {
704c87742abSCrt Mori 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
705c87742abSCrt Mori 	struct mlx90632_data *data = iio_priv(indio_dev);
706c87742abSCrt Mori 
707c87742abSCrt Mori 	iio_device_unregister(indio_dev);
708c87742abSCrt Mori 
709c87742abSCrt Mori 	pm_runtime_disable(&client->dev);
710c87742abSCrt Mori 	pm_runtime_set_suspended(&client->dev);
711c87742abSCrt Mori 	pm_runtime_put_noidle(&client->dev);
712c87742abSCrt Mori 
713c87742abSCrt Mori 	mlx90632_sleep(data);
714c87742abSCrt Mori 
715c87742abSCrt Mori 	return 0;
716c87742abSCrt Mori }
717c87742abSCrt Mori 
718c87742abSCrt Mori static const struct i2c_device_id mlx90632_id[] = {
719c87742abSCrt Mori 	{ "mlx90632", 0 },
720c87742abSCrt Mori 	{ }
721c87742abSCrt Mori };
722c87742abSCrt Mori MODULE_DEVICE_TABLE(i2c, mlx90632_id);
723c87742abSCrt Mori 
724c87742abSCrt Mori static const struct of_device_id mlx90632_of_match[] = {
725c87742abSCrt Mori 	{ .compatible = "melexis,mlx90632" },
726c87742abSCrt Mori 	{ }
727c87742abSCrt Mori };
728c87742abSCrt Mori MODULE_DEVICE_TABLE(of, mlx90632_of_match);
729c87742abSCrt Mori 
730c87742abSCrt Mori static int __maybe_unused mlx90632_pm_suspend(struct device *dev)
731c87742abSCrt Mori {
732c87742abSCrt Mori 	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
733c87742abSCrt Mori 	struct mlx90632_data *data = iio_priv(indio_dev);
734c87742abSCrt Mori 
735c87742abSCrt Mori 	return mlx90632_sleep(data);
736c87742abSCrt Mori }
737c87742abSCrt Mori 
738c87742abSCrt Mori static int __maybe_unused mlx90632_pm_resume(struct device *dev)
739c87742abSCrt Mori {
740c87742abSCrt Mori 	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
741c87742abSCrt Mori 	struct mlx90632_data *data = iio_priv(indio_dev);
742c87742abSCrt Mori 
743c87742abSCrt Mori 	return mlx90632_wakeup(data);
744c87742abSCrt Mori }
745c87742abSCrt Mori 
746c87742abSCrt Mori static UNIVERSAL_DEV_PM_OPS(mlx90632_pm_ops, mlx90632_pm_suspend,
747c87742abSCrt Mori 			    mlx90632_pm_resume, NULL);
748c87742abSCrt Mori 
749c87742abSCrt Mori static struct i2c_driver mlx90632_driver = {
750c87742abSCrt Mori 	.driver = {
751c87742abSCrt Mori 		.name	= "mlx90632",
752c87742abSCrt Mori 		.of_match_table = mlx90632_of_match,
753c87742abSCrt Mori 		.pm	= &mlx90632_pm_ops,
754c87742abSCrt Mori 	},
755c87742abSCrt Mori 	.probe = mlx90632_probe,
756c87742abSCrt Mori 	.remove = mlx90632_remove,
757c87742abSCrt Mori 	.id_table = mlx90632_id,
758c87742abSCrt Mori };
759c87742abSCrt Mori module_i2c_driver(mlx90632_driver);
760c87742abSCrt Mori 
761c87742abSCrt Mori MODULE_AUTHOR("Crt Mori <cmo@melexis.com>");
762c87742abSCrt Mori MODULE_DESCRIPTION("Melexis MLX90632 contactless Infra Red temperature sensor driver");
763c87742abSCrt Mori MODULE_LICENSE("GPL v2");
764