summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/hid/amd-sfh-hid.rst145
-rw-r--r--Documentation/hid/index.rst1
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/hid/Kconfig2
-rw-r--r--drivers/hid/Makefile2
-rw-r--r--drivers/hid/amd-sfh-hid/Kconfig18
-rw-r--r--drivers/hid/amd-sfh-hid/Makefile13
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_client.c246
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_hid.c174
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_hid.h67
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_pcie.c152
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_pcie.h79
-rw-r--r--drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c224
-rw-r--r--drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h107
-rw-r--r--drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h645
-rw-r--r--drivers/hid/hid-cypress.c44
-rw-r--r--drivers/hid/hid-ids.h11
-rw-r--r--drivers/hid/hid-input.c3
-rw-r--r--drivers/hid/hid-ite.c72
-rw-r--r--drivers/hid/hid-logitech-dj.c22
-rw-r--r--drivers/hid/hid-logitech-hidpp.c34
-rw-r--r--drivers/hid/hid-mcp2221.c48
-rw-r--r--drivers/hid/hid-mf.c2
-rw-r--r--drivers/hid/hid-quirks.c7
-rw-r--r--drivers/hid/hid-sensor-hub.c3
-rw-r--r--drivers/hid/hid-sony.c34
-rw-r--r--drivers/hid/hid-uclogic-core.c2
-rw-r--r--drivers/hid/hid-uclogic-params.c2
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-core.c9
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c8
30 files changed, 2161 insertions, 23 deletions
diff --git a/Documentation/hid/amd-sfh-hid.rst b/Documentation/hid/amd-sfh-hid.rst
new file mode 100644
index 000000000000..1f2fe29ccd4f
--- /dev/null
+++ b/Documentation/hid/amd-sfh-hid.rst
@@ -0,0 +1,145 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+
+AMD Sensor Fusion Hub
+=====================
+AMD Sensor Fusion Hub (SFH) is part of an SOC starting from Ryzen based platforms.
+The solution is working well on several OEM products. AMD SFH uses HID over PCIe bus.
+In terms of architecture it resembles ISH, however the major difference is all
+the HID reports are generated as part of the kernel driver.
+
+1. Block Diagram
+================
+
+::
+
+ ---------------------------------
+ | HID User Space Applications |
+ - -------------------------------
+
+ ---------------------------------------------
+ ---------------------------------
+ | HID Core |
+ ---------------------------------
+
+ ---------------------------------
+ | AMD HID Transport |
+ ---------------------------------
+
+ --------------------------------
+ | AMD HID Client |
+ | with HID Report Generator|
+ --------------------------------
+
+ --------------------------------
+ | AMD MP2 PCIe Driver |
+ --------------------------------
+ OS
+ ---------------------------------------------
+ Hardware + Firmware
+ --------------------------------
+ | SFH MP2 Processor |
+ --------------------------------
+
+
+AMD HID Transport Layer
+-----------------------
+AMD SFH transport is also implemented as a bus. Each client application executing in the AMD MP2 is
+registered as a device on this bus. Here: MP2 which is an ARM core connected to x86 for processing
+sensor data. The layer, which binds each device (AMD SFH HID driver) identifies the device type and
+registers with the hid core. Transport layer attach a constant "struct hid_ll_driver" object with
+each device. Once a device is registered with HID core, the callbacks provided via this struct are
+used by HID core to communicate with the device. AMD HID Transport layer implements the synchronous calls.
+
+AMD HID Client Layer
+--------------------
+This layer is responsible to implement HID request and descriptors. As firmware is OS agnostic, HID
+client layer fills the HID request structure and descriptors. HID client layer is complex as it is
+interface between MP2 PCIe layer and HID. HID client layer initialized the MP2 PCIe layer and holds
+the instance of MP2 layer. It identifies the number of sensors connected using MP2-PCIe layer. Base
+on that allocates the DRAM address for each and every sensor and pass it to MP2-PCIe driver.On
+enumeration of each the sensor, client layer fills the HID Descriptor structure and HID input repor
+structure. HID Feature report structure is optional. The report descriptor structure varies from
+sensor to sensor.
+
+AMD MP2 PCIe layer
+------------------
+MP2 PCIe Layer is responsible for making all transactions with the firmware over PCIe.
+The connection establishment between firmware and PCIe happens here.
+
+The communication between X86 and MP2 is split into three parts.
+1. Command transfer via the C2P mailbox registers.
+2. Data transfer via DRAM.
+3. Supported sensor info via P2C registers.
+
+Commands are sent to MP2 using C2P Mailbox registers. Writing into C2P Message registers generate
+interrupt to MP2. The client layer allocates the physical memory and the same is sent to MP2 via
+the PCI layer. MP2 firmware writes the command output to the access DRAM memory which the client
+layer has allocated. Firmware always writes minimum of 32 bytes into DRAM. So as a protocol driver
+shall allocate minimum of 32 bytes DRAM space.
+
+Enumeration and Probing flow
+----------------------------
+::
+
+ HID AMD AMD AMD -PCIe MP2
+ Core Transport Client layer layer FW
+ | | | | |
+ | | | on Boot Driver Loaded |
+ | | | | |
+ | | | MP2-PCIe Int |
+ | | | | |
+ | | |---Get Number of sensors-> | |
+ | | | Read P2C |
+ | | | Register |
+ | | | | |
+ | | | Loop(for No of Sensors) | |
+ | | |----------------------| | |
+ | | | Create HID Descriptor| | |
+ | | | Create Input report | | |
+ | | | Descriptor Map | | |
+ | | | the MP2 FW Index to | | |
+ | | | HID Index | | |
+ | | | Allocate the DRAM | Enable |
+ | | | address | Sensors |
+ | | |----------------------| | |
+ | | HID transport| | Enable |
+ | |<--Probe------| |---Sensor CMD--> |
+ | | Create the | | |
+ | | HID device | | |
+ | | (MFD) | | |
+ | | by Populating| | |
+ | | the HID | | |
+ | | ll_driver | | |
+ | HID | | | |
+ | add | | | |
+ |Device | | | |
+ |<------------- | | | |
+
+
+Data Flow from Application to the AMD SFH Driver
+------------------------------------------------
+
+::
+
+ | | | | |
+ | | | | |
+ | | | | |
+ | | | | |
+ | | | | |
+ |HID_req | | | |
+ |get_report | | | |
+ |------------->| | | |
+ | | HID_get_input| | |
+ | | report | | |
+ | |------------->|------------------------| | |
+ | | | Read the DRAM data for| | |
+ | | | requested sensor and | | |
+ | | | create the HID input | | |
+ | | | report | | |
+ | | |------------------------| | |
+ | |Data received | | |
+ | | in HID report| | |
+ To |<-------------|<-------------| | |
+ Applications| | | | |
+ <-------| | | | |
diff --git a/Documentation/hid/index.rst b/Documentation/hid/index.rst
index 737d66dc16a1..e50f513c579c 100644
--- a/Documentation/hid/index.rst
+++ b/Documentation/hid/index.rst
@@ -16,3 +16,4 @@ Human Interface Devices (HID)
hid-alps
intel-ish-hid
+ amd-sfh-hid
diff --git a/MAINTAINERS b/MAINTAINERS
index dd1887c3c5bf..9d12f61d0519 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -950,6 +950,14 @@ S: Supported
F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
F: drivers/net/ethernet/amd/xgbe/
+AMD SENSOR FUSION HUB DRIVER
+M: Nehal Shah <nehal-bakulchandra.shah@amd.com>
+M: Sandeep Singh <sandeep.singh@amd.com>
+L: linux-input@vger.kernel.org
+S: Maintained
+F: Documentation/hid/amd-sfh*
+F: drivers/hid/amd-sfh-hid/
+
AMS AS73211 DRIVER
M: Christian Eggers <ceggers@arri.de>
L: linux-iio@vger.kernel.org
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 612629678c84..fff3963ba02b 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -1183,4 +1183,6 @@ source "drivers/hid/i2c-hid/Kconfig"
source "drivers/hid/intel-ish-hid/Kconfig"
+source "drivers/hid/amd-sfh-hid/Kconfig"
+
endmenu
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 4acb583c92a6..014d21fe7dac 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -142,3 +142,5 @@ obj-$(CONFIG_I2C_HID) += i2c-hid/
obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/
obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
+
+obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/
diff --git a/drivers/hid/amd-sfh-hid/Kconfig b/drivers/hid/amd-sfh-hid/Kconfig
new file mode 100644
index 000000000000..db069a83e9a2
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+menu "AMD SFH HID Support"
+ depends on X86_64 || COMPILE_TEST
+ depends on PCI
+ depends on HID
+
+config AMD_SFH_HID
+ tristate "AMD Sensor Fusion Hub"
+ help
+ If you say yes to this option, support will be included for the
+ AMD Sensor Fusion Hub.
+ This driver will enable sensors functionality on AMD platforms
+ starting from 17h family of RYZEN parts.
+
+ This driver can also be built as a module. If so, the module will
+ be called amd-sfh.
+ Say Y or M here if you want to support AMD SFH. If unsure, say N.
+endmenu
diff --git a/drivers/hid/amd-sfh-hid/Makefile b/drivers/hid/amd-sfh-hid/Makefile
new file mode 100644
index 000000000000..35e704da5612
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Makefile - AMD SFH HID drivers
+# Copyright (c) 2019-2020, Advanced Micro Devices, Inc.
+#
+#
+obj-$(CONFIG_AMD_SFH_HID) += amd_sfh.o
+amd_sfh-objs := amd_sfh_hid.o
+amd_sfh-objs += amd_sfh_client.o
+amd_sfh-objs += amd_sfh_pcie.o
+amd_sfh-objs += hid_descriptor/amd_sfh_hid_desc.o
+
+ccflags-y += -I $(srctree)/$(src)/
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
new file mode 100644
index 000000000000..3d1ccac5d99a
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD SFH Client Layer
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ * Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com>
+ * Sandeep Singh <Sandeep.singh@amd.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/hid.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+
+#include "hid_descriptor/amd_sfh_hid_desc.h"
+#include "amd_sfh_pcie.h"
+#include "amd_sfh_hid.h"
+
+#define AMD_SFH_IDLE_LOOP 200
+
+struct request_list {
+ struct hid_device *hid;
+ struct list_head list;
+ u8 report_id;
+ u8 sensor_idx;
+ u8 report_type;
+ u8 current_index;
+};
+
+static struct request_list req_list;
+
+void amd_sfh_set_report(struct hid_device *hid, int report_id,
+ int report_type)
+{
+ struct amdtp_hid_data *hid_data = hid->driver_data;
+ struct amdtp_cl_data *cli_data = hid_data->cli_data;
+ int i;
+
+ for (i = 0; i < cli_data->num_hid_devices; i++) {
+ if (cli_data->hid_sensor_hubs[i] == hid) {
+ cli_data->cur_hid_dev = i;
+ break;
+ }
+ }
+ amdtp_hid_wakeup(hid);
+}
+
+int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type)
+{
+ struct amdtp_hid_data *hid_data = hid->driver_data;
+ struct amdtp_cl_data *cli_data = hid_data->cli_data;
+ int i;
+
+ for (i = 0; i < cli_data->num_hid_devices; i++) {
+ if (cli_data->hid_sensor_hubs[i] == hid) {
+ struct request_list *new = kzalloc(sizeof(*new), GFP_KERNEL);
+
+ if (!new)
+ return -ENOMEM;
+
+ new->current_index = i;
+ new->sensor_idx = cli_data->sensor_idx[i];
+ new->hid = hid;
+ new->report_type = report_type;
+ new->report_id = report_id;
+ cli_data->report_id[i] = report_id;
+ cli_data->request_done[i] = false;
+ list_add(&new->list, &req_list.list);
+ break;
+ }
+ }
+ schedule_delayed_work(&cli_data->work, 0);
+ return 0;
+}
+
+static void amd_sfh_work(struct work_struct *work)
+{
+ struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work);
+ struct request_list *req_node;
+ u8 current_index, sensor_index;
+ u8 report_id, node_type;
+ u8 report_size = 0;
+
+ req_node = list_last_entry(&req_list.list, struct request_list, list);
+ list_del(&req_node->list);
+ current_index = req_node->current_index;
+ sensor_index = req_node->sensor_idx;
+ report_id = req_node->report_id;
+ node_type = req_node->report_type;
+
+ if (node_type == HID_FEATURE_REPORT) {
+ report_size = get_feature_report(sensor_index, report_id,
+ cli_data->feature_report[current_index]);
+ if (report_size)
+ hid_input_report(cli_data->hid_sensor_hubs[current_index],
+ cli_data->report_type[current_index],
+ cli_data->feature_report[current_index], report_size, 0);
+ else
+ pr_err("AMDSFH: Invalid report size\n");
+
+ } else if (node_type == HID_INPUT_REPORT) {
+ report_size = get_input_report(sensor_index, report_id,
+ cli_data->input_report[current_index],
+ cli_data->sensor_virt_addr[current_index]);
+ if (report_size)
+ hid_input_report(cli_data->hid_sensor_hubs[current_index],
+ cli_data->report_type[current_index],
+ cli_data->input_report[current_index], report_size, 0);
+ else
+ pr_err("AMDSFH: Invalid report size\n");
+ }
+ cli_data->cur_hid_dev = current_index;
+ cli_data->sensor_requested_cnt[current_index] = 0;
+ amdtp_hid_wakeup(cli_data->hid_sensor_hubs[current_index]);
+}
+
+static void amd_sfh_work_buffer(struct work_struct *work)
+{
+ struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work);
+ u8 report_size;
+ int i;
+
+ for (i = 0; i < cli_data->num_hid_devices; i++) {
+ report_size = get_input_report(cli_data->sensor_idx[i], cli_data->report_id[i],
+ cli_data->input_report[i],
+ cli_data->sensor_virt_addr[i]);
+ hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
+ cli_data->input_report[i], report_size, 0);
+ }
+ schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
+}
+
+int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
+{
+ struct amdtp_cl_data *cl_data = privdata->cl_data;
+ struct amd_mp2_sensor_info info;
+ struct device *dev;
+ u32 feature_report_size;
+ u32 input_report_size;
+ u8 cl_idx;
+ int rc, i;
+
+ dev = &privdata->pdev->dev;
+ cl_data = kzalloc(sizeof(*cl_data), GFP_KERNEL);
+ if (!cl_data)
+ return -ENOMEM;
+
+ cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
+
+ INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
+ INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
+ INIT_LIST_HEAD(&req_list.list);
+
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ cl_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
+ &cl_data->sensor_phys_addr[i],
+ GFP_KERNEL);
+ cl_data->sensor_sts[i] = 0;
+ cl_data->sensor_requested_cnt[i] = 0;
+ cl_data->cur_hid_dev = i;
+ cl_idx = cl_data->sensor_idx[i];
+ cl_data->report_descr_sz[i] = get_descr_sz(cl_idx, descr_size);
+ if (!cl_data->report_descr_sz[i]) {
+ rc = -EINVAL;
+ goto cleanup;
+ }
+ feature_report_size = get_descr_sz(cl_idx, feature_size);
+ if (!feature_report_size) {
+ rc = -EINVAL;
+ goto cleanup;
+ }
+ input_report_size = get_descr_sz(cl_idx, input_size);
+ if (!input_report_size) {
+ rc = -EINVAL;
+ goto cleanup;
+ }
+ cl_data->feature_report[i] = kzalloc(feature_report_size, GFP_KERNEL);
+ if (!cl_data->feature_report[i]) {
+ rc = -ENOMEM;
+ goto cleanup;
+ }
+ cl_data->input_report[i] = kzalloc(input_report_size, GFP_KERNEL);
+ if (!cl_data->input_report[i]) {
+ rc = -ENOMEM;
+ goto cleanup;
+ }
+ info.period = msecs_to_jiffies(AMD_SFH_IDLE_LOOP);
+ info.sensor_idx = cl_idx;
+ info.phys_address = cl_data->sensor_phys_addr[i];
+
+ cl_data->report_descr[i] = kzalloc(cl_data->report_descr_sz[i], GFP_KERNEL);
+ if (!cl_data->report_descr[i]) {
+ rc = -ENOMEM;
+ goto cleanup;
+ }
+ rc = get_report_descriptor(cl_idx, cl_data->report_descr[i]);
+ if (rc)
+ return rc;
+ rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
+ if (rc)
+ return rc;
+ amd_start_sensor(privdata, info);
+ cl_data->sensor_sts[i] = 1;
+ }
+ privdata->cl_data = cl_data;
+ schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
+ return 0;
+
+cleanup:
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ if (cl_data->sensor_virt_addr[i]) {
+ dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
+ cl_data->sensor_virt_addr[i],
+ cl_data->sensor_phys_addr[i]);
+ }
+ kfree(cl_data->feature_report[i]);
+ kfree(cl_data->input_report[i]);
+ kfree(cl_data->report_descr[i]);
+ }
+ kfree(cl_data);
+ return rc;
+}
+
+int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
+{
+ struct amdtp_cl_data *cl_data = privdata->cl_data;
+ int i;
+
+ for (i = 0; i < cl_data->num_hid_devices; i++)
+ amd_stop_sensor(privdata, i);
+
+ cancel_delayed_work_sync(&cl_data->work);
+ cancel_delayed_work_sync(&cl_data->work_buffer);
+ amdtp_hid_remove(cl_data);
+
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ if (cl_data->sensor_virt_addr[i]) {
+ dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
+ cl_data->sensor_virt_addr[i],
+ cl_data->sensor_phys_addr[i]);
+ }
+ }
+ kfree(cl_data);
+ return 0;
+}
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
new file mode 100644
index 000000000000..4f989483aa03
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD MP2 Sensors transport driver
+ *
+ * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
+ * Sandeep Singh <sandeep.singh@amd.com>
+ */
+#include <linux/hid.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+#include "amd_sfh_hid.h"
+
+#define AMD_SFH_RESPONSE_TIMEOUT 1500
+
+/**
+ * amdtp_hid_parse() - hid-core .parse() callback
+ * @hid: hid device instance
+ *
+ * This function gets called during call to hid_add_device
+ *
+ * Return: 0 on success and non zero on error
+ */
+static int amdtp_hid_parse(struct hid_device *hid)
+{
+ struct amdtp_hid_data *hid_data = hid->driver_data;
+ struct amdtp_cl_data *cli_data = hid_data->cli_data;
+
+ return hid_parse_report(hid, cli_data->report_descr[hid_data->index],
+ cli_data->report_descr_sz[hid_data->index]);
+}
+
+/* Empty callbacks with success return code */
+static int amdtp_hid_start(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void amdtp_hid_stop(struct hid_device *hid)
+{
+}
+
+static int amdtp_hid_open(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void amdtp_hid_close(struct hid_device *hid)
+{
+}
+
+static int amdtp_raw_request(struct hid_device *hdev, u8 reportnum,
+ u8 *buf, size_t len, u8 rtype, int reqtype)
+{
+ return 0;
+}
+
+static void amdtp_hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype)
+{
+ int rc;
+
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ rc = amd_sfh_get_report(hid, rep->id, rep->type);
+ if (rc)
+ dev_err(&hid->dev, "AMDSFH get report error\n");
+ break;
+ case HID_REQ_SET_REPORT:
+ amd_sfh_set_report(hid, rep->id, reqtype);
+ break;
+ default:
+ break;
+ }
+}
+
+static int amdtp_wait_for_response(struct hid_device *hid)
+{
+ struct amdtp_hid_data *hid_data = hid->driver_data;
+ struct amdtp_cl_data *cli_data = hid_data->cli_data;
+ int i, ret = 0;
+
+ for (i = 0; i < cli_data->num_hid_devices; i++) {
+ if (cli_data->hid_sensor_hubs[i] == hid)
+ break;
+ }
+
+ if (!cli_data->request_done[i])
+ ret = wait_event_interruptible_timeout(hid_data->hid_wait,
+ cli_data->request_done[i],
+ msecs_to_jiffies(AMD_SFH_RESPONSE_TIMEOUT));
+ if (ret == -ERESTARTSYS)
+ return -ERESTARTSYS;
+ else if (ret < 0)
+ return -ETIMEDOUT;
+ else
+ return 0;
+}
+
+void amdtp_hid_wakeup(struct hid_device *hid)
+{
+ struct amdtp_hid_data *hid_data = hid->driver_data;
+ struct amdtp_cl_data *cli_data = hid_data->cli_data;
+
+ cli_data->request_done[cli_data->cur_hid_dev] = true;
+ wake_up_interruptible(&hid_data->hid_wait);
+}
+
+static struct hid_ll_driver amdtp_hid_ll_driver = {
+ .parse = amdtp_hid_parse,
+ .start = amdtp_hid_start,
+ .stop = amdtp_hid_stop,
+ .open = amdtp_hid_open,
+ .close = amdtp_hid_close,
+ .request = amdtp_hid_request,
+ .wait = amdtp_wait_for_response,
+ .raw_request = amdtp_raw_request,
+};
+
+int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data)
+{
+ struct hid_device *hid;
+ struct amdtp_hid_data *hid_data;
+ int rc;
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid))
+ return PTR_ERR(hid);
+
+ hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL);
+ if (!hid_data) {
+ rc = -ENOMEM;
+ goto err_hid_data;
+ }
+
+ hid->ll_driver = &amdtp_hid_ll_driver;
+ hid_data->index = cur_hid_dev;
+ hid_data->cli_data = cli_data;
+ init_waitqueue_head(&hid_data->hid_wait);
+
+ hid->driver_data = hid_data;
+ cli_data->hid_sensor_hubs[cur_hid_dev] = hid;
+ hid->bus = BUS_AMD_AMDTP;
+ hid->vendor = AMD_SFH_HID_VENDOR;
+ hid->product = AMD_SFH_HID_PRODUCT;
+ snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-amdtp",
+ hid->vendor, hid->product);
+
+ rc = hid_add_device(hid);
+ if (rc)
+ goto err_hid_device;
+ return 0;
+
+err_hid_device:
+ kfree(hid_data);
+err_hid_data:
+ hid_destroy_device(hid);
+ return rc;
+}
+
+void amdtp_hid_remove(struct amdtp_cl_data *cli_data)
+{
+ int i;
+
+ for (i = 0; i < cli_data->num_hid_devices; ++i) {
+ kfree(cli_data->feature_report[i]);
+ kfree(cli_data->input_report[i]);
+ kfree(cli_data->report_descr[i]);
+ if (cli_data->hid_sensor_hubs[i]) {
+ kfree(cli_data->hid_sensor_hubs[i]->driver_data);
+ hid_destroy_device(cli_data->hid_sensor_hubs[i]);
+ cli_data->hid_sensor_hubs[i] = NULL;
+ }
+ }
+}
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
new file mode 100644
index 000000000000..6be0783d885c
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AMD MP2 Sensors transport driver
+ *
+ * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
+ * Sandeep Singh <sandeep.singh@amd.com>
+ */
+
+#ifndef AMDSFH_HID_H
+#define AMDSFH_HID_H
+
+#define MAX_HID_DEVICES 4
+#define BUS_AMD_AMDTP 0x20
+#define AMD_SFH_HID_VENDOR 0x1022
+#define AMD_SFH_HID_PRODUCT 0x0001
+
+struct amdtp_cl_data {
+ u8 init_done;
+ u32 cur_hid_dev;
+ u32 hid_dev_count;
+ u32 num_hid_devices;
+ struct device_info *hid_devices;
+ u8 *report_descr[MAX_HID_DEVICES];
+ int report_descr_sz[MAX_HID_DEVICES];
+ struct hid_device *hid_sensor_hubs[MAX_HID_DEVICES];
+ u8 *hid_descr[MAX_HID_DEVICES];
+ int hid_descr_size[MAX_HID_DEVICES];
+ phys_addr_t phys_addr_base;
+ u32 *sensor_virt_addr[MAX_HID_DEVICES];
+ phys_addr_t sensor_phys_addr[MAX_HID_DEVICES];
+ u32 sensor_sts[MAX_HID_DEVICES];
+ u32 sensor_requested_cnt[MAX_HID_DEVICES];
+ u8 report_type[MAX_HID_DEVICES];
+ u8 report_id[MAX_HID_DEVICES];
+ u8 sensor_idx[MAX_HID_DEVICES];
+ u8 *feature_report[MAX_HID_DEVICES];
+ u8 *input_report[MAX_HID_DEVICES];
+ u8 request_done[MAX_HID_DEVICES];
+ struct delayed_work work;
+ struct delayed_work work_buffer;
+};
+
+/**
+ * struct amdtp_hid_data - Per instance HID data
+ * @index: Device index in the order of enumeration
+ * @request_done: Get Feature/Input report complete flag
+ * used during get/set request from hid core
+ * @cli_data: Link to the client instance
+ * @hid_wait: Completion waitq
+ *
+ * Used to tie hid->driver data to driver client instance
+ */
+struct amdtp_hid_data {
+ int index;
+ struct amdtp_cl_data *cli_data;
+ wait_queue_head_t hid_wait;
+};
+
+/* Interface functions between HID LL driver and AMD SFH client */
+void hid_amdtp_set_feature(struct hid_device *hid, char *buf, u32 len, int report_id);
+void hid_amdtp_get_report(struct hid_device *hid, int report_id, int report_type);
+int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data);
+void amdtp_hid_remove(struct amdtp_cl_data *cli_data);
+int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type);
+void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type);
+void amdtp_hid_wakeup(struct hid_device *hid);
+#endif
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
new file mode 100644
index 000000000000..a51c7b76283b
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD MP2 PCIe communication driver
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ *
+ * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ * Sandeep Singh <Sandeep.singh@amd.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "amd_sfh_pcie.h"
+
+#define DRIVER_NAME "pcie_mp2_amd"
+#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
+
+#define ACEL_EN BIT(0)
+#define GYRO_EN BIT(1)
+#define MAGNO_EN BIT(2)
+#define ALS_EN BIT(19)
+
+void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
+{
+ union sfh_cmd_param cmd_param;
+ union sfh_cmd_base cmd_base;
+
+ /* fill up command register */
+ memset(&cmd_base, 0, sizeof(cmd_base));
+ cmd_base.s.cmd_id = ENABLE_SENSOR;
+ cmd_base.s.period = info.period;
+ cmd_base.s.sensor_id = info.sensor_idx;
+
+ /* fill up command param register */
+ memset(&cmd_param, 0, sizeof(cmd_param));
+ cmd_param.s.buf_layout = 1;
+ cmd_param.s.buf_length = 16;
+
+ writeq(info.phys_address, privdata->mmio + AMD_C2P_MSG2);
+ writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
+ writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
+}
+
+void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
+{
+ union sfh_cmd_base cmd_base;
+
+ /* fill up command register */
+ memset(&cmd_base, 0, sizeof(cmd_base));
+ cmd_base.s.cmd_id = DISABLE_SENSOR;
+ cmd_base.s.period = 0;
+ cmd_base.s.sensor_id = sensor_idx;
+
+ writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
+ writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
+}
+
+void amd_stop_all_sensors(struct amd_mp2_dev *privdata)
+{
+ union sfh_cmd_base cmd_base;
+
+ /* fill up command register */
+ memset(&cmd_base, 0, sizeof(cmd_base));
+ cmd_base.s.cmd_id = STOP_ALL_SENSORS;
+ cmd_base.s.period = 0;
+ cmd_base.s.sensor_id = 0;
+
+ writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
+}
+
+int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
+{
+ int activestatus, num_of_sensors = 0;
+
+ privdata->activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3);
+ activestatus = privdata->activecontrolstatus >> 4;
+ if (ACEL_EN & activestatus)
+ sensor_id[num_of_sensors++] = accel_idx;
+
+ if (GYRO_EN & activestatus)
+ sensor_id[num_of_sensors++] = gyro_idx;
+
+ if (MAGNO_EN & activestatus)
+ sensor_id[num_of_sensors++] = mag_idx;
+
+ if (ALS_EN & activestatus)
+ sensor_id[num_of_sensors++] = als_idx;
+
+ return num_of_sensors;
+}
+
+static void amd_mp2_pci_remove(void *privdata)
+{
+ amd_sfh_hid_client_deinit(privdata);
+ amd_stop_all_sensors(privdata);
+}
+
+static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct amd_mp2_dev *privdata;
+ int rc;
+
+ privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL);
+ if (!privdata)
+ return -ENOMEM;
+
+ privdata->pdev = pdev;
+ pci_set_drvdata(pdev, privdata);
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME);
+ if (rc)
+ return rc;
+
+ privdata->mmio = pcim_iomap_table(pdev)[2];
+ pci_set_master(pdev);
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (rc) {
+ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ return rc;
+ }
+ rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
+ if (rc)
+ return rc;
+
+ return amd_sfh_hid_client_init(privdata);
+}
+
+static const struct pci_device_id amd_mp2_pci_tbl[] = {
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
+
+static struct pci_driver amd_mp2_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = amd_mp2_pci_tbl,
+ .probe = amd_mp2_pci_probe,
+};
+module_pci_driver(amd_mp2_pci_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
+MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>");
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
new file mode 100644
index 000000000000..e8be94f935b7
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AMD MP2 PCIe communication driver
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ * Sandeep Singh <Sandeep.singh@amd.com>
+ */
+
+#ifndef PCIE_MP2_AMD_H
+#define PCIE_MP2_AMD_H
+
+#include <linux/pci.h>
+
+#define PCI_DEVICE_ID_AMD_MP2 0x15E4
+
+#define ENABLE_SENSOR 1
+#define DISABLE_SENSOR 2
+#define STOP_ALL_SENSORS 8
+
+/* MP2 C2P Message Registers */
+#define AMD_C2P_MSG0 0x10500
+#define AMD_C2P_MSG1 0x10504
+#define AMD_C2P_MSG2 0x10508
+
+/* MP2 P2C Message Registers */
+#define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */
+
+/* SFH Command register */
+union sfh_cmd_base {
+ u32 ul;
+ struct {
+ u32 cmd_id : 8;
+ u32 sensor_id : 8;
+ u32 period : 16;
+ } s;
+};
+
+union sfh_cmd_param {
+ u32 ul;
+ struct {
+ u32 buf_layout : 2;
+ u32 buf_length : 6;
+ u32 rsvd : 24;
+ } s;
+};
+
+struct sfh_cmd_reg {
+ union sfh_cmd_base cmd_base;
+ union sfh_cmd_param cmd_param;
+ phys_addr_t phys_addr;
+};
+
+enum sensor_idx {
+ accel_idx = 0,
+ gyro_idx = 1,
+ mag_idx = 2,
+ als_idx = 19
+};
+
+struct amd_mp2_dev {
+ struct pci_dev *pdev;
+ struct amdtp_cl_data *cl_data;
+ void __iomem *mmio;
+ u32 activecontrolstatus;
+};
+
+struct amd_mp2_sensor_info {
+ u8 sensor_idx;
+ u32 period;
+ phys_addr_t phys_address;
+};
+
+void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
+void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx);
+void amd_stop_all_sensors(struct amd_mp2_dev *privdata);
+int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id);
+int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata);
+int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata);
+#endif
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
new file mode 100644
index 000000000000..6e3ad66e57a4
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD SFH Report Descriptor generator
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ * Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com>
+ * Sandeep Singh <sandeep.singh@amd.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "amd_sfh_pcie.h"
+#include "amd_sfh_hid_desc.h"
+#include "amd_sfh_hid_report_desc.h"
+
+#define AMD_SFH_FW_MULTIPLIER (1000)
+#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41
+#define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x51
+#define HID_DEFAULT_REPORT_INTERVAL 0x50
+#define HID_DEFAULT_MIN_VALUE 0X7F
+#define HID_DEFAULT_MAX_VALUE 0x80
+#define HID_DEFAULT_SENSITIVITY 0x7F
+#define HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM 0x01
+/* state enums */
+#define HID_USAGE_SENSOR_STATE_READY_ENUM 0x02
+#define HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM 0x05
+#define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM 0x04
+
+int get_report_descriptor(int sensor_idx, u8 *rep_desc)
+{
+ switch (sensor_idx) {
+ case accel_idx: /* accel */
+ memset(rep_desc, 0, sizeof(accel3_report_descriptor));
+ memcpy(rep_desc, accel3_report_descriptor,
+ sizeof(accel3_report_descriptor));
+ break;
+ case gyro_idx: /* gyro */
+ memset(rep_desc, 0, sizeof(gyro3_report_descriptor));
+ memcpy(rep_desc, gyro3_report_descriptor,
+ sizeof(gyro3_report_descriptor));
+ break;
+ case mag_idx: /* Magnetometer */
+ memset(rep_desc, 0, sizeof(comp3_report_descriptor));
+ memcpy(rep_desc, comp3_report_descriptor,
+ sizeof(comp3_report_descriptor));
+ break;
+ case als_idx: /* ambient light sensor */
+ memset(rep_desc, 0, sizeof(als_report_descriptor));
+ memcpy(rep_desc, als_report_descriptor,
+ sizeof(als_report_descriptor));
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+u32 get_descr_sz(int sensor_idx, int descriptor_name)
+{
+ switch (sensor_idx) {
+ case accel_idx:
+ switch (descriptor_name) {
+ case descr_size:
+ return sizeof(accel3_report_descriptor);
+ case input_size:
+ return sizeof(struct accel3_input_report);
+ case feature_size:
+ return sizeof(struct accel3_feature_report);
+ }
+ break;
+ case gyro_idx:
+ switch (descriptor_name) {
+ case descr_size:
+ return sizeof(gyro3_report_descriptor);
+ case input_size:
+ return sizeof(struct gyro_input_report);
+ case feature_size:
+ return sizeof(struct gyro_feature_report);
+ }
+ break;
+ case mag_idx:
+ switch (descriptor_name) {
+ case descr_size:
+ return sizeof(comp3_report_descriptor);
+ case input_size:
+ return sizeof(struct magno_input_report);
+ case feature_size:
+ return sizeof(struct magno_feature_report);
+ }
+ break;
+ case als_idx:
+ switch (descriptor_name) {
+ case descr_size:
+ return sizeof(als_report_descriptor);
+ case input_size:
+ return sizeof(struct als_input_report);
+ case feature_size:
+ return sizeof(struct als_feature_report);
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void get_common_features(struct common_feature_property *common, int report_id)
+{
+ common->report_id = report_id;
+ common->connection_type = HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM;
+ common->report_state = HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
+ common->power_state = HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
+ common->sensor_state = HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM;
+ common->report_interval = HID_DEFAULT_REPORT_INTERVAL;
+}
+
+u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
+{
+ struct accel3_feature_report acc_feature;
+ struct gyro_feature_report gyro_feature;
+ struct magno_feature_report magno_feature;
+ struct als_feature_report als_feature;
+ u8 report_size = 0;
+
+ if (!feature_report)
+ return report_size;
+
+ switch (sensor_idx) {
+ case accel_idx: /* accel */
+ get_common_features(&acc_feature.common_property, report_id);
+ acc_feature.accel_change_sesnitivity = HID_DEFAULT_SENSITIVITY;
+ acc_feature.accel_sensitivity_min = HID_DEFAULT_MIN_VALUE;
+ acc_feature.accel_sensitivity_max = HID_DEFAULT_MAX_VALUE;
+ memcpy(feature_report, &acc_feature, sizeof(acc_feature));
+ report_size = sizeof(acc_feature);
+ break;
+ case gyro_idx: /* gyro */
+ get_common_features(&gyro_feature.common_property, report_id);
+ gyro_feature.gyro_change_sesnitivity = HID_DEFAULT_SENSITIVITY;
+ gyro_feature.gyro_sensitivity_min = HID_DEFAULT_MIN_VALUE;
+ gyro_feature.gyro_sensitivity_max = HID_DEFAULT_MAX_VALUE;
+ memcpy(feature_report, &gyro_feature, sizeof(gyro_feature));
+ report_size = sizeof(gyro_feature);
+ break;
+ case mag_idx: /* Magnetometer */
+ get_common_features(&magno_feature.common_property, report_id);
+ magno_feature.magno_headingchange_sensitivity = HID_DEFAULT_SENSITIVITY;
+ magno_feature.heading_min = HID_DEFAULT_MIN_VALUE;
+ magno_feature.heading_max = HID_DEFAULT_MAX_VALUE;
+ magno_feature.flux_change_sensitivity = HID_DEFAULT_MIN_VALUE;
+ magno_feature.flux_min = HID_DEFAULT_MIN_VALUE;
+ magno_feature.flux_max = HID_DEFAULT_MAX_VALUE;
+ memcpy(feature_report, &magno_feature, sizeof(magno_feature));
+ report_size = sizeof(magno_feature);
+ break;
+ case als_idx: /* ambient light sensor */
+ get_common_features(&als_feature.common_property, report_id);
+ als_feature.als_change_sesnitivity = HID_DEFAULT_SENSITIVITY;
+ als_feature.als_sensitivity_min = HID_DEFAULT_MIN_VALUE;
+ als_feature.als_sensitivity_max = HID_DEFAULT_MAX_VALUE;
+ memcpy(feature_report, &als_feature, sizeof(als_feature));
+ report_size = sizeof(als_feature);
+ break;
+ default:
+ break;
+ }
+ return report_size;
+}
+
+static void get_common_inputs(struct common_input_property *common, int report_id)
+{
+ common->report_id = report_id;
+ common->sensor_state = HID_USAGE_SENSOR_STATE_READY_ENUM;
+ common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM;
+}
+
+u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr)
+{
+ struct accel3_input_report acc_input;
+ struct gyro_input_report gyro_input;
+ struct magno_input_report magno_input;
+ struct als_input_report als_input;
+ u8 report_size = 0;
+
+ if (!sensor_virt_addr || !input_report)
+ return report_size;
+
+ switch (sensor_idx) {
+ case accel_idx: /* accel */
+ get_common_inputs(&acc_input.common_property, report_id);
+ acc_input.in_accel_x_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
+ acc_input.in_accel_y_value = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER;
+ acc_input.in_accel_z_value = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER;
+ memcpy(input_report, &acc_input, sizeof(acc_input));
+ report_size = sizeof(acc_input);
+ break;
+ case gyro_idx: /* gyro */
+ get_common_inputs(&gyro_input.common_property, report_id);
+ gyro_input.in_angel_x_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
+ gyro_input.in_angel_y_value = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER;
+ gyro_input.in_angel_z_value = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER;
+ memcpy(input_report, &gyro_input, sizeof(gyro_input));
+ report_size = sizeof(gyro_input);
+ break;
+ case mag_idx: /* Magnetometer */
+ get_common_inputs(&magno_input.common_property, report_id);
+ magno_input.in_magno_x = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
+ magno_input.in_magno_y = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER;
+ magno_input.in_magno_z = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER;
+ magno_input.in_magno_accuracy = (u16)sensor_virt_addr[3] / AMD_SFH_FW_MULTIPLIER;
+ memcpy(input_report, &magno_input, sizeof(magno_input));
+ report_size = sizeof(magno_input);
+ break;
+ case als_idx: /* Als */
+ get_common_inputs(&als_input.common_property, report_id);
+ als_input.illuminance_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
+ report_size = sizeof(als_input);
+ memcpy(input_report, &als_input, sizeof(als_input));
+ break;
+ default:
+ break;
+ }
+ return report_size;
+}
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
new file mode 100644
index 000000000000..095c471d8fd6
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * HID report descriptors, structures and routines
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
+ * Sandeep Singh <Sandeep.singh@amd.com>
+ */
+
+#ifndef AMD_SFH_HID_DESCRIPTOR_H
+#define AMD_SFH_HID_DESCRIPTOR_H
+
+enum desc_type {
+ /* Report descriptor name */
+ descr_size = 1,
+ input_size,
+ feature_size,
+};
+
+struct common_feature_property {
+ /* common properties */
+ u8 report_id;
+ u8 connection_type;
+ u8 report_state;
+ u8 power_state;
+ u8 sensor_state;
+ u32 report_interval;
+} __packed;
+
+struct common_input_property {
+ /* common properties */
+ u8 report_id;
+ u8 sensor_state;
+ u8 event_type;
+} __packed;
+
+struct accel3_feature_report {
+ struct common_feature_property common_property;
+ /* properties specific to this sensor */
+ u16 accel_change_sesnitivity;
+ s16 accel_sensitivity_max;
+ s16 accel_sensitivity_min;
+} __packed;
+
+struct accel3_input_report {
+ struct common_input_property common_property;
+ /* values specific to this sensor */
+ int in_accel_x_value;
+ int in_accel_y_value;
+ int in_accel_z_value;
+ /* include if required to support the "shake" event */
+ u8 in_accel_shake_detection;
+} __packed;
+
+struct gyro_feature_report {
+ struct common_feature_property common_property;
+ /* properties specific to this sensor */
+ u16 gyro_change_sesnitivity;
+ s16 gyro_sensitivity_max;
+ s16 gyro_sensitivity_min;
+} __packed;
+
+struct gyro_input_report {
+ struct common_input_property common_property;
+ /* values specific to this sensor */
+ int in_angel_x_value;
+ int in_angel_y_value;
+ int in_angel_z_value;
+} __packed;
+
+struct magno_feature_report {
+ struct common_feature_property common_property;
+ /*properties specific to this sensor */
+ u16 magno_headingchange_sensitivity;
+ s16 heading_min;
+ s16 heading_max;
+ u16 flux_change_sensitivity;
+ s16 flux_min;
+ s16 flux_max;
+} __packed;
+
+struct magno_input_report {
+ struct common_input_property common_property;
+ int in_magno_x;
+ int in_magno_y;
+ int in_magno_z;
+ int in_magno_accuracy;
+} __packed;
+
+struct als_feature_report {
+ struct common_feature_property common_property;
+ /* properties specific to this sensor */
+ u16 als_change_sesnitivity;
+ s16 als_sensitivity_max;
+ s16 als_sensitivity_min;
+} __packed;
+
+struct als_input_report {
+ struct common_input_property common_property;
+ /* values specific to this sensor */
+ int illuminance_value;
+} __packed;
+
+int get_report_descriptor(int sensor_idx, u8 rep_desc[]);
+u32 get_descr_sz(int sensor_idx, int descriptor_name);
+u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report);
+u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr);
+#endif
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
new file mode 100644
index 000000000000..44271d39b322
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
@@ -0,0 +1,645 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * HID descriptor stuructures
+ * Copyright 2020 Advanced Micro Devices, Inc.
+ * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
+ * Sandeep Singh <Sandeep.singh@amd.com>
+ */
+
+#ifndef AMD_SFH_HID_REPORT_DESCRIPTOR_H
+#define AMD_SFH_HID_REPORT_DESCRIPTOR_H
+
+// Accelerometer 3D Sensor
+static const u8 accel3_report_descriptor[] = {
+0x05, 0x20, /* Usage page */
+0x09, 0x73, /* Motion type Accel 3D */
+0xA1, 0x00, /* HID Collection (Physical) */
+
+//feature reports(xmit/receive)
+0x85, 1, /* HID Report ID */
+0x05, 0x20, /* HID usage page sensor */
+0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
+0x15, 0, /* HID logical MIN_8(0) */
+0x25, 2, /* HID logical MAX_8(2) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection (logical) */
+0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel*/
+0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
+0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x40, 0x08, /* Sensor property report state no events sel */
+0x0A, 0x41, 0x08, /* Sensor property report state all events sel */
+0x0A, 0x42, 0x08, /* Sensor property report state threshold events sel */
+0x0A, 0x43, 0x08, /* Sensor property report state no events wake sel */
+0x0A, 0x44, 0x08, /* Sensor property report state all events wake sel */
+0x0A, 0x45, 0x08, /* Sensor property report state threshold events wake sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x19, 0x03, /* HID usage sensor property power state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x50, 0x08, /* Sensor property power state undefined sel */
+0x0A, 0x51, 0x08, /* Sensor property power state D0 full power sel */
+0x0A, 0x52, 0x08, /* Sensor property power state D1 low power sel */
+0x0A, 0x53, 0x08, /* Sensor property power state D2 standby with wake sel */
+0x0A, 0x54, 0x08, /* Sensor property power state D3 sleep with wake sel */
+0x0A, 0x55, 0x08, /* Sensor property power state D4 power off sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x01, 0x02, /* HID usage sensor state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 6, /* HID logical Max_8(6) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
+0x15, 0, /* HID logical Min_8(0) */
+0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
+
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count(1) */
+0x55, 0, /* HID unit exponent(0) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x52, 0x14, /* Sensor data motion accel and mod change sensitivity ABS) */
+
+0x15, 0, /* HID logical Min_8(0) */
+0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
+
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x52, 0x24, /* HID usage sensor data (motion accel and mod max) */
+
+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
+
+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
+
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x52, 0x34, /* HID usage sensor data (motion accel and mod min) */
+
+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
+
+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
+
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+
+//input report (transmit)
+0x05, 0x20, /* HID usage page sensors */
+0x0A, 0x01, 0x02, /* HID usage sensor state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 6, /* HID logical Max_8(6) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0xA1, 0x02, /* HID end collection (logical) */
+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x02, 0x02, /* HID usage sensor event */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0xA1, 0x02, /* HID end collection (logical) */
+0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
+0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
+0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
+0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
+0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
+0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x53, 0x04, /* HID usage sensor data motion Acceleration X axis */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+
+0x27, 0xFF, 0xff, 0XFF, 0XFF, /* HID logical Max_32 */
+
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0x0A, 0x54, 0x04, /* HID usage sensor data motion Acceleration Y axis */
+0x17, 0X00, 0X00, 0x01, 0x80, /* HID logical Min_32 */
+
+0x27, 0xFF, 0xFF, 0XFF, 0XFF, /* HID logical Max_32 */
+
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0x0A, 0x55, 0x04, /* HID usage sensor data motion Acceleration Z axis */
+0x17, 0X00, 0X00, 0x01, 0x80, /* HID logical Min_32 */
+
+0x27, 0XFF, 0XFF, 0xFF, 0x7F, /* HID logical Max_32 */
+
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+
+0x0A, 0x51, 0x04, /* HID usage sensor data motion state */
+0x15, 0, /* HID logical Min_8(0) False = Still*/
+0x25, 1, /* HID logical Min_8(1) True = In motion */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0xC0 /* HID end collection */
+};
+
+const u8 gyro3_report_descriptor[] = {
+0x05, 0x20, /* Usage page */
+0x09, 0x76, /* Motion type Gyro3D */
+0xA1, 0x00, /* HID Collection (Physical) */
+
+0x85, 2, /* HID Report ID */
+0x05, 0x20, /* HID usage page sensor */
+0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
+0x15, 0, /* HID logical MIN_8(0) */
+0x25, 2, /* HID logical MAX_8(2) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection (logical) */
+0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */
+0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
+0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */
+0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */
+0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */
+0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */
+0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */
+0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x19, 0x03, /* HID usage sensor property power state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x50, 0x08, /* Sensor power state undefined sel */
+0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */
+0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */
+0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */
+0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */
+0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x01, 0x02, /* HID usage sensor state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 6, /* HID logical Max_8(6) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
+0x15, 0, /* HID logical Min_8(0) */
+0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
+
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count(1) */
+0x55, 0, /* HID unit exponent(0) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x56, 0x14, /* Angular velocity and mod change sensitivity ABS)*/
+
+0x15, 0, /* HID logical Min_8(0) */
+0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
+
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x56, 0x24, /* Sensor data (motion angular velocity and mod max) */
+
+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
+
+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
+
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x56, 0x34, /* HID usage sensor data (motion accel and mod min) */
+
+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
+
+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
+
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+
+//Input reports(transmit)
+0x05, 0x20, /* HID usage page sensors */
+0x0A, 0x01, 0x02, /* HID usage sensor state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 6, /* HID logical Max_8(6) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0xA1, 0x02, /* HID end collection (logical) */
+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x02, 0x02, /* HID usage sensor event */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0xA1, 0x02, /* HID end collection (logical) */
+0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
+0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
+0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
+0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
+0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
+0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x57, 0x04, /* Sensor data motion Angular velocity X axis */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0x0A, 0x58, 0x04, /* Sensor data motion Angular velocity Y axis */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0x0A, 0x59, 0x04, /* Sensor data motion Angular velocity Z axis */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+
+0xC0, /* HID end collection */
+};
+
+const u8 comp3_report_descriptor[] = {
+0x05, 0x20, /* Usage page */
+0x09, 0x83, /* Motion type Orientation compass 3D */
+0xA1, 0x00, /* HID Collection (Physical) */
+
+0x85, 3, /* HID Report ID */
+0x05, 0x20, /* HID usage page sensor */
+0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
+0x15, 0, /* HID logical MIN_8(0) */
+0x25, 2, /* HID logical MAX_8(2) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection (logical) */
+0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */
+0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
+0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */
+0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */
+0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */
+0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */
+0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */
+0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x19, 0x03, /* HID usage sensor property power state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x50, 0x08, /* Sensor power state undefined sel */
+0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */
+0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */
+0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */
+0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */
+0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x01, 0x02, /* HID usage sensor state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 6, /* HID logical Max_8(6) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
+0x15, 0, /* HID logical Min_8(0) */
+0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count(1) */
+0x55, 0, /* HID unit exponent(0) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x71, 0x14, /* Orientation and mod change sensitivity ABS)*/
+0x15, 0, /* HID logical Min_8(0) */
+0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x71, 0x24, /* Sensor data (motion orientation and mod max) */
+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0F, /* HID unit exponent(0x0F) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x71, 0x34, /* Sensor data (motion orientation and mod min) */
+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0F, /* HID unit exponent(0x0F) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x84, 0x14, /* Maganetic flux and change sensitivity ABS) */
+0x15, 0, /* HID logical Min_8(0) */
+0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x84, 0x24, /* Maganetic flux and mod change sensitivity Max) */
+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0F, /* HID unit exponent(0x0F) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0x84, 0x34, /* Maganetic flux and mod change sensitivity Min */
+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0F, /* HID unit exponent(0x0F) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+
+//Input reports(transmit)
+0x05, 0x20, /* HID usage page sensors */
+0x0A, 0x01, 0x02, /* HID usage sensor state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 6, /* HID logical Max_8(6) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0xA1, 0x02, /* HID end collection (logical) */
+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x02, 0x02, /* HID usage sensor event */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0xA1, 0x02, /* HID end collection (logical) */
+0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
+0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
+0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
+0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
+0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
+0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x85, 0x04, /* Sensor data orientation magnetic flux X axis */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0x55, 0x0D, /* HID unit exponent(0x0D) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0x0A, 0x86, 0x04, /* Sensor data orientation magnetic flux Y axis */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0x55, 0x0D, /* HID unit exponent(0x0D) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0x0A, 0x87, 0x04, /* Sensor data orientation magnetic flux Z axis */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0x55, 0x0D, /* HID unit exponent(0x0D) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0x0A, 0x88, 0x04, /* Sensor data orientation magnetometer accuracy */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0xC0 /* HID end collection */
+};
+
+const u8 als_report_descriptor[] = {
+0x05, 0x20, /* HID usage page sensor */
+0x09, 0x41, /* HID usage sensor type Ambientlight */
+0xA1, 0x00, /* HID Collection (Physical) */
+
+//feature reports(xmit/receive)//
+0x85, 4, /* HID Report ID */
+0x05, 0x20, /* HID usage page sensor */
+0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
+0x15, 0, /* HID logical MIN_8(0) */
+0x25, 2, /* HID logical MAX_8(2) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection (logical) */
+0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */
+0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
+0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */
+0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */
+0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */
+0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */
+0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */
+0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x19, 0x03, /* HID usage sensor property power state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x50, 0x08, /* Sensor power state undefined sel */
+0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */
+0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */
+0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */
+0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */
+0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x01, 0x02, /* HID usage sensor state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 6, /* HID logical Max_8(6) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count(1) */
+0xA1, 0x02, /* HID collection(logical) */
+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
+0x15, 0, /* HID logical Min_8(0) */
+0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count(1) */
+0x55, 0, /* HID unit exponent(0) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0xD1, 0xE4, /* Light illuminance and sensitivity REL PCT) */
+0x15, 0, /* HID logical Min_8(0) */
+0x26, 0x10, 0x27, /* HID logical Max_16(0x10,0x27) */
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0E, /* HID unit exponent(0x0E) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0xD1, 0x24, /* Sensor data (Light illuminance and mod max) */
+0x15, 0, /* HID logical Min_8(0) */
+0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0F, /* HID unit exponent(0x0F) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+0x0A, 0xD1, 0x34, /* Sensor data (Light illuminance and mod min) */
+0x15, 0, /* HID logical Min_8(0) */
+0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
+0x75, 16, /* HID report size(16) */
+0x95, 1, /* HID report count(1) */
+0x55, 0x0F, /* HID unit exponent(0x0F) */
+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
+
+//Input reports (transmit)
+0x05, 0x20, /* HID usage page sensors */
+0x0A, 0x01, 0x02, /* HID usage sensor state */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 6, /* HID logical Max_8(6) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0xA1, 0x02, /* HID end collection (logical) */
+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0x02, 0x02, /* HID usage sensor event */
+0x15, 0, /* HID logical Min_8(0) */
+0x25, 5, /* HID logical Max_8(5) */
+0x75, 8, /* HID report size(8) */
+0x95, 1, /* HID report count (1) */
+0xA1, 0x02, /* HID end collection (logical) */
+0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
+0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
+0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
+0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
+0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
+0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
+0xC0, /* HID end collection */
+0x0A, 0xD1, 0x04, /* HID usage sensor data light illuminance */
+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
+0x55, 0x0F, /* HID unit exponent(0x0F) */
+0x75, 32, /* HID report size(32) */
+0x95, 1, /* HID report count (1) */
+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
+0xC0 /* HID end collection */
+};
+#endif
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
index a50ba4a4a1d7..b88f889b3932 100644
--- a/drivers/hid/hid-cypress.c
+++ b/drivers/hid/hid-cypress.c
@@ -23,19 +23,17 @@
#define CP_2WHEEL_MOUSE_HACK 0x02
#define CP_2WHEEL_MOUSE_HACK_ON 0x04
+#define VA_INVAL_LOGICAL_BOUNDARY 0x08
+
/*
* Some USB barcode readers from cypress have usage min and usage max in
* the wrong order
*/
-static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+static __u8 *cp_rdesc_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
unsigned int i;
- if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
- return rdesc;
-
if (*rsize < 4)
return rdesc;
@@ -48,6 +46,40 @@ static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc;
}
+static __u8 *va_logical_boundary_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ /*
+ * Varmilo VA104M (with VID Cypress and device ID 07B1) incorrectly
+ * reports Logical Minimum of its Consumer Control device as 572
+ * (0x02 0x3c). Fix this by setting its Logical Minimum to zero.
+ */
+ if (*rsize == 25 &&
+ rdesc[0] == 0x05 && rdesc[1] == 0x0c &&
+ rdesc[2] == 0x09 && rdesc[3] == 0x01 &&
+ rdesc[6] == 0x19 && rdesc[7] == 0x00 &&
+ rdesc[11] == 0x16 && rdesc[12] == 0x3c && rdesc[13] == 0x02) {
+ hid_info(hdev,
+ "fixing up varmilo VA104M consumer control report descriptor\n");
+ rdesc[12] = 0x00;
+ rdesc[13] = 0x00;
+ }
+ return rdesc;
+}
+
+static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if (quirks & CP_RDESC_SWAPPED_MIN_MAX)
+ rdesc = cp_rdesc_fixup(hdev, rdesc, rsize);
+ if (quirks & VA_INVAL_LOGICAL_BOUNDARY)
+ rdesc = va_logical_boundary_fixup(hdev, rdesc, rsize);
+
+ return rdesc;
+}
+
static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
@@ -128,6 +160,8 @@ static const struct hid_device_id cp_devices[] = {
.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
.driver_data = CP_2WHEEL_MOUSE_HACK },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1),
+ .driver_data = VA_INVAL_LOGICAL_BOUNDARY },
{ }
};
MODULE_DEVICE_TABLE(hid, cp_devices);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 5077c05fada1..d07413ae255a 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -332,6 +332,8 @@
#define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81
#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001
+#define USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1 0X07b1
+
#define USB_VENDOR_ID_DATA_MODUL 0x7374
#define USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH 0x1201
@@ -358,6 +360,7 @@
#define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR 0x1803
#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE1 0x1843
#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE2 0x1844
+#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE3 0x1846
#define USB_VENDOR_ID_DWAV 0x0eef
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
@@ -444,6 +447,10 @@
#define USB_VENDOR_ID_FRUCTEL 0x25B6
#define USB_DEVICE_ID_GAMETEL_MT_MODE 0x0002
+#define USB_VENDOR_ID_GAMEVICE 0x27F8
+#define USB_DEVICE_ID_GAMEVICE_GV186 0x0BBE
+#define USB_DEVICE_ID_GAMEVICE_KISHI 0x0BBF
+
#define USB_VENDOR_ID_GAMERON 0x0810
#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
#define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002
@@ -486,6 +493,7 @@
#define USB_DEVICE_ID_PENPOWER 0x00f4
#define USB_VENDOR_ID_GREENASIA 0x0e8f
+#define USB_DEVICE_ID_GREENASIA_DUAL_SAT_ADAPTOR 0x3010
#define USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD 0x3013
#define USB_VENDOR_ID_GRETAGMACBETH 0x0971
@@ -744,6 +752,7 @@
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
#define USB_DEVICE_ID_LOGITECH_T651 0xb00c
+#define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309
#define USB_DEVICE_ID_LOGITECH_C007 0xc007
#define USB_DEVICE_ID_LOGITECH_C077 0xc077
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
@@ -1126,6 +1135,7 @@
#define USB_DEVICE_ID_SYNAPTICS_DELL_K12A 0x2819
#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012 0x2968
#define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710
+#define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002 0x73f4
#define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003 0x73f5
#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5 0x81a7
@@ -1299,6 +1309,7 @@
#define USB_VENDOR_ID_UGTIZER 0x2179
#define USB_DEVICE_ID_UGTIZER_TABLET_GP0610 0x0053
+#define USB_DEVICE_ID_UGTIZER_TABLET_GT5040 0x0077
#define USB_VENDOR_ID_VIEWSONIC 0x0543
#define USB_DEVICE_ID_VIEWSONIC_PD1011 0xe621
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 9770db624bfa..4dca11392459 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -319,6 +319,9 @@ static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD),
HID_BATTERY_QUIRK_IGNORE },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
+ USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD),
+ HID_BATTERY_QUIRK_IGNORE },
{}
};
diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c
index 044a93f3c117..22bfbebceaf4 100644
--- a/drivers/hid/hid-ite.c
+++ b/drivers/hid/hid-ite.c
@@ -11,6 +11,54 @@
#include "hid-ids.h"
+#define QUIRK_TOUCHPAD_ON_OFF_REPORT BIT(0)
+
+static __u8 *ite_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if (quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) {
+ /* For Acer Aspire Switch 10 SW5-012 keyboard-dock */
+ if (*rsize == 188 && rdesc[162] == 0x81 && rdesc[163] == 0x02) {
+ hid_info(hdev, "Fixing up Acer Sw5-012 ITE keyboard report descriptor\n");
+ rdesc[163] = HID_MAIN_ITEM_RELATIVE;
+ }
+ /* For Acer One S1002 keyboard-dock */
+ if (*rsize == 188 && rdesc[185] == 0x81 && rdesc[186] == 0x02) {
+ hid_info(hdev, "Fixing up Acer S1002 ITE keyboard report descriptor\n");
+ rdesc[186] = HID_MAIN_ITEM_RELATIVE;
+ }
+ }
+
+ return rdesc;
+}
+
+static int ite_input_mapping(struct hid_device *hdev,
+ struct hid_input *hi, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit,
+ int *max)
+{
+
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if ((quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) &&
+ (usage->hid & HID_USAGE_PAGE) == 0x00880000) {
+ if (usage->hid == 0x00880078) {
+ /* Touchpad on, userspace expects F22 for this */
+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_F22);
+ return 1;
+ }
+ if (usage->hid == 0x00880079) {
+ /* Touchpad off, userspace expects F23 for this */
+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_F23);
+ return 1;
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
static int ite_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
@@ -37,13 +85,32 @@ static int ite_event(struct hid_device *hdev, struct hid_field *field,
return 0;
}
+static int ite_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ hid_set_drvdata(hdev, (void *)id->driver_data);
+
+ ret = hid_open_report(hdev);
+ if (ret)
+ return ret;
+
+ return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+}
+
static const struct hid_device_id ite_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) },
{ HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) },
/* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
USB_VENDOR_ID_SYNAPTICS,
- USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) },
+ USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012),
+ .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT },
+ /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */
+ { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+ USB_VENDOR_ID_SYNAPTICS,
+ USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002),
+ .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT },
/* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
USB_VENDOR_ID_SYNAPTICS,
@@ -55,6 +122,9 @@ MODULE_DEVICE_TABLE(hid, ite_devices);
static struct hid_driver ite_driver = {
.name = "itetech",
.id_table = ite_devices,
+ .probe = ite_probe,
+ .report_fixup = ite_report_fixup,
+ .input_mapping = ite_input_mapping,
.event = ite_event,
};
module_hid_driver(ite_driver);
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 38ee25a813b9..1cbbcf607ee9 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -328,7 +328,7 @@ static const char mse_bluetooth_descriptor[] = {
0x25, 0x01, /* LOGICAL_MAX (1) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x95, 0x04, /* REPORT_COUNT (4) */
- 0x81, 0x06, /* INPUT */
+ 0x81, 0x02, /* INPUT (Data,Var,Abs) */
0xC0, /* END_COLLECTION */
0xC0, /* END_COLLECTION */
};
@@ -866,11 +866,24 @@ static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
schedule_work(&djrcv_dev->work);
}
+/*
+ * Some quad/bluetooth keyboards have a builtin touchpad in this case we see
+ * only 1 paired device with a device_type of REPORT_TYPE_KEYBOARD. For the
+ * touchpad to work we must also forward mouse input reports to the dj_hiddev
+ * created for the keyboard (instead of forwarding them to a second paired
+ * device with a device_type of REPORT_TYPE_MOUSE as we normally would).
+ */
+static const u16 kbd_builtin_touchpad_ids[] = {
+ 0xb309, /* Dinovo Edge */
+ 0xb30c, /* Dinovo Mini */
+};
+
static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev,
struct hidpp_event *hidpp_report,
struct dj_workitem *workitem)
{
struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
+ int i, id;
workitem->type = WORKITEM_TYPE_PAIRED;
workitem->device_type = hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] &
@@ -882,6 +895,13 @@ static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev,
workitem->reports_supported |= STD_KEYBOARD | MULTIMEDIA |
POWER_KEYS | MEDIA_CENTER |
HIDPP;
+ id = (workitem->quad_id_msb << 8) | workitem->quad_id_lsb;
+ for (i = 0; i < ARRAY_SIZE(kbd_builtin_touchpad_ids); i++) {
+ if (id == kbd_builtin_touchpad_ids[i]) {
+ workitem->reports_supported |= STD_MOUSE;
+ break;
+ }
+ }
break;
case REPORT_TYPE_MOUSE:
workitem->reports_supported |= STD_MOUSE | HIDPP;
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index b8b53dc95e86..f85781464807 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -93,6 +93,8 @@ MODULE_PARM_DESC(disable_tap_to_click,
#define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3)
#define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4)
+#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
+
/*
* There are two hidpp protocols in use, the first version hidpp10 is known
* as register access protocol or RAP, the second version hidpp20 is known as
@@ -2951,6 +2953,26 @@ static int g920_get_config(struct hidpp_device *hidpp,
}
/* -------------------------------------------------------------------------- */
+/* Logitech Dinovo Mini keyboard with builtin touchpad */
+/* -------------------------------------------------------------------------- */
+#define DINOVO_MINI_PRODUCT_ID 0xb30c
+
+static int lg_dinovo_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x00d: lg_map_key_clear(KEY_MEDIA); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/* -------------------------------------------------------------------------- */
/* HID++1.0 devices which use HID++ reports for their wheels */
/* -------------------------------------------------------------------------- */
static int hidpp10_wheel_connect(struct hidpp_device *hidpp)
@@ -3185,6 +3207,9 @@ static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->application != HID_GD_MOUSE)
return m560_input_mapping(hdev, hi, field, usage, bit, max);
+ if (hdev->product == DINOVO_MINI_PRODUCT_ID)
+ return lg_dinovo_input_mapping(hdev, hi, field, usage, bit, max);
+
return 0;
}
@@ -3947,6 +3972,7 @@ static const struct hid_device_id hidpp_devices[] = {
LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
{ /* Mouse Logitech MX Anywhere 2 */
LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
+ { LDJ_DEVICE(0x4072), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
{ LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
{ LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
{ LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
@@ -3971,6 +3997,9 @@ static const struct hid_device_id hidpp_devices[] = {
{ /* Keyboard MX5000 (Bluetooth-receiver in HID proxy mode) */
LDJ_DEVICE(0xb305),
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
+ { /* Dinovo Edge (Bluetooth-receiver in HID proxy mode) */
+ LDJ_DEVICE(0xb309),
+ .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
{ /* Keyboard MX5500 (Bluetooth-receiver in HID proxy mode) */
LDJ_DEVICE(0xb30b),
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
@@ -4013,9 +4042,14 @@ static const struct hid_device_id hidpp_devices[] = {
{ /* MX5000 keyboard over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb305),
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
+ { /* Dinovo Edge keyboard over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb309),
+ .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
{ /* MX5500 keyboard over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b),
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
+ { /* M-RCQ142 V470 Cordless Laser Mouse over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb008) },
{ /* MX Master mouse over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012),
.driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index 0d27ccb55dd9..4211b9839209 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -49,6 +49,36 @@ enum {
MCP2221_ALT_F_NOT_GPIOD = 0xEF,
};
+/* MCP GPIO direction encoding */
+enum {
+ MCP2221_DIR_OUT = 0x00,
+ MCP2221_DIR_IN = 0x01,
+};
+
+#define MCP_NGPIO 4
+
+/* MCP GPIO set command layout */
+struct mcp_set_gpio {
+ u8 cmd;
+ u8 dummy;
+ struct {
+ u8 change_value;
+ u8 value;
+ u8 change_direction;
+ u8 direction;
+ } gpio[MCP_NGPIO];
+} __packed;
+
+/* MCP GPIO get command layout */
+struct mcp_get_gpio {
+ u8 cmd;
+ u8 dummy;
+ struct {
+ u8 direction;
+ u8 value;
+ } gpio[MCP_NGPIO];
+} __packed;
+
/*
* There is no way to distinguish responses. Therefore next command
* is sent only after response to previous has been received. Mutex
@@ -542,7 +572,7 @@ static int mcp_gpio_get(struct gpio_chip *gc,
mcp->txbuf[0] = MCP2221_GPIO_GET;
- mcp->gp_idx = (offset + 1) * 2;
+ mcp->gp_idx = offsetof(struct mcp_get_gpio, gpio[offset].value);
mutex_lock(&mcp->lock);
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
@@ -559,7 +589,7 @@ static void mcp_gpio_set(struct gpio_chip *gc,
memset(mcp->txbuf, 0, 18);
mcp->txbuf[0] = MCP2221_GPIO_SET;
- mcp->gp_idx = ((offset + 1) * 4) - 1;
+ mcp->gp_idx = offsetof(struct mcp_set_gpio, gpio[offset].value);
mcp->txbuf[mcp->gp_idx - 1] = 1;
mcp->txbuf[mcp->gp_idx] = !!value;
@@ -575,7 +605,7 @@ static int mcp_gpio_dir_set(struct mcp2221 *mcp,
memset(mcp->txbuf, 0, 18);
mcp->txbuf[0] = MCP2221_GPIO_SET;
- mcp->gp_idx = (offset + 1) * 5;
+ mcp->gp_idx = offsetof(struct mcp_set_gpio, gpio[offset].direction);
mcp->txbuf[mcp->gp_idx - 1] = 1;
mcp->txbuf[mcp->gp_idx] = val;
@@ -590,7 +620,7 @@ static int mcp_gpio_direction_input(struct gpio_chip *gc,
struct mcp2221 *mcp = gpiochip_get_data(gc);
mutex_lock(&mcp->lock);
- ret = mcp_gpio_dir_set(mcp, offset, 0);
+ ret = mcp_gpio_dir_set(mcp, offset, MCP2221_DIR_IN);
mutex_unlock(&mcp->lock);
return ret;
@@ -603,7 +633,7 @@ static int mcp_gpio_direction_output(struct gpio_chip *gc,
struct mcp2221 *mcp = gpiochip_get_data(gc);
mutex_lock(&mcp->lock);
- ret = mcp_gpio_dir_set(mcp, offset, 1);
+ ret = mcp_gpio_dir_set(mcp, offset, MCP2221_DIR_OUT);
mutex_unlock(&mcp->lock);
/* Can't configure as output, bailout early */
@@ -623,7 +653,7 @@ static int mcp_gpio_get_direction(struct gpio_chip *gc,
mcp->txbuf[0] = MCP2221_GPIO_GET;
- mcp->gp_idx = (offset + 1) * 2;
+ mcp->gp_idx = offsetof(struct mcp_get_gpio, gpio[offset].direction);
mutex_lock(&mcp->lock);
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
@@ -632,7 +662,7 @@ static int mcp_gpio_get_direction(struct gpio_chip *gc,
if (ret)
return ret;
- if (mcp->gpio_dir)
+ if (mcp->gpio_dir == MCP2221_DIR_IN)
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
@@ -758,7 +788,7 @@ static int mcp2221_raw_event(struct hid_device *hdev,
mcp->status = -ENOENT;
} else {
mcp->status = !!data[mcp->gp_idx];
- mcp->gpio_dir = !!data[mcp->gp_idx + 1];
+ mcp->gpio_dir = data[mcp->gp_idx + 1];
}
break;
default:
@@ -860,7 +890,7 @@ static int mcp2221_probe(struct hid_device *hdev,
mcp->gc->get_direction = mcp_gpio_get_direction;
mcp->gc->set = mcp_gpio_set;
mcp->gc->get = mcp_gpio_get;
- mcp->gc->ngpio = 4;
+ mcp->gc->ngpio = MCP_NGPIO;
mcp->gc->base = -1;
mcp->gc->can_sleep = 1;
mcp->gc->parent = &hdev->dev;
diff --git a/drivers/hid/hid-mf.c b/drivers/hid/hid-mf.c
index fc75f30f537c..92d7ecd41a78 100644
--- a/drivers/hid/hid-mf.c
+++ b/drivers/hid/hid-mf.c
@@ -153,6 +153,8 @@ static const struct hid_device_id mf_devices[] = {
.driver_data = HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2),
.driver_data = 0 }, /* No quirk required */
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3),
+ .driver_data = HID_QUIRK_MULTI_INPUT },
{ }
};
MODULE_DEVICE_TABLE(hid, mf_devices);
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 7a2be0205dfd..2e38340e19df 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -72,6 +72,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER), HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
@@ -83,7 +84,12 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_FUTABA, USB_DEVICE_ID_LED_DISPLAY), HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_SAT_ADAPTOR), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD), HID_QUIRK_MULTI_INPUT },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_GAMEVICE, USB_DEVICE_ID_GAMEVICE_GV186),
+ HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GAMEVICE, USB_DEVICE_ID_GAMEVICE_KISHI),
+ HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
@@ -479,6 +485,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3) },
#endif
#if IS_ENABLED(CONFIG_HID_MICROSOFT)
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 94c7398b5c27..3dd7d3246737 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -483,7 +483,8 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
return 1;
ptr = raw_data;
- ptr++; /* Skip report id */
+ if (report->id)
+ ptr++; /* Skip report id */
spin_lock_irqsave(&pdata->lock, flags);
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 2f073f536070..c7baedfc78bd 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1597,16 +1597,38 @@ static int dualshock4_get_calibration_data(struct sony_sc *sc)
* of the controller, so that it sends input reports of type 0x11.
*/
if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) {
+ int retries;
+
buf = kmalloc(DS4_FEATURE_REPORT_0x02_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- ret = hid_hw_raw_request(sc->hdev, 0x02, buf,
- DS4_FEATURE_REPORT_0x02_SIZE,
- HID_FEATURE_REPORT,
- HID_REQ_GET_REPORT);
- if (ret < 0)
- goto err_stop;
+ /* We should normally receive the feature report data we asked
+ * for, but hidraw applications such as Steam can issue feature
+ * reports as well. In particular for Dongle reconnects, Steam
+ * and this function are competing resulting in often receiving
+ * data for a different HID report, so retry a few times.
+ */
+ for (retries = 0; retries < 3; retries++) {
+ ret = hid_hw_raw_request(sc->hdev, 0x02, buf,
+ DS4_FEATURE_REPORT_0x02_SIZE,
+ HID_FEATURE_REPORT,
+ HID_REQ_GET_REPORT);
+ if (ret < 0)
+ goto err_stop;
+
+ if (buf[0] != 0x02) {
+ if (retries < 2) {
+ hid_warn(sc->hdev, "Retrying DualShock 4 get calibration report (0x02) request\n");
+ continue;
+ } else {
+ ret = -EILSEQ;
+ goto err_stop;
+ }
+ } else {
+ break;
+ }
+ }
} else {
u8 bthdr = 0xA3;
u32 crc;
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index 86b568037cb8..8e9c9e646cb7 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -385,6 +385,8 @@ static const struct hid_device_id uclogic_devices[] = {
USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
+ USB_DEVICE_ID_UGTIZER_TABLET_GT5040) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_TABLET_G5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c
index 7d20d1fcf8d2..d26d8cd98efc 100644
--- a/drivers/hid/hid-uclogic-params.c
+++ b/drivers/hid/hid-uclogic-params.c
@@ -997,6 +997,8 @@ int uclogic_params_init(struct uclogic_params *params,
break;
case VID_PID(USB_VENDOR_ID_UGTIZER,
USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
+ case VID_PID(USB_VENDOR_ID_UGTIZER,
+ USB_DEVICE_ID_UGTIZER_TABLET_GT5040):
case VID_PID(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
case VID_PID(USB_VENDOR_ID_UGEE,
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 786e3e9af1c9..aeff1ffb0c8b 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -943,6 +943,11 @@ static void i2c_hid_acpi_enable_wakeup(struct device *dev)
}
}
+static void i2c_hid_acpi_shutdown(struct device *dev)
+{
+ acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D3_COLD);
+}
+
static const struct acpi_device_id i2c_hid_acpi_match[] = {
{"ACPI0C50", 0 },
{"PNP0C50", 0 },
@@ -959,6 +964,8 @@ static inline int i2c_hid_acpi_pdata(struct i2c_client *client,
static inline void i2c_hid_acpi_fix_up_power(struct device *dev) {}
static inline void i2c_hid_acpi_enable_wakeup(struct device *dev) {}
+
+static inline void i2c_hid_acpi_shutdown(struct device *dev) {}
#endif
#ifdef CONFIG_OF
@@ -1175,6 +1182,8 @@ static void i2c_hid_shutdown(struct i2c_client *client)
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
free_irq(client->irq, ihid);
+
+ i2c_hid_acpi_shutdown(&client->dev);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
index 35f3bfc3e6f5..8e0f67455c09 100644
--- a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
+++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
@@ -405,6 +405,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
},
.driver_data = (void *)&sipodev_desc
},
+ {
+ .ident = "Vero K147",
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VERO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "K147"),
+ },
+ .driver_data = (void *)&sipodev_desc
+ },
{ } /* Terminate list */
};