1 /* 2 * Measurements Specialties driver common i2c functions 3 * 4 * Copyright (c) 2015 Measurement-Specialties 5 * 6 * Licensed under the GPL-2. 7 */ 8 9 #include <linux/module.h> 10 #include <linux/iio/iio.h> 11 #include <linux/device.h> 12 #include <linux/delay.h> 13 14 #include "ms_sensors_i2c.h" 15 16 /* Conversion times in us */ 17 static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000, 18 13000, 7000 }; 19 static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000, 20 5000, 8000 }; 21 static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100, 22 4100, 8220, 16440 }; 23 24 #define MS_SENSORS_SERIAL_READ_MSB 0xFA0F 25 #define MS_SENSORS_SERIAL_READ_LSB 0xFCC9 26 #define MS_SENSORS_CONFIG_REG_WRITE 0xE6 27 #define MS_SENSORS_CONFIG_REG_READ 0xE7 28 #define MS_SENSORS_HT_T_CONVERSION_START 0xF3 29 #define MS_SENSORS_HT_H_CONVERSION_START 0xF5 30 31 #define MS_SENSORS_TP_PROM_READ 0xA0 32 #define MS_SENSORS_TP_T_CONVERSION_START 0x50 33 #define MS_SENSORS_TP_P_CONVERSION_START 0x40 34 #define MS_SENSORS_TP_ADC_READ 0x00 35 36 #define MS_SENSORS_NO_READ_CMD 0xFF 37 38 /** 39 * ms_sensors_reset() - Reset function 40 * @cli: pointer to device client 41 * @cmd: reset cmd. Depends on device in use 42 * @delay: usleep minimal delay after reset command is issued 43 * 44 * Generic I2C reset function for Measurement Specialties devices. 45 * 46 * Return: 0 on success, negative errno otherwise. 47 */ 48 int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay) 49 { 50 int ret; 51 struct i2c_client *client = cli; 52 53 ret = i2c_smbus_write_byte(client, cmd); 54 if (ret) { 55 dev_err(&client->dev, "Failed to reset device\n"); 56 return ret; 57 } 58 usleep_range(delay, delay + 1000); 59 60 return 0; 61 } 62 EXPORT_SYMBOL(ms_sensors_reset); 63 64 /** 65 * ms_sensors_read_prom_word() - PROM word read function 66 * @cli: pointer to device client 67 * @cmd: PROM read cmd. Depends on device and prom id 68 * @word: pointer to word destination value 69 * 70 * Generic i2c prom word read function for Measurement Specialties devices. 71 * 72 * Return: 0 on success, negative errno otherwise. 73 */ 74 int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word) 75 { 76 int ret; 77 struct i2c_client *client = cli; 78 79 ret = i2c_smbus_read_word_swapped(client, cmd); 80 if (ret < 0) { 81 dev_err(&client->dev, "Failed to read prom word\n"); 82 return ret; 83 } 84 *word = ret; 85 86 return 0; 87 } 88 EXPORT_SYMBOL(ms_sensors_read_prom_word); 89 90 /** 91 * ms_sensors_convert_and_read() - ADC conversion & read function 92 * @cli: pointer to device client 93 * @conv: ADC conversion command. Depends on device in use 94 * @rd: ADC read command. Depends on device in use 95 * @delay: usleep minimal delay after conversion command is issued 96 * @adc: pointer to ADC destination value 97 * 98 * Generic ADC conversion & read function for Measurement Specialties 99 * devices. 100 * The function will issue conversion command, sleep appopriate delay, and 101 * issue command to read ADC. 102 * 103 * Return: 0 on success, negative errno otherwise. 104 */ 105 int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd, 106 unsigned int delay, u32 *adc) 107 { 108 int ret; 109 __be32 buf = 0; 110 struct i2c_client *client = cli; 111 112 /* Trigger conversion */ 113 ret = i2c_smbus_write_byte(client, conv); 114 if (ret) 115 goto err; 116 usleep_range(delay, delay + 1000); 117 118 /* Retrieve ADC value */ 119 if (rd != MS_SENSORS_NO_READ_CMD) 120 ret = i2c_smbus_read_i2c_block_data(client, rd, 3, (u8 *)&buf); 121 else 122 ret = i2c_master_recv(client, (u8 *)&buf, 3); 123 if (ret < 0) 124 goto err; 125 126 dev_dbg(&client->dev, "ADC raw value : %x\n", be32_to_cpu(buf) >> 8); 127 *adc = be32_to_cpu(buf) >> 8; 128 129 return 0; 130 err: 131 dev_err(&client->dev, "Unable to make sensor adc conversion\n"); 132 return ret; 133 } 134 EXPORT_SYMBOL(ms_sensors_convert_and_read); 135 136 /** 137 * ms_sensors_crc_valid() - CRC check function 138 * @value: input and CRC compare value 139 * 140 * Cyclic Redundancy Check function used in TSYS02D, HTU21, MS8607. 141 * This function performs a x^8 + x^5 + x^4 + 1 polynomial CRC. 142 * The argument contains CRC value in LSB byte while the bytes 1 and 2 143 * are used for CRC computation. 144 * 145 * Return: 1 if CRC is valid, 0 otherwise. 146 */ 147 static bool ms_sensors_crc_valid(u32 value) 148 { 149 u32 polynom = 0x988000; /* x^8 + x^5 + x^4 + 1 */ 150 u32 msb = 0x800000; 151 u32 mask = 0xFF8000; 152 u32 result = value & 0xFFFF00; 153 u8 crc = value & 0xFF; 154 155 while (msb != 0x80) { 156 if (result & msb) 157 result = ((result ^ polynom) & mask) 158 | (result & ~mask); 159 msb >>= 1; 160 mask >>= 1; 161 polynom >>= 1; 162 } 163 164 return result == crc; 165 } 166 167 /** 168 * ms_sensors_read_serial() - Serial number read function 169 * @cli: pointer to i2c client 170 * @sn: pointer to 64-bits destination value 171 * 172 * Generic i2c serial number read function for Measurement Specialties devices. 173 * This function is used for TSYS02d, HTU21, MS8607 chipset. 174 * Refer to datasheet: 175 * http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf 176 * 177 * Sensor raw MSB serial number format is the following : 178 * [ SNB3, CRC, SNB2, CRC, SNB1, CRC, SNB0, CRC] 179 * Sensor raw LSB serial number format is the following : 180 * [ X, X, SNC1, SNC0, CRC, SNA1, SNA0, CRC] 181 * The resulting serial number is following : 182 * [ SNA1, SNA0, SNB3, SNB2, SNB1, SNB0, SNC1, SNC0] 183 * 184 * Return: 0 on success, negative errno otherwise. 185 */ 186 int ms_sensors_read_serial(struct i2c_client *client, u64 *sn) 187 { 188 u8 i; 189 __be64 rcv_buf = 0; 190 u64 rcv_val; 191 __be16 send_buf; 192 int ret; 193 194 struct i2c_msg msg[2] = { 195 { 196 .addr = client->addr, 197 .flags = client->flags, 198 .len = 2, 199 .buf = (__u8 *)&send_buf, 200 }, 201 { 202 .addr = client->addr, 203 .flags = client->flags | I2C_M_RD, 204 .buf = (__u8 *)&rcv_buf, 205 }, 206 }; 207 208 /* Read MSB part of serial number */ 209 send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB); 210 msg[1].len = 8; 211 ret = i2c_transfer(client->adapter, msg, 2); 212 if (ret < 0) { 213 dev_err(&client->dev, "Unable to read device serial number"); 214 return ret; 215 } 216 217 rcv_val = be64_to_cpu(rcv_buf); 218 dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_val); 219 220 for (i = 0; i < 64; i += 16) { 221 if (!ms_sensors_crc_valid((rcv_val >> i) & 0xFFFF)) 222 return -ENODEV; 223 } 224 225 *sn = (((rcv_val >> 32) & 0xFF000000) | 226 ((rcv_val >> 24) & 0x00FF0000) | 227 ((rcv_val >> 16) & 0x0000FF00) | 228 ((rcv_val >> 8) & 0x000000FF)) << 16; 229 230 /* Read LSB part of serial number */ 231 send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB); 232 msg[1].len = 6; 233 rcv_buf = 0; 234 ret = i2c_transfer(client->adapter, msg, 2); 235 if (ret < 0) { 236 dev_err(&client->dev, "Unable to read device serial number"); 237 return ret; 238 } 239 240 rcv_val = be64_to_cpu(rcv_buf) >> 16; 241 dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_val); 242 243 for (i = 0; i < 48; i += 24) { 244 if (!ms_sensors_crc_valid((rcv_val >> i) & 0xFFFFFF)) 245 return -ENODEV; 246 } 247 248 *sn |= (rcv_val & 0xFFFF00) << 40 | (rcv_val >> 32); 249 250 return 0; 251 } 252 EXPORT_SYMBOL(ms_sensors_read_serial); 253 254 static int ms_sensors_read_config_reg(struct i2c_client *client, 255 u8 *config_reg) 256 { 257 int ret; 258 259 ret = i2c_smbus_write_byte(client, MS_SENSORS_CONFIG_REG_READ); 260 if (ret) { 261 dev_err(&client->dev, "Unable to read config register"); 262 return ret; 263 } 264 265 ret = i2c_master_recv(client, config_reg, 1); 266 if (ret < 0) { 267 dev_err(&client->dev, "Unable to read config register"); 268 return ret; 269 } 270 dev_dbg(&client->dev, "Config register :%x\n", *config_reg); 271 272 return 0; 273 } 274 275 /** 276 * ms_sensors_write_resolution() - Set resolution function 277 * @dev_data: pointer to temperature/humidity device data 278 * @i: resolution index to set 279 * 280 * This function will program the appropriate resolution based on the index 281 * provided when user space will set samp_freq channel. 282 * This function is used for TSYS02D, HTU21 and MS8607 chipsets. 283 * 284 * Return: 0 on success, negative errno otherwise. 285 */ 286 ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data, 287 u8 i) 288 { 289 u8 config_reg; 290 int ret; 291 292 ret = ms_sensors_read_config_reg(dev_data->client, &config_reg); 293 if (ret) 294 return ret; 295 296 config_reg &= 0x7E; 297 config_reg |= ((i & 1) << 7) + ((i & 2) >> 1); 298 299 return i2c_smbus_write_byte_data(dev_data->client, 300 MS_SENSORS_CONFIG_REG_WRITE, 301 config_reg); 302 } 303 EXPORT_SYMBOL(ms_sensors_write_resolution); 304 305 /** 306 * ms_sensors_show_battery_low() - Show device battery low indicator 307 * @dev_data: pointer to temperature/humidity device data 308 * @buf: pointer to char buffer to write result 309 * 310 * This function will read battery indicator value in the device and 311 * return 1 if the device voltage is below 2.25V. 312 * This function is used for TSYS02D, HTU21 and MS8607 chipsets. 313 * 314 * Return: length of sprintf on success, negative errno otherwise. 315 */ 316 ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data, 317 char *buf) 318 { 319 int ret; 320 u8 config_reg; 321 322 mutex_lock(&dev_data->lock); 323 ret = ms_sensors_read_config_reg(dev_data->client, &config_reg); 324 mutex_unlock(&dev_data->lock); 325 if (ret) 326 return ret; 327 328 return sprintf(buf, "%d\n", (config_reg & 0x40) >> 6); 329 } 330 EXPORT_SYMBOL(ms_sensors_show_battery_low); 331 332 /** 333 * ms_sensors_show_heater() - Show device heater 334 * @dev_data: pointer to temperature/humidity device data 335 * @buf: pointer to char buffer to write result 336 * 337 * This function will read heater enable value in the device and 338 * return 1 if the heater is enabled. 339 * This function is used for HTU21 and MS8607 chipsets. 340 * 341 * Return: length of sprintf on success, negative errno otherwise. 342 */ 343 ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data, 344 char *buf) 345 { 346 u8 config_reg; 347 int ret; 348 349 mutex_lock(&dev_data->lock); 350 ret = ms_sensors_read_config_reg(dev_data->client, &config_reg); 351 mutex_unlock(&dev_data->lock); 352 if (ret) 353 return ret; 354 355 return sprintf(buf, "%d\n", (config_reg & 0x4) >> 2); 356 } 357 EXPORT_SYMBOL(ms_sensors_show_heater); 358 359 /** 360 * ms_sensors_write_heater() - Write device heater 361 * @dev_data: pointer to temperature/humidity device data 362 * @buf: pointer to char buffer from user space 363 * @len: length of buf 364 * 365 * This function will write 1 or 0 value in the device 366 * to enable or disable heater. 367 * This function is used for HTU21 and MS8607 chipsets. 368 * 369 * Return: length of buffer, negative errno otherwise. 370 */ 371 ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data, 372 const char *buf, size_t len) 373 { 374 u8 val, config_reg; 375 int ret; 376 377 ret = kstrtou8(buf, 10, &val); 378 if (ret) 379 return ret; 380 381 if (val > 1) 382 return -EINVAL; 383 384 mutex_lock(&dev_data->lock); 385 ret = ms_sensors_read_config_reg(dev_data->client, &config_reg); 386 if (ret) { 387 mutex_unlock(&dev_data->lock); 388 return ret; 389 } 390 391 config_reg &= 0xFB; 392 config_reg |= val << 2; 393 394 ret = i2c_smbus_write_byte_data(dev_data->client, 395 MS_SENSORS_CONFIG_REG_WRITE, 396 config_reg); 397 mutex_unlock(&dev_data->lock); 398 if (ret) { 399 dev_err(&dev_data->client->dev, "Unable to write config register\n"); 400 return ret; 401 } 402 403 return len; 404 } 405 EXPORT_SYMBOL(ms_sensors_write_heater); 406 407 /** 408 * ms_sensors_ht_read_temperature() - Read temperature 409 * @dev_data: pointer to temperature/humidity device data 410 * @temperature:pointer to temperature destination value 411 * 412 * This function will get temperature ADC value from the device, 413 * check the CRC and compute the temperature value. 414 * This function is used for TSYS02D, HTU21 and MS8607 chipsets. 415 * 416 * Return: 0 on success, negative errno otherwise. 417 */ 418 int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data, 419 s32 *temperature) 420 { 421 int ret; 422 u32 adc; 423 u16 delay; 424 425 mutex_lock(&dev_data->lock); 426 delay = ms_sensors_ht_t_conversion_time[dev_data->res_index]; 427 ret = ms_sensors_convert_and_read(dev_data->client, 428 MS_SENSORS_HT_T_CONVERSION_START, 429 MS_SENSORS_NO_READ_CMD, 430 delay, &adc); 431 mutex_unlock(&dev_data->lock); 432 if (ret) 433 return ret; 434 435 if (!ms_sensors_crc_valid(adc)) { 436 dev_err(&dev_data->client->dev, 437 "Temperature read crc check error\n"); 438 return -ENODEV; 439 } 440 441 /* Temperature algorithm */ 442 *temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850; 443 444 return 0; 445 } 446 EXPORT_SYMBOL(ms_sensors_ht_read_temperature); 447 448 /** 449 * ms_sensors_ht_read_humidity() - Read humidity 450 * @dev_data: pointer to temperature/humidity device data 451 * @humidity: pointer to humidity destination value 452 * 453 * This function will get humidity ADC value from the device, 454 * check the CRC and compute the temperature value. 455 * This function is used for HTU21 and MS8607 chipsets. 456 * 457 * Return: 0 on success, negative errno otherwise. 458 */ 459 int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data, 460 u32 *humidity) 461 { 462 int ret; 463 u32 adc; 464 u16 delay; 465 466 mutex_lock(&dev_data->lock); 467 delay = ms_sensors_ht_h_conversion_time[dev_data->res_index]; 468 ret = ms_sensors_convert_and_read(dev_data->client, 469 MS_SENSORS_HT_H_CONVERSION_START, 470 MS_SENSORS_NO_READ_CMD, 471 delay, &adc); 472 mutex_unlock(&dev_data->lock); 473 if (ret) 474 return ret; 475 476 if (!ms_sensors_crc_valid(adc)) { 477 dev_err(&dev_data->client->dev, 478 "Humidity read crc check error\n"); 479 return -ENODEV; 480 } 481 482 /* Humidity algorithm */ 483 *humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000; 484 if (*humidity >= 100000) 485 *humidity = 100000; 486 487 return 0; 488 } 489 EXPORT_SYMBOL(ms_sensors_ht_read_humidity); 490 491 /** 492 * ms_sensors_tp_crc_valid() - CRC check function for 493 * Temperature and pressure devices. 494 * This function is only used when reading PROM coefficients 495 * 496 * @prom: pointer to PROM coefficients array 497 * @len: length of PROM coefficients array 498 * 499 * Return: True if CRC is ok. 500 */ 501 static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len) 502 { 503 unsigned int cnt, n_bit; 504 u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12; 505 506 prom[len - 1] = 0; 507 prom[0] &= 0x0FFF; /* Clear the CRC computation part */ 508 509 for (cnt = 0; cnt < len * 2; cnt++) { 510 if (cnt % 2 == 1) 511 n_rem ^= prom[cnt >> 1] & 0x00FF; 512 else 513 n_rem ^= prom[cnt >> 1] >> 8; 514 515 for (n_bit = 8; n_bit > 0; n_bit--) { 516 if (n_rem & 0x8000) 517 n_rem = (n_rem << 1) ^ 0x3000; 518 else 519 n_rem <<= 1; 520 } 521 } 522 n_rem >>= 12; 523 prom[0] = crc_read; 524 525 return n_rem == crc; 526 } 527 528 /** 529 * ms_sensors_tp_read_prom() - prom coeff read function 530 * @dev_data: pointer to temperature/pressure device data 531 * 532 * This function will read prom coefficients and check CRC. 533 * This function is used for MS5637 and MS8607 chipsets. 534 * 535 * Return: 0 on success, negative errno otherwise. 536 */ 537 int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data) 538 { 539 int i, ret; 540 541 for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) { 542 ret = ms_sensors_read_prom_word( 543 dev_data->client, 544 MS_SENSORS_TP_PROM_READ + (i << 1), 545 &dev_data->prom[i]); 546 547 if (ret) 548 return ret; 549 } 550 551 if (!ms_sensors_tp_crc_valid(dev_data->prom, 552 MS_SENSORS_TP_PROM_WORDS_NB + 1)) { 553 dev_err(&dev_data->client->dev, 554 "Calibration coefficients crc check error\n"); 555 return -ENODEV; 556 } 557 558 return 0; 559 } 560 EXPORT_SYMBOL(ms_sensors_tp_read_prom); 561 562 /** 563 * ms_sensors_read_temp_and_pressure() - read temp and pressure 564 * @dev_data: pointer to temperature/pressure device data 565 * @temperature:pointer to temperature destination value 566 * @pressure: pointer to pressure destination value 567 * 568 * This function will read ADC and compute pressure and temperature value. 569 * This function is used for MS5637 and MS8607 chipsets. 570 * 571 * Return: 0 on success, negative errno otherwise. 572 */ 573 int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data, 574 int *temperature, 575 unsigned int *pressure) 576 { 577 int ret; 578 u32 t_adc, p_adc; 579 s32 dt, temp; 580 s64 off, sens, t2, off2, sens2; 581 u16 *prom = dev_data->prom, delay; 582 583 mutex_lock(&dev_data->lock); 584 delay = ms_sensors_tp_conversion_time[dev_data->res_index]; 585 586 ret = ms_sensors_convert_and_read( 587 dev_data->client, 588 MS_SENSORS_TP_T_CONVERSION_START + 589 dev_data->res_index * 2, 590 MS_SENSORS_TP_ADC_READ, 591 delay, &t_adc); 592 if (ret) { 593 mutex_unlock(&dev_data->lock); 594 return ret; 595 } 596 597 ret = ms_sensors_convert_and_read( 598 dev_data->client, 599 MS_SENSORS_TP_P_CONVERSION_START + 600 dev_data->res_index * 2, 601 MS_SENSORS_TP_ADC_READ, 602 delay, &p_adc); 603 mutex_unlock(&dev_data->lock); 604 if (ret) 605 return ret; 606 607 dt = (s32)t_adc - (prom[5] << 8); 608 609 /* Actual temperature = 2000 + dT * TEMPSENS */ 610 temp = 2000 + (((s64)dt * prom[6]) >> 23); 611 612 /* Second order temperature compensation */ 613 if (temp < 2000) { 614 s64 tmp = (s64)temp - 2000; 615 616 t2 = (3 * ((s64)dt * (s64)dt)) >> 33; 617 off2 = (61 * tmp * tmp) >> 4; 618 sens2 = (29 * tmp * tmp) >> 4; 619 620 if (temp < -1500) { 621 s64 tmp = (s64)temp + 1500; 622 623 off2 += 17 * tmp * tmp; 624 sens2 += 9 * tmp * tmp; 625 } 626 } else { 627 t2 = (5 * ((s64)dt * (s64)dt)) >> 38; 628 off2 = 0; 629 sens2 = 0; 630 } 631 632 /* OFF = OFF_T1 + TCO * dT */ 633 off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6); 634 off -= off2; 635 636 /* Sensitivity at actual temperature = SENS_T1 + TCS * dT */ 637 sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7); 638 sens -= sens2; 639 640 /* Temperature compensated pressure = D1 * SENS - OFF */ 641 *temperature = (temp - t2) * 10; 642 *pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15); 643 644 return 0; 645 } 646 EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure); 647 648 MODULE_DESCRIPTION("Measurement-Specialties common i2c driver"); 649 MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>"); 650 MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>"); 651 MODULE_LICENSE("GPL v2"); 652 653