18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * HID Sensors Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2012, Intel Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/device.h> 88c2ecf20Sopenharmony_ci#include <linux/hid.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/mfd/core.h> 128c2ecf20Sopenharmony_ci#include <linux/list.h> 138c2ecf20Sopenharmony_ci#include <linux/hid-sensor-ids.h> 148c2ecf20Sopenharmony_ci#include <linux/hid-sensor-hub.h> 158c2ecf20Sopenharmony_ci#include "hid-ids.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define HID_SENSOR_HUB_ENUM_QUIRK 0x01 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/** 208c2ecf20Sopenharmony_ci * struct sensor_hub_data - Hold a instance data for a HID hub device 218c2ecf20Sopenharmony_ci * @hsdev: Stored hid instance for current hub device. 228c2ecf20Sopenharmony_ci * @mutex: Mutex to serialize synchronous request. 238c2ecf20Sopenharmony_ci * @lock: Spin lock to protect pending request structure. 248c2ecf20Sopenharmony_ci * @dyn_callback_list: Holds callback function 258c2ecf20Sopenharmony_ci * @dyn_callback_lock: spin lock to protect callback list 268c2ecf20Sopenharmony_ci * @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance. 278c2ecf20Sopenharmony_ci * @hid_sensor_client_cnt: Number of MFD cells, (no of sensors attached). 288c2ecf20Sopenharmony_ci * @ref_cnt: Number of MFD clients have opened this device 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_cistruct sensor_hub_data { 318c2ecf20Sopenharmony_ci struct mutex mutex; 328c2ecf20Sopenharmony_ci spinlock_t lock; 338c2ecf20Sopenharmony_ci struct list_head dyn_callback_list; 348c2ecf20Sopenharmony_ci spinlock_t dyn_callback_lock; 358c2ecf20Sopenharmony_ci struct mfd_cell *hid_sensor_hub_client_devs; 368c2ecf20Sopenharmony_ci int hid_sensor_client_cnt; 378c2ecf20Sopenharmony_ci unsigned long quirks; 388c2ecf20Sopenharmony_ci int ref_cnt; 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/** 428c2ecf20Sopenharmony_ci * struct hid_sensor_hub_callbacks_list - Stores callback list 438c2ecf20Sopenharmony_ci * @list: list head. 448c2ecf20Sopenharmony_ci * @usage_id: usage id for a physical device. 458c2ecf20Sopenharmony_ci * @usage_callback: Stores registered callback functions. 468c2ecf20Sopenharmony_ci * @priv: Private data for a physical device. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_cistruct hid_sensor_hub_callbacks_list { 498c2ecf20Sopenharmony_ci struct list_head list; 508c2ecf20Sopenharmony_ci u32 usage_id; 518c2ecf20Sopenharmony_ci struct hid_sensor_hub_device *hsdev; 528c2ecf20Sopenharmony_ci struct hid_sensor_hub_callbacks *usage_callback; 538c2ecf20Sopenharmony_ci void *priv; 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic struct hid_report *sensor_hub_report(int id, struct hid_device *hdev, 578c2ecf20Sopenharmony_ci int dir) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct hid_report *report; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci list_for_each_entry(report, &hdev->report_enum[dir].report_list, list) { 628c2ecf20Sopenharmony_ci if (report->id == id) 638c2ecf20Sopenharmony_ci return report; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci hid_warn(hdev, "No report with id 0x%x found\n", id); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return NULL; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int sensor_hub_get_physical_device_count(struct hid_device *hdev) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int i; 738c2ecf20Sopenharmony_ci int count = 0; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci for (i = 0; i < hdev->maxcollection; ++i) { 768c2ecf20Sopenharmony_ci struct hid_collection *collection = &hdev->collection[i]; 778c2ecf20Sopenharmony_ci if (collection->type == HID_COLLECTION_PHYSICAL || 788c2ecf20Sopenharmony_ci collection->type == HID_COLLECTION_APPLICATION) 798c2ecf20Sopenharmony_ci ++count; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return count; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void sensor_hub_fill_attr_info( 868c2ecf20Sopenharmony_ci struct hid_sensor_hub_attribute_info *info, 878c2ecf20Sopenharmony_ci s32 index, s32 report_id, struct hid_field *field) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci info->index = index; 908c2ecf20Sopenharmony_ci info->report_id = report_id; 918c2ecf20Sopenharmony_ci info->units = field->unit; 928c2ecf20Sopenharmony_ci info->unit_expo = field->unit_exponent; 938c2ecf20Sopenharmony_ci info->size = (field->report_size * field->report_count)/8; 948c2ecf20Sopenharmony_ci info->logical_minimum = field->logical_minimum; 958c2ecf20Sopenharmony_ci info->logical_maximum = field->logical_maximum; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic struct hid_sensor_hub_callbacks *sensor_hub_get_callback( 998c2ecf20Sopenharmony_ci struct hid_device *hdev, 1008c2ecf20Sopenharmony_ci u32 usage_id, 1018c2ecf20Sopenharmony_ci int collection_index, 1028c2ecf20Sopenharmony_ci struct hid_sensor_hub_device **hsdev, 1038c2ecf20Sopenharmony_ci void **priv) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct hid_sensor_hub_callbacks_list *callback; 1068c2ecf20Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hdev); 1078c2ecf20Sopenharmony_ci unsigned long flags; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci spin_lock_irqsave(&pdata->dyn_callback_lock, flags); 1108c2ecf20Sopenharmony_ci list_for_each_entry(callback, &pdata->dyn_callback_list, list) 1118c2ecf20Sopenharmony_ci if ((callback->usage_id == usage_id || 1128c2ecf20Sopenharmony_ci callback->usage_id == HID_USAGE_SENSOR_COLLECTION) && 1138c2ecf20Sopenharmony_ci (collection_index >= 1148c2ecf20Sopenharmony_ci callback->hsdev->start_collection_index) && 1158c2ecf20Sopenharmony_ci (collection_index < 1168c2ecf20Sopenharmony_ci callback->hsdev->end_collection_index)) { 1178c2ecf20Sopenharmony_ci *priv = callback->priv; 1188c2ecf20Sopenharmony_ci *hsdev = callback->hsdev; 1198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, 1208c2ecf20Sopenharmony_ci flags); 1218c2ecf20Sopenharmony_ci return callback->usage_callback; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return NULL; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ciint sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, 1298c2ecf20Sopenharmony_ci u32 usage_id, 1308c2ecf20Sopenharmony_ci struct hid_sensor_hub_callbacks *usage_callback) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct hid_sensor_hub_callbacks_list *callback; 1338c2ecf20Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); 1348c2ecf20Sopenharmony_ci unsigned long flags; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci spin_lock_irqsave(&pdata->dyn_callback_lock, flags); 1378c2ecf20Sopenharmony_ci list_for_each_entry(callback, &pdata->dyn_callback_list, list) 1388c2ecf20Sopenharmony_ci if (callback->usage_id == usage_id && 1398c2ecf20Sopenharmony_ci callback->hsdev == hsdev) { 1408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 1418c2ecf20Sopenharmony_ci return -EINVAL; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci callback = kzalloc(sizeof(*callback), GFP_ATOMIC); 1448c2ecf20Sopenharmony_ci if (!callback) { 1458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 1468c2ecf20Sopenharmony_ci return -ENOMEM; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci callback->hsdev = hsdev; 1498c2ecf20Sopenharmony_ci callback->usage_callback = usage_callback; 1508c2ecf20Sopenharmony_ci callback->usage_id = usage_id; 1518c2ecf20Sopenharmony_ci callback->priv = NULL; 1528c2ecf20Sopenharmony_ci /* 1538c2ecf20Sopenharmony_ci * If there is a handler registered for the collection type, then 1548c2ecf20Sopenharmony_ci * it will handle all reports for sensors in this collection. If 1558c2ecf20Sopenharmony_ci * there is also an individual sensor handler registration, then 1568c2ecf20Sopenharmony_ci * we want to make sure that the reports are directed to collection 1578c2ecf20Sopenharmony_ci * handler, as this may be a fusion sensor. So add collection handlers 1588c2ecf20Sopenharmony_ci * to the beginning of the list, so that they are matched first. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci if (usage_id == HID_USAGE_SENSOR_COLLECTION) 1618c2ecf20Sopenharmony_ci list_add(&callback->list, &pdata->dyn_callback_list); 1628c2ecf20Sopenharmony_ci else 1638c2ecf20Sopenharmony_ci list_add_tail(&callback->list, &pdata->dyn_callback_list); 1648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_register_callback); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciint sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, 1718c2ecf20Sopenharmony_ci u32 usage_id) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct hid_sensor_hub_callbacks_list *callback; 1748c2ecf20Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); 1758c2ecf20Sopenharmony_ci unsigned long flags; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci spin_lock_irqsave(&pdata->dyn_callback_lock, flags); 1788c2ecf20Sopenharmony_ci list_for_each_entry(callback, &pdata->dyn_callback_list, list) 1798c2ecf20Sopenharmony_ci if (callback->usage_id == usage_id && 1808c2ecf20Sopenharmony_ci callback->hsdev == hsdev) { 1818c2ecf20Sopenharmony_ci list_del(&callback->list); 1828c2ecf20Sopenharmony_ci kfree(callback); 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_remove_callback); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ciint sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, 1928c2ecf20Sopenharmony_ci u32 field_index, int buffer_size, void *buffer) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct hid_report *report; 1958c2ecf20Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); 1968c2ecf20Sopenharmony_ci __s32 *buf32 = buffer; 1978c2ecf20Sopenharmony_ci int i = 0; 1988c2ecf20Sopenharmony_ci int remaining_bytes; 1998c2ecf20Sopenharmony_ci __s32 value; 2008c2ecf20Sopenharmony_ci int ret = 0; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 2038c2ecf20Sopenharmony_ci report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); 2048c2ecf20Sopenharmony_ci if (!report || (field_index >= report->maxfield)) { 2058c2ecf20Sopenharmony_ci ret = -EINVAL; 2068c2ecf20Sopenharmony_ci goto done_proc; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci remaining_bytes = buffer_size % sizeof(__s32); 2108c2ecf20Sopenharmony_ci buffer_size = buffer_size / sizeof(__s32); 2118c2ecf20Sopenharmony_ci if (buffer_size) { 2128c2ecf20Sopenharmony_ci for (i = 0; i < buffer_size; ++i) { 2138c2ecf20Sopenharmony_ci ret = hid_set_field(report->field[field_index], i, 2148c2ecf20Sopenharmony_ci (__force __s32)cpu_to_le32(*buf32)); 2158c2ecf20Sopenharmony_ci if (ret) 2168c2ecf20Sopenharmony_ci goto done_proc; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ++buf32; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci if (remaining_bytes) { 2228c2ecf20Sopenharmony_ci value = 0; 2238c2ecf20Sopenharmony_ci memcpy(&value, (u8 *)buf32, remaining_bytes); 2248c2ecf20Sopenharmony_ci ret = hid_set_field(report->field[field_index], i, 2258c2ecf20Sopenharmony_ci (__force __s32)cpu_to_le32(value)); 2268c2ecf20Sopenharmony_ci if (ret) 2278c2ecf20Sopenharmony_ci goto done_proc; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT); 2308c2ecf20Sopenharmony_ci hid_hw_wait(hsdev->hdev); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cidone_proc: 2338c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_set_feature); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ciint sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, 2408c2ecf20Sopenharmony_ci u32 field_index, int buffer_size, void *buffer) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct hid_report *report; 2438c2ecf20Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); 2448c2ecf20Sopenharmony_ci int report_size; 2458c2ecf20Sopenharmony_ci int ret = 0; 2468c2ecf20Sopenharmony_ci u8 *val_ptr; 2478c2ecf20Sopenharmony_ci int buffer_index = 0; 2488c2ecf20Sopenharmony_ci int i; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci memset(buffer, 0, buffer_size); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 2538c2ecf20Sopenharmony_ci report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); 2548c2ecf20Sopenharmony_ci if (!report || (field_index >= report->maxfield) || 2558c2ecf20Sopenharmony_ci report->field[field_index]->report_count < 1) { 2568c2ecf20Sopenharmony_ci ret = -EINVAL; 2578c2ecf20Sopenharmony_ci goto done_proc; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); 2608c2ecf20Sopenharmony_ci hid_hw_wait(hsdev->hdev); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* calculate number of bytes required to read this field */ 2638c2ecf20Sopenharmony_ci report_size = DIV_ROUND_UP(report->field[field_index]->report_size, 2648c2ecf20Sopenharmony_ci 8) * 2658c2ecf20Sopenharmony_ci report->field[field_index]->report_count; 2668c2ecf20Sopenharmony_ci if (!report_size) { 2678c2ecf20Sopenharmony_ci ret = -EINVAL; 2688c2ecf20Sopenharmony_ci goto done_proc; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci ret = min(report_size, buffer_size); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci val_ptr = (u8 *)report->field[field_index]->value; 2738c2ecf20Sopenharmony_ci for (i = 0; i < report->field[field_index]->report_count; ++i) { 2748c2ecf20Sopenharmony_ci if (buffer_index >= ret) 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci memcpy(&((u8 *)buffer)[buffer_index], val_ptr, 2788c2ecf20Sopenharmony_ci report->field[field_index]->report_size / 8); 2798c2ecf20Sopenharmony_ci val_ptr += sizeof(__s32); 2808c2ecf20Sopenharmony_ci buffer_index += (report->field[field_index]->report_size / 8); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cidone_proc: 2848c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return ret; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_get_feature); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciint sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, 2928c2ecf20Sopenharmony_ci u32 usage_id, 2938c2ecf20Sopenharmony_ci u32 attr_usage_id, u32 report_id, 2948c2ecf20Sopenharmony_ci enum sensor_hub_read_flags flag, 2958c2ecf20Sopenharmony_ci bool is_signed) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); 2988c2ecf20Sopenharmony_ci unsigned long flags; 2998c2ecf20Sopenharmony_ci struct hid_report *report; 3008c2ecf20Sopenharmony_ci int ret_val = 0; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci report = sensor_hub_report(report_id, hsdev->hdev, 3038c2ecf20Sopenharmony_ci HID_INPUT_REPORT); 3048c2ecf20Sopenharmony_ci if (!report) 3058c2ecf20Sopenharmony_ci return -EINVAL; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci mutex_lock(hsdev->mutex_ptr); 3088c2ecf20Sopenharmony_ci if (flag == SENSOR_HUB_SYNC) { 3098c2ecf20Sopenharmony_ci memset(&hsdev->pending, 0, sizeof(hsdev->pending)); 3108c2ecf20Sopenharmony_ci init_completion(&hsdev->pending.ready); 3118c2ecf20Sopenharmony_ci hsdev->pending.usage_id = usage_id; 3128c2ecf20Sopenharmony_ci hsdev->pending.attr_usage_id = attr_usage_id; 3138c2ecf20Sopenharmony_ci hsdev->pending.raw_size = 0; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci spin_lock_irqsave(&data->lock, flags); 3168c2ecf20Sopenharmony_ci hsdev->pending.status = true; 3178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&data->lock, flags); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 3208c2ecf20Sopenharmony_ci hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); 3218c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 3228c2ecf20Sopenharmony_ci if (flag == SENSOR_HUB_SYNC) { 3238c2ecf20Sopenharmony_ci wait_for_completion_interruptible_timeout( 3248c2ecf20Sopenharmony_ci &hsdev->pending.ready, HZ*5); 3258c2ecf20Sopenharmony_ci switch (hsdev->pending.raw_size) { 3268c2ecf20Sopenharmony_ci case 1: 3278c2ecf20Sopenharmony_ci if (is_signed) 3288c2ecf20Sopenharmony_ci ret_val = *(s8 *)hsdev->pending.raw_data; 3298c2ecf20Sopenharmony_ci else 3308c2ecf20Sopenharmony_ci ret_val = *(u8 *)hsdev->pending.raw_data; 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci case 2: 3338c2ecf20Sopenharmony_ci if (is_signed) 3348c2ecf20Sopenharmony_ci ret_val = *(s16 *)hsdev->pending.raw_data; 3358c2ecf20Sopenharmony_ci else 3368c2ecf20Sopenharmony_ci ret_val = *(u16 *)hsdev->pending.raw_data; 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci case 4: 3398c2ecf20Sopenharmony_ci ret_val = *(u32 *)hsdev->pending.raw_data; 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci default: 3428c2ecf20Sopenharmony_ci ret_val = 0; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci kfree(hsdev->pending.raw_data); 3458c2ecf20Sopenharmony_ci hsdev->pending.status = false; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci mutex_unlock(hsdev->mutex_ptr); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return ret_val; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ciint hid_sensor_get_usage_index(struct hid_sensor_hub_device *hsdev, 3548c2ecf20Sopenharmony_ci u32 report_id, int field_index, u32 usage_id) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct hid_report *report; 3578c2ecf20Sopenharmony_ci struct hid_field *field; 3588c2ecf20Sopenharmony_ci int i; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); 3618c2ecf20Sopenharmony_ci if (!report || (field_index >= report->maxfield)) 3628c2ecf20Sopenharmony_ci goto done_proc; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci field = report->field[field_index]; 3658c2ecf20Sopenharmony_ci for (i = 0; i < field->maxusage; ++i) { 3668c2ecf20Sopenharmony_ci if (field->usage[i].hid == usage_id) 3678c2ecf20Sopenharmony_ci return field->usage[i].usage_index; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cidone_proc: 3718c2ecf20Sopenharmony_ci return -EINVAL; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hid_sensor_get_usage_index); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ciint sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, 3768c2ecf20Sopenharmony_ci u8 type, 3778c2ecf20Sopenharmony_ci u32 usage_id, 3788c2ecf20Sopenharmony_ci u32 attr_usage_id, 3798c2ecf20Sopenharmony_ci struct hid_sensor_hub_attribute_info *info) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci int ret = -1; 3828c2ecf20Sopenharmony_ci int i; 3838c2ecf20Sopenharmony_ci struct hid_report *report; 3848c2ecf20Sopenharmony_ci struct hid_field *field; 3858c2ecf20Sopenharmony_ci struct hid_report_enum *report_enum; 3868c2ecf20Sopenharmony_ci struct hid_device *hdev = hsdev->hdev; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Initialize with defaults */ 3898c2ecf20Sopenharmony_ci info->usage_id = usage_id; 3908c2ecf20Sopenharmony_ci info->attrib_id = attr_usage_id; 3918c2ecf20Sopenharmony_ci info->report_id = -1; 3928c2ecf20Sopenharmony_ci info->index = -1; 3938c2ecf20Sopenharmony_ci info->units = -1; 3948c2ecf20Sopenharmony_ci info->unit_expo = -1; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci report_enum = &hdev->report_enum[type]; 3978c2ecf20Sopenharmony_ci list_for_each_entry(report, &report_enum->report_list, list) { 3988c2ecf20Sopenharmony_ci for (i = 0; i < report->maxfield; ++i) { 3998c2ecf20Sopenharmony_ci field = report->field[i]; 4008c2ecf20Sopenharmony_ci if (field->maxusage) { 4018c2ecf20Sopenharmony_ci if (field->physical == usage_id && 4028c2ecf20Sopenharmony_ci (field->logical == attr_usage_id || 4038c2ecf20Sopenharmony_ci field->usage[0].hid == 4048c2ecf20Sopenharmony_ci attr_usage_id) && 4058c2ecf20Sopenharmony_ci (field->usage[0].collection_index >= 4068c2ecf20Sopenharmony_ci hsdev->start_collection_index) && 4078c2ecf20Sopenharmony_ci (field->usage[0].collection_index < 4088c2ecf20Sopenharmony_ci hsdev->end_collection_index)) { 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci sensor_hub_fill_attr_info(info, i, 4118c2ecf20Sopenharmony_ci report->id, 4128c2ecf20Sopenharmony_ci field); 4138c2ecf20Sopenharmony_ci ret = 0; 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return ret; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4268c2ecf20Sopenharmony_cistatic int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hdev); 4298c2ecf20Sopenharmony_ci struct hid_sensor_hub_callbacks_list *callback; 4308c2ecf20Sopenharmony_ci unsigned long flags; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci hid_dbg(hdev, " sensor_hub_suspend\n"); 4338c2ecf20Sopenharmony_ci spin_lock_irqsave(&pdata->dyn_callback_lock, flags); 4348c2ecf20Sopenharmony_ci list_for_each_entry(callback, &pdata->dyn_callback_list, list) { 4358c2ecf20Sopenharmony_ci if (callback->usage_callback->suspend) 4368c2ecf20Sopenharmony_ci callback->usage_callback->suspend( 4378c2ecf20Sopenharmony_ci callback->hsdev, callback->priv); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int sensor_hub_resume(struct hid_device *hdev) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hdev); 4478c2ecf20Sopenharmony_ci struct hid_sensor_hub_callbacks_list *callback; 4488c2ecf20Sopenharmony_ci unsigned long flags; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci hid_dbg(hdev, " sensor_hub_resume\n"); 4518c2ecf20Sopenharmony_ci spin_lock_irqsave(&pdata->dyn_callback_lock, flags); 4528c2ecf20Sopenharmony_ci list_for_each_entry(callback, &pdata->dyn_callback_list, list) { 4538c2ecf20Sopenharmony_ci if (callback->usage_callback->resume) 4548c2ecf20Sopenharmony_ci callback->usage_callback->resume( 4558c2ecf20Sopenharmony_ci callback->hsdev, callback->priv); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return 0; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic int sensor_hub_reset_resume(struct hid_device *hdev) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci#endif 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci/* 4698c2ecf20Sopenharmony_ci * Handle raw report as sent by device 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_cistatic int sensor_hub_raw_event(struct hid_device *hdev, 4728c2ecf20Sopenharmony_ci struct hid_report *report, u8 *raw_data, int size) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci int i; 4758c2ecf20Sopenharmony_ci u8 *ptr; 4768c2ecf20Sopenharmony_ci int sz; 4778c2ecf20Sopenharmony_ci struct sensor_hub_data *pdata = hid_get_drvdata(hdev); 4788c2ecf20Sopenharmony_ci unsigned long flags; 4798c2ecf20Sopenharmony_ci struct hid_sensor_hub_callbacks *callback = NULL; 4808c2ecf20Sopenharmony_ci struct hid_collection *collection = NULL; 4818c2ecf20Sopenharmony_ci void *priv = NULL; 4828c2ecf20Sopenharmony_ci struct hid_sensor_hub_device *hsdev = NULL; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n", 4858c2ecf20Sopenharmony_ci report->id, size, report->type); 4868c2ecf20Sopenharmony_ci hid_dbg(hdev, "maxfield:%d\n", report->maxfield); 4878c2ecf20Sopenharmony_ci if (report->type != HID_INPUT_REPORT) 4888c2ecf20Sopenharmony_ci return 1; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci ptr = raw_data; 4918c2ecf20Sopenharmony_ci if (report->id) 4928c2ecf20Sopenharmony_ci ptr++; /* Skip report id */ 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci spin_lock_irqsave(&pdata->lock, flags); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci for (i = 0; i < report->maxfield; ++i) { 4978c2ecf20Sopenharmony_ci hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n", 4988c2ecf20Sopenharmony_ci i, report->field[i]->usage->collection_index, 4998c2ecf20Sopenharmony_ci report->field[i]->usage->hid, 5008c2ecf20Sopenharmony_ci (report->field[i]->report_size * 5018c2ecf20Sopenharmony_ci report->field[i]->report_count)/8); 5028c2ecf20Sopenharmony_ci sz = (report->field[i]->report_size * 5038c2ecf20Sopenharmony_ci report->field[i]->report_count)/8; 5048c2ecf20Sopenharmony_ci collection = &hdev->collection[ 5058c2ecf20Sopenharmony_ci report->field[i]->usage->collection_index]; 5068c2ecf20Sopenharmony_ci hid_dbg(hdev, "collection->usage %x\n", 5078c2ecf20Sopenharmony_ci collection->usage); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci callback = sensor_hub_get_callback(hdev, 5108c2ecf20Sopenharmony_ci report->field[i]->physical, 5118c2ecf20Sopenharmony_ci report->field[i]->usage[0].collection_index, 5128c2ecf20Sopenharmony_ci &hsdev, &priv); 5138c2ecf20Sopenharmony_ci if (!callback) { 5148c2ecf20Sopenharmony_ci ptr += sz; 5158c2ecf20Sopenharmony_ci continue; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci if (hsdev->pending.status && (hsdev->pending.attr_usage_id == 5188c2ecf20Sopenharmony_ci report->field[i]->usage->hid || 5198c2ecf20Sopenharmony_ci hsdev->pending.attr_usage_id == 5208c2ecf20Sopenharmony_ci report->field[i]->logical)) { 5218c2ecf20Sopenharmony_ci hid_dbg(hdev, "data was pending ...\n"); 5228c2ecf20Sopenharmony_ci hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); 5238c2ecf20Sopenharmony_ci if (hsdev->pending.raw_data) 5248c2ecf20Sopenharmony_ci hsdev->pending.raw_size = sz; 5258c2ecf20Sopenharmony_ci else 5268c2ecf20Sopenharmony_ci hsdev->pending.raw_size = 0; 5278c2ecf20Sopenharmony_ci complete(&hsdev->pending.ready); 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci if (callback->capture_sample) { 5308c2ecf20Sopenharmony_ci if (report->field[i]->logical) 5318c2ecf20Sopenharmony_ci callback->capture_sample(hsdev, 5328c2ecf20Sopenharmony_ci report->field[i]->logical, sz, ptr, 5338c2ecf20Sopenharmony_ci callback->pdev); 5348c2ecf20Sopenharmony_ci else 5358c2ecf20Sopenharmony_ci callback->capture_sample(hsdev, 5368c2ecf20Sopenharmony_ci report->field[i]->usage->hid, sz, ptr, 5378c2ecf20Sopenharmony_ci callback->pdev); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci ptr += sz; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci if (callback && collection && callback->send_event) 5428c2ecf20Sopenharmony_ci callback->send_event(hsdev, collection->usage, 5438c2ecf20Sopenharmony_ci callback->pdev); 5448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pdata->lock, flags); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci return 1; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ciint sensor_hub_device_open(struct hid_sensor_hub_device *hsdev) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci int ret = 0; 5528c2ecf20Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 5558c2ecf20Sopenharmony_ci if (!data->ref_cnt) { 5568c2ecf20Sopenharmony_ci ret = hid_hw_open(hsdev->hdev); 5578c2ecf20Sopenharmony_ci if (ret) { 5588c2ecf20Sopenharmony_ci hid_err(hsdev->hdev, "failed to open hid device\n"); 5598c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5608c2ecf20Sopenharmony_ci return ret; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci data->ref_cnt++; 5648c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci return ret; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_device_open); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_civoid sensor_hub_device_close(struct hid_sensor_hub_device *hsdev) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 5758c2ecf20Sopenharmony_ci data->ref_cnt--; 5768c2ecf20Sopenharmony_ci if (!data->ref_cnt) 5778c2ecf20Sopenharmony_ci hid_hw_close(hsdev->hdev); 5788c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sensor_hub_device_close); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic __u8 *sensor_hub_report_fixup(struct hid_device *hdev, __u8 *rdesc, 5838c2ecf20Sopenharmony_ci unsigned int *rsize) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci /* 5868c2ecf20Sopenharmony_ci * Checks if the report descriptor of Thinkpad Helix 2 has a logical 5878c2ecf20Sopenharmony_ci * minimum for magnetic flux axis greater than the maximum. 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci if (hdev->product == USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA && 5908c2ecf20Sopenharmony_ci *rsize == 2558 && rdesc[913] == 0x17 && rdesc[914] == 0x40 && 5918c2ecf20Sopenharmony_ci rdesc[915] == 0x81 && rdesc[916] == 0x08 && 5928c2ecf20Sopenharmony_ci rdesc[917] == 0x00 && rdesc[918] == 0x27 && 5938c2ecf20Sopenharmony_ci rdesc[921] == 0x07 && rdesc[922] == 0x00) { 5948c2ecf20Sopenharmony_ci /* Sets negative logical minimum for mag x, y and z */ 5958c2ecf20Sopenharmony_ci rdesc[914] = rdesc[935] = rdesc[956] = 0xc0; 5968c2ecf20Sopenharmony_ci rdesc[915] = rdesc[936] = rdesc[957] = 0x7e; 5978c2ecf20Sopenharmony_ci rdesc[916] = rdesc[937] = rdesc[958] = 0xf7; 5988c2ecf20Sopenharmony_ci rdesc[917] = rdesc[938] = rdesc[959] = 0xff; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci return rdesc; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic int sensor_hub_probe(struct hid_device *hdev, 6058c2ecf20Sopenharmony_ci const struct hid_device_id *id) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci int ret; 6088c2ecf20Sopenharmony_ci struct sensor_hub_data *sd; 6098c2ecf20Sopenharmony_ci int i; 6108c2ecf20Sopenharmony_ci char *name; 6118c2ecf20Sopenharmony_ci int dev_cnt; 6128c2ecf20Sopenharmony_ci struct hid_sensor_hub_device *hsdev; 6138c2ecf20Sopenharmony_ci struct hid_sensor_hub_device *last_hsdev = NULL; 6148c2ecf20Sopenharmony_ci struct hid_sensor_hub_device *collection_hsdev = NULL; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL); 6178c2ecf20Sopenharmony_ci if (!sd) { 6188c2ecf20Sopenharmony_ci hid_err(hdev, "cannot allocate Sensor data\n"); 6198c2ecf20Sopenharmony_ci return -ENOMEM; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci hid_set_drvdata(hdev, sd); 6238c2ecf20Sopenharmony_ci sd->quirks = id->driver_data; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci spin_lock_init(&sd->lock); 6268c2ecf20Sopenharmony_ci spin_lock_init(&sd->dyn_callback_lock); 6278c2ecf20Sopenharmony_ci mutex_init(&sd->mutex); 6288c2ecf20Sopenharmony_ci ret = hid_parse(hdev); 6298c2ecf20Sopenharmony_ci if (ret) { 6308c2ecf20Sopenharmony_ci hid_err(hdev, "parse failed\n"); 6318c2ecf20Sopenharmony_ci return ret; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hdev->inputs); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci ret = hid_hw_start(hdev, 0); 6368c2ecf20Sopenharmony_ci if (ret) { 6378c2ecf20Sopenharmony_ci hid_err(hdev, "hw start failed\n"); 6388c2ecf20Sopenharmony_ci return ret; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sd->dyn_callback_list); 6418c2ecf20Sopenharmony_ci sd->hid_sensor_client_cnt = 0; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci dev_cnt = sensor_hub_get_physical_device_count(hdev); 6448c2ecf20Sopenharmony_ci if (dev_cnt > HID_MAX_PHY_DEVICES) { 6458c2ecf20Sopenharmony_ci hid_err(hdev, "Invalid Physical device count\n"); 6468c2ecf20Sopenharmony_ci ret = -EINVAL; 6478c2ecf20Sopenharmony_ci goto err_stop_hw; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci sd->hid_sensor_hub_client_devs = devm_kcalloc(&hdev->dev, 6508c2ecf20Sopenharmony_ci dev_cnt, 6518c2ecf20Sopenharmony_ci sizeof(struct mfd_cell), 6528c2ecf20Sopenharmony_ci GFP_KERNEL); 6538c2ecf20Sopenharmony_ci if (sd->hid_sensor_hub_client_devs == NULL) { 6548c2ecf20Sopenharmony_ci hid_err(hdev, "Failed to allocate memory for mfd cells\n"); 6558c2ecf20Sopenharmony_ci ret = -ENOMEM; 6568c2ecf20Sopenharmony_ci goto err_stop_hw; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci for (i = 0; i < hdev->maxcollection; ++i) { 6608c2ecf20Sopenharmony_ci struct hid_collection *collection = &hdev->collection[i]; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (collection->type == HID_COLLECTION_PHYSICAL || 6638c2ecf20Sopenharmony_ci collection->type == HID_COLLECTION_APPLICATION) { 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev), 6668c2ecf20Sopenharmony_ci GFP_KERNEL); 6678c2ecf20Sopenharmony_ci if (!hsdev) { 6688c2ecf20Sopenharmony_ci hid_err(hdev, "cannot allocate hid_sensor_hub_device\n"); 6698c2ecf20Sopenharmony_ci ret = -ENOMEM; 6708c2ecf20Sopenharmony_ci goto err_stop_hw; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci hsdev->hdev = hdev; 6738c2ecf20Sopenharmony_ci hsdev->vendor_id = hdev->vendor; 6748c2ecf20Sopenharmony_ci hsdev->product_id = hdev->product; 6758c2ecf20Sopenharmony_ci hsdev->usage = collection->usage; 6768c2ecf20Sopenharmony_ci hsdev->mutex_ptr = devm_kzalloc(&hdev->dev, 6778c2ecf20Sopenharmony_ci sizeof(struct mutex), 6788c2ecf20Sopenharmony_ci GFP_KERNEL); 6798c2ecf20Sopenharmony_ci if (!hsdev->mutex_ptr) { 6808c2ecf20Sopenharmony_ci ret = -ENOMEM; 6818c2ecf20Sopenharmony_ci goto err_stop_hw; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci mutex_init(hsdev->mutex_ptr); 6848c2ecf20Sopenharmony_ci hsdev->start_collection_index = i; 6858c2ecf20Sopenharmony_ci if (last_hsdev) 6868c2ecf20Sopenharmony_ci last_hsdev->end_collection_index = i; 6878c2ecf20Sopenharmony_ci last_hsdev = hsdev; 6888c2ecf20Sopenharmony_ci name = devm_kasprintf(&hdev->dev, GFP_KERNEL, 6898c2ecf20Sopenharmony_ci "HID-SENSOR-%x", 6908c2ecf20Sopenharmony_ci collection->usage); 6918c2ecf20Sopenharmony_ci if (name == NULL) { 6928c2ecf20Sopenharmony_ci hid_err(hdev, "Failed MFD device name\n"); 6938c2ecf20Sopenharmony_ci ret = -ENOMEM; 6948c2ecf20Sopenharmony_ci goto err_stop_hw; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci sd->hid_sensor_hub_client_devs[ 6978c2ecf20Sopenharmony_ci sd->hid_sensor_client_cnt].name = name; 6988c2ecf20Sopenharmony_ci sd->hid_sensor_hub_client_devs[ 6998c2ecf20Sopenharmony_ci sd->hid_sensor_client_cnt].platform_data = 7008c2ecf20Sopenharmony_ci hsdev; 7018c2ecf20Sopenharmony_ci sd->hid_sensor_hub_client_devs[ 7028c2ecf20Sopenharmony_ci sd->hid_sensor_client_cnt].pdata_size = 7038c2ecf20Sopenharmony_ci sizeof(*hsdev); 7048c2ecf20Sopenharmony_ci hid_dbg(hdev, "Adding %s:%d\n", name, 7058c2ecf20Sopenharmony_ci hsdev->start_collection_index); 7068c2ecf20Sopenharmony_ci sd->hid_sensor_client_cnt++; 7078c2ecf20Sopenharmony_ci if (collection_hsdev) 7088c2ecf20Sopenharmony_ci collection_hsdev->end_collection_index = i; 7098c2ecf20Sopenharmony_ci if (collection->type == HID_COLLECTION_APPLICATION && 7108c2ecf20Sopenharmony_ci collection->usage == HID_USAGE_SENSOR_COLLECTION) 7118c2ecf20Sopenharmony_ci collection_hsdev = hsdev; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci if (last_hsdev) 7158c2ecf20Sopenharmony_ci last_hsdev->end_collection_index = i; 7168c2ecf20Sopenharmony_ci if (collection_hsdev) 7178c2ecf20Sopenharmony_ci collection_hsdev->end_collection_index = i; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci ret = mfd_add_hotplug_devices(&hdev->dev, 7208c2ecf20Sopenharmony_ci sd->hid_sensor_hub_client_devs, 7218c2ecf20Sopenharmony_ci sd->hid_sensor_client_cnt); 7228c2ecf20Sopenharmony_ci if (ret < 0) 7238c2ecf20Sopenharmony_ci goto err_stop_hw; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return ret; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cierr_stop_hw: 7288c2ecf20Sopenharmony_ci hid_hw_stop(hdev); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci return ret; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic void sensor_hub_remove(struct hid_device *hdev) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct sensor_hub_data *data = hid_get_drvdata(hdev); 7368c2ecf20Sopenharmony_ci unsigned long flags; 7378c2ecf20Sopenharmony_ci int i; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci hid_dbg(hdev, " hardware removed\n"); 7408c2ecf20Sopenharmony_ci hid_hw_close(hdev); 7418c2ecf20Sopenharmony_ci hid_hw_stop(hdev); 7428c2ecf20Sopenharmony_ci spin_lock_irqsave(&data->lock, flags); 7438c2ecf20Sopenharmony_ci for (i = 0; i < data->hid_sensor_client_cnt; ++i) { 7448c2ecf20Sopenharmony_ci struct hid_sensor_hub_device *hsdev = 7458c2ecf20Sopenharmony_ci data->hid_sensor_hub_client_devs[i].platform_data; 7468c2ecf20Sopenharmony_ci if (hsdev->pending.status) 7478c2ecf20Sopenharmony_ci complete(&hsdev->pending.ready); 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&data->lock, flags); 7508c2ecf20Sopenharmony_ci mfd_remove_devices(&hdev->dev); 7518c2ecf20Sopenharmony_ci mutex_destroy(&data->mutex); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic const struct hid_device_id sensor_hub_devices[] = { 7558c2ecf20Sopenharmony_ci { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, 7568c2ecf20Sopenharmony_ci HID_ANY_ID) }, 7578c2ecf20Sopenharmony_ci { } 7588c2ecf20Sopenharmony_ci}; 7598c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(hid, sensor_hub_devices); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic struct hid_driver sensor_hub_driver = { 7628c2ecf20Sopenharmony_ci .name = "hid-sensor-hub", 7638c2ecf20Sopenharmony_ci .id_table = sensor_hub_devices, 7648c2ecf20Sopenharmony_ci .probe = sensor_hub_probe, 7658c2ecf20Sopenharmony_ci .remove = sensor_hub_remove, 7668c2ecf20Sopenharmony_ci .raw_event = sensor_hub_raw_event, 7678c2ecf20Sopenharmony_ci .report_fixup = sensor_hub_report_fixup, 7688c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 7698c2ecf20Sopenharmony_ci .suspend = sensor_hub_suspend, 7708c2ecf20Sopenharmony_ci .resume = sensor_hub_resume, 7718c2ecf20Sopenharmony_ci .reset_resume = sensor_hub_reset_resume, 7728c2ecf20Sopenharmony_ci#endif 7738c2ecf20Sopenharmony_ci}; 7748c2ecf20Sopenharmony_cimodule_hid_driver(sensor_hub_driver); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HID Sensor Hub driver"); 7778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); 7788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 779