1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * HID Sensors Driver 4 * Copyright (c) 2013, Intel Corporation. 5 */ 6 7 #include <linux/device.h> 8 #include <linux/platform_device.h> 9 #include <linux/module.h> 10 #include <linux/interrupt.h> 11 #include <linux/irq.h> 12 #include <linux/slab.h> 13 #include <linux/delay.h> 14 #include <linux/hid-sensor-hub.h> 15 #include <linux/iio/iio.h> 16 #include <linux/iio/sysfs.h> 17 #include <linux/iio/buffer.h> 18 #include "../common/hid-sensors/hid-sensor-trigger.h" 19 20 enum incl_3d_channel { 21 CHANNEL_SCAN_INDEX_X, 22 CHANNEL_SCAN_INDEX_Y, 23 CHANNEL_SCAN_INDEX_Z, 24 INCLI_3D_CHANNEL_MAX, 25 }; 26 27 #define CHANNEL_SCAN_INDEX_TIMESTAMP INCLI_3D_CHANNEL_MAX 28 29 struct incl_3d_state { 30 struct hid_sensor_hub_callbacks callbacks; 31 struct hid_sensor_common common_attributes; 32 struct hid_sensor_hub_attribute_info incl[INCLI_3D_CHANNEL_MAX]; 33 struct { 34 u32 incl_val[INCLI_3D_CHANNEL_MAX]; 35 u64 timestamp __aligned(8); 36 } scan; 37 int scale_pre_decml; 38 int scale_post_decml; 39 int scale_precision; 40 int value_offset; 41 s64 timestamp; 42 }; 43 44 static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = { 45 HID_USAGE_SENSOR_ORIENT_TILT_X, 46 HID_USAGE_SENSOR_ORIENT_TILT_Y, 47 HID_USAGE_SENSOR_ORIENT_TILT_Z 48 }; 49 50 /* Channel definitions */ 51 static const struct iio_chan_spec incl_3d_channels[] = { 52 { 53 .type = IIO_INCLI, 54 .modified = 1, 55 .channel2 = IIO_MOD_X, 56 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 57 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | 58 BIT(IIO_CHAN_INFO_SCALE) | 59 BIT(IIO_CHAN_INFO_SAMP_FREQ) | 60 BIT(IIO_CHAN_INFO_HYSTERESIS), 61 .scan_index = CHANNEL_SCAN_INDEX_X, 62 }, { 63 .type = IIO_INCLI, 64 .modified = 1, 65 .channel2 = IIO_MOD_Y, 66 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 67 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | 68 BIT(IIO_CHAN_INFO_SCALE) | 69 BIT(IIO_CHAN_INFO_SAMP_FREQ) | 70 BIT(IIO_CHAN_INFO_HYSTERESIS), 71 .scan_index = CHANNEL_SCAN_INDEX_Y, 72 }, { 73 .type = IIO_INCLI, 74 .modified = 1, 75 .channel2 = IIO_MOD_Z, 76 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 77 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | 78 BIT(IIO_CHAN_INFO_SCALE) | 79 BIT(IIO_CHAN_INFO_SAMP_FREQ) | 80 BIT(IIO_CHAN_INFO_HYSTERESIS), 81 .scan_index = CHANNEL_SCAN_INDEX_Z, 82 }, 83 IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP), 84 }; 85 86 /* Adjust channel real bits based on report descriptor */ 87 static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, 88 int size) 89 { 90 chan->scan_type.sign = 's'; 91 /* Real storage bits will change based on the report desc. */ 92 chan->scan_type.realbits = size * 8; 93 /* Maximum size of a sample to capture is u32 */ 94 chan->scan_type.storagebits = sizeof(u32) * 8; 95 } 96 97 /* Channel read_raw handler */ 98 static int incl_3d_read_raw(struct iio_dev *indio_dev, 99 struct iio_chan_spec const *chan, 100 int *val, int *val2, 101 long mask) 102 { 103 struct incl_3d_state *incl_state = iio_priv(indio_dev); 104 int report_id = -1; 105 u32 address; 106 int ret_type; 107 s32 min; 108 109 *val = 0; 110 *val2 = 0; 111 switch (mask) { 112 case IIO_CHAN_INFO_RAW: 113 hid_sensor_power_state(&incl_state->common_attributes, true); 114 report_id = incl_state->incl[chan->scan_index].report_id; 115 min = incl_state->incl[chan->scan_index].logical_minimum; 116 address = incl_3d_addresses[chan->scan_index]; 117 if (report_id >= 0) 118 *val = sensor_hub_input_attr_get_raw_value( 119 incl_state->common_attributes.hsdev, 120 HID_USAGE_SENSOR_INCLINOMETER_3D, address, 121 report_id, 122 SENSOR_HUB_SYNC, 123 min < 0); 124 else { 125 hid_sensor_power_state(&incl_state->common_attributes, 126 false); 127 return -EINVAL; 128 } 129 hid_sensor_power_state(&incl_state->common_attributes, false); 130 ret_type = IIO_VAL_INT; 131 break; 132 case IIO_CHAN_INFO_SCALE: 133 *val = incl_state->scale_pre_decml; 134 *val2 = incl_state->scale_post_decml; 135 ret_type = incl_state->scale_precision; 136 break; 137 case IIO_CHAN_INFO_OFFSET: 138 *val = incl_state->value_offset; 139 ret_type = IIO_VAL_INT; 140 break; 141 case IIO_CHAN_INFO_SAMP_FREQ: 142 ret_type = hid_sensor_read_samp_freq_value( 143 &incl_state->common_attributes, val, val2); 144 break; 145 case IIO_CHAN_INFO_HYSTERESIS: 146 ret_type = hid_sensor_read_raw_hyst_value( 147 &incl_state->common_attributes, val, val2); 148 break; 149 default: 150 ret_type = -EINVAL; 151 break; 152 } 153 154 return ret_type; 155 } 156 157 /* Channel write_raw handler */ 158 static int incl_3d_write_raw(struct iio_dev *indio_dev, 159 struct iio_chan_spec const *chan, 160 int val, 161 int val2, 162 long mask) 163 { 164 struct incl_3d_state *incl_state = iio_priv(indio_dev); 165 int ret; 166 167 switch (mask) { 168 case IIO_CHAN_INFO_SAMP_FREQ: 169 ret = hid_sensor_write_samp_freq_value( 170 &incl_state->common_attributes, val, val2); 171 break; 172 case IIO_CHAN_INFO_HYSTERESIS: 173 ret = hid_sensor_write_raw_hyst_value( 174 &incl_state->common_attributes, val, val2); 175 break; 176 default: 177 ret = -EINVAL; 178 } 179 180 return ret; 181 } 182 183 static const struct iio_info incl_3d_info = { 184 .read_raw = &incl_3d_read_raw, 185 .write_raw = &incl_3d_write_raw, 186 }; 187 188 /* Callback handler to send event after all samples are received and captured */ 189 static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, 190 unsigned usage_id, 191 void *priv) 192 { 193 struct iio_dev *indio_dev = platform_get_drvdata(priv); 194 struct incl_3d_state *incl_state = iio_priv(indio_dev); 195 196 dev_dbg(&indio_dev->dev, "incl_3d_proc_event\n"); 197 if (atomic_read(&incl_state->common_attributes.data_ready)) { 198 if (!incl_state->timestamp) 199 incl_state->timestamp = iio_get_time_ns(indio_dev); 200 201 iio_push_to_buffers_with_timestamp(indio_dev, 202 &incl_state->scan, 203 incl_state->timestamp); 204 205 incl_state->timestamp = 0; 206 } 207 208 return 0; 209 } 210 211 /* Capture samples in local storage */ 212 static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev, 213 unsigned usage_id, 214 size_t raw_len, char *raw_data, 215 void *priv) 216 { 217 struct iio_dev *indio_dev = platform_get_drvdata(priv); 218 struct incl_3d_state *incl_state = iio_priv(indio_dev); 219 int ret = 0; 220 221 switch (usage_id) { 222 case HID_USAGE_SENSOR_ORIENT_TILT_X: 223 incl_state->scan.incl_val[CHANNEL_SCAN_INDEX_X] = *(u32 *)raw_data; 224 break; 225 case HID_USAGE_SENSOR_ORIENT_TILT_Y: 226 incl_state->scan.incl_val[CHANNEL_SCAN_INDEX_Y] = *(u32 *)raw_data; 227 break; 228 case HID_USAGE_SENSOR_ORIENT_TILT_Z: 229 incl_state->scan.incl_val[CHANNEL_SCAN_INDEX_Z] = *(u32 *)raw_data; 230 break; 231 case HID_USAGE_SENSOR_TIME_TIMESTAMP: 232 incl_state->timestamp = 233 hid_sensor_convert_timestamp(&incl_state->common_attributes, 234 *(s64 *)raw_data); 235 break; 236 default: 237 ret = -EINVAL; 238 break; 239 } 240 241 return ret; 242 } 243 244 /* Parse report which is specific to an usage id*/ 245 static int incl_3d_parse_report(struct platform_device *pdev, 246 struct hid_sensor_hub_device *hsdev, 247 struct iio_chan_spec *channels, 248 unsigned usage_id, 249 struct incl_3d_state *st) 250 { 251 int ret; 252 253 ret = sensor_hub_input_get_attribute_info(hsdev, 254 HID_INPUT_REPORT, 255 usage_id, 256 HID_USAGE_SENSOR_ORIENT_TILT_X, 257 &st->incl[CHANNEL_SCAN_INDEX_X]); 258 if (ret) 259 return ret; 260 incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_X], 261 st->incl[CHANNEL_SCAN_INDEX_X].size); 262 263 ret = sensor_hub_input_get_attribute_info(hsdev, 264 HID_INPUT_REPORT, 265 usage_id, 266 HID_USAGE_SENSOR_ORIENT_TILT_Y, 267 &st->incl[CHANNEL_SCAN_INDEX_Y]); 268 if (ret) 269 return ret; 270 incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_Y], 271 st->incl[CHANNEL_SCAN_INDEX_Y].size); 272 273 ret = sensor_hub_input_get_attribute_info(hsdev, 274 HID_INPUT_REPORT, 275 usage_id, 276 HID_USAGE_SENSOR_ORIENT_TILT_Z, 277 &st->incl[CHANNEL_SCAN_INDEX_Z]); 278 if (ret) 279 return ret; 280 incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_Z], 281 st->incl[CHANNEL_SCAN_INDEX_Z].size); 282 283 dev_dbg(&pdev->dev, "incl_3d %x:%x, %x:%x, %x:%x\n", 284 st->incl[0].index, 285 st->incl[0].report_id, 286 st->incl[1].index, st->incl[1].report_id, 287 st->incl[2].index, st->incl[2].report_id); 288 289 st->scale_precision = hid_sensor_format_scale( 290 HID_USAGE_SENSOR_INCLINOMETER_3D, 291 &st->incl[CHANNEL_SCAN_INDEX_X], 292 &st->scale_pre_decml, &st->scale_post_decml); 293 294 /* Set Sensitivity field ids, when there is no individual modifier */ 295 if (st->common_attributes.sensitivity.index < 0) { 296 sensor_hub_input_get_attribute_info(hsdev, 297 HID_FEATURE_REPORT, usage_id, 298 HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | 299 HID_USAGE_SENSOR_DATA_ORIENTATION, 300 &st->common_attributes.sensitivity); 301 dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", 302 st->common_attributes.sensitivity.index, 303 st->common_attributes.sensitivity.report_id); 304 } 305 return ret; 306 } 307 308 /* Function to initialize the processing for usage id */ 309 static int hid_incl_3d_probe(struct platform_device *pdev) 310 { 311 int ret; 312 static char *name = "incli_3d"; 313 struct iio_dev *indio_dev; 314 struct incl_3d_state *incl_state; 315 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; 316 317 indio_dev = devm_iio_device_alloc(&pdev->dev, 318 sizeof(struct incl_3d_state)); 319 if (indio_dev == NULL) 320 return -ENOMEM; 321 322 platform_set_drvdata(pdev, indio_dev); 323 324 incl_state = iio_priv(indio_dev); 325 incl_state->common_attributes.hsdev = hsdev; 326 incl_state->common_attributes.pdev = pdev; 327 328 ret = hid_sensor_parse_common_attributes(hsdev, 329 HID_USAGE_SENSOR_INCLINOMETER_3D, 330 &incl_state->common_attributes); 331 if (ret) { 332 dev_err(&pdev->dev, "failed to setup common attributes\n"); 333 return ret; 334 } 335 336 indio_dev->channels = kmemdup(incl_3d_channels, 337 sizeof(incl_3d_channels), GFP_KERNEL); 338 if (!indio_dev->channels) { 339 dev_err(&pdev->dev, "failed to duplicate channels\n"); 340 return -ENOMEM; 341 } 342 343 ret = incl_3d_parse_report(pdev, hsdev, 344 (struct iio_chan_spec *)indio_dev->channels, 345 HID_USAGE_SENSOR_INCLINOMETER_3D, 346 incl_state); 347 if (ret) { 348 dev_err(&pdev->dev, "failed to setup attributes\n"); 349 goto error_free_dev_mem; 350 } 351 352 indio_dev->num_channels = ARRAY_SIZE(incl_3d_channels); 353 indio_dev->info = &incl_3d_info; 354 indio_dev->name = name; 355 indio_dev->modes = INDIO_DIRECT_MODE; 356 357 atomic_set(&incl_state->common_attributes.data_ready, 0); 358 359 ret = hid_sensor_setup_trigger(indio_dev, name, 360 &incl_state->common_attributes); 361 if (ret) { 362 dev_err(&pdev->dev, "trigger setup failed\n"); 363 goto error_free_dev_mem; 364 } 365 366 ret = iio_device_register(indio_dev); 367 if (ret) { 368 dev_err(&pdev->dev, "device register failed\n"); 369 goto error_remove_trigger; 370 } 371 372 incl_state->callbacks.send_event = incl_3d_proc_event; 373 incl_state->callbacks.capture_sample = incl_3d_capture_sample; 374 incl_state->callbacks.pdev = pdev; 375 ret = sensor_hub_register_callback(hsdev, 376 HID_USAGE_SENSOR_INCLINOMETER_3D, 377 &incl_state->callbacks); 378 if (ret) { 379 dev_err(&pdev->dev, "callback reg failed\n"); 380 goto error_iio_unreg; 381 } 382 383 return 0; 384 385 error_iio_unreg: 386 iio_device_unregister(indio_dev); 387 error_remove_trigger: 388 hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes); 389 error_free_dev_mem: 390 kfree(indio_dev->channels); 391 return ret; 392 } 393 394 /* Function to deinitialize the processing for usage id */ 395 static int hid_incl_3d_remove(struct platform_device *pdev) 396 { 397 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; 398 struct iio_dev *indio_dev = platform_get_drvdata(pdev); 399 struct incl_3d_state *incl_state = iio_priv(indio_dev); 400 401 sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); 402 iio_device_unregister(indio_dev); 403 hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes); 404 kfree(indio_dev->channels); 405 406 return 0; 407 } 408 409 static const struct platform_device_id hid_incl_3d_ids[] = { 410 { 411 /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ 412 .name = "HID-SENSOR-200086", 413 }, 414 { /* sentinel */ } 415 }; 416 MODULE_DEVICE_TABLE(platform, hid_incl_3d_ids); 417 418 static struct platform_driver hid_incl_3d_platform_driver = { 419 .id_table = hid_incl_3d_ids, 420 .driver = { 421 .name = KBUILD_MODNAME, 422 .pm = &hid_sensor_pm_ops, 423 }, 424 .probe = hid_incl_3d_probe, 425 .remove = hid_incl_3d_remove, 426 }; 427 module_platform_driver(hid_incl_3d_platform_driver); 428 429 MODULE_DESCRIPTION("HID Sensor Inclinometer 3D"); 430 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 431 MODULE_LICENSE("GPL"); 432