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