162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * HID Sensors Driver 462306a36Sopenharmony_ci * Copyright (c) 2012, Intel Corporation. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/device.h> 862306a36Sopenharmony_ci#include <linux/hid.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/mfd/core.h> 1262306a36Sopenharmony_ci#include <linux/list.h> 1362306a36Sopenharmony_ci#include <linux/hid-sensor-ids.h> 1462306a36Sopenharmony_ci#include <linux/hid-sensor-hub.h> 1562306a36Sopenharmony_ci#include "hid-ids.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define HID_SENSOR_HUB_ENUM_QUIRK 0x01 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/** 2062306a36Sopenharmony_ci * struct sensor_hub_data - Hold a instance data for a HID hub device 2162306a36Sopenharmony_ci * @mutex: Mutex to serialize synchronous request. 2262306a36Sopenharmony_ci * @lock: Spin lock to protect pending request structure. 2362306a36Sopenharmony_ci * @dyn_callback_list: Holds callback function 2462306a36Sopenharmony_ci * @dyn_callback_lock: spin lock to protect callback list 2562306a36Sopenharmony_ci * @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance. 2662306a36Sopenharmony_ci * @hid_sensor_client_cnt: Number of MFD cells, (no of sensors attached). 2762306a36Sopenharmony_ci * @ref_cnt: Number of MFD clients have opened this device 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistruct sensor_hub_data { 3062306a36Sopenharmony_ci struct mutex mutex; 3162306a36Sopenharmony_ci spinlock_t lock; 3262306a36Sopenharmony_ci struct list_head dyn_callback_list; 3362306a36Sopenharmony_ci spinlock_t dyn_callback_lock; 3462306a36Sopenharmony_ci struct mfd_cell *hid_sensor_hub_client_devs; 3562306a36Sopenharmony_ci int hid_sensor_client_cnt; 3662306a36Sopenharmony_ci int ref_cnt; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/** 4062306a36Sopenharmony_ci * struct hid_sensor_hub_callbacks_list - Stores callback list 4162306a36Sopenharmony_ci * @list: list head. 4262306a36Sopenharmony_ci * @usage_id: usage id for a physical device. 4362306a36Sopenharmony_ci * @hsdev: Stored hid instance for current hub device. 4462306a36Sopenharmony_ci * @usage_callback: Stores registered callback functions. 4562306a36Sopenharmony_ci * @priv: Private data for a physical device. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cistruct hid_sensor_hub_callbacks_list { 4862306a36Sopenharmony_ci struct list_head list; 4962306a36Sopenharmony_ci u32 usage_id; 5062306a36Sopenharmony_ci struct hid_sensor_hub_device *hsdev; 5162306a36Sopenharmony_ci struct hid_sensor_hub_callbacks *usage_callback; 5262306a36Sopenharmony_ci void *priv; 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic struct hid_report *sensor_hub_report(int id, struct hid_device *hdev, 5662306a36Sopenharmony_ci int dir) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct hid_report *report; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci list_for_each_entry(report, &hdev->report_enum[dir].report_list, list) { 6162306a36Sopenharmony_ci if (report->id == id) 6262306a36Sopenharmony_ci return report; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci hid_warn(hdev, "No report with id 0x%x found\n", id); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return NULL; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int sensor_hub_get_physical_device_count(struct hid_device *hdev) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci int i; 7262306a36Sopenharmony_ci int count = 0; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci for (i = 0; i < hdev->maxcollection; ++i) { 7562306a36Sopenharmony_ci struct hid_collection *collection = &hdev->collection[i]; 7662306a36Sopenharmony_ci if (collection->type == HID_COLLECTION_PHYSICAL || 7762306a36Sopenharmony_ci collection->type == HID_COLLECTION_APPLICATION) 7862306a36Sopenharmony_ci ++count; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return count; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void sensor_hub_fill_attr_info( 8562306a36Sopenharmony_ci struct hid_sensor_hub_attribute_info *info, 8662306a36Sopenharmony_ci s32 index, s32 report_id, struct hid_field *field) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci info->index = index; 8962306a36Sopenharmony_ci info->report_id = report_id; 9062306a36Sopenharmony_ci info->units = field->unit; 9162306a36Sopenharmony_ci info->unit_expo = field->unit_exponent; 9262306a36Sopenharmony_ci info->size = (field->report_size * field->report_count)/8; 9362306a36Sopenharmony_ci info->logical_minimum = field->logical_minimum; 9462306a36Sopenharmony_ci info->logical_maximum = field->logical_maximum; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic struct hid_sensor_hub_callbacks *sensor_hub_get_callback( 9862306a36Sopenharmony_ci struct hid_device *hdev, 9962306a36Sopenharmony_ci u32 usage_id, 10062306a36Sopenharmony_ci int collection_index, 10162306a36Sopenharmony_ci struct hid_sensor_hub_device **hsdev, 10262306a36Sopenharmony_ci void **priv) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct hid_sensor_hub_callbacks_list *callback; 10562306a36Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hdev); 10662306a36Sopenharmony_ci unsigned long flags; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci spin_lock_irqsave(&pdata->dyn_callback_lock, flags); 10962306a36Sopenharmony_ci list_for_each_entry(callback, &pdata->dyn_callback_list, list) 11062306a36Sopenharmony_ci if ((callback->usage_id == usage_id || 11162306a36Sopenharmony_ci callback->usage_id == HID_USAGE_SENSOR_COLLECTION) && 11262306a36Sopenharmony_ci (collection_index >= 11362306a36Sopenharmony_ci callback->hsdev->start_collection_index) && 11462306a36Sopenharmony_ci (collection_index < 11562306a36Sopenharmony_ci callback->hsdev->end_collection_index)) { 11662306a36Sopenharmony_ci *priv = callback->priv; 11762306a36Sopenharmony_ci *hsdev = callback->hsdev; 11862306a36Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, 11962306a36Sopenharmony_ci flags); 12062306a36Sopenharmony_ci return callback->usage_callback; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return NULL; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ciint sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, 12862306a36Sopenharmony_ci u32 usage_id, 12962306a36Sopenharmony_ci struct hid_sensor_hub_callbacks *usage_callback) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct hid_sensor_hub_callbacks_list *callback; 13262306a36Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); 13362306a36Sopenharmony_ci unsigned long flags; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci spin_lock_irqsave(&pdata->dyn_callback_lock, flags); 13662306a36Sopenharmony_ci list_for_each_entry(callback, &pdata->dyn_callback_list, list) 13762306a36Sopenharmony_ci if (callback->usage_id == usage_id && 13862306a36Sopenharmony_ci callback->hsdev == hsdev) { 13962306a36Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 14062306a36Sopenharmony_ci return -EINVAL; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci callback = kzalloc(sizeof(*callback), GFP_ATOMIC); 14362306a36Sopenharmony_ci if (!callback) { 14462306a36Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 14562306a36Sopenharmony_ci return -ENOMEM; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci callback->hsdev = hsdev; 14862306a36Sopenharmony_ci callback->usage_callback = usage_callback; 14962306a36Sopenharmony_ci callback->usage_id = usage_id; 15062306a36Sopenharmony_ci callback->priv = NULL; 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * If there is a handler registered for the collection type, then 15362306a36Sopenharmony_ci * it will handle all reports for sensors in this collection. If 15462306a36Sopenharmony_ci * there is also an individual sensor handler registration, then 15562306a36Sopenharmony_ci * we want to make sure that the reports are directed to collection 15662306a36Sopenharmony_ci * handler, as this may be a fusion sensor. So add collection handlers 15762306a36Sopenharmony_ci * to the beginning of the list, so that they are matched first. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci if (usage_id == HID_USAGE_SENSOR_COLLECTION) 16062306a36Sopenharmony_ci list_add(&callback->list, &pdata->dyn_callback_list); 16162306a36Sopenharmony_ci else 16262306a36Sopenharmony_ci list_add_tail(&callback->list, &pdata->dyn_callback_list); 16362306a36Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_register_callback); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ciint sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, 17062306a36Sopenharmony_ci u32 usage_id) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct hid_sensor_hub_callbacks_list *callback; 17362306a36Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); 17462306a36Sopenharmony_ci unsigned long flags; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci spin_lock_irqsave(&pdata->dyn_callback_lock, flags); 17762306a36Sopenharmony_ci list_for_each_entry(callback, &pdata->dyn_callback_list, list) 17862306a36Sopenharmony_ci if (callback->usage_id == usage_id && 17962306a36Sopenharmony_ci callback->hsdev == hsdev) { 18062306a36Sopenharmony_ci list_del(&callback->list); 18162306a36Sopenharmony_ci kfree(callback); 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return 0; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_remove_callback); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ciint sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, 19162306a36Sopenharmony_ci u32 field_index, int buffer_size, void *buffer) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct hid_report *report; 19462306a36Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); 19562306a36Sopenharmony_ci __s32 *buf32 = buffer; 19662306a36Sopenharmony_ci int i = 0; 19762306a36Sopenharmony_ci int remaining_bytes; 19862306a36Sopenharmony_ci __s32 value; 19962306a36Sopenharmony_ci int ret = 0; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci mutex_lock(&data->mutex); 20262306a36Sopenharmony_ci report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); 20362306a36Sopenharmony_ci if (!report || (field_index >= report->maxfield)) { 20462306a36Sopenharmony_ci ret = -EINVAL; 20562306a36Sopenharmony_ci goto done_proc; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci remaining_bytes = buffer_size % sizeof(__s32); 20962306a36Sopenharmony_ci buffer_size = buffer_size / sizeof(__s32); 21062306a36Sopenharmony_ci if (buffer_size) { 21162306a36Sopenharmony_ci for (i = 0; i < buffer_size; ++i) { 21262306a36Sopenharmony_ci ret = hid_set_field(report->field[field_index], i, 21362306a36Sopenharmony_ci (__force __s32)cpu_to_le32(*buf32)); 21462306a36Sopenharmony_ci if (ret) 21562306a36Sopenharmony_ci goto done_proc; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ++buf32; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci if (remaining_bytes) { 22162306a36Sopenharmony_ci value = 0; 22262306a36Sopenharmony_ci memcpy(&value, (u8 *)buf32, remaining_bytes); 22362306a36Sopenharmony_ci ret = hid_set_field(report->field[field_index], i, 22462306a36Sopenharmony_ci (__force __s32)cpu_to_le32(value)); 22562306a36Sopenharmony_ci if (ret) 22662306a36Sopenharmony_ci goto done_proc; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT); 22962306a36Sopenharmony_ci hid_hw_wait(hsdev->hdev); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cidone_proc: 23262306a36Sopenharmony_ci mutex_unlock(&data->mutex); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return ret; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_set_feature); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ciint sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, 23962306a36Sopenharmony_ci u32 field_index, int buffer_size, void *buffer) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct hid_report *report; 24262306a36Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); 24362306a36Sopenharmony_ci int report_size; 24462306a36Sopenharmony_ci int ret = 0; 24562306a36Sopenharmony_ci u8 *val_ptr; 24662306a36Sopenharmony_ci int buffer_index = 0; 24762306a36Sopenharmony_ci int i; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci memset(buffer, 0, buffer_size); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci mutex_lock(&data->mutex); 25262306a36Sopenharmony_ci report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); 25362306a36Sopenharmony_ci if (!report || (field_index >= report->maxfield) || 25462306a36Sopenharmony_ci report->field[field_index]->report_count < 1) { 25562306a36Sopenharmony_ci ret = -EINVAL; 25662306a36Sopenharmony_ci goto done_proc; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); 25962306a36Sopenharmony_ci hid_hw_wait(hsdev->hdev); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* calculate number of bytes required to read this field */ 26262306a36Sopenharmony_ci report_size = DIV_ROUND_UP(report->field[field_index]->report_size, 26362306a36Sopenharmony_ci 8) * 26462306a36Sopenharmony_ci report->field[field_index]->report_count; 26562306a36Sopenharmony_ci if (!report_size) { 26662306a36Sopenharmony_ci ret = -EINVAL; 26762306a36Sopenharmony_ci goto done_proc; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci ret = min(report_size, buffer_size); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci val_ptr = (u8 *)report->field[field_index]->value; 27262306a36Sopenharmony_ci for (i = 0; i < report->field[field_index]->report_count; ++i) { 27362306a36Sopenharmony_ci if (buffer_index >= ret) 27462306a36Sopenharmony_ci break; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci memcpy(&((u8 *)buffer)[buffer_index], val_ptr, 27762306a36Sopenharmony_ci report->field[field_index]->report_size / 8); 27862306a36Sopenharmony_ci val_ptr += sizeof(__s32); 27962306a36Sopenharmony_ci buffer_index += (report->field[field_index]->report_size / 8); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cidone_proc: 28362306a36Sopenharmony_ci mutex_unlock(&data->mutex); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci return ret; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_get_feature); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ciint sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, 29162306a36Sopenharmony_ci u32 usage_id, 29262306a36Sopenharmony_ci u32 attr_usage_id, u32 report_id, 29362306a36Sopenharmony_ci enum sensor_hub_read_flags flag, 29462306a36Sopenharmony_ci bool is_signed) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); 29762306a36Sopenharmony_ci unsigned long flags; 29862306a36Sopenharmony_ci struct hid_report *report; 29962306a36Sopenharmony_ci int ret_val = 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci report = sensor_hub_report(report_id, hsdev->hdev, 30262306a36Sopenharmony_ci HID_INPUT_REPORT); 30362306a36Sopenharmony_ci if (!report) 30462306a36Sopenharmony_ci return -EINVAL; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci mutex_lock(hsdev->mutex_ptr); 30762306a36Sopenharmony_ci if (flag == SENSOR_HUB_SYNC) { 30862306a36Sopenharmony_ci memset(&hsdev->pending, 0, sizeof(hsdev->pending)); 30962306a36Sopenharmony_ci init_completion(&hsdev->pending.ready); 31062306a36Sopenharmony_ci hsdev->pending.usage_id = usage_id; 31162306a36Sopenharmony_ci hsdev->pending.attr_usage_id = attr_usage_id; 31262306a36Sopenharmony_ci hsdev->pending.raw_size = 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci spin_lock_irqsave(&data->lock, flags); 31562306a36Sopenharmony_ci hsdev->pending.status = true; 31662306a36Sopenharmony_ci spin_unlock_irqrestore(&data->lock, flags); 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci mutex_lock(&data->mutex); 31962306a36Sopenharmony_ci hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); 32062306a36Sopenharmony_ci mutex_unlock(&data->mutex); 32162306a36Sopenharmony_ci if (flag == SENSOR_HUB_SYNC) { 32262306a36Sopenharmony_ci wait_for_completion_interruptible_timeout( 32362306a36Sopenharmony_ci &hsdev->pending.ready, HZ*5); 32462306a36Sopenharmony_ci switch (hsdev->pending.raw_size) { 32562306a36Sopenharmony_ci case 1: 32662306a36Sopenharmony_ci if (is_signed) 32762306a36Sopenharmony_ci ret_val = *(s8 *)hsdev->pending.raw_data; 32862306a36Sopenharmony_ci else 32962306a36Sopenharmony_ci ret_val = *(u8 *)hsdev->pending.raw_data; 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci case 2: 33262306a36Sopenharmony_ci if (is_signed) 33362306a36Sopenharmony_ci ret_val = *(s16 *)hsdev->pending.raw_data; 33462306a36Sopenharmony_ci else 33562306a36Sopenharmony_ci ret_val = *(u16 *)hsdev->pending.raw_data; 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci case 4: 33862306a36Sopenharmony_ci ret_val = *(u32 *)hsdev->pending.raw_data; 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci default: 34162306a36Sopenharmony_ci ret_val = 0; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci kfree(hsdev->pending.raw_data); 34462306a36Sopenharmony_ci hsdev->pending.status = false; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci mutex_unlock(hsdev->mutex_ptr); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return ret_val; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ciint hid_sensor_get_usage_index(struct hid_sensor_hub_device *hsdev, 35362306a36Sopenharmony_ci u32 report_id, int field_index, u32 usage_id) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct hid_report *report; 35662306a36Sopenharmony_ci struct hid_field *field; 35762306a36Sopenharmony_ci int i; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); 36062306a36Sopenharmony_ci if (!report || (field_index >= report->maxfield)) 36162306a36Sopenharmony_ci goto done_proc; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci field = report->field[field_index]; 36462306a36Sopenharmony_ci for (i = 0; i < field->maxusage; ++i) { 36562306a36Sopenharmony_ci if (field->usage[i].hid == usage_id) 36662306a36Sopenharmony_ci return field->usage[i].usage_index; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cidone_proc: 37062306a36Sopenharmony_ci return -EINVAL; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hid_sensor_get_usage_index); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ciint sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, 37562306a36Sopenharmony_ci u8 type, 37662306a36Sopenharmony_ci u32 usage_id, 37762306a36Sopenharmony_ci u32 attr_usage_id, 37862306a36Sopenharmony_ci struct hid_sensor_hub_attribute_info *info) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci int ret = -1; 38162306a36Sopenharmony_ci int i; 38262306a36Sopenharmony_ci struct hid_report *report; 38362306a36Sopenharmony_ci struct hid_field *field; 38462306a36Sopenharmony_ci struct hid_report_enum *report_enum; 38562306a36Sopenharmony_ci struct hid_device *hdev = hsdev->hdev; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* Initialize with defaults */ 38862306a36Sopenharmony_ci info->usage_id = usage_id; 38962306a36Sopenharmony_ci info->attrib_id = attr_usage_id; 39062306a36Sopenharmony_ci info->report_id = -1; 39162306a36Sopenharmony_ci info->index = -1; 39262306a36Sopenharmony_ci info->units = -1; 39362306a36Sopenharmony_ci info->unit_expo = -1; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci report_enum = &hdev->report_enum[type]; 39662306a36Sopenharmony_ci list_for_each_entry(report, &report_enum->report_list, list) { 39762306a36Sopenharmony_ci for (i = 0; i < report->maxfield; ++i) { 39862306a36Sopenharmony_ci field = report->field[i]; 39962306a36Sopenharmony_ci if (field->maxusage) { 40062306a36Sopenharmony_ci if ((field->physical == usage_id || 40162306a36Sopenharmony_ci field->application == usage_id) && 40262306a36Sopenharmony_ci (field->logical == attr_usage_id || 40362306a36Sopenharmony_ci field->usage[0].hid == 40462306a36Sopenharmony_ci attr_usage_id) && 40562306a36Sopenharmony_ci (field->usage[0].collection_index >= 40662306a36Sopenharmony_ci hsdev->start_collection_index) && 40762306a36Sopenharmony_ci (field->usage[0].collection_index < 40862306a36Sopenharmony_ci hsdev->end_collection_index)) { 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci sensor_hub_fill_attr_info(info, i, 41162306a36Sopenharmony_ci report->id, 41262306a36Sopenharmony_ci field); 41362306a36Sopenharmony_ci ret = 0; 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return ret; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci#ifdef CONFIG_PM 42662306a36Sopenharmony_cistatic int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hdev); 42962306a36Sopenharmony_ci struct hid_sensor_hub_callbacks_list *callback; 43062306a36Sopenharmony_ci unsigned long flags; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci hid_dbg(hdev, " sensor_hub_suspend\n"); 43362306a36Sopenharmony_ci spin_lock_irqsave(&pdata->dyn_callback_lock, flags); 43462306a36Sopenharmony_ci list_for_each_entry(callback, &pdata->dyn_callback_list, list) { 43562306a36Sopenharmony_ci if (callback->usage_callback->suspend) 43662306a36Sopenharmony_ci callback->usage_callback->suspend( 43762306a36Sopenharmony_ci callback->hsdev, callback->priv); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic int sensor_hub_resume(struct hid_device *hdev) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hdev); 44762306a36Sopenharmony_ci struct hid_sensor_hub_callbacks_list *callback; 44862306a36Sopenharmony_ci unsigned long flags; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci hid_dbg(hdev, " sensor_hub_resume\n"); 45162306a36Sopenharmony_ci spin_lock_irqsave(&pdata->dyn_callback_lock, flags); 45262306a36Sopenharmony_ci list_for_each_entry(callback, &pdata->dyn_callback_list, list) { 45362306a36Sopenharmony_ci if (callback->usage_callback->resume) 45462306a36Sopenharmony_ci callback->usage_callback->resume( 45562306a36Sopenharmony_ci callback->hsdev, callback->priv); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int sensor_hub_reset_resume(struct hid_device *hdev) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci#endif 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci/* 46962306a36Sopenharmony_ci * Handle raw report as sent by device 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_cistatic int sensor_hub_raw_event(struct hid_device *hdev, 47262306a36Sopenharmony_ci struct hid_report *report, u8 *raw_data, int size) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci int i; 47562306a36Sopenharmony_ci u8 *ptr; 47662306a36Sopenharmony_ci int sz; 47762306a36Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hdev); 47862306a36Sopenharmony_ci unsigned long flags; 47962306a36Sopenharmony_ci struct hid_sensor_hub_callbacks *callback = NULL; 48062306a36Sopenharmony_ci struct hid_collection *collection = NULL; 48162306a36Sopenharmony_ci void *priv = NULL; 48262306a36Sopenharmony_ci struct hid_sensor_hub_device *hsdev = NULL; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n", 48562306a36Sopenharmony_ci report->id, size, report->type); 48662306a36Sopenharmony_ci hid_dbg(hdev, "maxfield:%d\n", report->maxfield); 48762306a36Sopenharmony_ci if (report->type != HID_INPUT_REPORT) 48862306a36Sopenharmony_ci return 1; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci ptr = raw_data; 49162306a36Sopenharmony_ci if (report->id) 49262306a36Sopenharmony_ci ptr++; /* Skip report id */ 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci spin_lock_irqsave(&pdata->lock, flags); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci for (i = 0; i < report->maxfield; ++i) { 49762306a36Sopenharmony_ci hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n", 49862306a36Sopenharmony_ci i, report->field[i]->usage->collection_index, 49962306a36Sopenharmony_ci report->field[i]->usage->hid, 50062306a36Sopenharmony_ci (report->field[i]->report_size * 50162306a36Sopenharmony_ci report->field[i]->report_count)/8); 50262306a36Sopenharmony_ci sz = (report->field[i]->report_size * 50362306a36Sopenharmony_ci report->field[i]->report_count)/8; 50462306a36Sopenharmony_ci collection = &hdev->collection[ 50562306a36Sopenharmony_ci report->field[i]->usage->collection_index]; 50662306a36Sopenharmony_ci hid_dbg(hdev, "collection->usage %x\n", 50762306a36Sopenharmony_ci collection->usage); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci callback = sensor_hub_get_callback(hdev, 51062306a36Sopenharmony_ci report->field[i]->physical ? report->field[i]->physical : 51162306a36Sopenharmony_ci report->field[i]->application, 51262306a36Sopenharmony_ci report->field[i]->usage[0].collection_index, 51362306a36Sopenharmony_ci &hsdev, &priv); 51462306a36Sopenharmony_ci if (!callback) { 51562306a36Sopenharmony_ci ptr += sz; 51662306a36Sopenharmony_ci continue; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci if (hsdev->pending.status && (hsdev->pending.attr_usage_id == 51962306a36Sopenharmony_ci report->field[i]->usage->hid || 52062306a36Sopenharmony_ci hsdev->pending.attr_usage_id == 52162306a36Sopenharmony_ci report->field[i]->logical)) { 52262306a36Sopenharmony_ci hid_dbg(hdev, "data was pending ...\n"); 52362306a36Sopenharmony_ci hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); 52462306a36Sopenharmony_ci if (hsdev->pending.raw_data) 52562306a36Sopenharmony_ci hsdev->pending.raw_size = sz; 52662306a36Sopenharmony_ci else 52762306a36Sopenharmony_ci hsdev->pending.raw_size = 0; 52862306a36Sopenharmony_ci complete(&hsdev->pending.ready); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci if (callback->capture_sample) { 53162306a36Sopenharmony_ci if (report->field[i]->logical) 53262306a36Sopenharmony_ci callback->capture_sample(hsdev, 53362306a36Sopenharmony_ci report->field[i]->logical, sz, ptr, 53462306a36Sopenharmony_ci callback->pdev); 53562306a36Sopenharmony_ci else 53662306a36Sopenharmony_ci callback->capture_sample(hsdev, 53762306a36Sopenharmony_ci report->field[i]->usage->hid, sz, ptr, 53862306a36Sopenharmony_ci callback->pdev); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci ptr += sz; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci if (callback && collection && callback->send_event) 54362306a36Sopenharmony_ci callback->send_event(hsdev, collection->usage, 54462306a36Sopenharmony_ci callback->pdev); 54562306a36Sopenharmony_ci spin_unlock_irqrestore(&pdata->lock, flags); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return 1; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ciint sensor_hub_device_open(struct hid_sensor_hub_device *hsdev) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci int ret = 0; 55362306a36Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci mutex_lock(&data->mutex); 55662306a36Sopenharmony_ci if (!data->ref_cnt) { 55762306a36Sopenharmony_ci ret = hid_hw_open(hsdev->hdev); 55862306a36Sopenharmony_ci if (ret) { 55962306a36Sopenharmony_ci hid_err(hsdev->hdev, "failed to open hid device\n"); 56062306a36Sopenharmony_ci mutex_unlock(&data->mutex); 56162306a36Sopenharmony_ci return ret; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci data->ref_cnt++; 56562306a36Sopenharmony_ci mutex_unlock(&data->mutex); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return ret; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_device_open); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_civoid sensor_hub_device_close(struct hid_sensor_hub_device *hsdev) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci mutex_lock(&data->mutex); 57662306a36Sopenharmony_ci data->ref_cnt--; 57762306a36Sopenharmony_ci if (!data->ref_cnt) 57862306a36Sopenharmony_ci hid_hw_close(hsdev->hdev); 57962306a36Sopenharmony_ci mutex_unlock(&data->mutex); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_device_close); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic __u8 *sensor_hub_report_fixup(struct hid_device *hdev, __u8 *rdesc, 58462306a36Sopenharmony_ci unsigned int *rsize) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci /* 58762306a36Sopenharmony_ci * Checks if the report descriptor of Thinkpad Helix 2 has a logical 58862306a36Sopenharmony_ci * minimum for magnetic flux axis greater than the maximum. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci if (hdev->product == USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA && 59162306a36Sopenharmony_ci *rsize == 2558 && rdesc[913] == 0x17 && rdesc[914] == 0x40 && 59262306a36Sopenharmony_ci rdesc[915] == 0x81 && rdesc[916] == 0x08 && 59362306a36Sopenharmony_ci rdesc[917] == 0x00 && rdesc[918] == 0x27 && 59462306a36Sopenharmony_ci rdesc[921] == 0x07 && rdesc[922] == 0x00) { 59562306a36Sopenharmony_ci /* Sets negative logical minimum for mag x, y and z */ 59662306a36Sopenharmony_ci rdesc[914] = rdesc[935] = rdesc[956] = 0xc0; 59762306a36Sopenharmony_ci rdesc[915] = rdesc[936] = rdesc[957] = 0x7e; 59862306a36Sopenharmony_ci rdesc[916] = rdesc[937] = rdesc[958] = 0xf7; 59962306a36Sopenharmony_ci rdesc[917] = rdesc[938] = rdesc[959] = 0xff; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci return rdesc; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic int sensor_hub_probe(struct hid_device *hdev, 60662306a36Sopenharmony_ci const struct hid_device_id *id) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci int ret; 60962306a36Sopenharmony_ci struct sensor_hub_data *sd; 61062306a36Sopenharmony_ci int i; 61162306a36Sopenharmony_ci char *name; 61262306a36Sopenharmony_ci int dev_cnt; 61362306a36Sopenharmony_ci struct hid_sensor_hub_device *hsdev; 61462306a36Sopenharmony_ci struct hid_sensor_hub_device *last_hsdev = NULL; 61562306a36Sopenharmony_ci struct hid_sensor_hub_device *collection_hsdev = NULL; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL); 61862306a36Sopenharmony_ci if (!sd) { 61962306a36Sopenharmony_ci hid_err(hdev, "cannot allocate Sensor data\n"); 62062306a36Sopenharmony_ci return -ENOMEM; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci hid_set_drvdata(hdev, sd); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci spin_lock_init(&sd->lock); 62662306a36Sopenharmony_ci spin_lock_init(&sd->dyn_callback_lock); 62762306a36Sopenharmony_ci mutex_init(&sd->mutex); 62862306a36Sopenharmony_ci ret = hid_parse(hdev); 62962306a36Sopenharmony_ci if (ret) { 63062306a36Sopenharmony_ci hid_err(hdev, "parse failed\n"); 63162306a36Sopenharmony_ci return ret; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci INIT_LIST_HEAD(&hdev->inputs); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | HID_CONNECT_DRIVER); 63662306a36Sopenharmony_ci if (ret) { 63762306a36Sopenharmony_ci hid_err(hdev, "hw start failed\n"); 63862306a36Sopenharmony_ci return ret; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci INIT_LIST_HEAD(&sd->dyn_callback_list); 64162306a36Sopenharmony_ci sd->hid_sensor_client_cnt = 0; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci dev_cnt = sensor_hub_get_physical_device_count(hdev); 64462306a36Sopenharmony_ci if (dev_cnt > HID_MAX_PHY_DEVICES) { 64562306a36Sopenharmony_ci hid_err(hdev, "Invalid Physical device count\n"); 64662306a36Sopenharmony_ci ret = -EINVAL; 64762306a36Sopenharmony_ci goto err_stop_hw; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci sd->hid_sensor_hub_client_devs = devm_kcalloc(&hdev->dev, 65062306a36Sopenharmony_ci dev_cnt, 65162306a36Sopenharmony_ci sizeof(struct mfd_cell), 65262306a36Sopenharmony_ci GFP_KERNEL); 65362306a36Sopenharmony_ci if (sd->hid_sensor_hub_client_devs == NULL) { 65462306a36Sopenharmony_ci hid_err(hdev, "Failed to allocate memory for mfd cells\n"); 65562306a36Sopenharmony_ci ret = -ENOMEM; 65662306a36Sopenharmony_ci goto err_stop_hw; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci for (i = 0; i < hdev->maxcollection; ++i) { 66062306a36Sopenharmony_ci struct hid_collection *collection = &hdev->collection[i]; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (collection->type == HID_COLLECTION_PHYSICAL || 66362306a36Sopenharmony_ci collection->type == HID_COLLECTION_APPLICATION) { 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev), 66662306a36Sopenharmony_ci GFP_KERNEL); 66762306a36Sopenharmony_ci if (!hsdev) { 66862306a36Sopenharmony_ci hid_err(hdev, "cannot allocate hid_sensor_hub_device\n"); 66962306a36Sopenharmony_ci ret = -ENOMEM; 67062306a36Sopenharmony_ci goto err_stop_hw; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci hsdev->hdev = hdev; 67362306a36Sopenharmony_ci hsdev->vendor_id = hdev->vendor; 67462306a36Sopenharmony_ci hsdev->product_id = hdev->product; 67562306a36Sopenharmony_ci hsdev->usage = collection->usage; 67662306a36Sopenharmony_ci hsdev->mutex_ptr = devm_kzalloc(&hdev->dev, 67762306a36Sopenharmony_ci sizeof(struct mutex), 67862306a36Sopenharmony_ci GFP_KERNEL); 67962306a36Sopenharmony_ci if (!hsdev->mutex_ptr) { 68062306a36Sopenharmony_ci ret = -ENOMEM; 68162306a36Sopenharmony_ci goto err_stop_hw; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci mutex_init(hsdev->mutex_ptr); 68462306a36Sopenharmony_ci hsdev->start_collection_index = i; 68562306a36Sopenharmony_ci if (last_hsdev) 68662306a36Sopenharmony_ci last_hsdev->end_collection_index = i; 68762306a36Sopenharmony_ci last_hsdev = hsdev; 68862306a36Sopenharmony_ci name = devm_kasprintf(&hdev->dev, GFP_KERNEL, 68962306a36Sopenharmony_ci "HID-SENSOR-%x", 69062306a36Sopenharmony_ci collection->usage); 69162306a36Sopenharmony_ci if (name == NULL) { 69262306a36Sopenharmony_ci hid_err(hdev, "Failed MFD device name\n"); 69362306a36Sopenharmony_ci ret = -ENOMEM; 69462306a36Sopenharmony_ci goto err_stop_hw; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci sd->hid_sensor_hub_client_devs[ 69762306a36Sopenharmony_ci sd->hid_sensor_client_cnt].name = name; 69862306a36Sopenharmony_ci sd->hid_sensor_hub_client_devs[ 69962306a36Sopenharmony_ci sd->hid_sensor_client_cnt].platform_data = 70062306a36Sopenharmony_ci hsdev; 70162306a36Sopenharmony_ci sd->hid_sensor_hub_client_devs[ 70262306a36Sopenharmony_ci sd->hid_sensor_client_cnt].pdata_size = 70362306a36Sopenharmony_ci sizeof(*hsdev); 70462306a36Sopenharmony_ci hid_dbg(hdev, "Adding %s:%d\n", name, 70562306a36Sopenharmony_ci hsdev->start_collection_index); 70662306a36Sopenharmony_ci sd->hid_sensor_client_cnt++; 70762306a36Sopenharmony_ci if (collection_hsdev) 70862306a36Sopenharmony_ci collection_hsdev->end_collection_index = i; 70962306a36Sopenharmony_ci if (collection->type == HID_COLLECTION_APPLICATION && 71062306a36Sopenharmony_ci collection->usage == HID_USAGE_SENSOR_COLLECTION) 71162306a36Sopenharmony_ci collection_hsdev = hsdev; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci if (last_hsdev) 71562306a36Sopenharmony_ci last_hsdev->end_collection_index = i; 71662306a36Sopenharmony_ci if (collection_hsdev) 71762306a36Sopenharmony_ci collection_hsdev->end_collection_index = i; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci ret = mfd_add_hotplug_devices(&hdev->dev, 72062306a36Sopenharmony_ci sd->hid_sensor_hub_client_devs, 72162306a36Sopenharmony_ci sd->hid_sensor_client_cnt); 72262306a36Sopenharmony_ci if (ret < 0) 72362306a36Sopenharmony_ci goto err_stop_hw; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci return ret; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cierr_stop_hw: 72862306a36Sopenharmony_ci hid_hw_stop(hdev); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci return ret; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic void sensor_hub_remove(struct hid_device *hdev) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hdev); 73662306a36Sopenharmony_ci unsigned long flags; 73762306a36Sopenharmony_ci int i; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci hid_dbg(hdev, " hardware removed\n"); 74062306a36Sopenharmony_ci hid_hw_close(hdev); 74162306a36Sopenharmony_ci hid_hw_stop(hdev); 74262306a36Sopenharmony_ci spin_lock_irqsave(&data->lock, flags); 74362306a36Sopenharmony_ci for (i = 0; i < data->hid_sensor_client_cnt; ++i) { 74462306a36Sopenharmony_ci struct hid_sensor_hub_device *hsdev = 74562306a36Sopenharmony_ci data->hid_sensor_hub_client_devs[i].platform_data; 74662306a36Sopenharmony_ci if (hsdev->pending.status) 74762306a36Sopenharmony_ci complete(&hsdev->pending.ready); 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci spin_unlock_irqrestore(&data->lock, flags); 75062306a36Sopenharmony_ci mfd_remove_devices(&hdev->dev); 75162306a36Sopenharmony_ci mutex_destroy(&data->mutex); 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic const struct hid_device_id sensor_hub_devices[] = { 75562306a36Sopenharmony_ci { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, 75662306a36Sopenharmony_ci HID_ANY_ID) }, 75762306a36Sopenharmony_ci { } 75862306a36Sopenharmony_ci}; 75962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(hid, sensor_hub_devices); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic struct hid_driver sensor_hub_driver = { 76262306a36Sopenharmony_ci .name = "hid-sensor-hub", 76362306a36Sopenharmony_ci .id_table = sensor_hub_devices, 76462306a36Sopenharmony_ci .probe = sensor_hub_probe, 76562306a36Sopenharmony_ci .remove = sensor_hub_remove, 76662306a36Sopenharmony_ci .raw_event = sensor_hub_raw_event, 76762306a36Sopenharmony_ci .report_fixup = sensor_hub_report_fixup, 76862306a36Sopenharmony_ci#ifdef CONFIG_PM 76962306a36Sopenharmony_ci .suspend = sensor_hub_suspend, 77062306a36Sopenharmony_ci .resume = sensor_hub_resume, 77162306a36Sopenharmony_ci .reset_resume = sensor_hub_reset_resume, 77262306a36Sopenharmony_ci#endif 77362306a36Sopenharmony_ci}; 77462306a36Sopenharmony_cimodule_hid_driver(sensor_hub_driver); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ciMODULE_DESCRIPTION("HID Sensor Hub driver"); 77762306a36Sopenharmony_ciMODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); 77862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 779