1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * mlx90632.c - Melexis MLX90632 contactless IR temperature sensor |
4 | * |
5 | * Copyright (c) 2017 Melexis <cmo@melexis.com> |
6 | * |
7 | * Driver for the Melexis MLX90632 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 | #include <linux/iio/sysfs.h> |
28 | |
29 | /* Memory sections addresses */ |
30 | #define MLX90632_ADDR_RAM 0x4000 /* Start address of ram */ |
31 | #define MLX90632_ADDR_EEPROM 0x2480 /* Start address of user eeprom */ |
32 | |
33 | /* EEPROM addresses - used at startup */ |
34 | #define MLX90632_EE_CTRL 0x24d4 /* Control register initial value */ |
35 | #define MLX90632_EE_I2C_ADDR 0x24d5 /* I2C address register initial value */ |
36 | #define MLX90632_EE_VERSION 0x240b /* EEPROM version reg address */ |
37 | #define MLX90632_EE_P_R 0x240c /* P_R calibration register 32bit */ |
38 | #define MLX90632_EE_P_G 0x240e /* P_G calibration register 32bit */ |
39 | #define MLX90632_EE_P_T 0x2410 /* P_T calibration register 32bit */ |
40 | #define MLX90632_EE_P_O 0x2412 /* P_O calibration register 32bit */ |
41 | #define MLX90632_EE_Aa 0x2414 /* Aa calibration register 32bit */ |
42 | #define MLX90632_EE_Ab 0x2416 /* Ab calibration register 32bit */ |
43 | #define MLX90632_EE_Ba 0x2418 /* Ba calibration register 32bit */ |
44 | #define MLX90632_EE_Bb 0x241a /* Bb calibration register 32bit */ |
45 | #define MLX90632_EE_Ca 0x241c /* Ca calibration register 32bit */ |
46 | #define MLX90632_EE_Cb 0x241e /* Cb calibration register 32bit */ |
47 | #define MLX90632_EE_Da 0x2420 /* Da calibration register 32bit */ |
48 | #define MLX90632_EE_Db 0x2422 /* Db calibration register 32bit */ |
49 | #define MLX90632_EE_Ea 0x2424 /* Ea calibration register 32bit */ |
50 | #define MLX90632_EE_Eb 0x2426 /* Eb calibration register 32bit */ |
51 | #define MLX90632_EE_Fa 0x2428 /* Fa calibration register 32bit */ |
52 | #define MLX90632_EE_Fb 0x242a /* Fb calibration register 32bit */ |
53 | #define MLX90632_EE_Ga 0x242c /* Ga calibration register 32bit */ |
54 | |
55 | #define MLX90632_EE_Gb 0x242e /* Gb calibration register 16bit */ |
56 | #define MLX90632_EE_Ka 0x242f /* Ka calibration register 16bit */ |
57 | |
58 | #define MLX90632_EE_Ha 0x2481 /* Ha customer calib value reg 16bit */ |
59 | #define MLX90632_EE_Hb 0x2482 /* Hb customer calib value reg 16bit */ |
60 | |
61 | #define MLX90632_EE_MEDICAL_MEAS1 0x24E1 /* Medical measurement 1 16bit */ |
62 | #define MLX90632_EE_MEDICAL_MEAS2 0x24E2 /* Medical measurement 2 16bit */ |
63 | #define MLX90632_EE_EXTENDED_MEAS1 0x24F1 /* Extended measurement 1 16bit */ |
64 | #define MLX90632_EE_EXTENDED_MEAS2 0x24F2 /* Extended measurement 2 16bit */ |
65 | #define MLX90632_EE_EXTENDED_MEAS3 0x24F3 /* Extended measurement 3 16bit */ |
66 | |
67 | /* Register addresses - volatile */ |
68 | #define MLX90632_REG_I2C_ADDR 0x3000 /* Chip I2C address register */ |
69 | |
70 | /* Control register address - volatile */ |
71 | #define MLX90632_REG_CONTROL 0x3001 /* Control Register address */ |
72 | #define MLX90632_CFG_PWR_MASK GENMASK(2, 1) /* PowerMode Mask */ |
73 | #define MLX90632_CFG_MTYP_MASK GENMASK(8, 4) /* Meas select Mask */ |
74 | #define MLX90632_CFG_SOB_MASK BIT(11) |
75 | |
76 | /* PowerModes statuses */ |
77 | #define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1) |
78 | #define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */ |
79 | #define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /* sleep step */ |
80 | #define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */ |
81 | #define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous */ |
82 | |
83 | #define MLX90632_EE_RR GENMASK(10, 8) /* Only Refresh Rate bits */ |
84 | #define MLX90632_REFRESH_RATE(ee_val) FIELD_GET(MLX90632_EE_RR, ee_val) |
85 | /* Extract Refresh Rate from ee register */ |
86 | #define MLX90632_REFRESH_RATE_STATUS(refresh_rate) (refresh_rate << 8) |
87 | |
88 | /* Measurement types */ |
89 | #define MLX90632_MTYP_MEDICAL 0 |
90 | #define MLX90632_MTYP_EXTENDED 17 |
91 | |
92 | /* Measurement type select*/ |
93 | #define MLX90632_MTYP_STATUS(ctrl_val) (ctrl_val << 4) |
94 | #define MLX90632_MTYP_STATUS_MEDICAL MLX90632_MTYP_STATUS(MLX90632_MTYP_MEDICAL) |
95 | #define MLX90632_MTYP_STATUS_EXTENDED MLX90632_MTYP_STATUS(MLX90632_MTYP_EXTENDED) |
96 | |
97 | /* I2C command register - volatile */ |
98 | #define MLX90632_REG_I2C_CMD 0x3005 /* I2C command Register address */ |
99 | |
100 | /* Device status register - volatile */ |
101 | #define MLX90632_REG_STATUS 0x3fff /* Device status register */ |
102 | #define MLX90632_STAT_BUSY BIT(10) /* Device busy indicator */ |
103 | #define MLX90632_STAT_EE_BUSY BIT(9) /* EEPROM busy indicator */ |
104 | #define MLX90632_STAT_BRST BIT(8) /* Brown out reset indicator */ |
105 | #define MLX90632_STAT_CYCLE_POS GENMASK(6, 2) /* Data position */ |
106 | #define MLX90632_STAT_DATA_RDY BIT(0) /* Data ready indicator */ |
107 | |
108 | /* RAM_MEAS address-es for each channel */ |
109 | #define MLX90632_RAM_1(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num) |
110 | #define MLX90632_RAM_2(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 1) |
111 | #define MLX90632_RAM_3(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 2) |
112 | |
113 | /* Name important RAM_MEAS channels */ |
114 | #define MLX90632_RAM_DSP5_EXTENDED_AMBIENT_1 MLX90632_RAM_3(17) |
115 | #define MLX90632_RAM_DSP5_EXTENDED_AMBIENT_2 MLX90632_RAM_3(18) |
116 | #define MLX90632_RAM_DSP5_EXTENDED_OBJECT_1 MLX90632_RAM_1(17) |
117 | #define MLX90632_RAM_DSP5_EXTENDED_OBJECT_2 MLX90632_RAM_2(17) |
118 | #define MLX90632_RAM_DSP5_EXTENDED_OBJECT_3 MLX90632_RAM_1(18) |
119 | #define MLX90632_RAM_DSP5_EXTENDED_OBJECT_4 MLX90632_RAM_2(18) |
120 | #define MLX90632_RAM_DSP5_EXTENDED_OBJECT_5 MLX90632_RAM_1(19) |
121 | #define MLX90632_RAM_DSP5_EXTENDED_OBJECT_6 MLX90632_RAM_2(19) |
122 | |
123 | /* Magic constants */ |
124 | #define MLX90632_ID_MEDICAL 0x0105 /* EEPROM DSPv5 Medical device id */ |
125 | #define MLX90632_ID_CONSUMER 0x0205 /* EEPROM DSPv5 Consumer device id */ |
126 | #define MLX90632_ID_EXTENDED 0x0505 /* EEPROM DSPv5 Extended range device id */ |
127 | #define MLX90632_ID_MASK GENMASK(14, 0) /* DSP version and device ID in EE_VERSION */ |
128 | #define MLX90632_DSP_VERSION 5 /* DSP version */ |
129 | #define MLX90632_DSP_MASK GENMASK(7, 0) /* DSP version in EE_VERSION */ |
130 | #define MLX90632_RESET_CMD 0x0006 /* Reset sensor (address or global) */ |
131 | #define MLX90632_REF_12 12LL /* ResCtrlRef value of Ch 1 or Ch 2 */ |
132 | #define MLX90632_REF_3 12LL /* ResCtrlRef value of Channel 3 */ |
133 | #define MLX90632_MAX_MEAS_NUM 31 /* Maximum measurements in list */ |
134 | #define MLX90632_SLEEP_DELAY_MS 6000 /* Autosleep delay */ |
135 | #define MLX90632_EXTENDED_LIMIT 27000 /* Extended mode raw value limit */ |
136 | #define MLX90632_MEAS_MAX_TIME 2000 /* Max measurement time in ms for the lowest refresh rate */ |
137 | |
138 | /** |
139 | * struct mlx90632_data - private data for the MLX90632 device |
140 | * @client: I2C client of the device |
141 | * @lock: Internal mutex for multiple reads for single measurement |
142 | * @regmap: Regmap of the device |
143 | * @emissivity: Object emissivity from 0 to 1000 where 1000 = 1. |
144 | * @mtyp: Measurement type physical sensor configuration for extended range |
145 | * calculations |
146 | * @object_ambient_temperature: Ambient temperature at object (might differ of |
147 | * the ambient temperature of sensor. |
148 | * @regulator: Regulator of the device |
149 | * @powerstatus: Current POWER status of the device |
150 | * @interaction_ts: Timestamp of the last temperature read that is used |
151 | * for power management in jiffies |
152 | */ |
153 | struct mlx90632_data { |
154 | struct i2c_client *client; |
155 | struct mutex lock; |
156 | struct regmap *regmap; |
157 | u16 emissivity; |
158 | u8 mtyp; |
159 | u32 object_ambient_temperature; |
160 | struct regulator *regulator; |
161 | int powerstatus; |
162 | unsigned long interaction_ts; |
163 | }; |
164 | |
165 | static const struct regmap_range mlx90632_volatile_reg_range[] = { |
166 | regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL), |
167 | regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD), |
168 | regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS), |
169 | regmap_reg_range(MLX90632_RAM_1(0), |
170 | MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)), |
171 | }; |
172 | |
173 | static const struct regmap_access_table mlx90632_volatile_regs_tbl = { |
174 | .yes_ranges = mlx90632_volatile_reg_range, |
175 | .n_yes_ranges = ARRAY_SIZE(mlx90632_volatile_reg_range), |
176 | }; |
177 | |
178 | static const struct regmap_range mlx90632_read_reg_range[] = { |
179 | regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka), |
180 | regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR), |
181 | regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb), |
182 | regmap_reg_range(MLX90632_EE_MEDICAL_MEAS1, MLX90632_EE_MEDICAL_MEAS2), |
183 | regmap_reg_range(MLX90632_EE_EXTENDED_MEAS1, MLX90632_EE_EXTENDED_MEAS3), |
184 | regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL), |
185 | regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD), |
186 | regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS), |
187 | regmap_reg_range(MLX90632_RAM_1(0), |
188 | MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)), |
189 | }; |
190 | |
191 | static const struct regmap_access_table mlx90632_readable_regs_tbl = { |
192 | .yes_ranges = mlx90632_read_reg_range, |
193 | .n_yes_ranges = ARRAY_SIZE(mlx90632_read_reg_range), |
194 | }; |
195 | |
196 | static const struct regmap_range mlx90632_no_write_reg_range[] = { |
197 | regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka), |
198 | regmap_reg_range(MLX90632_RAM_1(0), |
199 | MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)), |
200 | }; |
201 | |
202 | static const struct regmap_access_table mlx90632_writeable_regs_tbl = { |
203 | .no_ranges = mlx90632_no_write_reg_range, |
204 | .n_no_ranges = ARRAY_SIZE(mlx90632_no_write_reg_range), |
205 | }; |
206 | |
207 | static const struct regmap_config mlx90632_regmap = { |
208 | .reg_bits = 16, |
209 | .val_bits = 16, |
210 | |
211 | .volatile_table = &mlx90632_volatile_regs_tbl, |
212 | .rd_table = &mlx90632_readable_regs_tbl, |
213 | .wr_table = &mlx90632_writeable_regs_tbl, |
214 | |
215 | .use_single_read = true, |
216 | .use_single_write = true, |
217 | .reg_format_endian = REGMAP_ENDIAN_BIG, |
218 | .val_format_endian = REGMAP_ENDIAN_BIG, |
219 | .cache_type = REGCACHE_RBTREE, |
220 | }; |
221 | |
222 | static int mlx90632_pwr_set_sleep_step(struct regmap *regmap) |
223 | { |
224 | struct mlx90632_data *data = |
225 | iio_priv(indio_dev: dev_get_drvdata(dev: regmap_get_device(map: regmap))); |
226 | int ret; |
227 | |
228 | if (data->powerstatus == MLX90632_PWR_STATUS_SLEEP_STEP) |
229 | return 0; |
230 | |
231 | ret = regmap_write_bits(map: regmap, MLX90632_REG_CONTROL, MLX90632_CFG_PWR_MASK, |
232 | MLX90632_PWR_STATUS_SLEEP_STEP); |
233 | if (ret < 0) |
234 | return ret; |
235 | |
236 | data->powerstatus = MLX90632_PWR_STATUS_SLEEP_STEP; |
237 | return 0; |
238 | } |
239 | |
240 | static int mlx90632_pwr_continuous(struct regmap *regmap) |
241 | { |
242 | struct mlx90632_data *data = |
243 | iio_priv(indio_dev: dev_get_drvdata(dev: regmap_get_device(map: regmap))); |
244 | int ret; |
245 | |
246 | if (data->powerstatus == MLX90632_PWR_STATUS_CONTINUOUS) |
247 | return 0; |
248 | |
249 | ret = regmap_write_bits(map: regmap, MLX90632_REG_CONTROL, MLX90632_CFG_PWR_MASK, |
250 | MLX90632_PWR_STATUS_CONTINUOUS); |
251 | if (ret < 0) |
252 | return ret; |
253 | |
254 | data->powerstatus = MLX90632_PWR_STATUS_CONTINUOUS; |
255 | return 0; |
256 | } |
257 | |
258 | /** |
259 | * mlx90632_reset_delay() - Give the mlx90632 some time to reset properly |
260 | * If this is not done, the following I2C command(s) will not be accepted. |
261 | */ |
262 | static void mlx90632_reset_delay(void) |
263 | { |
264 | usleep_range(min: 150, max: 200); |
265 | } |
266 | |
267 | static int mlx90632_get_measurement_time(struct regmap *regmap, u16 meas) |
268 | { |
269 | unsigned int reg; |
270 | int ret; |
271 | |
272 | ret = regmap_read(map: regmap, reg: meas, val: ®); |
273 | if (ret < 0) |
274 | return ret; |
275 | |
276 | return MLX90632_MEAS_MAX_TIME >> FIELD_GET(MLX90632_EE_RR, reg); |
277 | } |
278 | |
279 | static int mlx90632_calculate_dataset_ready_time(struct mlx90632_data *data) |
280 | { |
281 | unsigned int refresh_time; |
282 | int ret; |
283 | |
284 | if (data->mtyp == MLX90632_MTYP_MEDICAL) { |
285 | ret = mlx90632_get_measurement_time(regmap: data->regmap, |
286 | MLX90632_EE_MEDICAL_MEAS1); |
287 | if (ret < 0) |
288 | return ret; |
289 | |
290 | refresh_time = ret; |
291 | |
292 | ret = mlx90632_get_measurement_time(regmap: data->regmap, |
293 | MLX90632_EE_MEDICAL_MEAS2); |
294 | if (ret < 0) |
295 | return ret; |
296 | |
297 | refresh_time += ret; |
298 | } else { |
299 | ret = mlx90632_get_measurement_time(regmap: data->regmap, |
300 | MLX90632_EE_EXTENDED_MEAS1); |
301 | if (ret < 0) |
302 | return ret; |
303 | |
304 | refresh_time = ret; |
305 | |
306 | ret = mlx90632_get_measurement_time(regmap: data->regmap, |
307 | MLX90632_EE_EXTENDED_MEAS2); |
308 | if (ret < 0) |
309 | return ret; |
310 | |
311 | refresh_time += ret; |
312 | |
313 | ret = mlx90632_get_measurement_time(regmap: data->regmap, |
314 | MLX90632_EE_EXTENDED_MEAS3); |
315 | if (ret < 0) |
316 | return ret; |
317 | |
318 | refresh_time += ret; |
319 | } |
320 | |
321 | return refresh_time; |
322 | } |
323 | |
324 | /** |
325 | * mlx90632_perform_measurement() - Trigger and retrieve current measurement cycle |
326 | * @data: pointer to mlx90632_data object containing regmap information |
327 | * |
328 | * Perform a measurement and return latest measurement cycle position reported |
329 | * by sensor. This is a blocking function for 500ms, as that is default sensor |
330 | * refresh rate. |
331 | */ |
332 | static int mlx90632_perform_measurement(struct mlx90632_data *data) |
333 | { |
334 | unsigned int reg_status; |
335 | int ret; |
336 | |
337 | ret = regmap_update_bits(map: data->regmap, MLX90632_REG_STATUS, |
338 | MLX90632_STAT_DATA_RDY, val: 0); |
339 | if (ret < 0) |
340 | return ret; |
341 | |
342 | ret = regmap_read_poll_timeout(data->regmap, MLX90632_REG_STATUS, reg_status, |
343 | !(reg_status & MLX90632_STAT_DATA_RDY), 10000, |
344 | 100 * 10000); |
345 | |
346 | if (ret < 0) { |
347 | dev_err(&data->client->dev, "data not ready" ); |
348 | return -ETIMEDOUT; |
349 | } |
350 | |
351 | return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2; |
352 | } |
353 | |
354 | /** |
355 | * mlx90632_perform_measurement_burst() - Trigger and retrieve current measurement |
356 | * cycle in step sleep mode |
357 | * @data: pointer to mlx90632_data object containing regmap information |
358 | * |
359 | * Perform a measurement and return 2 as measurement cycle position reported |
360 | * by sensor. This is a blocking function for amount dependent on the sensor |
361 | * refresh rate. |
362 | */ |
363 | static int mlx90632_perform_measurement_burst(struct mlx90632_data *data) |
364 | { |
365 | unsigned int reg_status; |
366 | int ret; |
367 | |
368 | ret = regmap_write_bits(map: data->regmap, MLX90632_REG_CONTROL, |
369 | MLX90632_CFG_SOB_MASK, MLX90632_CFG_SOB_MASK); |
370 | if (ret < 0) |
371 | return ret; |
372 | |
373 | ret = mlx90632_calculate_dataset_ready_time(data); |
374 | if (ret < 0) |
375 | return ret; |
376 | |
377 | msleep(msecs: ret); /* Wait minimum time for dataset to be ready */ |
378 | |
379 | ret = regmap_read_poll_timeout(data->regmap, MLX90632_REG_STATUS, |
380 | reg_status, |
381 | (reg_status & MLX90632_STAT_BUSY) == 0, |
382 | 10000, 100 * 10000); |
383 | if (ret < 0) { |
384 | dev_err(&data->client->dev, "data not ready" ); |
385 | return -ETIMEDOUT; |
386 | } |
387 | |
388 | return 2; |
389 | } |
390 | |
391 | static int mlx90632_set_meas_type(struct mlx90632_data *data, u8 type) |
392 | { |
393 | int current_powerstatus; |
394 | int ret; |
395 | |
396 | if (data->mtyp == type) |
397 | return 0; |
398 | |
399 | current_powerstatus = data->powerstatus; |
400 | ret = mlx90632_pwr_continuous(regmap: data->regmap); |
401 | if (ret < 0) |
402 | return ret; |
403 | |
404 | ret = regmap_write(map: data->regmap, MLX90632_REG_I2C_CMD, MLX90632_RESET_CMD); |
405 | if (ret < 0) |
406 | return ret; |
407 | |
408 | mlx90632_reset_delay(); |
409 | |
410 | ret = regmap_update_bits(map: data->regmap, MLX90632_REG_CONTROL, |
411 | mask: (MLX90632_CFG_MTYP_MASK | MLX90632_CFG_PWR_MASK), |
412 | val: (MLX90632_MTYP_STATUS(type) | MLX90632_PWR_STATUS_HALT)); |
413 | if (ret < 0) |
414 | return ret; |
415 | |
416 | data->mtyp = type; |
417 | data->powerstatus = MLX90632_PWR_STATUS_HALT; |
418 | |
419 | if (current_powerstatus == MLX90632_PWR_STATUS_SLEEP_STEP) |
420 | return mlx90632_pwr_set_sleep_step(regmap: data->regmap); |
421 | |
422 | return mlx90632_pwr_continuous(regmap: data->regmap); |
423 | } |
424 | |
425 | static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new, |
426 | uint8_t *channel_old) |
427 | { |
428 | switch (perform_ret) { |
429 | case 1: |
430 | *channel_new = 1; |
431 | *channel_old = 2; |
432 | break; |
433 | case 2: |
434 | *channel_new = 2; |
435 | *channel_old = 1; |
436 | break; |
437 | default: |
438 | return -ECHRNG; |
439 | } |
440 | |
441 | return 0; |
442 | } |
443 | |
444 | static int mlx90632_read_ambient_raw(struct regmap *regmap, |
445 | s16 *ambient_new_raw, s16 *ambient_old_raw) |
446 | { |
447 | unsigned int read_tmp; |
448 | int ret; |
449 | |
450 | ret = regmap_read(map: regmap, MLX90632_RAM_3(1), val: &read_tmp); |
451 | if (ret < 0) |
452 | return ret; |
453 | *ambient_new_raw = (s16)read_tmp; |
454 | |
455 | ret = regmap_read(map: regmap, MLX90632_RAM_3(2), val: &read_tmp); |
456 | if (ret < 0) |
457 | return ret; |
458 | *ambient_old_raw = (s16)read_tmp; |
459 | |
460 | return ret; |
461 | } |
462 | |
463 | static int mlx90632_read_object_raw(struct regmap *regmap, |
464 | int perform_measurement_ret, |
465 | s16 *object_new_raw, s16 *object_old_raw) |
466 | { |
467 | unsigned int read_tmp; |
468 | u8 channel_old = 0; |
469 | u8 channel = 0; |
470 | s16 read; |
471 | int ret; |
472 | |
473 | ret = mlx90632_channel_new_select(perform_ret: perform_measurement_ret, channel_new: &channel, |
474 | channel_old: &channel_old); |
475 | if (ret != 0) |
476 | return ret; |
477 | |
478 | ret = regmap_read(map: regmap, MLX90632_RAM_2(channel), val: &read_tmp); |
479 | if (ret < 0) |
480 | return ret; |
481 | |
482 | read = (s16)read_tmp; |
483 | |
484 | ret = regmap_read(map: regmap, MLX90632_RAM_1(channel), val: &read_tmp); |
485 | if (ret < 0) |
486 | return ret; |
487 | *object_new_raw = (read + (s16)read_tmp) / 2; |
488 | |
489 | ret = regmap_read(map: regmap, MLX90632_RAM_2(channel_old), val: &read_tmp); |
490 | if (ret < 0) |
491 | return ret; |
492 | read = (s16)read_tmp; |
493 | |
494 | ret = regmap_read(map: regmap, MLX90632_RAM_1(channel_old), val: &read_tmp); |
495 | if (ret < 0) |
496 | return ret; |
497 | *object_old_raw = (read + (s16)read_tmp) / 2; |
498 | |
499 | return ret; |
500 | } |
501 | |
502 | static int mlx90632_read_all_channel(struct mlx90632_data *data, |
503 | s16 *ambient_new_raw, s16 *ambient_old_raw, |
504 | s16 *object_new_raw, s16 *object_old_raw) |
505 | { |
506 | s32 measurement; |
507 | int ret; |
508 | |
509 | mutex_lock(&data->lock); |
510 | ret = mlx90632_set_meas_type(data, MLX90632_MTYP_MEDICAL); |
511 | if (ret < 0) |
512 | goto read_unlock; |
513 | |
514 | switch (data->powerstatus) { |
515 | case MLX90632_PWR_STATUS_CONTINUOUS: |
516 | ret = mlx90632_perform_measurement(data); |
517 | if (ret < 0) |
518 | goto read_unlock; |
519 | |
520 | break; |
521 | case MLX90632_PWR_STATUS_SLEEP_STEP: |
522 | ret = mlx90632_perform_measurement_burst(data); |
523 | if (ret < 0) |
524 | goto read_unlock; |
525 | |
526 | break; |
527 | default: |
528 | ret = -EOPNOTSUPP; |
529 | goto read_unlock; |
530 | } |
531 | |
532 | measurement = ret; /* If we came here ret holds the measurement position */ |
533 | |
534 | ret = mlx90632_read_ambient_raw(regmap: data->regmap, ambient_new_raw, |
535 | ambient_old_raw); |
536 | if (ret < 0) |
537 | goto read_unlock; |
538 | |
539 | ret = mlx90632_read_object_raw(regmap: data->regmap, perform_measurement_ret: measurement, |
540 | object_new_raw, object_old_raw); |
541 | read_unlock: |
542 | mutex_unlock(lock: &data->lock); |
543 | return ret; |
544 | } |
545 | |
546 | static int mlx90632_read_ambient_raw_extended(struct regmap *regmap, |
547 | s16 *ambient_new_raw, s16 *ambient_old_raw) |
548 | { |
549 | unsigned int read_tmp; |
550 | int ret; |
551 | |
552 | ret = regmap_read(map: regmap, MLX90632_RAM_DSP5_EXTENDED_AMBIENT_1, val: &read_tmp); |
553 | if (ret < 0) |
554 | return ret; |
555 | *ambient_new_raw = (s16)read_tmp; |
556 | |
557 | ret = regmap_read(map: regmap, MLX90632_RAM_DSP5_EXTENDED_AMBIENT_2, val: &read_tmp); |
558 | if (ret < 0) |
559 | return ret; |
560 | *ambient_old_raw = (s16)read_tmp; |
561 | |
562 | return 0; |
563 | } |
564 | |
565 | static int mlx90632_read_object_raw_extended(struct regmap *regmap, s16 *object_new_raw) |
566 | { |
567 | unsigned int read_tmp; |
568 | s32 read; |
569 | int ret; |
570 | |
571 | ret = regmap_read(map: regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_1, val: &read_tmp); |
572 | if (ret < 0) |
573 | return ret; |
574 | read = (s16)read_tmp; |
575 | |
576 | ret = regmap_read(map: regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_2, val: &read_tmp); |
577 | if (ret < 0) |
578 | return ret; |
579 | read = read - (s16)read_tmp; |
580 | |
581 | ret = regmap_read(map: regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_3, val: &read_tmp); |
582 | if (ret < 0) |
583 | return ret; |
584 | read = read - (s16)read_tmp; |
585 | |
586 | ret = regmap_read(map: regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_4, val: &read_tmp); |
587 | if (ret < 0) |
588 | return ret; |
589 | read = (read + (s16)read_tmp) / 2; |
590 | |
591 | ret = regmap_read(map: regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_5, val: &read_tmp); |
592 | if (ret < 0) |
593 | return ret; |
594 | read = read + (s16)read_tmp; |
595 | |
596 | ret = regmap_read(map: regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_6, val: &read_tmp); |
597 | if (ret < 0) |
598 | return ret; |
599 | read = read + (s16)read_tmp; |
600 | |
601 | if (read > S16_MAX || read < S16_MIN) |
602 | return -ERANGE; |
603 | |
604 | *object_new_raw = read; |
605 | |
606 | return 0; |
607 | } |
608 | |
609 | static int mlx90632_read_all_channel_extended(struct mlx90632_data *data, s16 *object_new_raw, |
610 | s16 *ambient_new_raw, s16 *ambient_old_raw) |
611 | { |
612 | s32 ret, meas; |
613 | |
614 | mutex_lock(&data->lock); |
615 | ret = mlx90632_set_meas_type(data, MLX90632_MTYP_EXTENDED); |
616 | if (ret < 0) |
617 | goto read_unlock; |
618 | |
619 | switch (data->powerstatus) { |
620 | case MLX90632_PWR_STATUS_CONTINUOUS: |
621 | ret = read_poll_timeout(mlx90632_perform_measurement, meas, meas == 19, |
622 | 50000, 800000, false, data); |
623 | if (ret) |
624 | goto read_unlock; |
625 | break; |
626 | case MLX90632_PWR_STATUS_SLEEP_STEP: |
627 | ret = mlx90632_perform_measurement_burst(data); |
628 | if (ret < 0) |
629 | goto read_unlock; |
630 | break; |
631 | default: |
632 | ret = -EOPNOTSUPP; |
633 | goto read_unlock; |
634 | } |
635 | |
636 | ret = mlx90632_read_object_raw_extended(regmap: data->regmap, object_new_raw); |
637 | if (ret < 0) |
638 | goto read_unlock; |
639 | |
640 | ret = mlx90632_read_ambient_raw_extended(regmap: data->regmap, ambient_new_raw, ambient_old_raw); |
641 | |
642 | read_unlock: |
643 | mutex_unlock(lock: &data->lock); |
644 | return ret; |
645 | } |
646 | |
647 | static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb, |
648 | s32 *reg_value) |
649 | { |
650 | unsigned int read; |
651 | u32 value; |
652 | int ret; |
653 | |
654 | ret = regmap_read(map: regmap, reg: reg_lsb, val: &read); |
655 | if (ret < 0) |
656 | return ret; |
657 | |
658 | value = read; |
659 | |
660 | ret = regmap_read(map: regmap, reg: reg_lsb + 1, val: &read); |
661 | if (ret < 0) |
662 | return ret; |
663 | |
664 | *reg_value = (read << 16) | (value & 0xffff); |
665 | |
666 | return 0; |
667 | } |
668 | |
669 | static s64 mlx90632_preprocess_temp_amb(s16 ambient_new_raw, |
670 | s16 ambient_old_raw, s16 Gb) |
671 | { |
672 | s64 VR_Ta, kGb, tmp; |
673 | |
674 | kGb = ((s64)Gb * 1000LL) >> 10ULL; |
675 | VR_Ta = (s64)ambient_old_raw * 1000000LL + |
676 | kGb * div64_s64(dividend: ((s64)ambient_new_raw * 1000LL), |
677 | divisor: (MLX90632_REF_3)); |
678 | tmp = div64_s64( |
679 | dividend: div64_s64(dividend: ((s64)ambient_new_raw * 1000000000000LL), |
680 | divisor: (MLX90632_REF_3)), divisor: VR_Ta); |
681 | return div64_s64(dividend: tmp << 19ULL, divisor: 1000LL); |
682 | } |
683 | |
684 | static s64 mlx90632_preprocess_temp_obj(s16 object_new_raw, s16 object_old_raw, |
685 | s16 ambient_new_raw, |
686 | s16 ambient_old_raw, s16 Ka) |
687 | { |
688 | s64 VR_IR, kKa, tmp; |
689 | |
690 | kKa = ((s64)Ka * 1000LL) >> 10ULL; |
691 | VR_IR = (s64)ambient_old_raw * 1000000LL + |
692 | kKa * div64_s64(dividend: ((s64)ambient_new_raw * 1000LL), |
693 | divisor: (MLX90632_REF_3)); |
694 | tmp = div64_s64( |
695 | dividend: div64_s64(dividend: ((s64)((object_new_raw + object_old_raw) / 2) |
696 | * 1000000000000LL), divisor: (MLX90632_REF_12)), |
697 | divisor: VR_IR); |
698 | return div64_s64(dividend: (tmp << 19ULL), divisor: 1000LL); |
699 | } |
700 | |
701 | static s64 mlx90632_preprocess_temp_obj_extended(s16 object_new_raw, s16 ambient_new_raw, |
702 | s16 ambient_old_raw, s16 Ka) |
703 | { |
704 | s64 VR_IR, kKa, tmp; |
705 | |
706 | kKa = ((s64)Ka * 1000LL) >> 10ULL; |
707 | VR_IR = (s64)ambient_old_raw * 1000000LL + |
708 | kKa * div64_s64(dividend: (s64)ambient_new_raw * 1000LL, |
709 | MLX90632_REF_3); |
710 | tmp = div64_s64( |
711 | dividend: div64_s64(dividend: (s64) object_new_raw * 1000000000000LL, MLX90632_REF_12), |
712 | divisor: VR_IR); |
713 | return div64_s64(dividend: tmp << 19ULL, divisor: 1000LL); |
714 | } |
715 | |
716 | static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw, |
717 | s32 P_T, s32 P_R, s32 P_G, s32 P_O, s16 Gb) |
718 | { |
719 | s64 Asub, Bsub, Ablock, Bblock, Cblock, AMB, sum; |
720 | |
721 | AMB = mlx90632_preprocess_temp_amb(ambient_new_raw, ambient_old_raw, |
722 | Gb); |
723 | Asub = ((s64)P_T * 10000000000LL) >> 44ULL; |
724 | Bsub = AMB - (((s64)P_R * 1000LL) >> 8ULL); |
725 | Ablock = Asub * (Bsub * Bsub); |
726 | Bblock = (div64_s64(dividend: Bsub * 10000000LL, divisor: P_G)) << 20ULL; |
727 | Cblock = ((s64)P_O * 10000000000LL) >> 8ULL; |
728 | |
729 | sum = div64_s64(dividend: Ablock, divisor: 1000000LL) + Bblock + Cblock; |
730 | |
731 | return div64_s64(dividend: sum, divisor: 10000000LL); |
732 | } |
733 | |
734 | static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object, |
735 | s64 TAdut, s64 TAdut4, s32 Fa, s32 Fb, |
736 | s32 Ga, s16 Ha, s16 Hb, |
737 | u16 emissivity) |
738 | { |
739 | s64 calcedKsTO, calcedKsTA, ir_Alpha, Alpha_corr; |
740 | s64 Ha_customer, Hb_customer; |
741 | |
742 | Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL; |
743 | Hb_customer = ((s64)Hb * 100) >> 10ULL; |
744 | |
745 | calcedKsTO = ((s64)((s64)Ga * (prev_object_temp - 25 * 1000LL) |
746 | * 1000LL)) >> 36LL; |
747 | calcedKsTA = ((s64)(Fb * (TAdut - 25 * 1000000LL))) >> 36LL; |
748 | Alpha_corr = div64_s64(dividend: (((s64)(Fa * 10000000000LL) >> 46LL) |
749 | * Ha_customer), divisor: 1000LL); |
750 | Alpha_corr *= ((s64)(1 * 1000000LL + calcedKsTO + calcedKsTA)); |
751 | Alpha_corr = emissivity * div64_s64(dividend: Alpha_corr, divisor: 100000LL); |
752 | Alpha_corr = div64_s64(dividend: Alpha_corr, divisor: 1000LL); |
753 | ir_Alpha = div64_s64(dividend: (s64)object * 10000000LL, divisor: Alpha_corr); |
754 | |
755 | return (int_sqrt64(x: int_sqrt64(x: ir_Alpha * 1000000000000LL + TAdut4)) |
756 | - 27315 - Hb_customer) * 10; |
757 | } |
758 | |
759 | static s64 mlx90632_calc_ta4(s64 TAdut, s64 scale) |
760 | { |
761 | return (div64_s64(dividend: TAdut, divisor: scale) + 27315) * |
762 | (div64_s64(dividend: TAdut, divisor: scale) + 27315) * |
763 | (div64_s64(dividend: TAdut, divisor: scale) + 27315) * |
764 | (div64_s64(dividend: TAdut, divisor: scale) + 27315); |
765 | } |
766 | |
767 | static s32 mlx90632_calc_temp_object(s64 object, s64 ambient, s32 Ea, s32 Eb, |
768 | s32 Fa, s32 Fb, s32 Ga, s16 Ha, s16 Hb, |
769 | u16 tmp_emi) |
770 | { |
771 | s64 kTA, kTA0, TAdut, TAdut4; |
772 | s64 temp = 25000; |
773 | s8 i; |
774 | |
775 | kTA = (Ea * 1000LL) >> 16LL; |
776 | kTA0 = (Eb * 1000LL) >> 8LL; |
777 | TAdut = div64_s64(dividend: ((ambient - kTA0) * 1000000LL), divisor: kTA) + 25 * 1000000LL; |
778 | TAdut4 = mlx90632_calc_ta4(TAdut, scale: 10000LL); |
779 | |
780 | /* Iterations of calculation as described in datasheet */ |
781 | for (i = 0; i < 5; ++i) { |
782 | temp = mlx90632_calc_temp_object_iteration(prev_object_temp: temp, object, TAdut, TAdut4, |
783 | Fa, Fb, Ga, Ha, Hb, |
784 | emissivity: tmp_emi); |
785 | } |
786 | return temp; |
787 | } |
788 | |
789 | static s32 mlx90632_calc_temp_object_extended(s64 object, s64 ambient, s64 reflected, |
790 | s32 Ea, s32 Eb, s32 Fa, s32 Fb, s32 Ga, |
791 | s16 Ha, s16 Hb, u16 tmp_emi) |
792 | { |
793 | s64 kTA, kTA0, TAdut, TAdut4, Tr4, TaTr4; |
794 | s64 temp = 25000; |
795 | s8 i; |
796 | |
797 | kTA = (Ea * 1000LL) >> 16LL; |
798 | kTA0 = (Eb * 1000LL) >> 8LL; |
799 | TAdut = div64_s64(dividend: (ambient - kTA0) * 1000000LL, divisor: kTA) + 25 * 1000000LL; |
800 | Tr4 = mlx90632_calc_ta4(TAdut: reflected, scale: 10); |
801 | TAdut4 = mlx90632_calc_ta4(TAdut, scale: 10000LL); |
802 | TaTr4 = Tr4 - div64_s64(dividend: Tr4 - TAdut4, divisor: tmp_emi) * 1000; |
803 | |
804 | /* Iterations of calculation as described in datasheet */ |
805 | for (i = 0; i < 5; ++i) { |
806 | temp = mlx90632_calc_temp_object_iteration(prev_object_temp: temp, object, TAdut, TAdut4: TaTr4, |
807 | Fa: Fa / 2, Fb, Ga, Ha, Hb, |
808 | emissivity: tmp_emi); |
809 | } |
810 | |
811 | return temp; |
812 | } |
813 | |
814 | static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val) |
815 | { |
816 | s16 ambient_new_raw, ambient_old_raw, object_new_raw, object_old_raw; |
817 | s32 Ea, Eb, Fa, Fb, Ga; |
818 | unsigned int read_tmp; |
819 | s64 object, ambient; |
820 | s16 Ha, Hb, Gb, Ka; |
821 | int ret; |
822 | |
823 | ret = mlx90632_read_ee_register(regmap: data->regmap, MLX90632_EE_Ea, reg_value: &Ea); |
824 | if (ret < 0) |
825 | return ret; |
826 | ret = mlx90632_read_ee_register(regmap: data->regmap, MLX90632_EE_Eb, reg_value: &Eb); |
827 | if (ret < 0) |
828 | return ret; |
829 | ret = mlx90632_read_ee_register(regmap: data->regmap, MLX90632_EE_Fa, reg_value: &Fa); |
830 | if (ret < 0) |
831 | return ret; |
832 | ret = mlx90632_read_ee_register(regmap: data->regmap, MLX90632_EE_Fb, reg_value: &Fb); |
833 | if (ret < 0) |
834 | return ret; |
835 | ret = mlx90632_read_ee_register(regmap: data->regmap, MLX90632_EE_Ga, reg_value: &Ga); |
836 | if (ret < 0) |
837 | return ret; |
838 | ret = regmap_read(map: data->regmap, MLX90632_EE_Ha, val: &read_tmp); |
839 | if (ret < 0) |
840 | return ret; |
841 | Ha = (s16)read_tmp; |
842 | ret = regmap_read(map: data->regmap, MLX90632_EE_Hb, val: &read_tmp); |
843 | if (ret < 0) |
844 | return ret; |
845 | Hb = (s16)read_tmp; |
846 | ret = regmap_read(map: data->regmap, MLX90632_EE_Gb, val: &read_tmp); |
847 | if (ret < 0) |
848 | return ret; |
849 | Gb = (s16)read_tmp; |
850 | ret = regmap_read(map: data->regmap, MLX90632_EE_Ka, val: &read_tmp); |
851 | if (ret < 0) |
852 | return ret; |
853 | Ka = (s16)read_tmp; |
854 | |
855 | ret = mlx90632_read_all_channel(data, |
856 | ambient_new_raw: &ambient_new_raw, ambient_old_raw: &ambient_old_raw, |
857 | object_new_raw: &object_new_raw, object_old_raw: &object_old_raw); |
858 | if (ret < 0) |
859 | return ret; |
860 | |
861 | if (object_new_raw > MLX90632_EXTENDED_LIMIT && |
862 | data->mtyp == MLX90632_MTYP_EXTENDED) { |
863 | ret = mlx90632_read_all_channel_extended(data, object_new_raw: &object_new_raw, |
864 | ambient_new_raw: &ambient_new_raw, ambient_old_raw: &ambient_old_raw); |
865 | if (ret < 0) |
866 | return ret; |
867 | |
868 | /* Use extended mode calculations */ |
869 | ambient = mlx90632_preprocess_temp_amb(ambient_new_raw, |
870 | ambient_old_raw, Gb); |
871 | object = mlx90632_preprocess_temp_obj_extended(object_new_raw, |
872 | ambient_new_raw, |
873 | ambient_old_raw, Ka); |
874 | *val = mlx90632_calc_temp_object_extended(object, ambient, |
875 | reflected: data->object_ambient_temperature, |
876 | Ea, Eb, Fa, Fb, Ga, |
877 | Ha, Hb, tmp_emi: data->emissivity); |
878 | return 0; |
879 | } |
880 | |
881 | ambient = mlx90632_preprocess_temp_amb(ambient_new_raw, |
882 | ambient_old_raw, Gb); |
883 | object = mlx90632_preprocess_temp_obj(object_new_raw, |
884 | object_old_raw, |
885 | ambient_new_raw, |
886 | ambient_old_raw, Ka); |
887 | |
888 | *val = mlx90632_calc_temp_object(object, ambient, Ea, Eb, Fa, Fb, Ga, |
889 | Ha, Hb, tmp_emi: data->emissivity); |
890 | return 0; |
891 | } |
892 | |
893 | static int mlx90632_calc_ambient_dsp105(struct mlx90632_data *data, int *val) |
894 | { |
895 | s16 ambient_new_raw, ambient_old_raw; |
896 | unsigned int read_tmp; |
897 | s32 PT, PR, PG, PO; |
898 | int ret; |
899 | s16 Gb; |
900 | |
901 | ret = mlx90632_read_ee_register(regmap: data->regmap, MLX90632_EE_P_R, reg_value: &PR); |
902 | if (ret < 0) |
903 | return ret; |
904 | ret = mlx90632_read_ee_register(regmap: data->regmap, MLX90632_EE_P_G, reg_value: &PG); |
905 | if (ret < 0) |
906 | return ret; |
907 | ret = mlx90632_read_ee_register(regmap: data->regmap, MLX90632_EE_P_T, reg_value: &PT); |
908 | if (ret < 0) |
909 | return ret; |
910 | ret = mlx90632_read_ee_register(regmap: data->regmap, MLX90632_EE_P_O, reg_value: &PO); |
911 | if (ret < 0) |
912 | return ret; |
913 | ret = regmap_read(map: data->regmap, MLX90632_EE_Gb, val: &read_tmp); |
914 | if (ret < 0) |
915 | return ret; |
916 | Gb = (s16)read_tmp; |
917 | |
918 | ret = mlx90632_read_ambient_raw(regmap: data->regmap, ambient_new_raw: &ambient_new_raw, |
919 | ambient_old_raw: &ambient_old_raw); |
920 | if (ret < 0) |
921 | return ret; |
922 | *val = mlx90632_calc_temp_ambient(ambient_new_raw, ambient_old_raw, |
923 | P_T: PT, P_R: PR, P_G: PG, P_O: PO, Gb); |
924 | return ret; |
925 | } |
926 | |
927 | static int mlx90632_get_refresh_rate(struct mlx90632_data *data, |
928 | int *refresh_rate) |
929 | { |
930 | unsigned int meas1; |
931 | int ret; |
932 | |
933 | ret = regmap_read(map: data->regmap, MLX90632_EE_MEDICAL_MEAS1, val: &meas1); |
934 | if (ret < 0) |
935 | return ret; |
936 | |
937 | *refresh_rate = MLX90632_REFRESH_RATE(meas1); |
938 | |
939 | return ret; |
940 | } |
941 | |
942 | static const int mlx90632_freqs[][2] = { |
943 | {0, 500000}, |
944 | {1, 0}, |
945 | {2, 0}, |
946 | {4, 0}, |
947 | {8, 0}, |
948 | {16, 0}, |
949 | {32, 0}, |
950 | {64, 0} |
951 | }; |
952 | |
953 | /** |
954 | * mlx90632_pm_interraction_wakeup() - Measure time between user interactions to change powermode |
955 | * @data: pointer to mlx90632_data object containing interaction_ts information |
956 | * |
957 | * Switch to continuous mode when interaction is faster than MLX90632_MEAS_MAX_TIME. Update the |
958 | * interaction_ts for each function call with the jiffies to enable measurement between function |
959 | * calls. Initial value of the interaction_ts needs to be set before this function call. |
960 | */ |
961 | static int mlx90632_pm_interraction_wakeup(struct mlx90632_data *data) |
962 | { |
963 | unsigned long now; |
964 | int ret; |
965 | |
966 | now = jiffies; |
967 | if (time_in_range(now, data->interaction_ts, |
968 | data->interaction_ts + |
969 | msecs_to_jiffies(MLX90632_MEAS_MAX_TIME + 100))) { |
970 | if (data->powerstatus == MLX90632_PWR_STATUS_SLEEP_STEP) { |
971 | ret = mlx90632_pwr_continuous(regmap: data->regmap); |
972 | if (ret < 0) |
973 | return ret; |
974 | } |
975 | } |
976 | |
977 | data->interaction_ts = now; |
978 | |
979 | return 0; |
980 | } |
981 | |
982 | static int mlx90632_read_raw(struct iio_dev *indio_dev, |
983 | struct iio_chan_spec const *channel, int *val, |
984 | int *val2, long mask) |
985 | { |
986 | struct mlx90632_data *data = iio_priv(indio_dev); |
987 | int ret; |
988 | int cr; |
989 | |
990 | pm_runtime_get_sync(dev: &data->client->dev); |
991 | ret = mlx90632_pm_interraction_wakeup(data); |
992 | if (ret < 0) |
993 | goto mlx90632_read_raw_pm; |
994 | |
995 | switch (mask) { |
996 | case IIO_CHAN_INFO_PROCESSED: |
997 | switch (channel->channel2) { |
998 | case IIO_MOD_TEMP_AMBIENT: |
999 | ret = mlx90632_calc_ambient_dsp105(data, val); |
1000 | if (ret < 0) |
1001 | goto mlx90632_read_raw_pm; |
1002 | |
1003 | ret = IIO_VAL_INT; |
1004 | break; |
1005 | case IIO_MOD_TEMP_OBJECT: |
1006 | ret = mlx90632_calc_object_dsp105(data, val); |
1007 | if (ret < 0) |
1008 | goto mlx90632_read_raw_pm; |
1009 | |
1010 | ret = IIO_VAL_INT; |
1011 | break; |
1012 | default: |
1013 | ret = -EINVAL; |
1014 | break; |
1015 | } |
1016 | break; |
1017 | case IIO_CHAN_INFO_CALIBEMISSIVITY: |
1018 | if (data->emissivity == 1000) { |
1019 | *val = 1; |
1020 | *val2 = 0; |
1021 | } else { |
1022 | *val = 0; |
1023 | *val2 = data->emissivity * 1000; |
1024 | } |
1025 | ret = IIO_VAL_INT_PLUS_MICRO; |
1026 | break; |
1027 | case IIO_CHAN_INFO_CALIBAMBIENT: |
1028 | *val = data->object_ambient_temperature; |
1029 | ret = IIO_VAL_INT; |
1030 | break; |
1031 | case IIO_CHAN_INFO_SAMP_FREQ: |
1032 | ret = mlx90632_get_refresh_rate(data, refresh_rate: &cr); |
1033 | if (ret < 0) |
1034 | goto mlx90632_read_raw_pm; |
1035 | |
1036 | *val = mlx90632_freqs[cr][0]; |
1037 | *val2 = mlx90632_freqs[cr][1]; |
1038 | ret = IIO_VAL_INT_PLUS_MICRO; |
1039 | break; |
1040 | default: |
1041 | ret = -EINVAL; |
1042 | break; |
1043 | } |
1044 | |
1045 | mlx90632_read_raw_pm: |
1046 | pm_runtime_mark_last_busy(dev: &data->client->dev); |
1047 | pm_runtime_put_autosuspend(dev: &data->client->dev); |
1048 | return ret; |
1049 | } |
1050 | |
1051 | static int mlx90632_write_raw(struct iio_dev *indio_dev, |
1052 | struct iio_chan_spec const *channel, int val, |
1053 | int val2, long mask) |
1054 | { |
1055 | struct mlx90632_data *data = iio_priv(indio_dev); |
1056 | |
1057 | switch (mask) { |
1058 | case IIO_CHAN_INFO_CALIBEMISSIVITY: |
1059 | /* Confirm we are within 0 and 1.0 */ |
1060 | if (val < 0 || val2 < 0 || val > 1 || |
1061 | (val == 1 && val2 != 0)) |
1062 | return -EINVAL; |
1063 | data->emissivity = val * 1000 + val2 / 1000; |
1064 | return 0; |
1065 | case IIO_CHAN_INFO_CALIBAMBIENT: |
1066 | data->object_ambient_temperature = val; |
1067 | return 0; |
1068 | default: |
1069 | return -EINVAL; |
1070 | } |
1071 | } |
1072 | |
1073 | static int mlx90632_read_avail(struct iio_dev *indio_dev, |
1074 | struct iio_chan_spec const *chan, |
1075 | const int **vals, int *type, int *length, |
1076 | long mask) |
1077 | { |
1078 | switch (mask) { |
1079 | case IIO_CHAN_INFO_SAMP_FREQ: |
1080 | *vals = (int *)mlx90632_freqs; |
1081 | *type = IIO_VAL_INT_PLUS_MICRO; |
1082 | *length = 2 * ARRAY_SIZE(mlx90632_freqs); |
1083 | return IIO_AVAIL_LIST; |
1084 | default: |
1085 | return -EINVAL; |
1086 | } |
1087 | } |
1088 | |
1089 | static const struct iio_chan_spec mlx90632_channels[] = { |
1090 | { |
1091 | .type = IIO_TEMP, |
1092 | .modified = 1, |
1093 | .channel2 = IIO_MOD_TEMP_AMBIENT, |
1094 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), |
1095 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
1096 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
1097 | }, |
1098 | { |
1099 | .type = IIO_TEMP, |
1100 | .modified = 1, |
1101 | .channel2 = IIO_MOD_TEMP_OBJECT, |
1102 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | |
1103 | BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) | BIT(IIO_CHAN_INFO_CALIBAMBIENT), |
1104 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
1105 | .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
1106 | }, |
1107 | }; |
1108 | |
1109 | static const struct iio_info mlx90632_info = { |
1110 | .read_raw = mlx90632_read_raw, |
1111 | .write_raw = mlx90632_write_raw, |
1112 | .read_avail = mlx90632_read_avail, |
1113 | }; |
1114 | |
1115 | static void mlx90632_sleep(void *_data) |
1116 | { |
1117 | struct mlx90632_data *data = _data; |
1118 | |
1119 | mlx90632_pwr_set_sleep_step(regmap: data->regmap); |
1120 | } |
1121 | |
1122 | static int mlx90632_suspend(struct mlx90632_data *data) |
1123 | { |
1124 | regcache_mark_dirty(map: data->regmap); |
1125 | |
1126 | dev_dbg(&data->client->dev, "Requesting suspend" ); |
1127 | return mlx90632_pwr_set_sleep_step(regmap: data->regmap); |
1128 | } |
1129 | |
1130 | static int mlx90632_wakeup(struct mlx90632_data *data) |
1131 | { |
1132 | int ret; |
1133 | |
1134 | ret = regcache_sync(map: data->regmap); |
1135 | if (ret < 0) { |
1136 | dev_err(&data->client->dev, |
1137 | "Failed to sync regmap registers: %d\n" , ret); |
1138 | return ret; |
1139 | } |
1140 | |
1141 | dev_dbg(&data->client->dev, "Requesting wake-up\n" ); |
1142 | return mlx90632_pwr_continuous(regmap: data->regmap); |
1143 | } |
1144 | |
1145 | static void mlx90632_disable_regulator(void *_data) |
1146 | { |
1147 | struct mlx90632_data *data = _data; |
1148 | int ret; |
1149 | |
1150 | ret = regulator_disable(regulator: data->regulator); |
1151 | if (ret < 0) |
1152 | dev_err(regmap_get_device(data->regmap), |
1153 | "Failed to disable power regulator: %d\n" , ret); |
1154 | } |
1155 | |
1156 | static int mlx90632_enable_regulator(struct mlx90632_data *data) |
1157 | { |
1158 | int ret; |
1159 | |
1160 | ret = regulator_enable(regulator: data->regulator); |
1161 | if (ret < 0) { |
1162 | dev_err(regmap_get_device(data->regmap), "Failed to enable power regulator!\n" ); |
1163 | return ret; |
1164 | } |
1165 | |
1166 | mlx90632_reset_delay(); |
1167 | |
1168 | return ret; |
1169 | } |
1170 | |
1171 | static int mlx90632_probe(struct i2c_client *client) |
1172 | { |
1173 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
1174 | struct mlx90632_data *mlx90632; |
1175 | struct iio_dev *indio_dev; |
1176 | struct regmap *regmap; |
1177 | unsigned int read; |
1178 | int ret; |
1179 | |
1180 | indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*mlx90632)); |
1181 | if (!indio_dev) { |
1182 | dev_err(&client->dev, "Failed to allocate device\n" ); |
1183 | return -ENOMEM; |
1184 | } |
1185 | |
1186 | regmap = devm_regmap_init_i2c(client, &mlx90632_regmap); |
1187 | if (IS_ERR(ptr: regmap)) { |
1188 | ret = PTR_ERR(ptr: regmap); |
1189 | dev_err(&client->dev, "Failed to allocate regmap: %d\n" , ret); |
1190 | return ret; |
1191 | } |
1192 | |
1193 | mlx90632 = iio_priv(indio_dev); |
1194 | i2c_set_clientdata(client, data: indio_dev); |
1195 | mlx90632->client = client; |
1196 | mlx90632->regmap = regmap; |
1197 | mlx90632->mtyp = MLX90632_MTYP_MEDICAL; |
1198 | mlx90632->powerstatus = MLX90632_PWR_STATUS_HALT; |
1199 | |
1200 | mutex_init(&mlx90632->lock); |
1201 | indio_dev->name = id->name; |
1202 | indio_dev->modes = INDIO_DIRECT_MODE; |
1203 | indio_dev->info = &mlx90632_info; |
1204 | indio_dev->channels = mlx90632_channels; |
1205 | indio_dev->num_channels = ARRAY_SIZE(mlx90632_channels); |
1206 | |
1207 | mlx90632->regulator = devm_regulator_get(dev: &client->dev, id: "vdd" ); |
1208 | if (IS_ERR(ptr: mlx90632->regulator)) |
1209 | return dev_err_probe(dev: &client->dev, err: PTR_ERR(ptr: mlx90632->regulator), |
1210 | fmt: "failed to get vdd regulator" ); |
1211 | |
1212 | ret = mlx90632_enable_regulator(data: mlx90632); |
1213 | if (ret < 0) |
1214 | return ret; |
1215 | |
1216 | ret = devm_add_action_or_reset(&client->dev, mlx90632_disable_regulator, |
1217 | mlx90632); |
1218 | if (ret < 0) { |
1219 | dev_err(&client->dev, "Failed to setup regulator cleanup action %d\n" , |
1220 | ret); |
1221 | return ret; |
1222 | } |
1223 | |
1224 | ret = mlx90632_wakeup(data: mlx90632); |
1225 | if (ret < 0) { |
1226 | dev_err(&client->dev, "Wakeup failed: %d\n" , ret); |
1227 | return ret; |
1228 | } |
1229 | |
1230 | ret = devm_add_action_or_reset(&client->dev, mlx90632_sleep, mlx90632); |
1231 | if (ret < 0) { |
1232 | dev_err(&client->dev, "Failed to setup low power cleanup action %d\n" , |
1233 | ret); |
1234 | return ret; |
1235 | } |
1236 | |
1237 | ret = regmap_read(map: mlx90632->regmap, MLX90632_EE_VERSION, val: &read); |
1238 | if (ret < 0) { |
1239 | dev_err(&client->dev, "read of version failed: %d\n" , ret); |
1240 | return ret; |
1241 | } |
1242 | read = read & MLX90632_ID_MASK; |
1243 | if (read == MLX90632_ID_MEDICAL) { |
1244 | dev_dbg(&client->dev, |
1245 | "Detected Medical EEPROM calibration %x\n" , read); |
1246 | } else if (read == MLX90632_ID_CONSUMER) { |
1247 | dev_dbg(&client->dev, |
1248 | "Detected Consumer EEPROM calibration %x\n" , read); |
1249 | } else if (read == MLX90632_ID_EXTENDED) { |
1250 | dev_dbg(&client->dev, |
1251 | "Detected Extended range EEPROM calibration %x\n" , read); |
1252 | mlx90632->mtyp = MLX90632_MTYP_EXTENDED; |
1253 | } else if ((read & MLX90632_DSP_MASK) == MLX90632_DSP_VERSION) { |
1254 | dev_dbg(&client->dev, |
1255 | "Detected Unknown EEPROM calibration %x\n" , read); |
1256 | } else { |
1257 | dev_err(&client->dev, |
1258 | "Wrong DSP version %x (expected %x)\n" , |
1259 | read, MLX90632_DSP_VERSION); |
1260 | return -EPROTONOSUPPORT; |
1261 | } |
1262 | |
1263 | mlx90632->emissivity = 1000; |
1264 | mlx90632->object_ambient_temperature = 25000; /* 25 degrees milliCelsius */ |
1265 | mlx90632->interaction_ts = jiffies; /* Set initial value */ |
1266 | |
1267 | pm_runtime_get_noresume(dev: &client->dev); |
1268 | pm_runtime_set_active(dev: &client->dev); |
1269 | |
1270 | ret = devm_pm_runtime_enable(dev: &client->dev); |
1271 | if (ret) |
1272 | return ret; |
1273 | |
1274 | pm_runtime_set_autosuspend_delay(dev: &client->dev, MLX90632_SLEEP_DELAY_MS); |
1275 | pm_runtime_use_autosuspend(dev: &client->dev); |
1276 | pm_runtime_put_autosuspend(dev: &client->dev); |
1277 | |
1278 | return devm_iio_device_register(&client->dev, indio_dev); |
1279 | } |
1280 | |
1281 | static const struct i2c_device_id mlx90632_id[] = { |
1282 | { "mlx90632" , 0 }, |
1283 | { } |
1284 | }; |
1285 | MODULE_DEVICE_TABLE(i2c, mlx90632_id); |
1286 | |
1287 | static const struct of_device_id mlx90632_of_match[] = { |
1288 | { .compatible = "melexis,mlx90632" }, |
1289 | { } |
1290 | }; |
1291 | MODULE_DEVICE_TABLE(of, mlx90632_of_match); |
1292 | |
1293 | static int mlx90632_pm_suspend(struct device *dev) |
1294 | { |
1295 | struct mlx90632_data *data = iio_priv(indio_dev: dev_get_drvdata(dev)); |
1296 | int ret; |
1297 | |
1298 | ret = mlx90632_suspend(data); |
1299 | if (ret < 0) |
1300 | return ret; |
1301 | |
1302 | ret = regulator_disable(regulator: data->regulator); |
1303 | if (ret < 0) |
1304 | dev_err(regmap_get_device(data->regmap), |
1305 | "Failed to disable power regulator: %d\n" , ret); |
1306 | |
1307 | return ret; |
1308 | } |
1309 | |
1310 | static int mlx90632_pm_resume(struct device *dev) |
1311 | { |
1312 | struct mlx90632_data *data = iio_priv(indio_dev: dev_get_drvdata(dev)); |
1313 | int ret; |
1314 | |
1315 | ret = mlx90632_enable_regulator(data); |
1316 | if (ret < 0) |
1317 | return ret; |
1318 | |
1319 | return mlx90632_wakeup(data); |
1320 | } |
1321 | |
1322 | static int mlx90632_pm_runtime_suspend(struct device *dev) |
1323 | { |
1324 | struct mlx90632_data *data = iio_priv(indio_dev: dev_get_drvdata(dev)); |
1325 | |
1326 | return mlx90632_pwr_set_sleep_step(regmap: data->regmap); |
1327 | } |
1328 | |
1329 | static const struct dev_pm_ops mlx90632_pm_ops = { |
1330 | SYSTEM_SLEEP_PM_OPS(mlx90632_pm_suspend, mlx90632_pm_resume) |
1331 | RUNTIME_PM_OPS(mlx90632_pm_runtime_suspend, NULL, NULL) |
1332 | }; |
1333 | |
1334 | static struct i2c_driver mlx90632_driver = { |
1335 | .driver = { |
1336 | .name = "mlx90632" , |
1337 | .of_match_table = mlx90632_of_match, |
1338 | .pm = pm_ptr(&mlx90632_pm_ops), |
1339 | }, |
1340 | .probe = mlx90632_probe, |
1341 | .id_table = mlx90632_id, |
1342 | }; |
1343 | module_i2c_driver(mlx90632_driver); |
1344 | |
1345 | MODULE_AUTHOR("Crt Mori <cmo@melexis.com>" ); |
1346 | MODULE_DESCRIPTION("Melexis MLX90632 contactless Infra Red temperature sensor driver" ); |
1347 | MODULE_LICENSE("GPL v2" ); |
1348 | |