1 /* 2 * HID Sensors Driver 3 * Copyright (c) 2012, Intel Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 */ 19 #include <linux/device.h> 20 #include <linux/platform_device.h> 21 #include <linux/module.h> 22 #include <linux/interrupt.h> 23 #include <linux/irq.h> 24 #include <linux/slab.h> 25 #include <linux/hid-sensor-hub.h> 26 #include <linux/iio/iio.h> 27 #include <linux/iio/sysfs.h> 28 29 static struct { 30 u32 usage_id; 31 int unit; /* 0 for default others from HID sensor spec */ 32 int scale_val0; /* scale, whole number */ 33 int scale_val1; /* scale, fraction in nanos */ 34 } unit_conversion[] = { 35 {HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650000}, 36 {HID_USAGE_SENSOR_ACCEL_3D, 37 HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0}, 38 {HID_USAGE_SENSOR_ACCEL_3D, 39 HID_USAGE_SENSOR_UNITS_G, 9, 806650000}, 40 41 {HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453293}, 42 {HID_USAGE_SENSOR_GYRO_3D, 43 HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0}, 44 {HID_USAGE_SENSOR_GYRO_3D, 45 HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453293}, 46 47 {HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000000}, 48 {HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0}, 49 50 {HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453293}, 51 {HID_USAGE_SENSOR_INCLINOMETER_3D, 52 HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453293}, 53 {HID_USAGE_SENSOR_INCLINOMETER_3D, 54 HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0}, 55 56 {HID_USAGE_SENSOR_ALS, 0, 1, 0}, 57 {HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0}, 58 59 {HID_USAGE_SENSOR_PRESSURE, 0, 100, 0}, 60 {HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 0, 1000000}, 61 62 {HID_USAGE_SENSOR_TIME_TIMESTAMP, 0, 1000000000, 0}, 63 {HID_USAGE_SENSOR_TIME_TIMESTAMP, HID_USAGE_SENSOR_UNITS_MILLISECOND, 64 1000000, 0}, 65 }; 66 67 static int pow_10(unsigned power) 68 { 69 int i; 70 int ret = 1; 71 for (i = 0; i < power; ++i) 72 ret = ret * 10; 73 74 return ret; 75 } 76 77 static void simple_div(int dividend, int divisor, int *whole, 78 int *micro_frac) 79 { 80 int rem; 81 int exp = 0; 82 83 *micro_frac = 0; 84 if (divisor == 0) { 85 *whole = 0; 86 return; 87 } 88 *whole = dividend/divisor; 89 rem = dividend % divisor; 90 if (rem) { 91 while (rem <= divisor) { 92 rem *= 10; 93 exp++; 94 } 95 *micro_frac = (rem / divisor) * pow_10(6-exp); 96 } 97 } 98 99 static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2) 100 { 101 *val1 = no/pow_10(exp); 102 *val2 = no%pow_10(exp) * 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 * 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 u32 value; 138 int sign = 1; 139 140 if (val1 < 0 || val2 < 0) 141 sign = -1; 142 exp = hid_sensor_convert_exponent(exp); 143 if (exp < 0) { 144 value = abs(val1) * pow_10(-exp); 145 value += abs(val2) / pow_10(6+exp); 146 } else 147 value = abs(val1) / pow_10(exp); 148 if (sign < 0) 149 value = ((1LL << (size * 8)) - value); 150 151 return value; 152 } 153 154 s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) 155 { 156 s32 value = 0; 157 int ret; 158 159 ret = sensor_hub_get_feature(st->hsdev, 160 st->poll.report_id, 161 st->poll.index, sizeof(value), &value); 162 163 if (ret < 0 || value < 0) { 164 return -EINVAL; 165 } else { 166 if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) 167 value = value * 1000; 168 } 169 170 return value; 171 } 172 EXPORT_SYMBOL(hid_sensor_read_poll_value); 173 174 int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, 175 int *val1, int *val2) 176 { 177 s32 value; 178 int ret; 179 180 ret = sensor_hub_get_feature(st->hsdev, 181 st->poll.report_id, 182 st->poll.index, sizeof(value), &value); 183 if (ret < 0 || value < 0) { 184 *val1 = *val2 = 0; 185 return -EINVAL; 186 } else { 187 if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND) 188 simple_div(1000, value, val1, val2); 189 else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) 190 simple_div(1, value, val1, val2); 191 else { 192 *val1 = *val2 = 0; 193 return -EINVAL; 194 } 195 } 196 197 return IIO_VAL_INT_PLUS_MICRO; 198 } 199 EXPORT_SYMBOL(hid_sensor_read_samp_freq_value); 200 201 int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, 202 int val1, int val2) 203 { 204 s32 value; 205 int ret; 206 207 if (val1 < 0 || val2 < 0) 208 return -EINVAL; 209 210 value = val1 * pow_10(6) + val2; 211 if (value) { 212 if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND) 213 value = pow_10(9)/value; 214 else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) 215 value = pow_10(6)/value; 216 else 217 value = 0; 218 } 219 ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id, 220 st->poll.index, sizeof(value), &value); 221 if (ret < 0 || value < 0) 222 ret = -EINVAL; 223 224 return ret; 225 } 226 EXPORT_SYMBOL(hid_sensor_write_samp_freq_value); 227 228 int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, 229 int *val1, int *val2) 230 { 231 s32 value; 232 int ret; 233 234 ret = sensor_hub_get_feature(st->hsdev, 235 st->sensitivity.report_id, 236 st->sensitivity.index, sizeof(value), 237 &value); 238 if (ret < 0 || value < 0) { 239 *val1 = *val2 = 0; 240 return -EINVAL; 241 } else { 242 convert_from_vtf_format(value, st->sensitivity.size, 243 st->sensitivity.unit_expo, 244 val1, val2); 245 } 246 247 return IIO_VAL_INT_PLUS_MICRO; 248 } 249 EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value); 250 251 int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, 252 int val1, int val2) 253 { 254 s32 value; 255 int ret; 256 257 if (val1 < 0 || val2 < 0) 258 return -EINVAL; 259 260 value = convert_to_vtf_format(st->sensitivity.size, 261 st->sensitivity.unit_expo, 262 val1, val2); 263 ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id, 264 st->sensitivity.index, sizeof(value), 265 &value); 266 if (ret < 0 || value < 0) 267 ret = -EINVAL; 268 269 return ret; 270 } 271 EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); 272 273 /* 274 * This fuction applies the unit exponent to the scale. 275 * For example: 276 * 9.806650000 ->exp:2-> val0[980]val1[665000000] 277 * 9.000806000 ->exp:2-> val0[900]val1[80600000] 278 * 0.174535293 ->exp:2-> val0[17]val1[453529300] 279 * 1.001745329 ->exp:0-> val0[1]val1[1745329] 280 * 1.001745329 ->exp:2-> val0[100]val1[174532900] 281 * 1.001745329 ->exp:4-> val0[10017]val1[453290000] 282 * 9.806650000 ->exp:-2-> val0[0]val1[98066500] 283 */ 284 static void adjust_exponent_nano(int *val0, int *val1, int scale0, 285 int scale1, int exp) 286 { 287 int i; 288 int x; 289 int res; 290 int rem; 291 292 if (exp > 0) { 293 *val0 = scale0 * pow_10(exp); 294 res = 0; 295 if (exp > 9) { 296 *val1 = 0; 297 return; 298 } 299 for (i = 0; i < exp; ++i) { 300 x = scale1 / pow_10(8 - i); 301 res += (pow_10(exp - 1 - i) * x); 302 scale1 = scale1 % pow_10(8 - i); 303 } 304 *val0 += res; 305 *val1 = scale1 * pow_10(exp); 306 } else if (exp < 0) { 307 exp = abs(exp); 308 if (exp > 9) { 309 *val0 = *val1 = 0; 310 return; 311 } 312 *val0 = scale0 / pow_10(exp); 313 rem = scale0 % pow_10(exp); 314 res = 0; 315 for (i = 0; i < (9 - exp); ++i) { 316 x = scale1 / pow_10(8 - i); 317 res += (pow_10(8 - exp - i) * x); 318 scale1 = scale1 % pow_10(8 - i); 319 } 320 *val1 = rem * pow_10(9 - exp) + res; 321 } else { 322 *val0 = scale0; 323 *val1 = scale1; 324 } 325 } 326 327 int hid_sensor_format_scale(u32 usage_id, 328 struct hid_sensor_hub_attribute_info *attr_info, 329 int *val0, int *val1) 330 { 331 int i; 332 int exp; 333 334 *val0 = 1; 335 *val1 = 0; 336 337 for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) { 338 if (unit_conversion[i].usage_id == usage_id && 339 unit_conversion[i].unit == attr_info->units) { 340 exp = hid_sensor_convert_exponent( 341 attr_info->unit_expo); 342 adjust_exponent_nano(val0, val1, 343 unit_conversion[i].scale_val0, 344 unit_conversion[i].scale_val1, exp); 345 break; 346 } 347 } 348 349 return IIO_VAL_INT_PLUS_NANO; 350 } 351 EXPORT_SYMBOL(hid_sensor_format_scale); 352 353 int64_t hid_sensor_convert_timestamp(struct hid_sensor_common *st, 354 int64_t raw_value) 355 { 356 return st->timestamp_ns_scale * raw_value; 357 } 358 EXPORT_SYMBOL(hid_sensor_convert_timestamp); 359 360 static 361 int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev, 362 u32 usage_id, 363 struct hid_sensor_common *st) 364 { 365 sensor_hub_input_get_attribute_info(hsdev, 366 HID_FEATURE_REPORT, usage_id, 367 HID_USAGE_SENSOR_PROP_REPORT_INTERVAL, 368 &st->poll); 369 /* Default unit of measure is milliseconds */ 370 if (st->poll.units == 0) 371 st->poll.units = HID_USAGE_SENSOR_UNITS_MILLISECOND; 372 return 0; 373 374 } 375 376 int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, 377 u32 usage_id, 378 struct hid_sensor_common *st) 379 { 380 381 struct hid_sensor_hub_attribute_info timestamp; 382 383 hid_sensor_get_reporting_interval(hsdev, usage_id, st); 384 385 sensor_hub_input_get_attribute_info(hsdev, 386 HID_FEATURE_REPORT, usage_id, 387 HID_USAGE_SENSOR_PROP_REPORT_STATE, 388 &st->report_state); 389 390 sensor_hub_input_get_attribute_info(hsdev, 391 HID_FEATURE_REPORT, usage_id, 392 HID_USAGE_SENSOR_PROY_POWER_STATE, 393 &st->power_state); 394 395 sensor_hub_input_get_attribute_info(hsdev, 396 HID_FEATURE_REPORT, usage_id, 397 HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS, 398 &st->sensitivity); 399 400 sensor_hub_input_get_attribute_info(hsdev, 401 HID_INPUT_REPORT, usage_id, 402 HID_USAGE_SENSOR_TIME_TIMESTAMP, 403 ×tamp); 404 if (timestamp.index >= 0 && timestamp.report_id) { 405 int val0, val1; 406 407 hid_sensor_format_scale(HID_USAGE_SENSOR_TIME_TIMESTAMP, 408 ×tamp, &val0, &val1); 409 st->timestamp_ns_scale = val0; 410 } else 411 st->timestamp_ns_scale = 1000000000; 412 413 hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x %x:%x\n", 414 st->poll.index, st->poll.report_id, 415 st->report_state.index, st->report_state.report_id, 416 st->power_state.index, st->power_state.report_id, 417 st->sensitivity.index, st->sensitivity.report_id, 418 timestamp.index, timestamp.report_id); 419 420 return 0; 421 } 422 EXPORT_SYMBOL(hid_sensor_parse_common_attributes); 423 424 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); 425 MODULE_DESCRIPTION("HID Sensor common attribute processing"); 426 MODULE_LICENSE("GPL"); 427