1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * HID Sensors Driver 4 * Copyright (c) 2012, Intel Corporation. 5 */ 6 #include <linux/module.h> 7 #include <linux/kernel.h> 8 #include <linux/time.h> 9 #include <linux/units.h> 10 11 #include <linux/hid-sensor-hub.h> 12 #include <linux/iio/iio.h> 13 14 static const struct { 15 u32 usage_id; 16 int unit; /* 0 for default others from HID sensor spec */ 17 int scale_val0; /* scale, whole number */ 18 int scale_val1; /* scale, fraction in nanos */ 19 } unit_conversion[] = { 20 {HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650000}, 21 {HID_USAGE_SENSOR_ACCEL_3D, 22 HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0}, 23 {HID_USAGE_SENSOR_ACCEL_3D, 24 HID_USAGE_SENSOR_UNITS_G, 9, 806650000}, 25 26 {HID_USAGE_SENSOR_GRAVITY_VECTOR, 0, 9, 806650000}, 27 {HID_USAGE_SENSOR_GRAVITY_VECTOR, 28 HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0}, 29 {HID_USAGE_SENSOR_GRAVITY_VECTOR, 30 HID_USAGE_SENSOR_UNITS_G, 9, 806650000}, 31 32 {HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453293}, 33 {HID_USAGE_SENSOR_GYRO_3D, 34 HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0}, 35 {HID_USAGE_SENSOR_GYRO_3D, 36 HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453293}, 37 38 {HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000000}, 39 {HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0}, 40 41 {HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453293}, 42 {HID_USAGE_SENSOR_INCLINOMETER_3D, 43 HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453293}, 44 {HID_USAGE_SENSOR_INCLINOMETER_3D, 45 HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0}, 46 47 {HID_USAGE_SENSOR_ALS, 0, 1, 0}, 48 {HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0}, 49 50 {HID_USAGE_SENSOR_PRESSURE, 0, 100, 0}, 51 {HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 0, 1000000}, 52 53 {HID_USAGE_SENSOR_TIME_TIMESTAMP, 0, 1000000000, 0}, 54 {HID_USAGE_SENSOR_TIME_TIMESTAMP, HID_USAGE_SENSOR_UNITS_MILLISECOND, 55 1000000, 0}, 56 57 {HID_USAGE_SENSOR_DEVICE_ORIENTATION, 0, 1, 0}, 58 59 {HID_USAGE_SENSOR_RELATIVE_ORIENTATION, 0, 1, 0}, 60 61 {HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION, 0, 1, 0}, 62 63 {HID_USAGE_SENSOR_TEMPERATURE, 0, 1000, 0}, 64 {HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 1000, 0}, 65 66 {HID_USAGE_SENSOR_HUMIDITY, 0, 1000, 0}, 67 {HID_USAGE_SENSOR_HINGE, 0, 0, 17453293}, 68 {HID_USAGE_SENSOR_HINGE, HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453293}, 69 70 {HID_USAGE_SENSOR_HUMAN_PRESENCE, 0, 1, 0}, 71 {HID_USAGE_SENSOR_HUMAN_PROXIMITY, 0, 1, 0}, 72 {HID_USAGE_SENSOR_HUMAN_ATTENTION, 0, 1, 0}, 73 }; 74 75 static void simple_div(int dividend, int divisor, int *whole, 76 int *micro_frac) 77 { 78 int rem; 79 int exp = 0; 80 81 *micro_frac = 0; 82 if (divisor == 0) { 83 *whole = 0; 84 return; 85 } 86 *whole = dividend/divisor; 87 rem = dividend % divisor; 88 if (rem) { 89 while (rem <= divisor) { 90 rem *= 10; 91 exp++; 92 } 93 *micro_frac = (rem / divisor) * int_pow(10, 6 - exp); 94 } 95 } 96 97 static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2) 98 { 99 int divisor = int_pow(10, exp); 100 101 *val1 = no / divisor; 102 *val2 = no % divisor * int_pow(10, 6 - exp); 103 } 104 105 /* 106 VTF format uses exponent and variable size format. 107 For example if the size is 2 bytes 108 0x0067 with VTF16E14 format -> +1.03 109 To convert just change to 0x67 to decimal and use two decimal as E14 stands 110 for 10^-2. 111 Negative numbers are 2's complement 112 */ 113 static void convert_from_vtf_format(u32 value, int size, int exp, 114 int *val1, int *val2) 115 { 116 int sign = 1; 117 118 if (value & BIT(size*8 - 1)) { 119 value = ((1LL << (size * 8)) - value); 120 sign = -1; 121 } 122 exp = hid_sensor_convert_exponent(exp); 123 if (exp >= 0) { 124 *val1 = sign * value * int_pow(10, exp); 125 *val2 = 0; 126 } else { 127 split_micro_fraction(value, -exp, val1, val2); 128 if (*val1) 129 *val1 = sign * (*val1); 130 else 131 *val2 = sign * (*val2); 132 } 133 } 134 135 static u32 convert_to_vtf_format(int size, int exp, int val1, int val2) 136 { 137 int divisor; 138 u32 value; 139 int sign = 1; 140 141 if (val1 < 0 || val2 < 0) 142 sign = -1; 143 exp = hid_sensor_convert_exponent(exp); 144 if (exp < 0) { 145 divisor = int_pow(10, 6 + exp); 146 value = abs(val1) * int_pow(10, -exp); 147 value += abs(val2) / divisor; 148 } else { 149 divisor = int_pow(10, exp); 150 value = abs(val1) / divisor; 151 } 152 if (sign < 0) 153 value = ((1LL << (size * 8)) - value); 154 155 return value; 156 } 157 158 s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) 159 { 160 s32 value = 0; 161 int ret; 162 163 ret = sensor_hub_get_feature(st->hsdev, 164 st->poll.report_id, 165 st->poll.index, sizeof(value), &value); 166 167 if (ret < 0 || value < 0) { 168 return -EINVAL; 169 } else { 170 if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) 171 value = value * 1000; 172 } 173 174 return value; 175 } 176 EXPORT_SYMBOL_NS(hid_sensor_read_poll_value, "IIO_HID_ATTRIBUTES"); 177 178 int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, 179 int *val1, int *val2) 180 { 181 s32 value; 182 int ret; 183 184 ret = sensor_hub_get_feature(st->hsdev, 185 st->poll.report_id, 186 st->poll.index, sizeof(value), &value); 187 if (ret < 0 || value < 0) { 188 *val1 = *val2 = 0; 189 return -EINVAL; 190 } else { 191 if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND) 192 simple_div(1000, value, val1, val2); 193 else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) 194 simple_div(1, value, val1, val2); 195 else { 196 *val1 = *val2 = 0; 197 return -EINVAL; 198 } 199 } 200 201 return IIO_VAL_INT_PLUS_MICRO; 202 } 203 EXPORT_SYMBOL_NS(hid_sensor_read_samp_freq_value, "IIO_HID"); 204 205 int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, 206 int val1, int val2) 207 { 208 s32 value; 209 int ret; 210 211 if (val1 < 0 || val2 < 0) 212 return -EINVAL; 213 214 value = val1 * HZ_PER_MHZ + val2; 215 if (value) { 216 if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND) 217 value = NSEC_PER_SEC / value; 218 else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) 219 value = USEC_PER_SEC / value; 220 else 221 value = 0; 222 } 223 ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id, 224 st->poll.index, sizeof(value), &value); 225 if (ret < 0 || value < 0) 226 return -EINVAL; 227 228 ret = sensor_hub_get_feature(st->hsdev, 229 st->poll.report_id, 230 st->poll.index, sizeof(value), &value); 231 if (ret < 0 || value < 0) 232 return -EINVAL; 233 234 st->poll_interval = value; 235 236 return 0; 237 } 238 EXPORT_SYMBOL_NS(hid_sensor_write_samp_freq_value, "IIO_HID"); 239 240 int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, 241 int *val1, int *val2) 242 { 243 s32 value; 244 int ret; 245 246 ret = sensor_hub_get_feature(st->hsdev, 247 st->sensitivity.report_id, 248 st->sensitivity.index, sizeof(value), 249 &value); 250 if (ret < 0 || value < 0) { 251 *val1 = *val2 = 0; 252 return -EINVAL; 253 } else { 254 convert_from_vtf_format(value, st->sensitivity.size, 255 st->sensitivity.unit_expo, 256 val1, val2); 257 } 258 259 return IIO_VAL_INT_PLUS_MICRO; 260 } 261 EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_value, "IIO_HID"); 262 263 int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1, 264 int *val2) 265 { 266 s32 value; 267 int ret; 268 269 ret = sensor_hub_get_feature(st->hsdev, 270 st->sensitivity_rel.report_id, 271 st->sensitivity_rel.index, sizeof(value), 272 &value); 273 if (ret < 0 || value < 0) { 274 *val1 = *val2 = 0; 275 return -EINVAL; 276 } 277 278 convert_from_vtf_format(value, st->sensitivity_rel.size, 279 st->sensitivity_rel.unit_expo, val1, val2); 280 281 return IIO_VAL_INT_PLUS_MICRO; 282 } 283 EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_rel_value, "IIO_HID"); 284 285 286 int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, 287 int val1, int val2) 288 { 289 s32 value; 290 int ret; 291 292 if (val1 < 0 || val2 < 0) 293 return -EINVAL; 294 295 value = convert_to_vtf_format(st->sensitivity.size, 296 st->sensitivity.unit_expo, 297 val1, val2); 298 ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id, 299 st->sensitivity.index, sizeof(value), 300 &value); 301 if (ret < 0 || value < 0) 302 return -EINVAL; 303 304 ret = sensor_hub_get_feature(st->hsdev, 305 st->sensitivity.report_id, 306 st->sensitivity.index, sizeof(value), 307 &value); 308 if (ret < 0 || value < 0) 309 return -EINVAL; 310 311 st->raw_hystersis = value; 312 313 return 0; 314 } 315 EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_value, "IIO_HID"); 316 317 int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, 318 int val1, int val2) 319 { 320 s32 value; 321 int ret; 322 323 if (val1 < 0 || val2 < 0) 324 return -EINVAL; 325 326 value = convert_to_vtf_format(st->sensitivity_rel.size, 327 st->sensitivity_rel.unit_expo, 328 val1, val2); 329 ret = sensor_hub_set_feature(st->hsdev, st->sensitivity_rel.report_id, 330 st->sensitivity_rel.index, sizeof(value), 331 &value); 332 if (ret < 0 || value < 0) 333 return -EINVAL; 334 335 ret = sensor_hub_get_feature(st->hsdev, 336 st->sensitivity_rel.report_id, 337 st->sensitivity_rel.index, sizeof(value), 338 &value); 339 if (ret < 0 || value < 0) 340 return -EINVAL; 341 342 st->raw_hystersis = value; 343 344 return 0; 345 } 346 EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, "IIO_HID"); 347 348 /* 349 * This fuction applies the unit exponent to the scale. 350 * For example: 351 * 9.806650000 ->exp:2-> val0[980]val1[665000000] 352 * 9.000806000 ->exp:2-> val0[900]val1[80600000] 353 * 0.174535293 ->exp:2-> val0[17]val1[453529300] 354 * 1.001745329 ->exp:0-> val0[1]val1[1745329] 355 * 1.001745329 ->exp:2-> val0[100]val1[174532900] 356 * 1.001745329 ->exp:4-> val0[10017]val1[453290000] 357 * 9.806650000 ->exp:-2-> val0[0]val1[98066500] 358 */ 359 static void adjust_exponent_nano(int *val0, int *val1, int scale0, 360 int scale1, int exp) 361 { 362 int divisor; 363 int i; 364 int x; 365 int res; 366 int rem; 367 368 if (exp > 0) { 369 *val0 = scale0 * int_pow(10, exp); 370 res = 0; 371 if (exp > 9) { 372 *val1 = 0; 373 return; 374 } 375 for (i = 0; i < exp; ++i) { 376 divisor = int_pow(10, 8 - i); 377 x = scale1 / divisor; 378 res += int_pow(10, exp - 1 - i) * x; 379 scale1 = scale1 % divisor; 380 } 381 *val0 += res; 382 *val1 = scale1 * int_pow(10, exp); 383 } else if (exp < 0) { 384 exp = abs(exp); 385 if (exp > 9) { 386 *val0 = *val1 = 0; 387 return; 388 } 389 divisor = int_pow(10, exp); 390 *val0 = scale0 / divisor; 391 rem = scale0 % divisor; 392 res = 0; 393 for (i = 0; i < (9 - exp); ++i) { 394 divisor = int_pow(10, 8 - i); 395 x = scale1 / divisor; 396 res += int_pow(10, 8 - exp - i) * x; 397 scale1 = scale1 % divisor; 398 } 399 *val1 = rem * int_pow(10, 9 - exp) + res; 400 } else { 401 *val0 = scale0; 402 *val1 = scale1; 403 } 404 } 405 406 int hid_sensor_format_scale(u32 usage_id, 407 struct hid_sensor_hub_attribute_info *attr_info, 408 int *val0, int *val1) 409 { 410 int i; 411 int exp; 412 413 *val0 = 1; 414 *val1 = 0; 415 416 for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) { 417 if (unit_conversion[i].usage_id == usage_id && 418 unit_conversion[i].unit == attr_info->units) { 419 exp = hid_sensor_convert_exponent( 420 attr_info->unit_expo); 421 adjust_exponent_nano(val0, val1, 422 unit_conversion[i].scale_val0, 423 unit_conversion[i].scale_val1, exp); 424 break; 425 } 426 } 427 428 return IIO_VAL_INT_PLUS_NANO; 429 } 430 EXPORT_SYMBOL_NS(hid_sensor_format_scale, "IIO_HID"); 431 432 int64_t hid_sensor_convert_timestamp(struct hid_sensor_common *st, 433 int64_t raw_value) 434 { 435 return st->timestamp_ns_scale * raw_value; 436 } 437 EXPORT_SYMBOL_NS(hid_sensor_convert_timestamp, "IIO_HID"); 438 439 static 440 int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev, 441 u32 usage_id, 442 struct hid_sensor_common *st) 443 { 444 sensor_hub_input_get_attribute_info(hsdev, 445 HID_FEATURE_REPORT, usage_id, 446 HID_USAGE_SENSOR_PROP_REPORT_INTERVAL, 447 &st->poll); 448 /* Default unit of measure is milliseconds */ 449 if (st->poll.units == 0) 450 st->poll.units = HID_USAGE_SENSOR_UNITS_MILLISECOND; 451 452 st->poll_interval = -1; 453 454 return 0; 455 456 } 457 458 static void hid_sensor_get_report_latency_info(struct hid_sensor_hub_device *hsdev, 459 u32 usage_id, 460 struct hid_sensor_common *st) 461 { 462 sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, 463 usage_id, 464 HID_USAGE_SENSOR_PROP_REPORT_LATENCY, 465 &st->report_latency); 466 467 hid_dbg(hsdev->hdev, "Report latency attributes: %x:%x\n", 468 st->report_latency.index, st->report_latency.report_id); 469 } 470 471 int hid_sensor_get_report_latency(struct hid_sensor_common *st) 472 { 473 int ret; 474 int value; 475 476 ret = sensor_hub_get_feature(st->hsdev, st->report_latency.report_id, 477 st->report_latency.index, sizeof(value), 478 &value); 479 if (ret < 0) 480 return ret; 481 482 return value; 483 } 484 EXPORT_SYMBOL_NS(hid_sensor_get_report_latency, "IIO_HID_ATTRIBUTES"); 485 486 int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency_ms) 487 { 488 return sensor_hub_set_feature(st->hsdev, st->report_latency.report_id, 489 st->report_latency.index, 490 sizeof(latency_ms), &latency_ms); 491 } 492 EXPORT_SYMBOL_NS(hid_sensor_set_report_latency, "IIO_HID_ATTRIBUTES"); 493 494 bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st) 495 { 496 return st->report_latency.index > 0 && st->report_latency.report_id > 0; 497 } 498 EXPORT_SYMBOL_NS(hid_sensor_batch_mode_supported, "IIO_HID_ATTRIBUTES"); 499 500 int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, 501 u32 usage_id, 502 struct hid_sensor_common *st, 503 const u32 *sensitivity_addresses, 504 u32 sensitivity_addresses_len) 505 { 506 507 struct hid_sensor_hub_attribute_info timestamp; 508 s32 value; 509 int ret; 510 int i; 511 512 hid_sensor_get_reporting_interval(hsdev, usage_id, st); 513 514 sensor_hub_input_get_attribute_info(hsdev, 515 HID_FEATURE_REPORT, usage_id, 516 HID_USAGE_SENSOR_PROP_REPORT_STATE, 517 &st->report_state); 518 519 sensor_hub_input_get_attribute_info(hsdev, 520 HID_FEATURE_REPORT, usage_id, 521 HID_USAGE_SENSOR_PROY_POWER_STATE, 522 &st->power_state); 523 524 st->power_state.logical_minimum = 1; 525 st->report_state.logical_minimum = 1; 526 527 sensor_hub_input_get_attribute_info(hsdev, 528 HID_FEATURE_REPORT, usage_id, 529 HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS, 530 &st->sensitivity); 531 532 sensor_hub_input_get_attribute_info(hsdev, 533 HID_FEATURE_REPORT, usage_id, 534 HID_USAGE_SENSOR_PROP_SENSITIVITY_REL_PCT, 535 &st->sensitivity_rel); 536 /* 537 * Set Sensitivity field ids, when there is no individual modifier, will 538 * check absolute sensitivity and relative sensitivity of data field 539 */ 540 for (i = 0; i < sensitivity_addresses_len; i++) { 541 if (st->sensitivity.index < 0) 542 sensor_hub_input_get_attribute_info( 543 hsdev, HID_FEATURE_REPORT, usage_id, 544 HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | 545 sensitivity_addresses[i], 546 &st->sensitivity); 547 548 if (st->sensitivity_rel.index < 0) 549 sensor_hub_input_get_attribute_info( 550 hsdev, HID_FEATURE_REPORT, usage_id, 551 HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_REL_PCT | 552 sensitivity_addresses[i], 553 &st->sensitivity_rel); 554 } 555 556 st->raw_hystersis = -1; 557 558 sensor_hub_input_get_attribute_info(hsdev, 559 HID_INPUT_REPORT, usage_id, 560 HID_USAGE_SENSOR_TIME_TIMESTAMP, 561 ×tamp); 562 if (timestamp.index >= 0 && timestamp.report_id) { 563 int val0, val1; 564 565 hid_sensor_format_scale(HID_USAGE_SENSOR_TIME_TIMESTAMP, 566 ×tamp, &val0, &val1); 567 st->timestamp_ns_scale = val0; 568 } else 569 st->timestamp_ns_scale = 1000000000; 570 571 hid_sensor_get_report_latency_info(hsdev, usage_id, st); 572 573 hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x %x:%x\n", 574 st->poll.index, st->poll.report_id, 575 st->report_state.index, st->report_state.report_id, 576 st->power_state.index, st->power_state.report_id, 577 st->sensitivity.index, st->sensitivity.report_id, 578 timestamp.index, timestamp.report_id); 579 580 ret = sensor_hub_get_feature(hsdev, 581 st->power_state.report_id, 582 st->power_state.index, sizeof(value), &value); 583 if (ret < 0) 584 return ret; 585 if (value < 0) 586 return -EINVAL; 587 588 return 0; 589 } 590 EXPORT_SYMBOL_NS(hid_sensor_parse_common_attributes, "IIO_HID"); 591 592 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); 593 MODULE_DESCRIPTION("HID Sensor common attribute processing"); 594 MODULE_LICENSE("GPL"); 595