| .. | .. |
|---|
| 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); |
|---|