.. | .. |
---|
10 | 10 | #include <linux/err.h> |
---|
11 | 11 | #include <linux/gpio/consumer.h> |
---|
12 | 12 | #include <linux/i2c.h> |
---|
| 13 | +#include <linux/iopoll.h> |
---|
13 | 14 | #include <linux/kernel.h> |
---|
| 15 | +#include <linux/limits.h> |
---|
14 | 16 | #include <linux/module.h> |
---|
15 | 17 | #include <linux/math64.h> |
---|
16 | 18 | #include <linux/of.h> |
---|
.. | .. |
---|
58 | 60 | /* Control register address - volatile */ |
---|
59 | 61 | #define MLX90632_REG_CONTROL 0x3001 /* Control Register address */ |
---|
60 | 62 | #define MLX90632_CFG_PWR_MASK GENMASK(2, 1) /* PowerMode Mask */ |
---|
| 63 | +#define MLX90632_CFG_MTYP_MASK GENMASK(8, 4) /* Meas select Mask */ |
---|
| 64 | + |
---|
61 | 65 | /* PowerModes statuses */ |
---|
62 | 66 | #define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1) |
---|
63 | 67 | #define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */ |
---|
64 | 68 | #define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /* sleep step*/ |
---|
65 | 69 | #define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */ |
---|
66 | 70 | #define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous*/ |
---|
| 71 | + |
---|
| 72 | +/* Measurement types */ |
---|
| 73 | +#define MLX90632_MTYP_MEDICAL 0 |
---|
| 74 | +#define MLX90632_MTYP_EXTENDED 17 |
---|
| 75 | + |
---|
| 76 | +/* Measurement type select*/ |
---|
| 77 | +#define MLX90632_MTYP_STATUS(ctrl_val) (ctrl_val << 4) |
---|
| 78 | +#define MLX90632_MTYP_STATUS_MEDICAL MLX90632_MTYP_STATUS(MLX90632_MTYP_MEDICAL) |
---|
| 79 | +#define MLX90632_MTYP_STATUS_EXTENDED MLX90632_MTYP_STATUS(MLX90632_MTYP_EXTENDED) |
---|
| 80 | + |
---|
| 81 | +/* I2C command register - volatile */ |
---|
| 82 | +#define MLX90632_REG_I2C_CMD 0x3005 /* I2C command Register address */ |
---|
67 | 83 | |
---|
68 | 84 | /* Device status register - volatile */ |
---|
69 | 85 | #define MLX90632_REG_STATUS 0x3fff /* Device status register */ |
---|
.. | .. |
---|
78 | 94 | #define MLX90632_RAM_2(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 1) |
---|
79 | 95 | #define MLX90632_RAM_3(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 2) |
---|
80 | 96 | |
---|
| 97 | +/* Name important RAM_MEAS channels */ |
---|
| 98 | +#define MLX90632_RAM_DSP5_EXTENDED_AMBIENT_1 MLX90632_RAM_3(17) |
---|
| 99 | +#define MLX90632_RAM_DSP5_EXTENDED_AMBIENT_2 MLX90632_RAM_3(18) |
---|
| 100 | +#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_1 MLX90632_RAM_1(17) |
---|
| 101 | +#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_2 MLX90632_RAM_2(17) |
---|
| 102 | +#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_3 MLX90632_RAM_1(18) |
---|
| 103 | +#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_4 MLX90632_RAM_2(18) |
---|
| 104 | +#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_5 MLX90632_RAM_1(19) |
---|
| 105 | +#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_6 MLX90632_RAM_2(19) |
---|
| 106 | + |
---|
81 | 107 | /* Magic constants */ |
---|
82 | 108 | #define MLX90632_ID_MEDICAL 0x0105 /* EEPROM DSPv5 Medical device id */ |
---|
83 | 109 | #define MLX90632_ID_CONSUMER 0x0205 /* EEPROM DSPv5 Consumer device id */ |
---|
| 110 | +#define MLX90632_ID_EXTENDED 0x0505 /* EEPROM DSPv5 Extended range device id */ |
---|
| 111 | +#define MLX90632_ID_MASK GENMASK(14, 0) /* DSP version and device ID in EE_VERSION */ |
---|
84 | 112 | #define MLX90632_DSP_VERSION 5 /* DSP version */ |
---|
85 | 113 | #define MLX90632_DSP_MASK GENMASK(7, 0) /* DSP version in EE_VERSION */ |
---|
86 | 114 | #define MLX90632_RESET_CMD 0x0006 /* Reset sensor (address or global) */ |
---|
87 | | -#define MLX90632_REF_12 12LL /**< ResCtrlRef value of Ch 1 or Ch 2 */ |
---|
88 | | -#define MLX90632_REF_3 12LL /**< ResCtrlRef value of Channel 3 */ |
---|
89 | | -#define MLX90632_MAX_MEAS_NUM 31 /**< Maximum measurements in list */ |
---|
90 | | -#define MLX90632_SLEEP_DELAY_MS 3000 /**< Autosleep delay */ |
---|
| 115 | +#define MLX90632_REF_12 12LL /* ResCtrlRef value of Ch 1 or Ch 2 */ |
---|
| 116 | +#define MLX90632_REF_3 12LL /* ResCtrlRef value of Channel 3 */ |
---|
| 117 | +#define MLX90632_MAX_MEAS_NUM 31 /* Maximum measurements in list */ |
---|
| 118 | +#define MLX90632_SLEEP_DELAY_MS 3000 /* Autosleep delay */ |
---|
| 119 | +#define MLX90632_EXTENDED_LIMIT 27000 /* Extended mode raw value limit */ |
---|
91 | 120 | |
---|
| 121 | +/** |
---|
| 122 | + * struct mlx90632_data - private data for the MLX90632 device |
---|
| 123 | + * @client: I2C client of the device |
---|
| 124 | + * @lock: Internal mutex for multiple reads for single measurement |
---|
| 125 | + * @regmap: Regmap of the device |
---|
| 126 | + * @emissivity: Object emissivity from 0 to 1000 where 1000 = 1. |
---|
| 127 | + * @mtyp: Measurement type physical sensor configuration for extended range |
---|
| 128 | + * calculations |
---|
| 129 | + * @object_ambient_temperature: Ambient temperature at object (might differ of |
---|
| 130 | + * the ambient temperature of sensor. |
---|
| 131 | + */ |
---|
92 | 132 | struct mlx90632_data { |
---|
93 | 133 | struct i2c_client *client; |
---|
94 | | - struct mutex lock; /* Multiple reads for single measurement */ |
---|
| 134 | + struct mutex lock; |
---|
95 | 135 | struct regmap *regmap; |
---|
96 | 136 | u16 emissivity; |
---|
| 137 | + u8 mtyp; |
---|
| 138 | + u32 object_ambient_temperature; |
---|
97 | 139 | }; |
---|
98 | 140 | |
---|
99 | 141 | static const struct regmap_range mlx90632_volatile_reg_range[] = { |
---|
100 | 142 | regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL), |
---|
| 143 | + regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD), |
---|
101 | 144 | regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS), |
---|
102 | 145 | regmap_reg_range(MLX90632_RAM_1(0), |
---|
103 | 146 | MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)), |
---|
.. | .. |
---|
113 | 156 | regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR), |
---|
114 | 157 | regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb), |
---|
115 | 158 | regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL), |
---|
| 159 | + regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD), |
---|
116 | 160 | regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS), |
---|
117 | 161 | regmap_reg_range(MLX90632_RAM_1(0), |
---|
118 | 162 | MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)), |
---|
.. | .. |
---|
142 | 186 | .rd_table = &mlx90632_readable_regs_tbl, |
---|
143 | 187 | .wr_table = &mlx90632_writeable_regs_tbl, |
---|
144 | 188 | |
---|
145 | | - .use_single_rw = true, |
---|
| 189 | + .use_single_read = true, |
---|
| 190 | + .use_single_write = true, |
---|
146 | 191 | .reg_format_endian = REGMAP_ENDIAN_BIG, |
---|
147 | 192 | .val_format_endian = REGMAP_ENDIAN_BIG, |
---|
148 | 193 | .cache_type = REGCACHE_RBTREE, |
---|
.. | .. |
---|
163 | 208 | } |
---|
164 | 209 | |
---|
165 | 210 | /** |
---|
166 | | - * mlx90632_perform_measurement - Trigger and retrieve current measurement cycle |
---|
167 | | - * @*data: pointer to mlx90632_data object containing regmap information |
---|
| 211 | + * mlx90632_perform_measurement() - Trigger and retrieve current measurement cycle |
---|
| 212 | + * @data: pointer to mlx90632_data object containing regmap information |
---|
168 | 213 | * |
---|
169 | 214 | * Perform a measurement and return latest measurement cycle position reported |
---|
170 | 215 | * by sensor. This is a blocking function for 500ms, as that is default sensor |
---|
.. | .. |
---|
172 | 217 | */ |
---|
173 | 218 | static int mlx90632_perform_measurement(struct mlx90632_data *data) |
---|
174 | 219 | { |
---|
175 | | - int ret, tries = 100; |
---|
176 | 220 | unsigned int reg_status; |
---|
| 221 | + int ret; |
---|
177 | 222 | |
---|
178 | 223 | ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS, |
---|
179 | 224 | MLX90632_STAT_DATA_RDY, 0); |
---|
180 | 225 | if (ret < 0) |
---|
181 | 226 | return ret; |
---|
182 | 227 | |
---|
183 | | - while (tries-- > 0) { |
---|
184 | | - ret = regmap_read(data->regmap, MLX90632_REG_STATUS, |
---|
185 | | - ®_status); |
---|
186 | | - if (ret < 0) |
---|
187 | | - return ret; |
---|
188 | | - if (reg_status & MLX90632_STAT_DATA_RDY) |
---|
189 | | - break; |
---|
190 | | - usleep_range(10000, 11000); |
---|
191 | | - } |
---|
| 228 | + ret = regmap_read_poll_timeout(data->regmap, MLX90632_REG_STATUS, reg_status, |
---|
| 229 | + !(reg_status & MLX90632_STAT_DATA_RDY), 10000, |
---|
| 230 | + 100 * 10000); |
---|
192 | 231 | |
---|
193 | | - if (tries < 0) { |
---|
| 232 | + if (ret < 0) { |
---|
194 | 233 | dev_err(&data->client->dev, "data not ready"); |
---|
195 | 234 | return -ETIMEDOUT; |
---|
196 | 235 | } |
---|
197 | 236 | |
---|
198 | 237 | return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2; |
---|
| 238 | +} |
---|
| 239 | + |
---|
| 240 | +static int mlx90632_set_meas_type(struct regmap *regmap, u8 type) |
---|
| 241 | +{ |
---|
| 242 | + int ret; |
---|
| 243 | + |
---|
| 244 | + if ((type != MLX90632_MTYP_MEDICAL) && (type != MLX90632_MTYP_EXTENDED)) |
---|
| 245 | + return -EINVAL; |
---|
| 246 | + |
---|
| 247 | + ret = regmap_write(regmap, MLX90632_REG_I2C_CMD, MLX90632_RESET_CMD); |
---|
| 248 | + if (ret < 0) |
---|
| 249 | + return ret; |
---|
| 250 | + |
---|
| 251 | + /* |
---|
| 252 | + * Give the mlx90632 some time to reset properly before sending a new I2C command |
---|
| 253 | + * if this is not done, the following I2C command(s) will not be accepted. |
---|
| 254 | + */ |
---|
| 255 | + usleep_range(150, 200); |
---|
| 256 | + |
---|
| 257 | + ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL, |
---|
| 258 | + (MLX90632_CFG_MTYP_MASK | MLX90632_CFG_PWR_MASK), |
---|
| 259 | + (MLX90632_MTYP_STATUS(type) | MLX90632_PWR_STATUS_HALT)); |
---|
| 260 | + if (ret < 0) |
---|
| 261 | + return ret; |
---|
| 262 | + |
---|
| 263 | + return mlx90632_pwr_continuous(regmap); |
---|
199 | 264 | } |
---|
200 | 265 | |
---|
201 | 266 | static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new, |
---|
.. | .. |
---|
299 | 364 | return ret; |
---|
300 | 365 | } |
---|
301 | 366 | |
---|
| 367 | +static int mlx90632_read_ambient_raw_extended(struct regmap *regmap, |
---|
| 368 | + s16 *ambient_new_raw, s16 *ambient_old_raw) |
---|
| 369 | +{ |
---|
| 370 | + unsigned int read_tmp; |
---|
| 371 | + int ret; |
---|
| 372 | + |
---|
| 373 | + ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_AMBIENT_1, &read_tmp); |
---|
| 374 | + if (ret < 0) |
---|
| 375 | + return ret; |
---|
| 376 | + *ambient_new_raw = (s16)read_tmp; |
---|
| 377 | + |
---|
| 378 | + ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_AMBIENT_2, &read_tmp); |
---|
| 379 | + if (ret < 0) |
---|
| 380 | + return ret; |
---|
| 381 | + *ambient_old_raw = (s16)read_tmp; |
---|
| 382 | + |
---|
| 383 | + return 0; |
---|
| 384 | +} |
---|
| 385 | + |
---|
| 386 | +static int mlx90632_read_object_raw_extended(struct regmap *regmap, s16 *object_new_raw) |
---|
| 387 | +{ |
---|
| 388 | + unsigned int read_tmp; |
---|
| 389 | + s32 read; |
---|
| 390 | + int ret; |
---|
| 391 | + |
---|
| 392 | + ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_1, &read_tmp); |
---|
| 393 | + if (ret < 0) |
---|
| 394 | + return ret; |
---|
| 395 | + read = (s16)read_tmp; |
---|
| 396 | + |
---|
| 397 | + ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_2, &read_tmp); |
---|
| 398 | + if (ret < 0) |
---|
| 399 | + return ret; |
---|
| 400 | + read = read - (s16)read_tmp; |
---|
| 401 | + |
---|
| 402 | + ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_3, &read_tmp); |
---|
| 403 | + if (ret < 0) |
---|
| 404 | + return ret; |
---|
| 405 | + read = read - (s16)read_tmp; |
---|
| 406 | + |
---|
| 407 | + ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_4, &read_tmp); |
---|
| 408 | + if (ret < 0) |
---|
| 409 | + return ret; |
---|
| 410 | + read = (read + (s16)read_tmp) / 2; |
---|
| 411 | + |
---|
| 412 | + ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_5, &read_tmp); |
---|
| 413 | + if (ret < 0) |
---|
| 414 | + return ret; |
---|
| 415 | + read = read + (s16)read_tmp; |
---|
| 416 | + |
---|
| 417 | + ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_6, &read_tmp); |
---|
| 418 | + if (ret < 0) |
---|
| 419 | + return ret; |
---|
| 420 | + read = read + (s16)read_tmp; |
---|
| 421 | + |
---|
| 422 | + if (read > S16_MAX || read < S16_MIN) |
---|
| 423 | + return -ERANGE; |
---|
| 424 | + |
---|
| 425 | + *object_new_raw = read; |
---|
| 426 | + |
---|
| 427 | + return 0; |
---|
| 428 | +} |
---|
| 429 | + |
---|
| 430 | +static int mlx90632_read_all_channel_extended(struct mlx90632_data *data, s16 *object_new_raw, |
---|
| 431 | + s16 *ambient_new_raw, s16 *ambient_old_raw) |
---|
| 432 | +{ |
---|
| 433 | + s32 ret, meas; |
---|
| 434 | + |
---|
| 435 | + mutex_lock(&data->lock); |
---|
| 436 | + ret = mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_EXTENDED); |
---|
| 437 | + if (ret < 0) |
---|
| 438 | + goto read_unlock; |
---|
| 439 | + |
---|
| 440 | + ret = read_poll_timeout(mlx90632_perform_measurement, meas, meas == 19, |
---|
| 441 | + 50000, 800000, false, data); |
---|
| 442 | + if (ret != 0) |
---|
| 443 | + goto read_unlock; |
---|
| 444 | + |
---|
| 445 | + ret = mlx90632_read_object_raw_extended(data->regmap, object_new_raw); |
---|
| 446 | + if (ret < 0) |
---|
| 447 | + goto read_unlock; |
---|
| 448 | + |
---|
| 449 | + ret = mlx90632_read_ambient_raw_extended(data->regmap, ambient_new_raw, ambient_old_raw); |
---|
| 450 | + |
---|
| 451 | +read_unlock: |
---|
| 452 | + (void) mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_MEDICAL); |
---|
| 453 | + |
---|
| 454 | + mutex_unlock(&data->lock); |
---|
| 455 | + return ret; |
---|
| 456 | +} |
---|
| 457 | + |
---|
302 | 458 | static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb, |
---|
303 | 459 | s32 *reg_value) |
---|
304 | 460 | { |
---|
.. | .. |
---|
353 | 509 | return div64_s64((tmp << 19ULL), 1000LL); |
---|
354 | 510 | } |
---|
355 | 511 | |
---|
| 512 | +static s64 mlx90632_preprocess_temp_obj_extended(s16 object_new_raw, s16 ambient_new_raw, |
---|
| 513 | + s16 ambient_old_raw, s16 Ka) |
---|
| 514 | +{ |
---|
| 515 | + s64 VR_IR, kKa, tmp; |
---|
| 516 | + |
---|
| 517 | + kKa = ((s64)Ka * 1000LL) >> 10ULL; |
---|
| 518 | + VR_IR = (s64)ambient_old_raw * 1000000LL + |
---|
| 519 | + kKa * div64_s64((s64)ambient_new_raw * 1000LL, |
---|
| 520 | + MLX90632_REF_3); |
---|
| 521 | + tmp = div64_s64( |
---|
| 522 | + div64_s64((s64) object_new_raw * 1000000000000LL, MLX90632_REF_12), |
---|
| 523 | + VR_IR); |
---|
| 524 | + return div64_s64(tmp << 19ULL, 1000LL); |
---|
| 525 | +} |
---|
| 526 | + |
---|
356 | 527 | static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw, |
---|
357 | | - s32 P_T, s32 P_R, s32 P_G, s32 P_O, |
---|
358 | | - s16 Gb) |
---|
| 528 | + s32 P_T, s32 P_R, s32 P_G, s32 P_O, s16 Gb) |
---|
359 | 529 | { |
---|
360 | 530 | s64 Asub, Bsub, Ablock, Bblock, Cblock, AMB, sum; |
---|
361 | 531 | |
---|
.. | .. |
---|
373 | 543 | } |
---|
374 | 544 | |
---|
375 | 545 | static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object, |
---|
376 | | - s64 TAdut, s32 Fa, s32 Fb, |
---|
| 546 | + s64 TAdut, s64 TAdut4, s32 Fa, s32 Fb, |
---|
377 | 547 | s32 Ga, s16 Ha, s16 Hb, |
---|
378 | 548 | u16 emissivity) |
---|
379 | 549 | { |
---|
380 | | - s64 calcedKsTO, calcedKsTA, ir_Alpha, TAdut4, Alpha_corr; |
---|
| 550 | + s64 calcedKsTO, calcedKsTA, ir_Alpha, Alpha_corr; |
---|
381 | 551 | s64 Ha_customer, Hb_customer; |
---|
382 | 552 | |
---|
383 | 553 | Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL; |
---|
.. | .. |
---|
392 | 562 | Alpha_corr = emissivity * div64_s64(Alpha_corr, 100000LL); |
---|
393 | 563 | Alpha_corr = div64_s64(Alpha_corr, 1000LL); |
---|
394 | 564 | ir_Alpha = div64_s64((s64)object * 10000000LL, Alpha_corr); |
---|
395 | | - TAdut4 = (div64_s64(TAdut, 10000LL) + 27315) * |
---|
396 | | - (div64_s64(TAdut, 10000LL) + 27315) * |
---|
397 | | - (div64_s64(TAdut, 10000LL) + 27315) * |
---|
398 | | - (div64_s64(TAdut, 10000LL) + 27315); |
---|
399 | 565 | |
---|
400 | 566 | return (int_sqrt64(int_sqrt64(ir_Alpha * 1000000000000LL + TAdut4)) |
---|
401 | 567 | - 27315 - Hb_customer) * 10; |
---|
| 568 | +} |
---|
| 569 | + |
---|
| 570 | +static s64 mlx90632_calc_ta4(s64 TAdut, s64 scale) |
---|
| 571 | +{ |
---|
| 572 | + return (div64_s64(TAdut, scale) + 27315) * |
---|
| 573 | + (div64_s64(TAdut, scale) + 27315) * |
---|
| 574 | + (div64_s64(TAdut, scale) + 27315) * |
---|
| 575 | + (div64_s64(TAdut, scale) + 27315); |
---|
402 | 576 | } |
---|
403 | 577 | |
---|
404 | 578 | static s32 mlx90632_calc_temp_object(s64 object, s64 ambient, s32 Ea, s32 Eb, |
---|
405 | 579 | s32 Fa, s32 Fb, s32 Ga, s16 Ha, s16 Hb, |
---|
406 | 580 | u16 tmp_emi) |
---|
407 | 581 | { |
---|
408 | | - s64 kTA, kTA0, TAdut; |
---|
| 582 | + s64 kTA, kTA0, TAdut, TAdut4; |
---|
409 | 583 | s64 temp = 25000; |
---|
410 | 584 | s8 i; |
---|
411 | 585 | |
---|
412 | 586 | kTA = (Ea * 1000LL) >> 16LL; |
---|
413 | 587 | kTA0 = (Eb * 1000LL) >> 8LL; |
---|
414 | 588 | TAdut = div64_s64(((ambient - kTA0) * 1000000LL), kTA) + 25 * 1000000LL; |
---|
| 589 | + TAdut4 = mlx90632_calc_ta4(TAdut, 10000LL); |
---|
415 | 590 | |
---|
416 | 591 | /* Iterations of calculation as described in datasheet */ |
---|
417 | 592 | for (i = 0; i < 5; ++i) { |
---|
418 | | - temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, |
---|
| 593 | + temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, TAdut4, |
---|
419 | 594 | Fa, Fb, Ga, Ha, Hb, |
---|
420 | 595 | tmp_emi); |
---|
421 | 596 | } |
---|
| 597 | + return temp; |
---|
| 598 | +} |
---|
| 599 | + |
---|
| 600 | +static s32 mlx90632_calc_temp_object_extended(s64 object, s64 ambient, s64 reflected, |
---|
| 601 | + s32 Ea, s32 Eb, s32 Fa, s32 Fb, s32 Ga, |
---|
| 602 | + s16 Ha, s16 Hb, u16 tmp_emi) |
---|
| 603 | +{ |
---|
| 604 | + s64 kTA, kTA0, TAdut, TAdut4, Tr4, TaTr4; |
---|
| 605 | + s64 temp = 25000; |
---|
| 606 | + s8 i; |
---|
| 607 | + |
---|
| 608 | + kTA = (Ea * 1000LL) >> 16LL; |
---|
| 609 | + kTA0 = (Eb * 1000LL) >> 8LL; |
---|
| 610 | + TAdut = div64_s64((ambient - kTA0) * 1000000LL, kTA) + 25 * 1000000LL; |
---|
| 611 | + Tr4 = mlx90632_calc_ta4(reflected, 10); |
---|
| 612 | + TAdut4 = mlx90632_calc_ta4(TAdut, 10000LL); |
---|
| 613 | + TaTr4 = Tr4 - div64_s64(Tr4 - TAdut4, tmp_emi) * 1000; |
---|
| 614 | + |
---|
| 615 | + /* Iterations of calculation as described in datasheet */ |
---|
| 616 | + for (i = 0; i < 5; ++i) { |
---|
| 617 | + temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, TaTr4, |
---|
| 618 | + Fa / 2, Fb, Ga, Ha, Hb, |
---|
| 619 | + tmp_emi); |
---|
| 620 | + } |
---|
| 621 | + |
---|
422 | 622 | return temp; |
---|
423 | 623 | } |
---|
424 | 624 | |
---|
.. | .. |
---|
468 | 668 | &object_new_raw, &object_old_raw); |
---|
469 | 669 | if (ret < 0) |
---|
470 | 670 | return ret; |
---|
| 671 | + |
---|
| 672 | + if (object_new_raw > MLX90632_EXTENDED_LIMIT && |
---|
| 673 | + data->mtyp == MLX90632_MTYP_EXTENDED) { |
---|
| 674 | + ret = mlx90632_read_all_channel_extended(data, &object_new_raw, |
---|
| 675 | + &ambient_new_raw, &ambient_old_raw); |
---|
| 676 | + if (ret < 0) |
---|
| 677 | + return ret; |
---|
| 678 | + |
---|
| 679 | + /* Use extended mode calculations */ |
---|
| 680 | + ambient = mlx90632_preprocess_temp_amb(ambient_new_raw, |
---|
| 681 | + ambient_old_raw, Gb); |
---|
| 682 | + object = mlx90632_preprocess_temp_obj_extended(object_new_raw, |
---|
| 683 | + ambient_new_raw, |
---|
| 684 | + ambient_old_raw, Ka); |
---|
| 685 | + *val = mlx90632_calc_temp_object_extended(object, ambient, |
---|
| 686 | + data->object_ambient_temperature, |
---|
| 687 | + Ea, Eb, Fa, Fb, Ga, |
---|
| 688 | + Ha, Hb, data->emissivity); |
---|
| 689 | + return 0; |
---|
| 690 | + } |
---|
471 | 691 | |
---|
472 | 692 | ambient = mlx90632_preprocess_temp_amb(ambient_new_raw, |
---|
473 | 693 | ambient_old_raw, Gb); |
---|
.. | .. |
---|
547 | 767 | *val2 = data->emissivity * 1000; |
---|
548 | 768 | } |
---|
549 | 769 | return IIO_VAL_INT_PLUS_MICRO; |
---|
550 | | - |
---|
| 770 | + case IIO_CHAN_INFO_CALIBAMBIENT: |
---|
| 771 | + *val = data->object_ambient_temperature; |
---|
| 772 | + return IIO_VAL_INT; |
---|
551 | 773 | default: |
---|
552 | 774 | return -EINVAL; |
---|
553 | 775 | } |
---|
.. | .. |
---|
567 | 789 | return -EINVAL; |
---|
568 | 790 | data->emissivity = val * 1000 + val2 / 1000; |
---|
569 | 791 | return 0; |
---|
| 792 | + case IIO_CHAN_INFO_CALIBAMBIENT: |
---|
| 793 | + data->object_ambient_temperature = val; |
---|
| 794 | + return 0; |
---|
570 | 795 | default: |
---|
571 | 796 | return -EINVAL; |
---|
572 | 797 | } |
---|
.. | .. |
---|
584 | 809 | .modified = 1, |
---|
585 | 810 | .channel2 = IIO_MOD_TEMP_OBJECT, |
---|
586 | 811 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | |
---|
587 | | - BIT(IIO_CHAN_INFO_CALIBEMISSIVITY), |
---|
| 812 | + BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) | BIT(IIO_CHAN_INFO_CALIBAMBIENT), |
---|
588 | 813 | }, |
---|
589 | 814 | }; |
---|
590 | 815 | |
---|
.. | .. |
---|
642 | 867 | i2c_set_clientdata(client, indio_dev); |
---|
643 | 868 | mlx90632->client = client; |
---|
644 | 869 | mlx90632->regmap = regmap; |
---|
| 870 | + mlx90632->mtyp = MLX90632_MTYP_MEDICAL; |
---|
645 | 871 | |
---|
646 | 872 | mutex_init(&mlx90632->lock); |
---|
647 | | - indio_dev->dev.parent = &client->dev; |
---|
648 | 873 | indio_dev->name = id->name; |
---|
649 | 874 | indio_dev->modes = INDIO_DIRECT_MODE; |
---|
650 | 875 | indio_dev->info = &mlx90632_info; |
---|
.. | .. |
---|
662 | 887 | dev_err(&client->dev, "read of version failed: %d\n", ret); |
---|
663 | 888 | return ret; |
---|
664 | 889 | } |
---|
| 890 | + read = read & MLX90632_ID_MASK; |
---|
665 | 891 | if (read == MLX90632_ID_MEDICAL) { |
---|
666 | 892 | dev_dbg(&client->dev, |
---|
667 | 893 | "Detected Medical EEPROM calibration %x\n", read); |
---|
668 | 894 | } else if (read == MLX90632_ID_CONSUMER) { |
---|
669 | 895 | dev_dbg(&client->dev, |
---|
670 | 896 | "Detected Consumer EEPROM calibration %x\n", read); |
---|
| 897 | + } else if (read == MLX90632_ID_EXTENDED) { |
---|
| 898 | + dev_dbg(&client->dev, |
---|
| 899 | + "Detected Extended range EEPROM calibration %x\n", read); |
---|
| 900 | + mlx90632->mtyp = MLX90632_MTYP_EXTENDED; |
---|
671 | 901 | } else if ((read & MLX90632_DSP_MASK) == MLX90632_DSP_VERSION) { |
---|
672 | 902 | dev_dbg(&client->dev, |
---|
673 | 903 | "Detected Unknown EEPROM calibration %x\n", read); |
---|
.. | .. |
---|
679 | 909 | } |
---|
680 | 910 | |
---|
681 | 911 | mlx90632->emissivity = 1000; |
---|
| 912 | + mlx90632->object_ambient_temperature = 25000; /* 25 degrees milliCelsius */ |
---|
682 | 913 | |
---|
683 | 914 | pm_runtime_disable(&client->dev); |
---|
684 | 915 | ret = pm_runtime_set_active(&client->dev); |
---|