1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * mlx90635.c - Melexis MLX90635 contactless IR temperature sensor |
4 | * |
5 | * Copyright (c) 2023 Melexis <cmo@melexis.com> |
6 | * |
7 | * Driver for the Melexis MLX90635 I2C 16-bit IR thermopile sensor |
8 | */ |
9 | #include <linux/bitfield.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/device.h> |
12 | #include <linux/err.h> |
13 | #include <linux/gpio/consumer.h> |
14 | #include <linux/i2c.h> |
15 | #include <linux/iopoll.h> |
16 | #include <linux/jiffies.h> |
17 | #include <linux/kernel.h> |
18 | #include <linux/limits.h> |
19 | #include <linux/mod_devicetable.h> |
20 | #include <linux/module.h> |
21 | #include <linux/math64.h> |
22 | #include <linux/pm_runtime.h> |
23 | #include <linux/regmap.h> |
24 | #include <linux/regulator/consumer.h> |
25 | |
26 | #include <linux/iio/iio.h> |
27 | |
28 | /* Memory sections addresses */ |
29 | #define MLX90635_ADDR_RAM 0x0000 /* Start address of ram */ |
30 | #define MLX90635_ADDR_EEPROM 0x0018 /* Start address of user eeprom */ |
31 | |
32 | /* EEPROM addresses - used at startup */ |
33 | #define MLX90635_EE_I2C_CFG 0x0018 /* I2C address register initial value */ |
34 | #define MLX90635_EE_CTRL1 0x001A /* Control register1 initial value */ |
35 | #define MLX90635_EE_CTRL2 0x001C /* Control register2 initial value */ |
36 | |
37 | #define MLX90635_EE_Ha 0x001E /* Ha customer calib value reg 16bit */ |
38 | #define MLX90635_EE_Hb 0x0020 /* Hb customer calib value reg 16bit */ |
39 | #define MLX90635_EE_Fa 0x0026 /* Fa calibration register 32bit */ |
40 | #define MLX90635_EE_FASCALE 0x002A /* Scaling coefficient for Fa register 16bit */ |
41 | #define MLX90635_EE_Ga 0x002C /* Ga calibration register 16bit */ |
42 | #define MLX90635_EE_Fb 0x002E /* Fb calibration register 16bit */ |
43 | #define MLX90635_EE_Ea 0x0030 /* Ea calibration register 32bit */ |
44 | #define MLX90635_EE_Eb 0x0034 /* Eb calibration register 32bit */ |
45 | #define MLX90635_EE_P_G 0x0038 /* P_G calibration register 16bit */ |
46 | #define MLX90635_EE_P_O 0x003A /* P_O calibration register 16bit */ |
47 | #define MLX90635_EE_Aa 0x003C /* Aa calibration register 16bit */ |
48 | #define MLX90635_EE_VERSION 0x003E /* Version bits 4:7 and 12:15 */ |
49 | #define MLX90635_EE_Gb 0x0040 /* Gb calibration register 16bit */ |
50 | |
51 | /* Device status register - volatile */ |
52 | #define MLX90635_REG_STATUS 0x0000 |
53 | #define MLX90635_STAT_BUSY BIT(6) /* Device busy indicator */ |
54 | #define MLX90635_STAT_BRST BIT(5) /* Brown out reset indicator */ |
55 | #define MLX90635_STAT_CYCLE_POS GENMASK(4, 2) /* Data position */ |
56 | #define MLX90635_STAT_END_CONV BIT(1) /* End of conversion indicator */ |
57 | #define MLX90635_STAT_DATA_RDY BIT(0) /* Data ready indicator */ |
58 | |
59 | /* EEPROM control register address - volatile */ |
60 | #define MLX90635_REG_EE 0x000C |
61 | #define MLX90635_EE_ACTIVE BIT(4) /* Power-on EEPROM */ |
62 | #define MLX90635_EE_BUSY_MASK BIT(15) |
63 | |
64 | #define MLX90635_REG_CMD 0x0010 /* Command register address */ |
65 | |
66 | /* Control register1 address - volatile */ |
67 | #define MLX90635_REG_CTRL1 0x0014 |
68 | #define MLX90635_CTRL1_REFRESH_RATE_MASK GENMASK(2, 0) |
69 | #define MLX90635_CTRL1_RES_CTRL_MASK GENMASK(4, 3) |
70 | #define MLX90635_CTRL1_TABLE_MASK BIT(15) /* Table select */ |
71 | |
72 | /* Control register2 address - volatile */ |
73 | #define MLX90635_REG_CTRL2 0x0016 |
74 | #define MLX90635_CTRL2_BURST_CNT_MASK GENMASK(10, 6) /* Burst count */ |
75 | #define MLX90635_CTRL2_MODE_MASK GENMASK(12, 11) /* Power mode */ |
76 | #define MLX90635_CTRL2_SOB_MASK BIT(15) |
77 | |
78 | /* PowerModes statuses */ |
79 | #define MLX90635_PWR_STATUS_HALT 0 |
80 | #define MLX90635_PWR_STATUS_SLEEP_STEP 1 |
81 | #define MLX90635_PWR_STATUS_STEP 2 |
82 | #define MLX90635_PWR_STATUS_CONTINUOUS 3 |
83 | |
84 | /* Measurement data addresses */ |
85 | #define MLX90635_RESULT_1 0x0002 |
86 | #define MLX90635_RESULT_2 0x0004 |
87 | #define MLX90635_RESULT_3 0x0006 |
88 | #define MLX90635_RESULT_4 0x0008 |
89 | #define MLX90635_RESULT_5 0x000A |
90 | |
91 | /* Timings (ms) */ |
92 | #define MLX90635_TIMING_RST_MIN 200 /* Minimum time after addressed reset command */ |
93 | #define MLX90635_TIMING_RST_MAX 250 /* Maximum time after addressed reset command */ |
94 | #define MLX90635_TIMING_POLLING 10000 /* Time between bit polling*/ |
95 | #define MLX90635_TIMING_EE_ACTIVE_MIN 100 /* Minimum time after activating the EEPROM for read */ |
96 | #define MLX90635_TIMING_EE_ACTIVE_MAX 150 /* Maximum time after activating the EEPROM for read */ |
97 | |
98 | /* Magic constants */ |
99 | #define MLX90635_ID_DSPv1 0x01 /* EEPROM DSP version */ |
100 | #define MLX90635_RESET_CMD 0x0006 /* Reset sensor (address or global) */ |
101 | #define MLX90635_MAX_MEAS_NUM 31 /* Maximum number of measurements in list */ |
102 | #define MLX90635_PTAT_DIV 12 /* Used to divide the PTAT value in pre-processing */ |
103 | #define MLX90635_IR_DIV 24 /* Used to divide the IR value in pre-processing */ |
104 | #define MLX90635_SLEEP_DELAY_MS 6000 /* Autosleep delay */ |
105 | #define MLX90635_MEAS_MAX_TIME 2000 /* Max measurement time in ms for the lowest refresh rate */ |
106 | #define MLX90635_READ_RETRIES 100 /* Number of read retries before quitting with timeout error */ |
107 | #define MLX90635_VERSION_MASK (GENMASK(15, 12) | GENMASK(7, 4)) |
108 | #define MLX90635_DSP_VERSION(reg) (((reg & GENMASK(14, 12)) >> 9) | ((reg & GENMASK(6, 4)) >> 4)) |
109 | #define MLX90635_DSP_FIXED BIT(15) |
110 | |
111 | |
112 | /** |
113 | * struct mlx90635_data - private data for the MLX90635 device |
114 | * @client: I2C client of the device |
115 | * @lock: Internal mutex because multiple reads are needed for single triggered |
116 | * measurement to ensure data consistency |
117 | * @regmap: Regmap of the device registers |
118 | * @regmap_ee: Regmap of the device EEPROM which can be cached |
119 | * @emissivity: Object emissivity from 0 to 1000 where 1000 = 1 |
120 | * @regulator: Regulator of the device |
121 | * @powerstatus: Current POWER status of the device |
122 | * @interaction_ts: Timestamp of the last temperature read that is used |
123 | * for power management in jiffies |
124 | */ |
125 | struct mlx90635_data { |
126 | struct i2c_client *client; |
127 | struct mutex lock; |
128 | struct regmap *regmap; |
129 | struct regmap *regmap_ee; |
130 | u16 emissivity; |
131 | struct regulator *regulator; |
132 | int powerstatus; |
133 | unsigned long interaction_ts; |
134 | }; |
135 | |
136 | static const struct regmap_range mlx90635_volatile_reg_range[] = { |
137 | regmap_reg_range(MLX90635_REG_STATUS, MLX90635_REG_STATUS), |
138 | regmap_reg_range(MLX90635_RESULT_1, MLX90635_RESULT_5), |
139 | regmap_reg_range(MLX90635_REG_EE, MLX90635_REG_EE), |
140 | regmap_reg_range(MLX90635_REG_CMD, MLX90635_REG_CMD), |
141 | regmap_reg_range(MLX90635_REG_CTRL1, MLX90635_REG_CTRL2), |
142 | }; |
143 | |
144 | static const struct regmap_access_table mlx90635_volatile_regs_tbl = { |
145 | .yes_ranges = mlx90635_volatile_reg_range, |
146 | .n_yes_ranges = ARRAY_SIZE(mlx90635_volatile_reg_range), |
147 | }; |
148 | |
149 | static const struct regmap_range mlx90635_read_reg_range[] = { |
150 | regmap_reg_range(MLX90635_REG_STATUS, MLX90635_REG_STATUS), |
151 | regmap_reg_range(MLX90635_RESULT_1, MLX90635_RESULT_5), |
152 | regmap_reg_range(MLX90635_REG_EE, MLX90635_REG_EE), |
153 | regmap_reg_range(MLX90635_REG_CMD, MLX90635_REG_CMD), |
154 | regmap_reg_range(MLX90635_REG_CTRL1, MLX90635_REG_CTRL2), |
155 | }; |
156 | |
157 | static const struct regmap_access_table mlx90635_readable_regs_tbl = { |
158 | .yes_ranges = mlx90635_read_reg_range, |
159 | .n_yes_ranges = ARRAY_SIZE(mlx90635_read_reg_range), |
160 | }; |
161 | |
162 | static const struct regmap_range mlx90635_no_write_reg_range[] = { |
163 | regmap_reg_range(MLX90635_RESULT_1, MLX90635_RESULT_5), |
164 | }; |
165 | |
166 | static const struct regmap_access_table mlx90635_writeable_regs_tbl = { |
167 | .no_ranges = mlx90635_no_write_reg_range, |
168 | .n_no_ranges = ARRAY_SIZE(mlx90635_no_write_reg_range), |
169 | }; |
170 | |
171 | static const struct regmap_config mlx90635_regmap = { |
172 | .name = "mlx90635-registers" , |
173 | .reg_stride = 1, |
174 | .reg_bits = 16, |
175 | .val_bits = 16, |
176 | |
177 | .volatile_table = &mlx90635_volatile_regs_tbl, |
178 | .rd_table = &mlx90635_readable_regs_tbl, |
179 | .wr_table = &mlx90635_writeable_regs_tbl, |
180 | |
181 | .use_single_read = true, |
182 | .use_single_write = true, |
183 | .can_multi_write = false, |
184 | .reg_format_endian = REGMAP_ENDIAN_BIG, |
185 | .val_format_endian = REGMAP_ENDIAN_BIG, |
186 | .cache_type = REGCACHE_RBTREE, |
187 | }; |
188 | |
189 | static const struct regmap_range mlx90635_read_ee_range[] = { |
190 | regmap_reg_range(MLX90635_EE_I2C_CFG, MLX90635_EE_CTRL2), |
191 | regmap_reg_range(MLX90635_EE_Ha, MLX90635_EE_Gb), |
192 | }; |
193 | |
194 | static const struct regmap_access_table mlx90635_readable_ees_tbl = { |
195 | .yes_ranges = mlx90635_read_ee_range, |
196 | .n_yes_ranges = ARRAY_SIZE(mlx90635_read_ee_range), |
197 | }; |
198 | |
199 | static const struct regmap_range mlx90635_no_write_ee_range[] = { |
200 | regmap_reg_range(MLX90635_ADDR_EEPROM, MLX90635_EE_Gb), |
201 | }; |
202 | |
203 | static const struct regmap_access_table mlx90635_writeable_ees_tbl = { |
204 | .no_ranges = mlx90635_no_write_ee_range, |
205 | .n_no_ranges = ARRAY_SIZE(mlx90635_no_write_ee_range), |
206 | }; |
207 | |
208 | static const struct regmap_config mlx90635_regmap_ee = { |
209 | .name = "mlx90635-eeprom" , |
210 | .reg_stride = 1, |
211 | .reg_bits = 16, |
212 | .val_bits = 16, |
213 | |
214 | .volatile_table = NULL, |
215 | .rd_table = &mlx90635_readable_ees_tbl, |
216 | .wr_table = &mlx90635_writeable_ees_tbl, |
217 | |
218 | .use_single_read = true, |
219 | .use_single_write = true, |
220 | .can_multi_write = false, |
221 | .reg_format_endian = REGMAP_ENDIAN_BIG, |
222 | .val_format_endian = REGMAP_ENDIAN_BIG, |
223 | .cache_type = REGCACHE_RBTREE, |
224 | }; |
225 | |
226 | /** |
227 | * mlx90635_reset_delay() - Give the mlx90635 some time to reset properly |
228 | * If this is not done, the following I2C command(s) will not be accepted. |
229 | */ |
230 | static void mlx90635_reset_delay(void) |
231 | { |
232 | usleep_range(MLX90635_TIMING_RST_MIN, MLX90635_TIMING_RST_MAX); |
233 | } |
234 | |
235 | static int mlx90635_pwr_sleep_step(struct mlx90635_data *data) |
236 | { |
237 | int ret; |
238 | |
239 | if (data->powerstatus == MLX90635_PWR_STATUS_SLEEP_STEP) |
240 | return 0; |
241 | |
242 | ret = regmap_write_bits(map: data->regmap, MLX90635_REG_CTRL2, MLX90635_CTRL2_MODE_MASK, |
243 | FIELD_PREP(MLX90635_CTRL2_MODE_MASK, MLX90635_PWR_STATUS_SLEEP_STEP)); |
244 | if (ret < 0) |
245 | return ret; |
246 | |
247 | data->powerstatus = MLX90635_PWR_STATUS_SLEEP_STEP; |
248 | return 0; |
249 | } |
250 | |
251 | static int mlx90635_pwr_continuous(struct mlx90635_data *data) |
252 | { |
253 | int ret; |
254 | |
255 | if (data->powerstatus == MLX90635_PWR_STATUS_CONTINUOUS) |
256 | return 0; |
257 | |
258 | ret = regmap_write_bits(map: data->regmap, MLX90635_REG_CTRL2, MLX90635_CTRL2_MODE_MASK, |
259 | FIELD_PREP(MLX90635_CTRL2_MODE_MASK, MLX90635_PWR_STATUS_CONTINUOUS)); |
260 | if (ret < 0) |
261 | return ret; |
262 | |
263 | data->powerstatus = MLX90635_PWR_STATUS_CONTINUOUS; |
264 | return 0; |
265 | } |
266 | |
267 | static int mlx90635_read_ee_register(struct regmap *regmap, u16 reg_lsb, |
268 | s32 *reg_value) |
269 | { |
270 | unsigned int read; |
271 | u32 value; |
272 | int ret; |
273 | |
274 | ret = regmap_read(map: regmap, reg: reg_lsb + 2, val: &read); |
275 | if (ret < 0) |
276 | return ret; |
277 | |
278 | value = read; |
279 | |
280 | ret = regmap_read(map: regmap, reg: reg_lsb, val: &read); |
281 | if (ret < 0) |
282 | return ret; |
283 | |
284 | *reg_value = (read << 16) | (value & 0xffff); |
285 | |
286 | return 0; |
287 | } |
288 | |
289 | static int mlx90635_read_ee_ambient(struct regmap *regmap, s16 *PG, s16 *PO, s16 *Gb) |
290 | { |
291 | unsigned int read_tmp; |
292 | int ret; |
293 | |
294 | ret = regmap_read(map: regmap, MLX90635_EE_P_O, val: &read_tmp); |
295 | if (ret < 0) |
296 | return ret; |
297 | *PO = (s16)read_tmp; |
298 | |
299 | ret = regmap_read(map: regmap, MLX90635_EE_P_G, val: &read_tmp); |
300 | if (ret < 0) |
301 | return ret; |
302 | *PG = (s16)read_tmp; |
303 | |
304 | ret = regmap_read(map: regmap, MLX90635_EE_Gb, val: &read_tmp); |
305 | if (ret < 0) |
306 | return ret; |
307 | *Gb = (u16)read_tmp; |
308 | |
309 | return 0; |
310 | } |
311 | |
312 | static int mlx90635_read_ee_object(struct regmap *regmap, u32 *Ea, u32 *Eb, u32 *Fa, s16 *Fb, |
313 | s16 *Ga, s16 *Gb, s16 *Ha, s16 *Hb, u16 *Fa_scale) |
314 | { |
315 | unsigned int read_tmp; |
316 | int ret; |
317 | |
318 | ret = mlx90635_read_ee_register(regmap, MLX90635_EE_Ea, reg_value: Ea); |
319 | if (ret < 0) |
320 | return ret; |
321 | |
322 | ret = mlx90635_read_ee_register(regmap, MLX90635_EE_Eb, reg_value: Eb); |
323 | if (ret < 0) |
324 | return ret; |
325 | |
326 | ret = mlx90635_read_ee_register(regmap, MLX90635_EE_Fa, reg_value: Fa); |
327 | if (ret < 0) |
328 | return ret; |
329 | |
330 | ret = regmap_read(map: regmap, MLX90635_EE_Ha, val: &read_tmp); |
331 | if (ret < 0) |
332 | return ret; |
333 | *Ha = (s16)read_tmp; |
334 | |
335 | ret = regmap_read(map: regmap, MLX90635_EE_Hb, val: &read_tmp); |
336 | if (ret < 0) |
337 | return ret; |
338 | *Hb = (s16)read_tmp; |
339 | |
340 | ret = regmap_read(map: regmap, MLX90635_EE_Ga, val: &read_tmp); |
341 | if (ret < 0) |
342 | return ret; |
343 | *Ga = (s16)read_tmp; |
344 | |
345 | ret = regmap_read(map: regmap, MLX90635_EE_Gb, val: &read_tmp); |
346 | if (ret < 0) |
347 | return ret; |
348 | *Gb = (s16)read_tmp; |
349 | |
350 | ret = regmap_read(map: regmap, MLX90635_EE_Fb, val: &read_tmp); |
351 | if (ret < 0) |
352 | return ret; |
353 | *Fb = (s16)read_tmp; |
354 | |
355 | ret = regmap_read(map: regmap, MLX90635_EE_FASCALE, val: &read_tmp); |
356 | if (ret < 0) |
357 | return ret; |
358 | *Fa_scale = (u16)read_tmp; |
359 | |
360 | return 0; |
361 | } |
362 | |
363 | static int mlx90635_calculate_dataset_ready_time(struct mlx90635_data *data, int *refresh_time) |
364 | { |
365 | unsigned int reg; |
366 | int ret; |
367 | |
368 | ret = regmap_read(map: data->regmap, MLX90635_REG_CTRL1, val: ®); |
369 | if (ret < 0) |
370 | return ret; |
371 | |
372 | *refresh_time = 2 * (MLX90635_MEAS_MAX_TIME >> FIELD_GET(MLX90635_CTRL1_REFRESH_RATE_MASK, reg)) + 80; |
373 | |
374 | return 0; |
375 | } |
376 | |
377 | static int mlx90635_perform_measurement_burst(struct mlx90635_data *data) |
378 | { |
379 | unsigned int reg_status; |
380 | int refresh_time; |
381 | int ret; |
382 | |
383 | ret = regmap_write_bits(map: data->regmap, MLX90635_REG_STATUS, |
384 | MLX90635_STAT_END_CONV, MLX90635_STAT_END_CONV); |
385 | if (ret < 0) |
386 | return ret; |
387 | |
388 | ret = mlx90635_calculate_dataset_ready_time(data, refresh_time: &refresh_time); |
389 | if (ret < 0) |
390 | return ret; |
391 | |
392 | ret = regmap_write_bits(map: data->regmap, MLX90635_REG_CTRL2, |
393 | FIELD_PREP(MLX90635_CTRL2_SOB_MASK, 1), |
394 | FIELD_PREP(MLX90635_CTRL2_SOB_MASK, 1)); |
395 | if (ret < 0) |
396 | return ret; |
397 | |
398 | msleep(msecs: refresh_time); /* Wait minimum time for dataset to be ready */ |
399 | |
400 | ret = regmap_read_poll_timeout(data->regmap, MLX90635_REG_STATUS, reg_status, |
401 | (!(reg_status & MLX90635_STAT_END_CONV)) == 0, |
402 | MLX90635_TIMING_POLLING, MLX90635_READ_RETRIES * 10000); |
403 | if (ret < 0) { |
404 | dev_err(&data->client->dev, "data not ready" ); |
405 | return -ETIMEDOUT; |
406 | } |
407 | |
408 | return 0; |
409 | } |
410 | |
411 | static int mlx90635_read_ambient_raw(struct regmap *regmap, |
412 | s16 *ambient_new_raw, s16 *ambient_old_raw) |
413 | { |
414 | unsigned int read_tmp; |
415 | int ret; |
416 | |
417 | ret = regmap_read(map: regmap, MLX90635_RESULT_2, val: &read_tmp); |
418 | if (ret < 0) |
419 | return ret; |
420 | *ambient_new_raw = (s16)read_tmp; |
421 | |
422 | ret = regmap_read(map: regmap, MLX90635_RESULT_3, val: &read_tmp); |
423 | if (ret < 0) |
424 | return ret; |
425 | *ambient_old_raw = (s16)read_tmp; |
426 | |
427 | return 0; |
428 | } |
429 | |
430 | static int mlx90635_read_object_raw(struct regmap *regmap, s16 *object_raw) |
431 | { |
432 | unsigned int read_tmp; |
433 | s16 read; |
434 | int ret; |
435 | |
436 | ret = regmap_read(map: regmap, MLX90635_RESULT_1, val: &read_tmp); |
437 | if (ret < 0) |
438 | return ret; |
439 | |
440 | read = (s16)read_tmp; |
441 | |
442 | ret = regmap_read(map: regmap, MLX90635_RESULT_4, val: &read_tmp); |
443 | if (ret < 0) |
444 | return ret; |
445 | *object_raw = (read - (s16)read_tmp) / 2; |
446 | |
447 | return 0; |
448 | } |
449 | |
450 | static int mlx90635_read_all_channel(struct mlx90635_data *data, |
451 | s16 *ambient_new_raw, s16 *ambient_old_raw, |
452 | s16 *object_raw) |
453 | { |
454 | int ret; |
455 | |
456 | mutex_lock(&data->lock); |
457 | if (data->powerstatus == MLX90635_PWR_STATUS_SLEEP_STEP) { |
458 | /* Trigger measurement in Sleep Step mode */ |
459 | ret = mlx90635_perform_measurement_burst(data); |
460 | if (ret < 0) |
461 | goto read_unlock; |
462 | } |
463 | |
464 | ret = mlx90635_read_ambient_raw(regmap: data->regmap, ambient_new_raw, |
465 | ambient_old_raw); |
466 | if (ret < 0) |
467 | goto read_unlock; |
468 | |
469 | ret = mlx90635_read_object_raw(regmap: data->regmap, object_raw); |
470 | read_unlock: |
471 | mutex_unlock(lock: &data->lock); |
472 | return ret; |
473 | } |
474 | |
475 | static s64 mlx90635_preprocess_temp_amb(s16 ambient_new_raw, |
476 | s16 ambient_old_raw, s16 Gb) |
477 | { |
478 | s64 VR_Ta, kGb, tmp; |
479 | |
480 | kGb = ((s64)Gb * 1000LL) >> 10ULL; |
481 | VR_Ta = (s64)ambient_old_raw * 1000000LL + |
482 | kGb * div64_s64(dividend: ((s64)ambient_new_raw * 1000LL), |
483 | divisor: (MLX90635_PTAT_DIV)); |
484 | tmp = div64_s64( |
485 | dividend: div64_s64(dividend: ((s64)ambient_new_raw * 1000000000000LL), |
486 | divisor: (MLX90635_PTAT_DIV)), divisor: VR_Ta); |
487 | return div64_s64(dividend: tmp << 19ULL, divisor: 1000LL); |
488 | } |
489 | |
490 | static s64 mlx90635_preprocess_temp_obj(s16 object_raw, |
491 | s16 ambient_new_raw, |
492 | s16 ambient_old_raw, s16 Gb) |
493 | { |
494 | s64 VR_IR, kGb, tmp; |
495 | |
496 | kGb = ((s64)Gb * 1000LL) >> 10ULL; |
497 | VR_IR = (s64)ambient_old_raw * 1000000LL + |
498 | kGb * (div64_s64(dividend: (s64)ambient_new_raw * 1000LL, |
499 | MLX90635_PTAT_DIV)); |
500 | tmp = div64_s64( |
501 | dividend: div64_s64(dividend: (s64)(object_raw * 1000000LL), |
502 | MLX90635_IR_DIV) * 1000000LL, |
503 | divisor: VR_IR); |
504 | return div64_s64(dividend: (tmp << 19ULL), divisor: 1000LL); |
505 | } |
506 | |
507 | static s32 mlx90635_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw, |
508 | u16 P_G, u16 P_O, s16 Gb) |
509 | { |
510 | s64 kPG, kPO, AMB; |
511 | |
512 | AMB = mlx90635_preprocess_temp_amb(ambient_new_raw, ambient_old_raw, |
513 | Gb); |
514 | kPG = ((s64)P_G * 1000000LL) >> 9ULL; |
515 | kPO = AMB - (((s64)P_O * 1000LL) >> 1ULL); |
516 | |
517 | return 30 * 1000LL + div64_s64(dividend: kPO * 1000000LL, divisor: kPG); |
518 | } |
519 | |
520 | static s32 mlx90635_calc_temp_object_iteration(s32 prev_object_temp, s64 object, |
521 | s64 TAdut, s64 TAdut4, s16 Ga, |
522 | u32 Fa, u16 Fa_scale, s16 Fb, |
523 | s16 Ha, s16 Hb, u16 emissivity) |
524 | { |
525 | s64 calcedGa, calcedGb, calcedFa, Alpha_corr; |
526 | s64 Ha_customer, Hb_customer; |
527 | |
528 | Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL; |
529 | Hb_customer = ((s64)Hb * 100) >> 10ULL; |
530 | |
531 | calcedGa = ((s64)((s64)Ga * (prev_object_temp - 35 * 1000LL) |
532 | * 1000LL)) >> 24LL; |
533 | calcedGb = ((s64)(Fb * (TAdut - 30 * 1000000LL))) >> 24LL; |
534 | |
535 | Alpha_corr = ((s64)((s64)Fa * Ha_customer * 10000LL) >> Fa_scale); |
536 | Alpha_corr *= ((s64)(1 * 1000000LL + calcedGa + calcedGb)); |
537 | |
538 | Alpha_corr = div64_s64(dividend: Alpha_corr, divisor: 1000LL); |
539 | Alpha_corr *= emissivity; |
540 | Alpha_corr = div64_s64(dividend: Alpha_corr, divisor: 100LL); |
541 | calcedFa = div64_s64(dividend: (s64)object * 100000000000LL, divisor: Alpha_corr); |
542 | |
543 | return (int_sqrt64(x: int_sqrt64(x: calcedFa * 100000000LL + TAdut4)) |
544 | - 27315 - Hb_customer) * 10; |
545 | } |
546 | |
547 | static s64 mlx90635_calc_ta4(s64 TAdut, s64 scale) |
548 | { |
549 | return (div64_s64(dividend: TAdut, divisor: scale) + 27315) * |
550 | (div64_s64(dividend: TAdut, divisor: scale) + 27315) * |
551 | (div64_s64(dividend: TAdut, divisor: scale) + 27315) * |
552 | (div64_s64(dividend: TAdut, divisor: scale) + 27315); |
553 | } |
554 | |
555 | static s32 mlx90635_calc_temp_object(s64 object, s64 ambient, u32 Ea, u32 Eb, |
556 | s16 Ga, u32 Fa, u16 Fa_scale, s16 Fb, s16 Ha, s16 Hb, |
557 | u16 tmp_emi) |
558 | { |
559 | s64 kTA, kTA0, TAdut, TAdut4; |
560 | s64 temp = 35000; |
561 | s8 i; |
562 | |
563 | kTA = (Ea * 1000LL) >> 16LL; |
564 | kTA0 = (Eb * 1000LL) >> 8LL; |
565 | TAdut = div64_s64(dividend: ((ambient - kTA0) * 1000000LL), divisor: kTA) + 30 * 1000000LL; |
566 | TAdut4 = mlx90635_calc_ta4(TAdut, scale: 10000LL); |
567 | |
568 | /* Iterations of calculation as described in datasheet */ |
569 | for (i = 0; i < 5; ++i) { |
570 | temp = mlx90635_calc_temp_object_iteration(prev_object_temp: temp, object, TAdut, TAdut4, |
571 | Ga, Fa, Fa_scale, Fb, Ha, Hb, |
572 | emissivity: tmp_emi); |
573 | } |
574 | return temp; |
575 | } |
576 | |
577 | static int mlx90635_calc_object(struct mlx90635_data *data, int *val) |
578 | { |
579 | s16 ambient_new_raw, ambient_old_raw, object_raw; |
580 | s16 Fb, Ga, Gb, Ha, Hb; |
581 | s64 object, ambient; |
582 | u32 Ea, Eb, Fa; |
583 | u16 Fa_scale; |
584 | int ret; |
585 | |
586 | ret = mlx90635_read_ee_object(regmap: data->regmap_ee, Ea: &Ea, Eb: &Eb, Fa: &Fa, Fb: &Fb, Ga: &Ga, Gb: &Gb, Ha: &Ha, Hb: &Hb, Fa_scale: &Fa_scale); |
587 | if (ret < 0) |
588 | return ret; |
589 | |
590 | ret = mlx90635_read_all_channel(data, |
591 | ambient_new_raw: &ambient_new_raw, ambient_old_raw: &ambient_old_raw, |
592 | object_raw: &object_raw); |
593 | if (ret < 0) |
594 | return ret; |
595 | |
596 | ambient = mlx90635_preprocess_temp_amb(ambient_new_raw, |
597 | ambient_old_raw, Gb); |
598 | object = mlx90635_preprocess_temp_obj(object_raw, |
599 | ambient_new_raw, |
600 | ambient_old_raw, Gb); |
601 | |
602 | *val = mlx90635_calc_temp_object(object, ambient, Ea, Eb, Ga, Fa, Fa_scale, Fb, |
603 | Ha, Hb, tmp_emi: data->emissivity); |
604 | return 0; |
605 | } |
606 | |
607 | static int mlx90635_calc_ambient(struct mlx90635_data *data, int *val) |
608 | { |
609 | s16 ambient_new_raw, ambient_old_raw; |
610 | s16 PG, PO, Gb; |
611 | int ret; |
612 | |
613 | ret = mlx90635_read_ee_ambient(regmap: data->regmap_ee, PG: &PG, PO: &PO, Gb: &Gb); |
614 | if (ret < 0) |
615 | return ret; |
616 | |
617 | mutex_lock(&data->lock); |
618 | if (data->powerstatus == MLX90635_PWR_STATUS_SLEEP_STEP) { |
619 | ret = mlx90635_perform_measurement_burst(data); |
620 | if (ret < 0) |
621 | goto read_ambient_unlock; |
622 | } |
623 | |
624 | ret = mlx90635_read_ambient_raw(regmap: data->regmap, ambient_new_raw: &ambient_new_raw, |
625 | ambient_old_raw: &ambient_old_raw); |
626 | read_ambient_unlock: |
627 | mutex_unlock(lock: &data->lock); |
628 | if (ret < 0) |
629 | return ret; |
630 | |
631 | *val = mlx90635_calc_temp_ambient(ambient_new_raw, ambient_old_raw, |
632 | P_G: PG, P_O: PO, Gb); |
633 | return ret; |
634 | } |
635 | |
636 | static int mlx90635_get_refresh_rate(struct mlx90635_data *data, |
637 | unsigned int *refresh_rate) |
638 | { |
639 | unsigned int reg; |
640 | int ret; |
641 | |
642 | ret = regmap_read(map: data->regmap, MLX90635_REG_CTRL1, val: ®); |
643 | if (ret < 0) |
644 | return ret; |
645 | |
646 | *refresh_rate = FIELD_GET(MLX90635_CTRL1_REFRESH_RATE_MASK, reg); |
647 | |
648 | return 0; |
649 | } |
650 | |
651 | static const struct { |
652 | int val; |
653 | int val2; |
654 | } mlx90635_freqs[] = { |
655 | { 0, 200000 }, |
656 | { 0, 500000 }, |
657 | { 0, 900000 }, |
658 | { 1, 700000 }, |
659 | { 3, 0 }, |
660 | { 4, 800000 }, |
661 | { 6, 900000 }, |
662 | { 8, 900000 } |
663 | }; |
664 | |
665 | /** |
666 | * mlx90635_pm_interaction_wakeup() - Measure time between user interactions to change powermode |
667 | * @data: pointer to mlx90635_data object containing interaction_ts information |
668 | * |
669 | * Switch to continuous mode when interaction is faster than MLX90635_MEAS_MAX_TIME. Update the |
670 | * interaction_ts for each function call with the jiffies to enable measurement between function |
671 | * calls. Initial value of the interaction_ts needs to be set before this function call. |
672 | */ |
673 | static int mlx90635_pm_interaction_wakeup(struct mlx90635_data *data) |
674 | { |
675 | unsigned long now; |
676 | int ret; |
677 | |
678 | now = jiffies; |
679 | if (time_in_range(now, data->interaction_ts, |
680 | data->interaction_ts + |
681 | msecs_to_jiffies(MLX90635_MEAS_MAX_TIME + 100))) { |
682 | ret = mlx90635_pwr_continuous(data); |
683 | if (ret < 0) |
684 | return ret; |
685 | } |
686 | |
687 | data->interaction_ts = now; |
688 | |
689 | return 0; |
690 | } |
691 | |
692 | static int mlx90635_read_raw(struct iio_dev *indio_dev, |
693 | struct iio_chan_spec const *channel, int *val, |
694 | int *val2, long mask) |
695 | { |
696 | struct mlx90635_data *data = iio_priv(indio_dev); |
697 | int ret; |
698 | int cr; |
699 | |
700 | pm_runtime_get_sync(dev: &data->client->dev); |
701 | ret = mlx90635_pm_interaction_wakeup(data); |
702 | if (ret < 0) |
703 | goto mlx90635_read_raw_pm; |
704 | |
705 | switch (mask) { |
706 | case IIO_CHAN_INFO_PROCESSED: |
707 | switch (channel->channel2) { |
708 | case IIO_MOD_TEMP_AMBIENT: |
709 | ret = mlx90635_calc_ambient(data, val); |
710 | if (ret < 0) |
711 | goto mlx90635_read_raw_pm; |
712 | |
713 | ret = IIO_VAL_INT; |
714 | break; |
715 | case IIO_MOD_TEMP_OBJECT: |
716 | ret = mlx90635_calc_object(data, val); |
717 | if (ret < 0) |
718 | goto mlx90635_read_raw_pm; |
719 | |
720 | ret = IIO_VAL_INT; |
721 | break; |
722 | default: |
723 | ret = -EINVAL; |
724 | break; |
725 | } |
726 | break; |
727 | case IIO_CHAN_INFO_CALIBEMISSIVITY: |
728 | if (data->emissivity == 1000) { |
729 | *val = 1; |
730 | *val2 = 0; |
731 | } else { |
732 | *val = 0; |
733 | *val2 = data->emissivity * 1000; |
734 | } |
735 | ret = IIO_VAL_INT_PLUS_MICRO; |
736 | break; |
737 | case IIO_CHAN_INFO_SAMP_FREQ: |
738 | ret = mlx90635_get_refresh_rate(data, refresh_rate: &cr); |
739 | if (ret < 0) |
740 | goto mlx90635_read_raw_pm; |
741 | |
742 | *val = mlx90635_freqs[cr].val; |
743 | *val2 = mlx90635_freqs[cr].val2; |
744 | ret = IIO_VAL_INT_PLUS_MICRO; |
745 | break; |
746 | default: |
747 | ret = -EINVAL; |
748 | break; |
749 | } |
750 | |
751 | mlx90635_read_raw_pm: |
752 | pm_runtime_mark_last_busy(dev: &data->client->dev); |
753 | pm_runtime_put_autosuspend(dev: &data->client->dev); |
754 | return ret; |
755 | } |
756 | |
757 | static int mlx90635_write_raw(struct iio_dev *indio_dev, |
758 | struct iio_chan_spec const *channel, int val, |
759 | int val2, long mask) |
760 | { |
761 | struct mlx90635_data *data = iio_priv(indio_dev); |
762 | int ret; |
763 | int i; |
764 | |
765 | switch (mask) { |
766 | case IIO_CHAN_INFO_CALIBEMISSIVITY: |
767 | /* Confirm we are within 0 and 1.0 */ |
768 | if (val < 0 || val2 < 0 || val > 1 || |
769 | (val == 1 && val2 != 0)) |
770 | return -EINVAL; |
771 | data->emissivity = val * 1000 + val2 / 1000; |
772 | return 0; |
773 | case IIO_CHAN_INFO_SAMP_FREQ: |
774 | for (i = 0; i < ARRAY_SIZE(mlx90635_freqs); i++) { |
775 | if (val == mlx90635_freqs[i].val && |
776 | val2 == mlx90635_freqs[i].val2) |
777 | break; |
778 | } |
779 | if (i == ARRAY_SIZE(mlx90635_freqs)) |
780 | return -EINVAL; |
781 | |
782 | ret = regmap_write_bits(map: data->regmap, MLX90635_REG_CTRL1, |
783 | MLX90635_CTRL1_REFRESH_RATE_MASK, val: i); |
784 | |
785 | return ret; |
786 | default: |
787 | return -EINVAL; |
788 | } |
789 | } |
790 | |
791 | static int mlx90635_read_avail(struct iio_dev *indio_dev, |
792 | struct iio_chan_spec const *chan, |
793 | const int **vals, int *type, int *length, |
794 | long mask) |
795 | { |
796 | switch (mask) { |
797 | case IIO_CHAN_INFO_SAMP_FREQ: |
798 | *vals = (int *)mlx90635_freqs; |
799 | *type = IIO_VAL_INT_PLUS_MICRO; |
800 | *length = 2 * ARRAY_SIZE(mlx90635_freqs); |
801 | return IIO_AVAIL_LIST; |
802 | default: |
803 | return -EINVAL; |
804 | } |
805 | } |
806 | |
807 | static const struct iio_chan_spec mlx90635_channels[] = { |
808 | { |
809 | .type = IIO_TEMP, |
810 | .modified = 1, |
811 | .channel2 = IIO_MOD_TEMP_AMBIENT, |
812 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), |
813 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
814 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
815 | }, |
816 | { |
817 | .type = IIO_TEMP, |
818 | .modified = 1, |
819 | .channel2 = IIO_MOD_TEMP_OBJECT, |
820 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | |
821 | BIT(IIO_CHAN_INFO_CALIBEMISSIVITY), |
822 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
823 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
824 | }, |
825 | }; |
826 | |
827 | static const struct iio_info mlx90635_info = { |
828 | .read_raw = mlx90635_read_raw, |
829 | .write_raw = mlx90635_write_raw, |
830 | .read_avail = mlx90635_read_avail, |
831 | }; |
832 | |
833 | static void mlx90635_sleep(void *_data) |
834 | { |
835 | struct mlx90635_data *data = _data; |
836 | |
837 | mlx90635_pwr_sleep_step(data); |
838 | } |
839 | |
840 | static int mlx90635_suspend(struct mlx90635_data *data) |
841 | { |
842 | return mlx90635_pwr_sleep_step(data); |
843 | } |
844 | |
845 | static int mlx90635_wakeup(struct mlx90635_data *data) |
846 | { |
847 | s16 Fb, Ga, Gb, Ha, Hb, PG, PO; |
848 | unsigned int dsp_version; |
849 | u32 Ea, Eb, Fa; |
850 | u16 Fa_scale; |
851 | int ret; |
852 | |
853 | regcache_cache_bypass(map: data->regmap_ee, enable: false); |
854 | regcache_cache_only(map: data->regmap_ee, enable: false); |
855 | regcache_cache_only(map: data->regmap, enable: false); |
856 | |
857 | ret = mlx90635_pwr_continuous(data); |
858 | if (ret < 0) { |
859 | dev_err(&data->client->dev, "Switch to continuous mode failed\n" ); |
860 | return ret; |
861 | } |
862 | ret = regmap_write_bits(map: data->regmap, MLX90635_REG_EE, |
863 | MLX90635_EE_ACTIVE, MLX90635_EE_ACTIVE); |
864 | if (ret < 0) { |
865 | dev_err(&data->client->dev, "Powering EEPROM failed\n" ); |
866 | return ret; |
867 | } |
868 | usleep_range(MLX90635_TIMING_EE_ACTIVE_MIN, MLX90635_TIMING_EE_ACTIVE_MAX); |
869 | |
870 | regcache_mark_dirty(map: data->regmap_ee); |
871 | |
872 | ret = regcache_sync(map: data->regmap_ee); |
873 | if (ret < 0) { |
874 | dev_err(&data->client->dev, |
875 | "Failed to sync cache: %d\n" , ret); |
876 | return ret; |
877 | } |
878 | |
879 | ret = mlx90635_read_ee_ambient(regmap: data->regmap_ee, PG: &PG, PO: &PO, Gb: &Gb); |
880 | if (ret < 0) { |
881 | dev_err(&data->client->dev, |
882 | "Failed to read to cache Ambient coefficients EEPROM region: %d\n" , ret); |
883 | return ret; |
884 | } |
885 | |
886 | ret = mlx90635_read_ee_object(regmap: data->regmap_ee, Ea: &Ea, Eb: &Eb, Fa: &Fa, Fb: &Fb, Ga: &Ga, Gb: &Gb, Ha: &Ha, Hb: &Hb, Fa_scale: &Fa_scale); |
887 | if (ret < 0) { |
888 | dev_err(&data->client->dev, |
889 | "Failed to read to cache Object coefficients EEPROM region: %d\n" , ret); |
890 | return ret; |
891 | } |
892 | |
893 | ret = regmap_read(map: data->regmap_ee, MLX90635_EE_VERSION, val: &dsp_version); |
894 | if (ret < 0) { |
895 | dev_err(&data->client->dev, |
896 | "Failed to read to cache of EEPROM version: %d\n" , ret); |
897 | return ret; |
898 | } |
899 | |
900 | regcache_cache_only(map: data->regmap_ee, enable: true); |
901 | |
902 | return ret; |
903 | } |
904 | |
905 | static void mlx90635_disable_regulator(void *_data) |
906 | { |
907 | struct mlx90635_data *data = _data; |
908 | int ret; |
909 | |
910 | ret = regulator_disable(regulator: data->regulator); |
911 | if (ret < 0) |
912 | dev_err(regmap_get_device(data->regmap), |
913 | "Failed to disable power regulator: %d\n" , ret); |
914 | } |
915 | |
916 | static int mlx90635_enable_regulator(struct mlx90635_data *data) |
917 | { |
918 | int ret; |
919 | |
920 | ret = regulator_enable(regulator: data->regulator); |
921 | if (ret < 0) { |
922 | dev_err(regmap_get_device(data->regmap), "Failed to enable power regulator!\n" ); |
923 | return ret; |
924 | } |
925 | |
926 | mlx90635_reset_delay(); |
927 | |
928 | return ret; |
929 | } |
930 | |
931 | static int mlx90635_probe(struct i2c_client *client) |
932 | { |
933 | struct mlx90635_data *mlx90635; |
934 | struct iio_dev *indio_dev; |
935 | unsigned int dsp_version; |
936 | struct regmap *regmap; |
937 | struct regmap *regmap_ee; |
938 | int ret; |
939 | |
940 | indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*mlx90635)); |
941 | if (!indio_dev) |
942 | return dev_err_probe(dev: &client->dev, err: -ENOMEM, fmt: "failed to allocate device\n" ); |
943 | |
944 | regmap = devm_regmap_init_i2c(client, &mlx90635_regmap); |
945 | if (IS_ERR(ptr: regmap)) |
946 | return dev_err_probe(dev: &client->dev, err: PTR_ERR(ptr: regmap), |
947 | fmt: "failed to allocate regmap\n" ); |
948 | |
949 | regmap_ee = devm_regmap_init_i2c(client, &mlx90635_regmap_ee); |
950 | if (IS_ERR(ptr: regmap)) |
951 | return dev_err_probe(dev: &client->dev, err: PTR_ERR(ptr: regmap), |
952 | fmt: "failed to allocate regmap\n" ); |
953 | |
954 | mlx90635 = iio_priv(indio_dev); |
955 | i2c_set_clientdata(client, data: indio_dev); |
956 | mlx90635->client = client; |
957 | mlx90635->regmap = regmap; |
958 | mlx90635->regmap_ee = regmap_ee; |
959 | mlx90635->powerstatus = MLX90635_PWR_STATUS_SLEEP_STEP; |
960 | |
961 | mutex_init(&mlx90635->lock); |
962 | indio_dev->name = "mlx90635" ; |
963 | indio_dev->modes = INDIO_DIRECT_MODE; |
964 | indio_dev->info = &mlx90635_info; |
965 | indio_dev->channels = mlx90635_channels; |
966 | indio_dev->num_channels = ARRAY_SIZE(mlx90635_channels); |
967 | |
968 | mlx90635->regulator = devm_regulator_get(dev: &client->dev, id: "vdd" ); |
969 | if (IS_ERR(ptr: mlx90635->regulator)) |
970 | return dev_err_probe(dev: &client->dev, err: PTR_ERR(ptr: mlx90635->regulator), |
971 | fmt: "failed to get vdd regulator" ); |
972 | |
973 | ret = mlx90635_enable_regulator(data: mlx90635); |
974 | if (ret < 0) |
975 | return ret; |
976 | |
977 | ret = devm_add_action_or_reset(&client->dev, mlx90635_disable_regulator, |
978 | mlx90635); |
979 | if (ret < 0) |
980 | return dev_err_probe(dev: &client->dev, err: ret, |
981 | fmt: "failed to setup regulator cleanup action\n" ); |
982 | |
983 | ret = mlx90635_wakeup(data: mlx90635); |
984 | if (ret < 0) |
985 | return dev_err_probe(dev: &client->dev, err: ret, fmt: "wakeup failed\n" ); |
986 | |
987 | ret = devm_add_action_or_reset(&client->dev, mlx90635_sleep, mlx90635); |
988 | if (ret < 0) |
989 | return dev_err_probe(dev: &client->dev, err: ret, |
990 | fmt: "failed to setup low power cleanup\n" ); |
991 | |
992 | ret = regmap_read(map: mlx90635->regmap_ee, MLX90635_EE_VERSION, val: &dsp_version); |
993 | if (ret < 0) |
994 | return dev_err_probe(dev: &client->dev, err: ret, fmt: "read of version failed\n" ); |
995 | |
996 | dsp_version = dsp_version & MLX90635_VERSION_MASK; |
997 | |
998 | if (FIELD_GET(MLX90635_DSP_FIXED, dsp_version)) { |
999 | if (MLX90635_DSP_VERSION(dsp_version) == MLX90635_ID_DSPv1) { |
1000 | dev_dbg(&client->dev, |
1001 | "Detected DSP v1 calibration %x\n" , dsp_version); |
1002 | } else { |
1003 | dev_dbg(&client->dev, |
1004 | "Detected Unknown EEPROM calibration %lx\n" , |
1005 | MLX90635_DSP_VERSION(dsp_version)); |
1006 | } |
1007 | } else { |
1008 | return dev_err_probe(dev: &client->dev, err: -EPROTONOSUPPORT, |
1009 | fmt: "Wrong fixed top bit %x (expected 0x8X0X)\n" , |
1010 | dsp_version); |
1011 | } |
1012 | |
1013 | mlx90635->emissivity = 1000; |
1014 | mlx90635->interaction_ts = jiffies; /* Set initial value */ |
1015 | |
1016 | pm_runtime_get_noresume(dev: &client->dev); |
1017 | pm_runtime_set_active(dev: &client->dev); |
1018 | |
1019 | ret = devm_pm_runtime_enable(dev: &client->dev); |
1020 | if (ret) |
1021 | return dev_err_probe(dev: &client->dev, err: ret, |
1022 | fmt: "failed to enable powermanagement\n" ); |
1023 | |
1024 | pm_runtime_set_autosuspend_delay(dev: &client->dev, MLX90635_SLEEP_DELAY_MS); |
1025 | pm_runtime_use_autosuspend(dev: &client->dev); |
1026 | pm_runtime_put_autosuspend(dev: &client->dev); |
1027 | |
1028 | return devm_iio_device_register(&client->dev, indio_dev); |
1029 | } |
1030 | |
1031 | static const struct i2c_device_id mlx90635_id[] = { |
1032 | { "mlx90635" }, |
1033 | { } |
1034 | }; |
1035 | MODULE_DEVICE_TABLE(i2c, mlx90635_id); |
1036 | |
1037 | static const struct of_device_id mlx90635_of_match[] = { |
1038 | { .compatible = "melexis,mlx90635" }, |
1039 | { } |
1040 | }; |
1041 | MODULE_DEVICE_TABLE(of, mlx90635_of_match); |
1042 | |
1043 | static int mlx90635_pm_suspend(struct device *dev) |
1044 | { |
1045 | struct mlx90635_data *data = iio_priv(indio_dev: dev_get_drvdata(dev)); |
1046 | int ret; |
1047 | |
1048 | ret = mlx90635_suspend(data); |
1049 | if (ret < 0) |
1050 | return ret; |
1051 | |
1052 | ret = regulator_disable(regulator: data->regulator); |
1053 | if (ret < 0) |
1054 | dev_err(regmap_get_device(data->regmap), |
1055 | "Failed to disable power regulator: %d\n" , ret); |
1056 | |
1057 | return ret; |
1058 | } |
1059 | |
1060 | static int mlx90635_pm_resume(struct device *dev) |
1061 | { |
1062 | struct mlx90635_data *data = iio_priv(indio_dev: dev_get_drvdata(dev)); |
1063 | int ret; |
1064 | |
1065 | ret = mlx90635_enable_regulator(data); |
1066 | if (ret < 0) |
1067 | return ret; |
1068 | |
1069 | return mlx90635_wakeup(data); |
1070 | } |
1071 | |
1072 | static int mlx90635_pm_runtime_suspend(struct device *dev) |
1073 | { |
1074 | struct mlx90635_data *data = iio_priv(indio_dev: dev_get_drvdata(dev)); |
1075 | |
1076 | return mlx90635_pwr_sleep_step(data); |
1077 | } |
1078 | |
1079 | static const struct dev_pm_ops mlx90635_pm_ops = { |
1080 | SYSTEM_SLEEP_PM_OPS(mlx90635_pm_suspend, mlx90635_pm_resume) |
1081 | RUNTIME_PM_OPS(mlx90635_pm_runtime_suspend, NULL, NULL) |
1082 | }; |
1083 | |
1084 | static struct i2c_driver mlx90635_driver = { |
1085 | .driver = { |
1086 | .name = "mlx90635" , |
1087 | .of_match_table = mlx90635_of_match, |
1088 | .pm = pm_ptr(&mlx90635_pm_ops), |
1089 | }, |
1090 | .probe = mlx90635_probe, |
1091 | .id_table = mlx90635_id, |
1092 | }; |
1093 | module_i2c_driver(mlx90635_driver); |
1094 | |
1095 | MODULE_AUTHOR("Crt Mori <cmo@melexis.com>" ); |
1096 | MODULE_DESCRIPTION("Melexis MLX90635 contactless Infra Red temperature sensor driver" ); |
1097 | MODULE_LICENSE("GPL" ); |
1098 | |