From: Sandeep Singh <[email protected]>
AMD SFH is HID based driver. SFH FW is part of MP2
processor and it runs on MP2 where in driver resides
on X86. The driver functionalities are divided into
three parts:-
1: amd-mp2-pcie:- This module will communicate with MP2 FW and
provide that data into DRAM.
2: Client driver :- This part for driver will use dram data and
convert that data into HID format based on
HID reports.
3: Transport driver :- This part of driver will communicate with
HID core. Communication between devices and
HID core is mostly done via HID reports
In terms of architecture it is much more reassembles like ISH.
However the major difference is all The hid reports are generated
as part of kernel driver. AMD SFH driver has taken reference
from ISH in terms of design and functionalities at fewer location.
AMD sensor fusion Hub is part of a SOC starting from Ryzen
based platforms. The solution is working well on windows OS
in several OEM products. AMD SFH uses HID over PCIe bus.
Sandeep Singh (4):
SFH: Add maintainer list and documentation for AMD SFH based on HID
framework
SFH: PCI driver to add support of AMD sensor fusion Hub using HID
framework
SFH: Transport Driver to add support of AMD sensor fusion Hub (SFH)
SFH: Create HID report to Enable support of AMD sensor fusion Hub
(SFH)
Changes since v1:
-Fix auto build test warnings
-Fix warnings captured using smatch
-Changes suggested by Dan Carpenter
Links of the review comments for v1:
1- https://patchwork.kernel.org/patch/11325163/
2- https://patchwork.kernel.org/patch/11325167/
3- https://patchwork.kernel.org/patch/11325171/
4- https://patchwork.kernel.org/patch/11325187/
Documentation/hid/amd-sfh-hid.rst | 159 +++++
MAINTAINERS | 8 +
drivers/hid/Kconfig | 2 +
drivers/hid/Makefile | 1 +
drivers/hid/amd-sfh-hid/Kconfig | 17 +
drivers/hid/amd-sfh-hid/Makefile | 17 +
drivers/hid/amd-sfh-hid/amd_mp2_pcie.c | 256 ++++++++
drivers/hid/amd-sfh-hid/amd_mp2_pcie.h | 169 ++++++
drivers/hid/amd-sfh-hid/amdsfh-debugfs.c | 251 ++++++++
drivers/hid/amd-sfh-hid/amdsfh-debugfs.h | 14 +
drivers/hid/amd-sfh-hid/amdsfh-hid-client.c | 261 +++++++++
drivers/hid/amd-sfh-hid/amdsfh-hid.c | 179 ++++++
drivers/hid/amd-sfh-hid/amdsfh-hid.h | 85 +++
.../hid_descriptor/amd_sfh_hid_descriptor.c | 275 +++++++++
.../hid_descriptor/amd_sfh_hid_descriptor.h | 125 ++++
.../hid_descriptor/amd_sfh_hid_report_descriptor.h | 642 +++++++++++++++++++++
16 files changed, 2461 insertions(+)
create mode 100644 Documentation/hid/amd-sfh-hid.rst
create mode 100644 drivers/hid/amd-sfh-hid/Kconfig
create mode 100644 drivers/hid/amd-sfh-hid/Makefile
create mode 100644 drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
create mode 100644 drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-debugfs.c
create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-debugfs.h
create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-hid-client.c
create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-hid.c
create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-hid.h
create mode 100644 drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_descriptor.c
create mode 100644 drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_descriptor.h
create mode 100644 drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_descriptor.h
--
2.7.4
From: Sandeep Singh <[email protected]>
Add Maintainer list for AMD SFH Solution and work flow
document.
Signed-off-by: Nehal Shah <[email protected]>
Signed-off-by: Sandeep Singh <[email protected]>
---
Documentation/hid/amd-sfh-hid.rst | 159 ++++++++++++++++++++++++++++++++++++++
MAINTAINERS | 8 ++
2 files changed, 167 insertions(+)
create mode 100644 Documentation/hid/amd-sfh-hid.rst
diff --git a/Documentation/hid/amd-sfh-hid.rst b/Documentation/hid/amd-sfh-hid.rst
new file mode 100644
index 0000000..1183350
--- /dev/null
+++ b/Documentation/hid/amd-sfh-hid.rst
@@ -0,0 +1,159 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+AMD Sensor Fusion Hub:-
+======================
+AMD sensor fushion Hub is part of a SOC starting from ryzon based platforms.
+The solution is working well on windows OS in several
+OEM products. AMD SFH uses HID over PCIe bus. In terms of architecture
+it is much more resmebles like ISH .However the major diffrence is all
+The hid reports are generated as part of kernel driver.
+
+Block Diagram:-
+=============
+ -------------------------------
+ | HID User Space Applications |
+ -------------------------------
+---------------------------------------------
+ ---------------------------------
+ | HID Core |
+ ---------------------------------
+
+ ---------------------------------
+ | AMD HID Transport Driver |
+ ---------------------------------
+
+ --------------------------------
+ | AMD HID Client Driver |
+ | with HID Report Generator|
+ --------------------------------
+
+ --------------------------------
+ | AMD MP2 PCIe Driver |
+ --------------------------------
+---------------------------------------------
+ -------------------------------
+ | 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.
+The driver, which binds each device (AMD SFH HID driver) identifies
+the device type and registers with the hid core. Transport drivers
+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 driver implements the synchronous calls.
+
+AMD HID Client Driver:-
+**********************
+This driver is responsible to implement HID request and descriptors.
+As firmware is OS agnostic, HID client driver fills the HID request
+structure and descriptors. HID client driver is in complex in nature
+as it is interface between MP2 PCIe driver and HID. HID client driver
+initialized the MP2 PCIe driver and holds the instance of MP2 driver.
+It identified the number of sensors connected using MP2- PCIe driver and
+based on that allocate the DRAM address for each and every sensor and
+pass it to MP2-PCIe driver.
+On enumeration of each sensor, client driver fills out the HID Descriptor
+structure and HID input report structure. HID Feature report structure can
+be optional. The report descriptor structure varies sensor to sensor.
+Now on enumeration client driver does two major things
+1. Register the HID sensor client to virtual bus (Platform driver) and bind it.
+2. Probes the AMD HID transport driver. Which in turns register device to the core.
+
+AMD MP2 PCIe Driver:-
+********************
+MP2 PCIe driver is responsible for making all transaction with the firmware over
+PCIe.The connection establishment between firmware and MP2 PCIe driver happens here.
+
+The communication between X86 and MP2 is spilt into three parts.
+1. Command Transfer => C2P Mailbox Register are used
+2. Data Transfer => DRAM
+
+Commands are sent to MP2 using C2P Mail Box registers. These C2P registers
+are mapped in PCIe address space.Writing into C2P Message register generate
+interrupt to MP2. The client driver allocates the physical memory and send
+the same to MP2 for data transfer. MP2 firmware uses DRAM interface registers
+to indirectly access DRAM memory. For Firmware always write minimum 32 bytes
+into DRAM.So it is expected that driver shall allocate minimum 32 bytes DRAM space.
+
+Enumeration and Probing flow:-
+*****************************
+ HID AMD AMD AMD -PCIe MP2
+ Core Transport Client Driver Driver 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:-
+*************************************************
+
+ | | | | |
+Get | | | | |
+Input | | | | |
+Report | | | | |
+---> | | | | |
+ |HID_req | | | |
+ |get_report | | | |
+ |------------->| | | |
+ | | HID_get_input| | |
+ | | report | | |
+ | |------------->|------------------------| | |
+ | | | Read the DRAM data for| | |
+ | | | requsted sensor and | | |
+ | | | create the HID input | | |
+ | | | report | | |
+ | | |------------------------| | |
+ | |Data received | | |
+ | | in HID report| | |
+ To |<-------------|<-------------| | |
+Applications | | | |
+<-------| | | | |
+
+
+Data Flow from AMD SFH Driver to Application:-
+**********************************************
+ | | | | |
+ | | |------------------------| | |
+ | | |Periodically Read | | |
+ | | |the data for all | | |
+ | | |enumerated sensors | | |
+ | | |from the dram and create| | |
+ | | | HID Input reports | | |
+ | | |------------------------| | |
+ | |HID Input | | |
+ | |Input report | | |
+ <----submit to Application-----| | |
+ | | | | |
diff --git a/MAINTAINERS b/MAINTAINERS
index 56765f5..7cfeb5a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -884,6 +884,14 @@ S: Supported
F: drivers/net/ethernet/amd/xgbe/
F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
+AMD SENSOR FUSION HUB DRIVER
+M: Nehal Shah <[email protected]>
+M: Sandeep Singh <[email protected]>
+L: [email protected]
+S: Maintained
+F: Documentation/hid/amd-sfh*
+F: drivers/hid/amd-sfh-hid/
+
ANALOG DEVICES INC AD5686 DRIVER
M: Stefan Popa <[email protected]>
L: [email protected]
--
2.7.4
From: Sandeep Singh <[email protected]>
AMD SFH uses HID over PCIe bus.SFH fw is part of MP2
processor and it runs on MP2 where in driver resides
on X86.This part of module will communicate with MP2 FW and
provide that data into DRAM
Signed-off-by: Sandeep Singh <[email protected]>
Signed-off-by: Nehal Shah <[email protected]>
Reported-by: kbuild test robot <[email protected]>
---
drivers/hid/Kconfig | 2 +
drivers/hid/Makefile | 1 +
drivers/hid/amd-sfh-hid/Kconfig | 17 +++
drivers/hid/amd-sfh-hid/Makefile | 17 +++
drivers/hid/amd-sfh-hid/amd_mp2_pcie.c | 256 +++++++++++++++++++++++++++++++++
drivers/hid/amd-sfh-hid/amd_mp2_pcie.h | 169 ++++++++++++++++++++++
6 files changed, 462 insertions(+)
create mode 100644 drivers/hid/amd-sfh-hid/Kconfig
create mode 100644 drivers/hid/amd-sfh-hid/Makefile
create mode 100644 drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
create mode 100644 drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 494a39e..b253ad1 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -1155,4 +1155,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 bfefa36..15a08e8 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -139,3 +139,4 @@ 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 0000000..e2dee39
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "AMD SFH HID support"
+ depends on (X86_64 || COMPILE_TEST) && PCI
+
+config AMD_SFH_HID
+ tristate "AMD Sensor Fusion Hub"
+ default n
+ select HID
+ help
+ If you say yes to this option, support will be included for the AMD
+ Sensor Fusion Hub.
+
+ This driver can also be built as modules. If so, the modules will
+ be called amd-mp2-pcie and amd-sfhtp-hid.
+ Say Y 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 0000000..5aae934
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile - AMD SFH HID drivers
+# Copyright (c) 2019-2020, Advanced Micro Devices, Inc.
+#
+#
+ccflags-m := -Werror
+obj-$(CONFIG_AMD_SFH_HID) += amd-mp2-pcie.o
+amd-mp2-pcie-objs := amd_mp2_pcie.o
+
+obj-$(CONFIG_AMD_SFH_HID) +=amd-sfhtp-hid.o
+amd-sfhtp-hid-objs := amdsfh-hid.o
+amd-sfhtp-hid-objs+= amdsfh-hid-client.o
+amd-sfhtp-hid-objs+= amdsfh-debugfs.o
+amd-sfhtp-hid-objs+= hid_descriptor/amd_sfh_hid_descriptor.o
+
+ccflags-y += -I$(srctree)/$(src)/
diff --git a/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
new file mode 100644
index 0000000..f264d60
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD MP2 PCIe communication driver
+ *
+ * Authors: Shyam Sundar S K <[email protected]>
+ * Nehal Bakulchandra Shah <[email protected]>
+ */
+
+#include "amd_mp2_pcie.h"
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#define DRIVER_NAME "pcie_mp2_amd"
+#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
+#define DRIVER_VER "1.0"
+
+#define ACEL_EN BIT(ACCEL_IDX)
+#define GYRO_EN BIT(GYRO_IDX)
+#define MAGNO_EN BIT(MAG_IDX)
+#define ALS_EN BIT(AMBIENT_LIGHT_IDX)
+
+int amd_start_sensor(struct pci_dev *pdev, struct amd_mp2_sensor_info info)
+{
+ struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
+ union sfh_cmd_base cmd_base;
+ union sfh_command_parameter cmd_param;
+
+ /*fill up command register*/
+ cmd_base.ul = 0;
+ 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*/
+ cmd_param.ul = 0;
+ cmd_param.s.buffer_layout = 1;
+ cmd_param.s.buffer_length = 16;
+
+ write64((u64)info.phy_address, privdata->mmio + AMD_C2P_MSG2);
+ writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
+ writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(amd_start_sensor);
+
+int amd_stop_sensor(struct pci_dev *pdev, u16 sensor_idx)
+{
+ struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
+ union sfh_cmd_base cmd_base;
+
+ /* fill up command register */
+ cmd_base.ul = 0;
+ cmd_base.s.cmd_id = disable_sensor;
+ cmd_base.s.period = 0;
+ cmd_base.s.sensor_id = sensor_idx;
+
+ write64(0x0, privdata->mmio + AMD_C2P_MSG2);
+ writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(amd_stop_sensor);
+
+int amd_stop_all_sensors(struct pci_dev *pdev)
+{
+ struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
+ union sfh_cmd_base cmd_base;
+
+ /*fill up command register */
+ cmd_base.ul = 0;
+ 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);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(amd_stop_all_sensors);
+
+int amd_mp2_get_sensor_num(struct pci_dev *dev, u8 *sensor_id)
+{
+ struct amd_mp2_dev *privdata = pci_get_drvdata(dev);
+ int activestatus;
+ int num_of_sensors = 0;
+
+ if (!sensor_id)
+ return -ENOMEM;
+
+ privdata->eventreg.activecontrolstatus =
+ readl(privdata->mmio + AMD_P2C_MSG3);
+ activestatus = privdata->eventreg.activecontrolstatus >> 4;
+
+ if (ACEL_EN & activestatus) {
+ sensor_id[num_of_sensors] = ACCEL_IDX;
+ num_of_sensors++;
+ }
+ if (GYRO_EN & activestatus) {
+ sensor_id[num_of_sensors] = GYRO_IDX;
+ num_of_sensors++;
+ }
+ if (MAGNO_EN & activestatus) {
+ sensor_id[num_of_sensors] = MAG_IDX;
+ num_of_sensors++;
+ }
+
+ if (ALS_EN & activestatus) {
+ sensor_id[num_of_sensors] = AMBIENT_LIGHT_IDX;
+ num_of_sensors++;
+ }
+
+ return num_of_sensors;
+}
+EXPORT_SYMBOL_GPL(amd_mp2_get_sensor_num);
+
+static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, struct pci_dev *pdev)
+{
+ int rc;
+ int bar_index = 2;
+ resource_size_t size, base;
+
+ pci_set_drvdata(pdev, privdata);
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ goto err_pci_enable;
+
+ rc = pci_request_regions(pdev, DRIVER_NAME);
+ if (rc)
+ goto err_pci_regions;
+
+ 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));
+ if (rc)
+ goto err_dma_mask;
+ dev_warn(ndev_dev(privdata), "Cannot DMA highmem\n");
+ }
+
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (rc)
+ goto err_dma_mask;
+ dev_warn(ndev_dev(privdata), "Cannot DMA consistent highmem\n");
+ }
+
+ base = pci_resource_start(pdev, bar_index);
+ size = pci_resource_len(pdev, bar_index);
+ dev_dbg(ndev_dev(privdata), "Base addr:%llx size:%llx\n",
+ (unsigned long long)base, (unsigned long long)size);
+
+ privdata->mmio = ioremap(base, size);
+ if (!privdata->mmio) {
+ rc = -EIO;
+ goto err_dma_mask;
+ }
+
+ return 0;
+
+err_dma_mask:
+ pci_clear_master(pdev);
+ pci_release_regions(pdev);
+err_pci_regions:
+ pci_disable_device(pdev);
+err_pci_enable:
+ pci_set_drvdata(pdev, NULL);
+ return rc;
+}
+
+static void amd_mp2_pci_deinit(struct amd_mp2_dev *privdata)
+{
+ struct pci_dev *pdev = ndev_pdev(privdata);
+
+ amd_stop_all_sensors(pdev);
+ pci_iounmap(pdev, privdata->mmio);
+
+ pci_clear_master(pdev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static int amd_mp2_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct amd_mp2_dev *privdata;
+ int rc;
+
+ dev_info(&pdev->dev, "MP2 device found [%04x:%04x] (rev %x)\n",
+ (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
+
+ privdata = kzalloc(sizeof(*privdata), GFP_KERNEL);
+
+ if (!privdata) {
+ rc = -ENOMEM;
+ goto err_dev;
+ }
+
+ privdata->pdev = pdev;
+
+ rc = amd_mp2_pci_init(privdata, pdev);
+ if (rc)
+ goto err_pci_init;
+
+ return 0;
+
+err_pci_init:
+ kfree(privdata);
+err_dev:
+ dev_err(&pdev->dev, "Memory Allocation Failed\n");
+ return rc;
+}
+
+static void amd_mp2_pci_remove(struct pci_dev *pdev)
+{
+ struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
+
+ amd_mp2_pci_deinit(privdata);
+ kfree(privdata);
+}
+
+static const struct pci_device_id amd_mp2_pci_tbl[] = {
+ {PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2)},
+ {0}
+};
+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,
+ .remove = amd_mp2_pci_remove,
+};
+
+static int __init amd_mp2_pci_driver_init(void)
+{
+ return pci_register_driver(&amd_mp2_pci_driver);
+}
+module_init(amd_mp2_pci_driver_init);
+
+static void __exit amd_mp2_pci_driver_exit(void)
+{
+ pci_unregister_driver(&amd_mp2_pci_driver);
+}
+module_exit(amd_mp2_pci_driver_exit);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VER);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Shyam Sundar S K <[email protected]>");
+MODULE_AUTHOR("Nehal Bakulchandra Shah <[email protected]>");
diff --git a/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
new file mode 100644
index 0000000..2bfd2de
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * AMD MP2 PCIe communication driver
+ *
+ * Authors: Shyam Sundar S K <[email protected]>
+ * Nehal Bakulchandra Shah <[email protected]>
+ */
+
+#ifndef PCIE_MP2_AMD_H
+#define PCIE_MP2_AMD_H
+
+#include <linux/pci.h>
+#define PCI_DEVICE_ID_AMD_MP2 0x15E4
+
+#define write64 _write64
+static inline void _write64(u64 val, void __iomem *mmio)
+{
+ writel(val, mmio);
+ writel(val >> 32, mmio + sizeof(u32));
+}
+
+#define read64 _read64
+static inline u64 _read64(void __iomem *mmio)
+{
+ u64 low, high;
+
+ low = readl(mmio);
+ high = readl(mmio + sizeof(u32));
+ return low | (high << 32);
+}
+
+enum {
+ /* MP2 C2P Message Registers */
+ AMD_C2P_MSG0 = 0x10500,
+ AMD_C2P_MSG1 = 0x10504,
+ AMD_C2P_MSG2 = 0x10508,
+ AMD_C2P_MSG3 = 0x1050c,
+ AMD_C2P_MSG4 = 0x10510,
+ AMD_C2P_MSG5 = 0x10514,
+ AMD_C2P_MSG6 = 0x10518,
+ AMD_C2P_MSG7 = 0x1051c,
+ AMD_C2P_MSG8 = 0x10520,
+ AMD_C2P_MSG9 = 0x10524,
+
+ /* MP2 P2C Message Registers */
+ AMD_P2C_MSG0 = 0x10680, /*Do not use*/
+ AMD_P2C_MSG1 = 0x10684,
+ AMD_P2C_MSG2 = 0x10688,
+ AMD_P2C_MSG3 = 0x1068C, /*MP2 debug info*/
+ AMD_P2C_MSG_INTEN = 0x10690, /*MP2 int gen register*/
+ AMD_P2C_MSG_INTSTS = 0x10694, /*Interrupt sts*/
+};
+
+/*
+ * SFH Command registers
+ */
+union sfh_cmd_base {
+ u32 ul;
+ struct {
+ u32 cmd_id : 8;
+ u32 sensor_id : 8;
+ u32 period : 16;
+ } s; /*!< Structure used for bit access */
+};
+
+union sfh_command_parameter {
+ u32 ul;
+ struct {
+ u32 buffer_layout : 2;
+ u32 buffer_length : 6;
+ u32 rsvd : 24;
+ } s;
+};
+
+struct sfh_command_register {
+ union sfh_cmd_base cmd_base;
+ union sfh_command_parameter cmd_param;
+ phys_addr_t phy_addr;
+};
+
+/*
+ * SFH Response registers
+ */
+enum response_type {
+ non_operationevent,
+ command_success,
+ command_failed,
+ sfi_dataready_event,
+ invalid_response = 0xff,
+};
+
+enum status_type {
+ cmd_success,
+ invalid_data_payload,
+ invalid_data_length,
+ invalid_sensor_id,
+ invalid_dram_addr,
+ invalid_command,
+ sensor_enabled,
+ sensor_disabled,
+ status_end,
+};
+
+enum command_id {
+ non_operation = 0,
+ enable_sensor = 1,
+ disable_sensor = 2,
+ dump_sensorinfo = 3,
+ numberof_sensordiscovered = 4,
+ who_am_i_regchipid = 5,
+ set_dcd_data = 6,
+ get_dcd_data = 7,
+ stop_all_sensors = 8,
+ invalid_cmd = 0xf,
+};
+
+union sfh_event_base {
+ u32 ul;
+ struct {
+ u32 response : 4; /*!< bit: 0..3 SFI response_type */
+ u32 status : 3; /*!< bit: 6..5 status_type */
+ u32 out_in_c2p : 1; /*!< bit: 5 0- output in DRAM,1-in C2PMsg */
+ u32 length : 6; /*!< bit: 8..13 length */
+ u32 dbg : 2; /*!< bit: 14.15 dbg msg include in p2c msg 1-2 */
+ u32 sensor_id : 8; /*!< bit: 16..23 Sensor ID */
+ u32 rsvd : 8; /*!< bit: 24..31 Reservered for future use */
+ } s;
+};
+
+struct sfi_event_register {
+ union sfh_event_base evtbase;
+ u32 debuginfo1;
+ u32 debuginfo2;
+ u32 activecontrolstatus;
+};
+
+enum sensor_idx {
+ ACCEL_IDX = 0,
+ GYRO_IDX = 1,
+ MAG_IDX = 2,
+ AMBIENT_LIGHT_IDX = 19,
+ NUM_ALL_SENSOR_CONSUMERS
+};
+
+struct amd_mp2_dev {
+ struct pci_dev *pdev;
+ struct dentry *debugfs_dir;
+ void __iomem *mmio;
+ union sfh_event_base eventval;
+ struct sfi_event_register eventreg;
+ struct delayed_work work;
+ void *ctx;
+ void *cl_data;
+};
+
+struct amd_mp2_sensor_info {
+ u8 sensor_idx;
+ u32 period;
+ phys_addr_t phy_address;
+};
+
+int amd_start_sensor(struct pci_dev *pdev, struct amd_mp2_sensor_info info);
+int amd_stop_sensor(struct pci_dev *pdev, u16 sensor_idx);
+int amd_stop_all_sensors(struct pci_dev *pdev);
+int amd_mp2_get_sensor_num(struct pci_dev *dev, u8 *sensor_id);
+#define ndev_pdev(ndev) ((ndev)->pdev)
+#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
+#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
+#endif
--
2.7.4
From: Sandeep Singh <[email protected]>
This part of module will provide the interaction between HID framework
and client driver.This modules will registered client driver with
HID framework.
Signed-off-by: Sandeep Singh <[email protected]>
Signed-off-by: Nehal Shah <[email protected]>
Reported-by: kbuild test robot <[email protected]>
Reported-by: Dan Carpenter <[email protected]>
---
drivers/hid/amd-sfh-hid/amdsfh-debugfs.c | 251 ++++++++++++++++++++++++++
drivers/hid/amd-sfh-hid/amdsfh-debugfs.h | 14 ++
drivers/hid/amd-sfh-hid/amdsfh-hid-client.c | 261 ++++++++++++++++++++++++++++
drivers/hid/amd-sfh-hid/amdsfh-hid.c | 179 +++++++++++++++++++
drivers/hid/amd-sfh-hid/amdsfh-hid.h | 85 +++++++++
5 files changed, 790 insertions(+)
create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-debugfs.c
create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-debugfs.h
create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-hid-client.c
create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-hid.c
create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-hid.h
diff --git a/drivers/hid/amd-sfh-hid/amdsfh-debugfs.c b/drivers/hid/amd-sfh-hid/amdsfh-debugfs.c
new file mode 100644
index 0000000..20859d4
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amdsfh-debugfs.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD SFH DebugFS
+ * This part of module will provide sensors raw value data
+ * for AMD SFH debugging.
+ * cat /sys/kernel/debug/amd_sfhtp_hid
+ * Author: Nehal Bakulchandra Shah <[email protected]>
+ */
+
+#include <linux/slab.h>
+#include "amd_mp2_pcie.h"
+#include "amdsfh-debugfs.h"
+
+/* DebugFS helpers */
+#define OBUFP (obuf + oboff)
+#define OBUFLEN 512
+#define OBUFSPC (OBUFLEN - oboff)
+#define OSCNPRINTF(fmt, ...) \
+ scnprintf(OBUFP, OBUFSPC, fmt, ## __VA_ARGS__)
+
+static ssize_t amdsfh_debugfs_accel_read(struct file *filp, char __user *ubuf,
+ size_t count, loff_t *offp)
+{
+ unsigned int oboff = 0, i;
+ struct amdtp_cl_data *cl_data = filp->private_data;
+ bool found = false;
+ ssize_t ret;
+ char *obuf;
+
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ if (cl_data->sensor_idx[i] == ACCEL_IDX) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return -1;
+
+ obuf = kmalloc(OBUFLEN, GFP_KERNEL);
+ if (!obuf)
+ return -ENOMEM;
+
+ oboff += OSCNPRINTF("Accel_X_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][0]);
+ oboff += OSCNPRINTF("Accel_Y_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][1]);
+ oboff += OSCNPRINTF("Accel_Z_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][2]);
+ ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
+
+ kfree(obuf);
+
+ return ret;
+}
+
+static ssize_t amdsfh_debugfs_gyro_read(struct file *filp, char __user *ubuf,
+ size_t count, loff_t *offp)
+{
+ unsigned int oboff = 0, i;
+ bool found = false;
+ struct amdtp_cl_data *cl_data = filp->private_data;
+ ssize_t ret;
+ char *obuf;
+
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ if (cl_data->sensor_idx[i] == GYRO_IDX) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return -1;
+
+ obuf = kmalloc(OBUFLEN, GFP_KERNEL);
+ if (!obuf)
+ return -ENOMEM;
+
+ oboff += OSCNPRINTF("Gyro_X_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][0]);
+ oboff += OSCNPRINTF("Gyro_Y_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][1]);
+ oboff += OSCNPRINTF("Gyro_Z_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][2]);
+ ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
+
+ kfree(obuf);
+
+ return ret;
+}
+
+static ssize_t amdsfh_debugfs_mag_read(struct file *filp, char __user *ubuf,
+ size_t count, loff_t *offp)
+{
+ unsigned int oboff = 0, i;
+ bool found = false;
+ ssize_t ret;
+ char *obuf;
+ struct amdtp_cl_data *cl_data = filp->private_data;
+
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ if (cl_data->sensor_idx[i] == MAG_IDX) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return -1;
+
+ obuf = kmalloc(OBUFLEN, GFP_KERNEL);
+ if (!obuf)
+ return -ENOMEM;
+
+ oboff += OSCNPRINTF("Mag_X_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][0]);
+ oboff += OSCNPRINTF("Mag_Y_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][1]);
+ oboff += OSCNPRINTF("Mag_Z_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][2]);
+ ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
+
+ kfree(obuf);
+
+ return ret;
+}
+
+static ssize_t amdsfh_debugfs_als_read(struct file *filp, char __user *ubuf,
+ size_t count, loff_t *offp)
+{
+ unsigned int oboff = 0, i;
+ bool found = false;
+ ssize_t ret;
+ char *obuf;
+ struct amdtp_cl_data *cl_data = filp->private_data;
+
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ if (cl_data->sensor_idx[i] == AMBIENT_LIGHT_IDX) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return -1;
+
+ obuf = kmalloc(OBUFLEN, GFP_KERNEL);
+ if (!obuf)
+ return -ENOMEM;
+
+ oboff += OSCNPRINTF("Gyro_X_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][0]);
+ oboff += OSCNPRINTF("Gyro_Y_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][1]);
+ oboff += OSCNPRINTF("Gyro_Z_Raw:%d\n",
+ (int)cl_data->sensor_virt_addr[i][2]);
+ ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
+
+ kfree(obuf);
+
+ return ret;
+}
+
+static const struct file_operations amdsfh_debugfs_accel_ops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = amdsfh_debugfs_accel_read,
+};
+
+static const struct file_operations amdsfh_debugfs_gyro_ops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = amdsfh_debugfs_gyro_read,
+};
+
+static const struct file_operations amdsfh_debugfs_mag_ops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = amdsfh_debugfs_mag_read,
+};
+
+static const struct file_operations amdsfh_debugfs_als_ops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = amdsfh_debugfs_als_read,
+};
+
+int amdsfh_debugfs_setup(struct amdtp_cl_data *cl_data)
+{
+ /* DebugFS info */
+ struct dentry *dbgfs;
+ int i;
+
+ if (!debugfs_initialized())
+ return -1;
+
+ if (!cl_data->amd_debugfs_dir)
+ cl_data->amd_debugfs_dir = debugfs_create_dir
+ (KBUILD_MODNAME, NULL);
+
+ if (!cl_data->amd_debugfs_dir)
+ return -1;
+
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ switch (cl_data->sensor_idx[i]) {
+ case ACCEL_IDX:
+ dbgfs = debugfs_create_dir("accel",
+ cl_data->amd_debugfs_dir);
+ debugfs_create_file("raw_value", 0400,
+ dbgfs, cl_data,
+ &amdsfh_debugfs_accel_ops);
+ break;
+
+ case GYRO_IDX:
+ dbgfs = debugfs_create_dir("gyro",
+ cl_data->amd_debugfs_dir);
+ debugfs_create_file("raw_value", 0400,
+ dbgfs, cl_data,
+ &amdsfh_debugfs_gyro_ops);
+ break;
+
+ case MAG_IDX:
+ dbgfs = debugfs_create_dir("magnetometer",
+ cl_data->amd_debugfs_dir);
+ debugfs_create_file("raw_value", 0400,
+ dbgfs, cl_data,
+ &amdsfh_debugfs_mag_ops);
+ break;
+
+ case AMBIENT_LIGHT_IDX:
+ dbgfs = debugfs_create_dir("als",
+ cl_data->amd_debugfs_dir);
+ debugfs_create_file("raw_value", 0400,
+ dbgfs, cl_data,
+ &amdsfh_debugfs_als_ops);
+ break;
+
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(amdsfh_debugfs_setup);
+
+void amdsfh_debugfs_destroy(struct amdtp_cl_data *cl_data)
+{
+ debugfs_remove_recursive(cl_data->amd_debugfs_dir);
+}
+EXPORT_SYMBOL(amdsfh_debugfs_destroy);
diff --git a/drivers/hid/amd-sfh-hid/amdsfh-debugfs.h b/drivers/hid/amd-sfh-hid/amdsfh-debugfs.h
new file mode 100644
index 0000000..470f1f12
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amdsfh-debugfs.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * AMD SFH DebugFS
+ * Author: Nehal Bakulchandra Shah <[email protected]>
+ */
+#include "amdsfh-hid.h"
+
+#ifndef AMDSFH_DEBUGFS_H
+#define AMDSFH_DEBUGFS_H
+
+int amdsfh_debugfs_setup(struct amdtp_cl_data *cl_data);
+void amdsfh_debugfs_destroy(struct amdtp_cl_data *cl_data);
+
+#endif
diff --git a/drivers/hid/amd-sfh-hid/amdsfh-hid-client.c b/drivers/hid/amd-sfh-hid/amdsfh-hid-client.c
new file mode 100644
index 0000000..b59cb2f
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amdsfh-hid-client.c
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * AMD SFH Client Driver
+ * Author: Nehal Bakulchandra Shah <[email protected]>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/hid.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/dma-mapping.h>
+#include "amdsfh-hid.h"
+#include "amd_mp2_pcie.h"
+#include "hid_descriptor/amd_sfh_hid_descriptor.h"
+#include "amdsfh-debugfs.h"
+
+#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Client Driver"
+#define DRIVER_VER "1.0"
+#define DRIVER_NAME "AMD_SFH_HID_CLIENT"
+#define PERIOD 200
+
+struct request_list {
+ u8 report_id;
+ u8 sensor_idx;
+ u8 report_type;
+ u8 current_index;
+ struct hid_device *hid;
+ struct list_head list;
+};
+
+static struct request_list req_list;
+static struct amdtp_cl_data *cl_data_context;
+
+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);
+}
+EXPORT_SYMBOL(amd_sfh_set_report);
+
+void 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_request = kzalloc
+ (sizeof(*new_request), GFP_KERNEL);
+ new_request->current_index = i;
+ new_request->sensor_idx = cli_data->sensor_idx[i];
+ new_request->hid = hid;
+ new_request->report_type = report_type;
+ new_request->report_id = report_id;
+ cli_data->report_id[i] = report_id;
+ cli_data->request_done[i] = false;
+ list_add(&new_request->list, &req_list.list);
+ break;
+ }
+ }
+ schedule_delayed_work(&cli_data->work, 0);
+}
+EXPORT_SYMBOL(amd_sfh_get_report);
+
+static void amd_sfh_work(struct work_struct *work)
+{
+ struct amdtp_cl_data *cli_data = amd_sfh_cldata(work);
+ struct request_list *req_node;
+ u8 report_size = 0;
+ u8 current_index;
+ u8 sensor_index;
+ u8 report_id;
+ u8 node_type;
+
+ 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->current_index;
+ 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]);
+ } 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]);
+ }
+
+ 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);
+ cli_data->cur_hid_dev = current_index;
+ cli_data->sensor_requested_cnt[current_index] = 0;
+ kfree(req_node);
+ 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 = cl_data_context;
+ unsigned int i;
+ u8 report_size = 0;
+
+ 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, PERIOD);
+}
+
+static int amd_sfh_hid_client_probe(struct platform_device *pdev)
+{
+ struct amd_mp2_sensor_info info;
+ int rc = 0;
+ int i;
+ struct amdtp_cl_device *cl_dev;
+ struct amdtp_cl_data *cl_data;
+ u32 feature_report_size = 0;
+ u32 input_report_size = 0;
+
+ cl_dev = devm_kzalloc(&pdev->dev, sizeof(*cl_dev), GFP_KERNEL);
+ if (!cl_dev)
+ return -ENOMEM;
+
+ cl_dev->pdev = pci_get_device(PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_AMD_MP2, NULL);
+ if (!cl_dev->pdev)
+ return -ENOMEM;
+
+ cl_data = kzalloc(sizeof(*cl_data), GFP_KERNEL);
+ cl_data->num_hid_devices = amd_mp2_get_sensor_num
+ (cl_dev->pdev, &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);
+
+ amdsfh_debugfs_setup(cl_data);
+
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ cl_data->sensor_virt_addr[i] = dma_alloc_coherent
+ (&pdev->dev, sizeof(int) * 8,
+ &cl_data->sensor_phy_addr[i], GFP_KERNEL);
+ cl_data->sensor_sts[i] = 0;
+ cl_data->sensor_requested_cnt[i] = 0;
+ cl_data->cur_hid_dev = i;
+
+ cl_data->report_descr_size[i] = get_descriptor_size
+ (cl_data->sensor_idx[i], descr_size);
+
+ feature_report_size = get_descriptor_size
+ (cl_data->sensor_idx[i], feature_size);
+
+ input_report_size = get_descriptor_size
+ (cl_data->sensor_idx[i], input_size);
+
+ cl_data->feature_report[i] = kzalloc(feature_report_size,
+ GFP_KERNEL);
+ cl_data->input_report[i] = kzalloc(input_report_size,
+ GFP_KERNEL);
+ info.period = PERIOD;
+ info.sensor_idx = cl_data->sensor_idx[i];
+ info.phy_address = cl_data->sensor_phy_addr[i];
+ cl_data->report_descr[i] = kzalloc
+ (cl_data->report_descr_size[i], GFP_KERNEL);
+ if (!cl_data->report_descr[i])
+ return -ENOMEM;
+ rc = get_report_descriptor(cl_data->sensor_idx[i],
+ cl_data->report_descr[i]);
+ rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
+ rc = amd_start_sensor(cl_dev->pdev, info);
+ cl_data->sensor_sts[i] = 1;
+ }
+
+ cl_dev->cl_data = cl_data;
+ cl_data_context = cl_data;
+ platform_set_drvdata(pdev, cl_dev);
+ schedule_delayed_work(&cl_data->work_buffer, PERIOD);
+ return 0;
+}
+
+static int amd_sfh_hid_client_remove(struct platform_device *pdev)
+{
+ int i;
+ struct amdtp_cl_device *cl_dev;
+ struct amdtp_cl_data *cl_data;
+
+ cl_dev = platform_get_drvdata(pdev);
+ if (!(cl_dev))
+ return -EINVAL;
+
+ cl_data = cl_dev->cl_data;
+ if (!(cl_data))
+ return -EINVAL;
+
+ for (i = 0; i < cl_data->num_hid_devices; i++)
+ amd_stop_sensor(cl_dev->pdev, i);
+ cancel_delayed_work_sync(&cl_data->work);
+ cancel_delayed_work_sync(&cl_data->work_buffer);
+ amdsfh_debugfs_destroy(cl_data);
+ 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(&pdev->dev, 8 * sizeof(int),
+ cl_data->sensor_virt_addr[i],
+ cl_data->sensor_phy_addr[i]);
+ }
+
+ kfree(cl_data);
+ pr_info("%s:%s Exit\n", DRIVER_NAME, __func__);
+ return 0;
+}
+
+static const struct acpi_device_id amd_sfh_acpi_match[] = { {
+ "AMDI0080" },
+ { },
+};
+
+MODULE_DEVICE_TABLE(acpi, amd_sfh_acpi_match);
+static struct platform_driver amd_sfh_plat_driver = {
+ .probe = amd_sfh_hid_client_probe,
+ .remove = amd_sfh_hid_client_remove,
+ .driver = {
+ .name = "amd_sfh_platform",
+ .acpi_match_table = ACPI_PTR(amd_sfh_acpi_match),
+ },
+};
+module_platform_driver(amd_sfh_plat_driver);
+MODULE_DESCRIPTION("AMD(R) SFH Client Driver");
+MODULE_AUTHOR("Nehal Shah <[email protected]>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/hid/amd-sfh-hid/amdsfh-hid.c b/drivers/hid/amd-sfh-hid/amdsfh-hid.c
new file mode 100644
index 0000000..89fe35a8
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amdsfh-hid.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * AMD MP2 Sensors transport driver
+ *
+ * Authors: Sandeep Singh <[email protected]>
+ * Nehal Bakulchandra Shah <[email protected]>
+ */
+#include <linux/hid.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include "amdsfh-hid.h"
+
+#define DRIVER_NAME "AMD_MP2_SENSORS_TRANSPORT"
+
+/**
+ * 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;
+ int rc;
+
+ rc = hid_parse_report(hid, cli_data->report_descr[hid_data->index],
+ cli_data->report_descr_size[hid_data->index]);
+ if (rc)
+ return rc;
+ return 0;
+}
+
+/* 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, unsigned char reportnum,
+ u8 *buf, size_t len, unsigned char rtype,
+ int reqtype)
+{
+ return 0;
+}
+
+static void amdtp_hid_request(struct hid_device *hid, struct hid_report *rep,
+ int reqtype)
+{
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ amd_sfh_get_report(hid, rep->id, rep->type);
+ break;
+ case HID_REQ_SET_REPORT:
+ amd_sfh_set_report(hid, rep->id, reqtype);
+ 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 = 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])
+ wait_event_interruptible_timeout(hid_data->hid_wait,
+ cli_data->request_done[i],
+ 1500);
+ if (!cli_data->request_done[i]) {
+ hid_err(hid,
+ "timeout waiting for response from device\n");
+ return -ETIMEDOUT;
+ }
+ cli_data->request_done[i] = false;
+
+ 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(unsigned int cur_hid_dev,
+ struct amdtp_cl_data *cli_data)
+{
+ int rc;
+ struct hid_device *hid;
+ struct amdtp_hid_data *hid_data;
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid)) {
+ rc = PTR_ERR(hid);
+ return -ENOMEM;
+ }
+
+ 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->version = AMD_SFH_HID_VERSION;
+ 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/amdsfh-hid.h b/drivers/hid/amd-sfh-hid/amdsfh-hid.h
new file mode 100644
index 0000000..8bbe40c
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/amdsfh-hid.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AMD MP2 Sensors transport driver
+ *
+ * Authors: Sandeep Singh <[email protected]>
+ * Nehal Bakulchandra Shah <[email protected]>
+ */
+
+#ifndef AMDSFH_HID_H
+#define AMDSFH_HID_H
+#include <linux/debugfs.h>
+
+#define MAX_HID_DEVICES 4
+#define DCD_DATA_SIZE_CHAR 512
+#define BUS_AMD_AMDTP 0x20
+#define AMD_SFH_HID_VENDOR 1022
+#define AMD_SFH_HID_PRODUCT 0x0001
+#define AMD_SFH_HID_VERSION 0x0001
+
+struct amdtp_cl_device {
+ struct pci_dev *pdev;
+ struct amdtp_cl_data *cl_data;
+};
+
+struct amdtp_cl_data {
+ u8 init_done;
+ unsigned int cur_hid_dev;
+ unsigned int hid_dev_count;
+ unsigned int num_hid_devices;
+ struct device_info *hid_devices;
+ unsigned char *report_descr[MAX_HID_DEVICES];
+ int report_descr_size[MAX_HID_DEVICES];
+ struct hid_device *hid_sensor_hubs[MAX_HID_DEVICES];
+ unsigned char *hid_descr[MAX_HID_DEVICES];
+ int hid_descr_size[MAX_HID_DEVICES];
+ phys_addr_t phy_addr_base;
+ u32 *sensor_virt_addr[MAX_HID_DEVICES];
+ phys_addr_t sensor_phy_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 dentry *amd_debugfs_dir;
+
+};
+
+/**
+ * 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 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, unsigned int len,
+ int report_id);
+void hid_amdtp_get_report(struct hid_device *hid, int report_id,
+ int report_type);
+int amdtp_hid_probe(unsigned int cur_hid_dev,
+ struct amdtp_cl_data *cli_data);
+void amdtp_hid_remove(struct amdtp_cl_data *cli_data);
+void 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);
+
+#define amd_sfh_cldata(__work) container_of(__work,\
+ struct amdtp_cl_data, work.work)
+#endif /* AMDSFH_HID */
--
2.7.4
From: Sandeep Singh <[email protected]>
This part of module will define the data into HID reports.
Get data from PCIe driver and populate that data into
reports. HID core communication between devices and
HID core is mostly done via HID reports.
Signed-off-by: Nehal Shah <[email protected]>
Signed-off-by: Sandeep Singh <[email protected]>
---
.../hid_descriptor/amd_sfh_hid_descriptor.c | 275 +++++++++
.../hid_descriptor/amd_sfh_hid_descriptor.h | 125 ++++
.../hid_descriptor/amd_sfh_hid_report_descriptor.h | 642 +++++++++++++++++++++
3 files changed, 1042 insertions(+)
create mode 100644 drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_descriptor.c
create mode 100644 drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_descriptor.h
create mode 100644 drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_descriptor.h
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_descriptor.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_descriptor.c
new file mode 100644
index 0000000..766b0ed
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_descriptor.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * AMD SFH Report Descriptor generator logic
+ * Author: Nehal Bakulchandra Shah <[email protected]>
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "amd_sfh_hid_descriptor.h"
+#include "amd_sfh_hid_report_descriptor.h"
+#include "amd_mp2_pcie.h"
+
+#define AMD_SFH_FIRMWARE_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 AMBIENT_LIGHT_IDX: /* ambient light sensor */
+ memset(rep_desc, 0, sizeof(als_report_descriptor));
+ memcpy(rep_desc, als_report_descriptor,
+ sizeof(als_report_descriptor));
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(get_report_descriptor);
+
+u32 get_descriptor_size(int sensor_idx, int descriptor_name)
+{
+ switch (sensor_idx) {
+ case ACCEL_IDX:
+ if (descriptor_name == descr_size)
+ return sizeof(accel3_report_descriptor);
+ else if (descriptor_name == input_size)
+ return sizeof(struct accel3_input_report);
+ else if (descriptor_name == feature_size)
+ return sizeof(struct accel3_feature_report);
+ break;
+
+ case GYRO_IDX:
+ if (descriptor_name == descr_size)
+ return sizeof(gyro3_report_descriptor);
+ else if (descriptor_name == input_size)
+ return sizeof(struct gyro_input_report);
+ else if (descriptor_name == feature_size)
+ return sizeof(struct gyro_feature_report);
+ break;
+
+ case MAG_IDX:
+ if (descriptor_name == descr_size)
+ return sizeof(comp3_report_descriptor);
+ else if (descriptor_name == input_size)
+ return sizeof(struct magno_input_report);
+ else if (descriptor_name == feature_size)
+ return sizeof(struct magno_input_report);
+ break;
+
+ case AMBIENT_LIGHT_IDX:
+ if (descriptor_name == descr_size)
+ return sizeof(als_report_descriptor);
+ else if (descriptor_name == input_size)
+ return sizeof(struct als_input_report);
+ else if (descriptor_name == feature_size)
+ return sizeof(struct als_feature_report);
+ break;
+
+ default:
+ pr_info("Unknown Sensor index detected");
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(get_descriptor_size);
+
+u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
+{
+ u8 report_size = 0;
+ struct accel3_feature_report acc_feature;
+ struct gyro_feature_report gyro_feature;
+ struct magno_feature_report magno_feature;
+ struct als_feature_report als_feature;
+
+ if (!feature_report)
+ return report_size;
+
+ switch (sensor_idx) {
+ case ACCEL_IDX: /* accel */
+ acc_feature.common_property.connection_type =
+ HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM;
+ acc_feature.common_property.report_state =
+ HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
+ acc_feature.common_property.power_state =
+ HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
+ acc_feature.common_property.sensor_state =
+ HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM;
+ acc_feature.common_property.report_interval =
+ HID_DEFAULT_REPORT_INTERVAL;
+ 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 */
+ gyro_feature.common_property.connection_type =
+ HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM;
+ gyro_feature.common_property.report_state =
+ HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
+ gyro_feature.common_property.power_state =
+ HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
+ gyro_feature.common_property.sensor_state =
+ HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM;
+ gyro_feature.common_property.report_interval =
+ HID_DEFAULT_REPORT_INTERVAL;
+ 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 */
+ magno_feature.common_property.report_id = report_id;
+ magno_feature.common_property.connection_type =
+ HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM;
+ magno_feature.common_property.report_state =
+ HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
+ magno_feature.common_property.power_state =
+ HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
+ magno_feature.common_property.sensor_state =
+ HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM;
+ magno_feature.common_property.report_interval =
+ HID_DEFAULT_REPORT_INTERVAL;
+ 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 AMBIENT_LIGHT_IDX: /* ambient light sensor */
+ als_feature.common_property.report_id = report_id;
+ als_feature.common_property.connection_type =
+ HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM;
+ als_feature.common_property.report_state =
+ HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
+ als_feature.common_property.power_state =
+ HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
+ als_feature.common_property.sensor_state =
+ HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM;
+ als_feature.common_property.report_interval =
+ HID_DEFAULT_REPORT_INTERVAL;
+ 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;
+ }
+ return report_size;
+}
+EXPORT_SYMBOL_GPL(get_feature_report);
+
+u8 get_input_report(int sensor_idx, int report_id,
+ u8 *input_report, u32 *sensor_virt_addr)
+{
+ u8 report_size = 0;
+ struct accel3_input_report acc_input;
+ struct gyro_input_report gyro_input;
+ struct magno_input_report magno_input;
+ struct als_input_report als_input;
+
+ if (!sensor_virt_addr || !input_report)
+ return report_size;
+
+ switch (sensor_idx) {
+ case ACCEL_IDX: /* accel */
+ acc_input.common_property.report_id = report_id;
+ acc_input.common_property.sensor_state =
+ HID_USAGE_SENSOR_STATE_READY_ENUM;
+ acc_input.common_property.event_type =
+ HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM;
+ acc_input.in_accel_x_value = (int)sensor_virt_addr[0] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ acc_input.in_accel_y_value = (int)sensor_virt_addr[1] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ acc_input.in_accel_z_value = (int)sensor_virt_addr[2] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ memcpy(input_report, &acc_input, sizeof(acc_input));
+ report_size = sizeof(acc_input);
+ break;
+
+ case GYRO_IDX: /* gyro */
+ gyro_input.common_property.report_id = report_id;
+ gyro_input.common_property.sensor_state =
+ HID_USAGE_SENSOR_STATE_READY_ENUM;
+ gyro_input.common_property.event_type =
+ HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM;
+ gyro_input.in_angel_x_value = (int)sensor_virt_addr[0] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ gyro_input.in_angel_y_value = (int)sensor_virt_addr[1] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ gyro_input.in_angel_z_value = (int)sensor_virt_addr[2] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ memcpy(input_report, &gyro_input, sizeof(gyro_input));
+ report_size = sizeof(gyro_input);
+ break;
+
+ case MAG_IDX: /* Magnetometer */
+ magno_input.common_property.report_id = report_id;
+ magno_input.common_property.sensor_state =
+ HID_USAGE_SENSOR_STATE_READY_ENUM;
+ magno_input.common_property.event_type =
+ HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM;
+ magno_input.in_magno_x = (int)sensor_virt_addr[0] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ magno_input.in_magno_y = (int)sensor_virt_addr[1] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ magno_input.in_magno_z = (int)sensor_virt_addr[2] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ magno_input.in_magno_accuracy = (u16)sensor_virt_addr[3] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ memcpy(input_report, &magno_input, sizeof(magno_input));
+ report_size = sizeof(magno_input);
+ break;
+
+ case AMBIENT_LIGHT_IDX: /* Als */
+ als_input.common_property.report_id = report_id;
+ als_input.common_property.sensor_state =
+ HID_USAGE_SENSOR_STATE_READY_ENUM;
+ als_input.common_property.event_type =
+ HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM;
+ als_input.illuminance_value = (int)sensor_virt_addr[0] /
+ AMD_SFH_FIRMWARE_MULTIPLIER;
+ report_size = sizeof(als_input);
+ memcpy(input_report, &als_input, sizeof(als_input));
+ break;
+ }
+ return report_size;
+}
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_descriptor.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_descriptor.h
new file mode 100644
index 0000000..9f0b042
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_descriptor.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * HID report and descriptor stuructures and routines
+ *
+ * Author: Nehal Bakulchandra Shah <[email protected]>
+ */
+
+#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 _hid_report_descriptor {
+ u8 bDescriptorType;
+ u8 wDescriptorLength;
+};
+
+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_porperty {
+ /* common properties */
+ u8 report_id;
+ u8 sensor_state;
+ u8 event_type;
+} __packed;
+
+struct _hid_device_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bcdHID[2];
+ u8 bCountryCode;
+ u8 bNumDescriptors;
+ struct _hid_report_descriptor *reports;
+};
+
+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_porperty 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_porperty 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_porperty 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_porperty common_property;
+ /* values specific to this sensor */
+ int illuminance_value;
+} __packed;
+
+int get_report_descriptor(int sensor_idx, u8 rep_desc[]);
+u32 get_descriptor_size(int sensor_idx, int descriptor_name);
+//u32 get_report_descriptor_size(int sensor_idx);
+//u32 get_feature_report_size(int sensor_idx);
+//u32 get_input_report_size(int sensor_idx);
+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_descriptor.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_descriptor.h
new file mode 100644
index 0000000..b686ed7
--- /dev/null
+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_descriptor.h
@@ -0,0 +1,642 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * HID descriptor stuructures
+ *
+ * Author: Nehal Bakulchandra Shah <[email protected]>
+ */
+
+#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 unsigned char 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 unsigned char comp3_report_descriptor[] = {
+0x05, 0x20, /* Usage page */
+0x09, 0x83, /* Motion type Orientation compass 3D */
+0xA1, 0x00, /* HID Collection (Physical) */
+
+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 unsigned char 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)
+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
--
2.7.4
Hi
On 1/29/2020 9:57 AM, Sandeep Singh wrote:
> From: Sandeep Singh <[email protected]>
>
> AMD SFH uses HID over PCIe bus.SFH fw is part of MP2
> processor and it runs on MP2 where in driver resides
> on X86.This part of module will communicate with MP2 FW and
> provide that data into DRAM
>
> Signed-off-by: Sandeep Singh <[email protected]>
> Signed-off-by: Nehal Shah <[email protected]>
> Reported-by: kbuild test robot <[email protected]>
> ---
> drivers/hid/Kconfig | 2 +
> drivers/hid/Makefile | 1 +
> drivers/hid/amd-sfh-hid/Kconfig | 17 +++
> drivers/hid/amd-sfh-hid/Makefile | 17 +++
> drivers/hid/amd-sfh-hid/amd_mp2_pcie.c | 256 +++++++++++++++++++++++++++++++++
> drivers/hid/amd-sfh-hid/amd_mp2_pcie.h | 169 ++++++++++++++++++++++
> 6 files changed, 462 insertions(+)
> create mode 100644 drivers/hid/amd-sfh-hid/Kconfig
> create mode 100644 drivers/hid/amd-sfh-hid/Makefile
> create mode 100644 drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> create mode 100644 drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
>
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index 494a39e..b253ad1 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -1155,4 +1155,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 bfefa36..15a08e8 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -139,3 +139,4 @@ 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 0000000..e2dee39
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/Kconfig
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +menu "AMD SFH HID support"
> + depends on (X86_64 || COMPILE_TEST) && PCI
> +
> +config AMD_SFH_HID
> + tristate "AMD Sensor Fusion Hub"
> + default n
> + select HID
> + help
> + If you say yes to this option, support will be included for the AMD
> + Sensor Fusion Hub.
> +
> + This driver can also be built as modules. If so, the modules will
> + be called amd-mp2-pcie and amd-sfhtp-hid.
> + Say Y 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 0000000..5aae934
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/Makefile
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Makefile - AMD SFH HID drivers
> +# Copyright (c) 2019-2020, Advanced Micro Devices, Inc.
> +#
> +#
> +ccflags-m := -Werror
> +obj-$(CONFIG_AMD_SFH_HID) += amd-mp2-pcie.o
> +amd-mp2-pcie-objs := amd_mp2_pcie.o
> +
> +obj-$(CONFIG_AMD_SFH_HID) +=amd-sfhtp-hid.o
> +amd-sfhtp-hid-objs := amdsfh-hid.o
> +amd-sfhtp-hid-objs+= amdsfh-hid-client.o
> +amd-sfhtp-hid-objs+= amdsfh-debugfs.o
> +amd-sfhtp-hid-objs+= hid_descriptor/amd_sfh_hid_descriptor.o
> +
> +ccflags-y += -I$(srctree)/$(src)/
> diff --git a/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> new file mode 100644
> index 0000000..f264d60
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> @@ -0,0 +1,256 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * AMD MP2 PCIe communication driver
> + *
> + * Authors: Shyam Sundar S K <[email protected]>
> + * Nehal Bakulchandra Shah <[email protected]>
> + */
> +
> +#include "amd_mp2_pcie.h"
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +
> +#define DRIVER_NAME "pcie_mp2_amd"
> +#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
> +#define DRIVER_VER "1.0"
> +
> +#define ACEL_EN BIT(ACCEL_IDX)
> +#define GYRO_EN BIT(GYRO_IDX)
> +#define MAGNO_EN BIT(MAG_IDX)
> +#define ALS_EN BIT(AMBIENT_LIGHT_IDX)
> +
> +int amd_start_sensor(struct pci_dev *pdev, struct amd_mp2_sensor_info info)
> +{
> + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> + union sfh_cmd_base cmd_base;
> + union sfh_command_parameter cmd_param;
> +
> + /*fill up command register*/
> + cmd_base.ul = 0;
> + 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*/
> + cmd_param.ul = 0;
> + cmd_param.s.buffer_layout = 1;
> + cmd_param.s.buffer_length = 16;
> +
> + write64((u64)info.phy_address, privdata->mmio + AMD_C2P_MSG2);
> + writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
> + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(amd_start_sensor);
> +
> +int amd_stop_sensor(struct pci_dev *pdev, u16 sensor_idx)
> +{
> + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> + union sfh_cmd_base cmd_base;
> +
> + /* fill up command register */
> + cmd_base.ul = 0;
> + cmd_base.s.cmd_id = disable_sensor;
> + cmd_base.s.period = 0;
> + cmd_base.s.sensor_id = sensor_idx;
> +
> + write64(0x0, privdata->mmio + AMD_C2P_MSG2);
> + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(amd_stop_sensor);
> +
> +int amd_stop_all_sensors(struct pci_dev *pdev)
> +{
> + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> + union sfh_cmd_base cmd_base;
> +
> + /*fill up command register */
> + cmd_base.ul = 0;
> + 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);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(amd_stop_all_sensors);
> +
> +int amd_mp2_get_sensor_num(struct pci_dev *dev, u8 *sensor_id)
> +{
> + struct amd_mp2_dev *privdata = pci_get_drvdata(dev);
> + int activestatus;
> + int num_of_sensors = 0;
> +
> + if (!sensor_id)
> + return -ENOMEM;
> +
> + privdata->eventreg.activecontrolstatus =
> + readl(privdata->mmio + AMD_P2C_MSG3);
> + activestatus = privdata->eventreg.activecontrolstatus >> 4;
> +
> + if (ACEL_EN & activestatus) {
> + sensor_id[num_of_sensors] = ACCEL_IDX;
> + num_of_sensors++;
> + }
> + if (GYRO_EN & activestatus) {
> + sensor_id[num_of_sensors] = GYRO_IDX;
> + num_of_sensors++;
> + }
> + if (MAGNO_EN & activestatus) {
> + sensor_id[num_of_sensors] = MAG_IDX;
> + num_of_sensors++;
> + }
> +
> + if (ALS_EN & activestatus) {
> + sensor_id[num_of_sensors] = AMBIENT_LIGHT_IDX;
> + num_of_sensors++;
> + }
> +
> + return num_of_sensors;
> +}
> +EXPORT_SYMBOL_GPL(amd_mp2_get_sensor_num);
> +
> +static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, struct pci_dev *pdev)
> +{
> + int rc;
> + int bar_index = 2;
> + resource_size_t size, base;
> +
> + pci_set_drvdata(pdev, privdata);
> +
> + rc = pci_enable_device(pdev);
> + if (rc)
> + goto err_pci_enable;
> +
> + rc = pci_request_regions(pdev, DRIVER_NAME);
> + if (rc)
> + goto err_pci_regions;
> +
> + 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));
> + if (rc)
> + goto err_dma_mask;
> + dev_warn(ndev_dev(privdata), "Cannot DMA highmem\n");
> + }
> +
> + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
> + if (rc) {
> + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
> + if (rc)
> + goto err_dma_mask;
> + dev_warn(ndev_dev(privdata), "Cannot DMA consistent highmem\n");
> + }
> +
> + base = pci_resource_start(pdev, bar_index);
> + size = pci_resource_len(pdev, bar_index);
> + dev_dbg(ndev_dev(privdata), "Base addr:%llx size:%llx\n",
> + (unsigned long long)base, (unsigned long long)size);
> +
> + privdata->mmio = ioremap(base, size);
> + if (!privdata->mmio) {
> + rc = -EIO;
> + goto err_dma_mask;
> + }
> +
> + return 0;
> +
> +err_dma_mask:
> + pci_clear_master(pdev);
> + pci_release_regions(pdev);
> +err_pci_regions:
> + pci_disable_device(pdev);
> +err_pci_enable:
> + pci_set_drvdata(pdev, NULL);
> + return rc;
> +}
> +
> +static void amd_mp2_pci_deinit(struct amd_mp2_dev *privdata)
> +{
> + struct pci_dev *pdev = ndev_pdev(privdata);
> +
> + amd_stop_all_sensors(pdev);
> + pci_iounmap(pdev, privdata->mmio);
> +
> + pci_clear_master(pdev);
> + pci_release_regions(pdev);
> + pci_disable_device(pdev);
> + pci_set_drvdata(pdev, NULL);
> +}
> +
> +static int amd_mp2_pci_probe(struct pci_dev *pdev,
> + const struct pci_device_id *id)
> +{
> + struct amd_mp2_dev *privdata;
> + int rc;
> +
> + dev_info(&pdev->dev, "MP2 device found [%04x:%04x] (rev %x)\n",
> + (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
> +
> + privdata = kzalloc(sizeof(*privdata), GFP_KERNEL);
> +
> + if (!privdata) {
> + rc = -ENOMEM;
> + goto err_dev;
> + }
> +
> + privdata->pdev = pdev;
> +
> + rc = amd_mp2_pci_init(privdata, pdev);
> + if (rc)
> + goto err_pci_init;
> +
> + return 0;
> +
> +err_pci_init:
> + kfree(privdata);
> +err_dev:
> + dev_err(&pdev->dev, "Memory Allocation Failed\n");
> + return rc;
> +}
> +
> +static void amd_mp2_pci_remove(struct pci_dev *pdev)
> +{
> + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> +
> + amd_mp2_pci_deinit(privdata);
> + kfree(privdata);
> +}
> +
> +static const struct pci_device_id amd_mp2_pci_tbl[] = {
> + {PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2)},
> + {0}
> +};
> +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,
> + .remove = amd_mp2_pci_remove,
> +};
> +
> +static int __init amd_mp2_pci_driver_init(void)
> +{
> + return pci_register_driver(&amd_mp2_pci_driver);
> +}
> +module_init(amd_mp2_pci_driver_init);
> +
> +static void __exit amd_mp2_pci_driver_exit(void)
> +{
> + pci_unregister_driver(&amd_mp2_pci_driver);
> +}
> +module_exit(amd_mp2_pci_driver_exit);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_VERSION(DRIVER_VER);
> +MODULE_LICENSE("Dual BSD/GPL");
> +MODULE_AUTHOR("Shyam Sundar S K <[email protected]>");
> +MODULE_AUTHOR("Nehal Bakulchandra Shah <[email protected]>");
> diff --git a/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
> new file mode 100644
> index 0000000..2bfd2de
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
> @@ -0,0 +1,169 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * AMD MP2 PCIe communication driver
> + *
> + * Authors: Shyam Sundar S K <[email protected]>
> + * Nehal Bakulchandra Shah <[email protected]>
> + */
> +
> +#ifndef PCIE_MP2_AMD_H
> +#define PCIE_MP2_AMD_H
> +
> +#include <linux/pci.h>
> +#define PCI_DEVICE_ID_AMD_MP2 0x15E4
> +
> +#define write64 _write64
> +static inline void _write64(u64 val, void __iomem *mmio)
> +{
> + writel(val, mmio);
> + writel(val >> 32, mmio + sizeof(u32));
> +}
> +
> +#define read64 _read64
> +static inline u64 _read64(void __iomem *mmio)
> +{
> + u64 low, high;
> +
> + low = readl(mmio);
> + high = readl(mmio + sizeof(u32));
> + return low | (high << 32);
> +}
> +
> +enum {
> + /* MP2 C2P Message Registers */
> + AMD_C2P_MSG0 = 0x10500,
> + AMD_C2P_MSG1 = 0x10504,
> + AMD_C2P_MSG2 = 0x10508,
> + AMD_C2P_MSG3 = 0x1050c,
> + AMD_C2P_MSG4 = 0x10510,
> + AMD_C2P_MSG5 = 0x10514,
> + AMD_C2P_MSG6 = 0x10518,
> + AMD_C2P_MSG7 = 0x1051c,
> + AMD_C2P_MSG8 = 0x10520,
> + AMD_C2P_MSG9 = 0x10524,
> +
> + /* MP2 P2C Message Registers */
> + AMD_P2C_MSG0 = 0x10680, /*Do not use*/
> + AMD_P2C_MSG1 = 0x10684,
> + AMD_P2C_MSG2 = 0x10688,
> + AMD_P2C_MSG3 = 0x1068C, /*MP2 debug info*/
> + AMD_P2C_MSG_INTEN = 0x10690, /*MP2 int gen register*/
> + AMD_P2C_MSG_INTSTS = 0x10694, /*Interrupt sts*/
> +};
> +
> +/*
> + * SFH Command registers
> + */
> +union sfh_cmd_base {
> + u32 ul;
> + struct {
> + u32 cmd_id : 8;
> + u32 sensor_id : 8;
> + u32 period : 16;
> + } s; /*!< Structure used for bit access */
> +};
> +
> +union sfh_command_parameter {
> + u32 ul;
> + struct {
> + u32 buffer_layout : 2;
> + u32 buffer_length : 6;
> + u32 rsvd : 24;
> + } s;
> +};
> +
> +struct sfh_command_register {
> + union sfh_cmd_base cmd_base;
> + union sfh_command_parameter cmd_param;
> + phys_addr_t phy_addr;
> +};
> +
> +/*
> + * SFH Response registers
> + */
> +enum response_type {
> + non_operationevent,
> + command_success,
> + command_failed,
> + sfi_dataready_event,
> + invalid_response = 0xff,
> +};
> +
> +enum status_type {
> + cmd_success,
> + invalid_data_payload,
> + invalid_data_length,
> + invalid_sensor_id,
> + invalid_dram_addr,
> + invalid_command,
> + sensor_enabled,
> + sensor_disabled,
> + status_end,
> +};
> +
> +enum command_id {
> + non_operation = 0,
> + enable_sensor = 1,
> + disable_sensor = 2,
> + dump_sensorinfo = 3,
> + numberof_sensordiscovered = 4,
> + who_am_i_regchipid = 5,
> + set_dcd_data = 6,
> + get_dcd_data = 7,
> + stop_all_sensors = 8,
> + invalid_cmd = 0xf,
> +};
> +
> +union sfh_event_base {
> + u32 ul;
> + struct {
> + u32 response : 4; /*!< bit: 0..3 SFI response_type */
> + u32 status : 3; /*!< bit: 6..5 status_type */
> + u32 out_in_c2p : 1; /*!< bit: 5 0- output in DRAM,1-in C2PMsg */
> + u32 length : 6; /*!< bit: 8..13 length */
> + u32 dbg : 2; /*!< bit: 14.15 dbg msg include in p2c msg 1-2 */
> + u32 sensor_id : 8; /*!< bit: 16..23 Sensor ID */
> + u32 rsvd : 8; /*!< bit: 24..31 Reservered for future use */
> + } s;
> +};
> +
> +struct sfi_event_register {
> + union sfh_event_base evtbase;
> + u32 debuginfo1;
> + u32 debuginfo2;
> + u32 activecontrolstatus;
> +};
> +
> +enum sensor_idx {
> + ACCEL_IDX = 0,
> + GYRO_IDX = 1,
> + MAG_IDX = 2,
> + AMBIENT_LIGHT_IDX = 19,
> + NUM_ALL_SENSOR_CONSUMERS
> +};
> +
> +struct amd_mp2_dev {
> + struct pci_dev *pdev;
> + struct dentry *debugfs_dir;
> + void __iomem *mmio;
> + union sfh_event_base eventval;
> + struct sfi_event_register eventreg;
> + struct delayed_work work;
> + void *ctx;
> + void *cl_data;
> +};
> +
> +struct amd_mp2_sensor_info {
> + u8 sensor_idx;
> + u32 period;
> + phys_addr_t phy_address;
> +};
> +
> +int amd_start_sensor(struct pci_dev *pdev, struct amd_mp2_sensor_info info);
> +int amd_stop_sensor(struct pci_dev *pdev, u16 sensor_idx);
> +int amd_stop_all_sensors(struct pci_dev *pdev);
> +int amd_mp2_get_sensor_num(struct pci_dev *dev, u8 *sensor_id);
> +#define ndev_pdev(ndev) ((ndev)->pdev)
> +#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
> +#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
> +#endif
>
any update on this?
Thanks
Nehal Shah
On Mon, 2020-02-03 at 10:35 +0530, Shah, Nehal-bakulchandra wrote:
> Hi
>
> On 1/29/2020 9:57 AM, Sandeep Singh wrote:
> > From: Sandeep Singh <[email protected]>
> >
> > AMD SFH uses HID over PCIe bus.SFH fw is part of MP2
> > processor and it runs on MP2 where in driver resides
> > on X86.This part of module will communicate with MP2 FW and
> > provide that data into DRAM
> >
> > Signed-off-by: Sandeep Singh <[email protected]>
> > Signed-off-by: Nehal Shah <[email protected]>
> > Reported-by: kbuild test robot <[email protected]>
Any possibility of using devm_* calls for both pci_* and memory
allocation?
Thanks,
Srinivas
> > ---
> > drivers/hid/Kconfig | 2 +
> > drivers/hid/Makefile | 1 +
> > drivers/hid/amd-sfh-hid/Kconfig | 17 +++
> > drivers/hid/amd-sfh-hid/Makefile | 17 +++
> > drivers/hid/amd-sfh-hid/amd_mp2_pcie.c | 256
> > +++++++++++++++++++++++++++++++++
> > drivers/hid/amd-sfh-hid/amd_mp2_pcie.h | 169
> > ++++++++++++++++++++++
> > 6 files changed, 462 insertions(+)
> > create mode 100644 drivers/hid/amd-sfh-hid/Kconfig
> > create mode 100644 drivers/hid/amd-sfh-hid/Makefile
> > create mode 100644 drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> > create mode 100644 drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
> >
> > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> > index 494a39e..b253ad1 100644
> > --- a/drivers/hid/Kconfig
> > +++ b/drivers/hid/Kconfig
> > @@ -1155,4 +1155,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 bfefa36..15a08e8 100644
> > --- a/drivers/hid/Makefile
> > +++ b/drivers/hid/Makefile
> > @@ -139,3 +139,4 @@ 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 0000000..e2dee39
> > --- /dev/null
> > +++ b/drivers/hid/amd-sfh-hid/Kconfig
> > @@ -0,0 +1,17 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +menu "AMD SFH HID support"
> > + depends on (X86_64 || COMPILE_TEST) && PCI
> > +
> > +config AMD_SFH_HID
> > + tristate "AMD Sensor Fusion Hub"
> > + default n
> > + select HID
> > + help
> > + If you say yes to this option, support will be included for
> > the AMD
> > + Sensor Fusion Hub.
> > +
> > + This driver can also be built as modules. If so, the modules
> > will
> > + be called amd-mp2-pcie and amd-sfhtp-hid.
> > + Say Y 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 0000000..5aae934
> > --- /dev/null
> > +++ b/drivers/hid/amd-sfh-hid/Makefile
> > @@ -0,0 +1,17 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +#
> > +# Makefile - AMD SFH HID drivers
> > +# Copyright (c) 2019-2020, Advanced Micro Devices, Inc.
> > +#
> > +#
> > +ccflags-m := -Werror
> > +obj-$(CONFIG_AMD_SFH_HID) += amd-mp2-pcie.o
> > +amd-mp2-pcie-objs := amd_mp2_pcie.o
> > +
> > +obj-$(CONFIG_AMD_SFH_HID) +=amd-sfhtp-hid.o
> > +amd-sfhtp-hid-objs := amdsfh-hid.o
> > +amd-sfhtp-hid-objs+= amdsfh-hid-client.o
> > +amd-sfhtp-hid-objs+= amdsfh-debugfs.o
> > +amd-sfhtp-hid-objs+= hid_descriptor/amd_sfh_hid_descriptor.o
> > +
> > +ccflags-y += -I$(srctree)/$(src)/
> > diff --git a/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> > b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> > new file mode 100644
> > index 0000000..f264d60
> > --- /dev/null
> > +++ b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> > @@ -0,0 +1,256 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * AMD MP2 PCIe communication driver
> > + *
> > + * Authors: Shyam Sundar S K <[email protected]>
> > + * Nehal Bakulchandra Shah <
> > [email protected]>
> > + */
> > +
> > +#include "amd_mp2_pcie.h"
> > +#include <linux/interrupt.h>
> > +#include <linux/module.h>
> > +#include <linux/pci.h>
> > +#include <linux/slab.h>
> > +#include <linux/delay.h>
> > +
> > +#define DRIVER_NAME "pcie_mp2_amd"
> > +#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
> > +#define DRIVER_VER "1.0"
> > +
> > +#define ACEL_EN BIT(ACCEL_IDX)
> > +#define GYRO_EN BIT(GYRO_IDX)
> > +#define MAGNO_EN BIT(MAG_IDX)
> > +#define ALS_EN BIT(AMBIENT_LIGHT_IDX)
> > +
> > +int amd_start_sensor(struct pci_dev *pdev, struct
> > amd_mp2_sensor_info info)
> > +{
> > + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> > + union sfh_cmd_base cmd_base;
> > + union sfh_command_parameter cmd_param;
> > +
> > + /*fill up command register*/
> > + cmd_base.ul = 0;
> > + 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*/
> > + cmd_param.ul = 0;
> > + cmd_param.s.buffer_layout = 1;
> > + cmd_param.s.buffer_length = 16;
> > +
> > + write64((u64)info.phy_address, privdata->mmio + AMD_C2P_MSG2);
> > + writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
> > + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(amd_start_sensor);
> > +
> > +int amd_stop_sensor(struct pci_dev *pdev, u16 sensor_idx)
> > +{
> > + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> > + union sfh_cmd_base cmd_base;
> > +
> > + /* fill up command register */
> > + cmd_base.ul = 0;
> > + cmd_base.s.cmd_id = disable_sensor;
> > + cmd_base.s.period = 0;
> > + cmd_base.s.sensor_id = sensor_idx;
> > +
> > + write64(0x0, privdata->mmio + AMD_C2P_MSG2);
> > + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(amd_stop_sensor);
> > +
> > +int amd_stop_all_sensors(struct pci_dev *pdev)
> > +{
> > + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> > + union sfh_cmd_base cmd_base;
> > +
> > + /*fill up command register */
> > + cmd_base.ul = 0;
> > + 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);
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(amd_stop_all_sensors);
> > +
> > +int amd_mp2_get_sensor_num(struct pci_dev *dev, u8 *sensor_id)
> > +{
> > + struct amd_mp2_dev *privdata = pci_get_drvdata(dev);
> > + int activestatus;
> > + int num_of_sensors = 0;
> > +
> > + if (!sensor_id)
> > + return -ENOMEM;
> > +
> > + privdata->eventreg.activecontrolstatus =
> > + readl(privdata->mmio + AMD_P2C_MSG3);
> > + activestatus = privdata->eventreg.activecontrolstatus >> 4;
> > +
> > + if (ACEL_EN & activestatus) {
> > + sensor_id[num_of_sensors] = ACCEL_IDX;
> > + num_of_sensors++;
> > + }
> > + if (GYRO_EN & activestatus) {
> > + sensor_id[num_of_sensors] = GYRO_IDX;
> > + num_of_sensors++;
> > + }
> > + if (MAGNO_EN & activestatus) {
> > + sensor_id[num_of_sensors] = MAG_IDX;
> > + num_of_sensors++;
> > + }
> > +
> > + if (ALS_EN & activestatus) {
> > + sensor_id[num_of_sensors] = AMBIENT_LIGHT_IDX;
> > + num_of_sensors++;
> > + }
> > +
> > + return num_of_sensors;
> > +}
> > +EXPORT_SYMBOL_GPL(amd_mp2_get_sensor_num);
> > +
> > +static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, struct
> > pci_dev *pdev)
> > +{
> > + int rc;
> > + int bar_index = 2;
> > + resource_size_t size, base;
> > +
> > + pci_set_drvdata(pdev, privdata);
> > +
> > + rc = pci_enable_device(pdev);
> > + if (rc)
> > + goto err_pci_enable;
> > +
> > + rc = pci_request_regions(pdev, DRIVER_NAME);
> > + if (rc)
> > + goto err_pci_regions;
> > +
> > + 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));
> > + if (rc)
> > + goto err_dma_mask;
> > + dev_warn(ndev_dev(privdata), "Cannot DMA highmem\n");
> > + }
> > +
> > + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
> > + if (rc) {
> > + rc = pci_set_consistent_dma_mask(pdev,
> > DMA_BIT_MASK(32));
> > + if (rc)
> > + goto err_dma_mask;
> > + dev_warn(ndev_dev(privdata), "Cannot DMA consistent
> > highmem\n");
> > + }
> > +
> > + base = pci_resource_start(pdev, bar_index);
> > + size = pci_resource_len(pdev, bar_index);
> > + dev_dbg(ndev_dev(privdata), "Base addr:%llx size:%llx\n",
> > + (unsigned long long)base, (unsigned long long)size);
> > +
> > + privdata->mmio = ioremap(base, size);
> > + if (!privdata->mmio) {
> > + rc = -EIO;
> > + goto err_dma_mask;
> > + }
> > +
> > + return 0;
> > +
> > +err_dma_mask:
> > + pci_clear_master(pdev);
> > + pci_release_regions(pdev);
> > +err_pci_regions:
> > + pci_disable_device(pdev);
> > +err_pci_enable:
> > + pci_set_drvdata(pdev, NULL);
> > + return rc;
> > +}
> > +
> > +static void amd_mp2_pci_deinit(struct amd_mp2_dev *privdata)
> > +{
> > + struct pci_dev *pdev = ndev_pdev(privdata);
> > +
> > + amd_stop_all_sensors(pdev);
> > + pci_iounmap(pdev, privdata->mmio);
> > +
> > + pci_clear_master(pdev);
> > + pci_release_regions(pdev);
> > + pci_disable_device(pdev);
> > + pci_set_drvdata(pdev, NULL);
> > +}
> > +
> > +static int amd_mp2_pci_probe(struct pci_dev *pdev,
> > + const struct pci_device_id *id)
> > +{
> > + struct amd_mp2_dev *privdata;
> > + int rc;
> > +
> > + dev_info(&pdev->dev, "MP2 device found [%04x:%04x] (rev %x)\n",
> > + (int)pdev->vendor, (int)pdev->device, (int)pdev-
> > >revision);
> > +
> > + privdata = kzalloc(sizeof(*privdata), GFP_KERNEL);
> > +
> > + if (!privdata) {
> > + rc = -ENOMEM;
> > + goto err_dev;
> > + }
> > +
> > + privdata->pdev = pdev;
> > +
> > + rc = amd_mp2_pci_init(privdata, pdev);
> > + if (rc)
> > + goto err_pci_init;
> > +
> > + return 0;
> > +
> > +err_pci_init:
> > + kfree(privdata);
> > +err_dev:
> > + dev_err(&pdev->dev, "Memory Allocation Failed\n");
> > + return rc;
> > +}
> > +
> > +static void amd_mp2_pci_remove(struct pci_dev *pdev)
> > +{
> > + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> > +
> > + amd_mp2_pci_deinit(privdata);
> > + kfree(privdata);
> > +}
> > +
> > +static const struct pci_device_id amd_mp2_pci_tbl[] = {
> > + {PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2)},
> > + {0}
> > +};
> > +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,
> > + .remove = amd_mp2_pci_remove,
> > +};
> > +
> > +static int __init amd_mp2_pci_driver_init(void)
> > +{
> > + return pci_register_driver(&amd_mp2_pci_driver);
> > +}
> > +module_init(amd_mp2_pci_driver_init);
> > +
> > +static void __exit amd_mp2_pci_driver_exit(void)
> > +{
> > + pci_unregister_driver(&amd_mp2_pci_driver);
> > +}
> > +module_exit(amd_mp2_pci_driver_exit);
> > +MODULE_DESCRIPTION(DRIVER_DESC);
> > +MODULE_VERSION(DRIVER_VER);
> > +MODULE_LICENSE("Dual BSD/GPL");
> > +MODULE_AUTHOR("Shyam Sundar S K <[email protected]>");
> > +MODULE_AUTHOR("Nehal Bakulchandra Shah <
> > [email protected]>");
> > diff --git a/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
> > b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
> > new file mode 100644
> > index 0000000..2bfd2de
> > --- /dev/null
> > +++ b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
> > @@ -0,0 +1,169 @@
> > +/* SPDX-License-Identifier: GPL-2.0
> > + *
> > + * AMD MP2 PCIe communication driver
> > + *
> > + * Authors: Shyam Sundar S K <[email protected]>
> > + * Nehal Bakulchandra Shah <
> > [email protected]>
> > + */
> > +
> > +#ifndef PCIE_MP2_AMD_H
> > +#define PCIE_MP2_AMD_H
> > +
> > +#include <linux/pci.h>
> > +#define PCI_DEVICE_ID_AMD_MP2 0x15E4
> > +
> > +#define write64 _write64
> > +static inline void _write64(u64 val, void __iomem *mmio)
> > +{
> > + writel(val, mmio);
> > + writel(val >> 32, mmio + sizeof(u32));
> > +}
> > +
> > +#define read64 _read64
> > +static inline u64 _read64(void __iomem *mmio)
> > +{
> > + u64 low, high;
> > +
> > + low = readl(mmio);
> > + high = readl(mmio + sizeof(u32));
> > + return low | (high << 32);
> > +}
> > +
> > +enum {
> > + /* MP2 C2P Message Registers */
> > + AMD_C2P_MSG0 = 0x10500,
> > + AMD_C2P_MSG1 = 0x10504,
> > + AMD_C2P_MSG2 = 0x10508,
> > + AMD_C2P_MSG3 = 0x1050c,
> > + AMD_C2P_MSG4 = 0x10510,
> > + AMD_C2P_MSG5 = 0x10514,
> > + AMD_C2P_MSG6 = 0x10518,
> > + AMD_C2P_MSG7 = 0x1051c,
> > + AMD_C2P_MSG8 = 0x10520,
> > + AMD_C2P_MSG9 = 0x10524,
> > +
> > + /* MP2 P2C Message Registers */
> > + AMD_P2C_MSG0 = 0x10680, /*Do not use*/
> > + AMD_P2C_MSG1 = 0x10684,
> > + AMD_P2C_MSG2 = 0x10688,
> > + AMD_P2C_MSG3 = 0x1068C, /*MP2 debug info*/
> > + AMD_P2C_MSG_INTEN = 0x10690, /*MP2 int gen register*/
> > + AMD_P2C_MSG_INTSTS = 0x10694, /*Interrupt sts*/
> > +};
> > +
> > +/*
> > + * SFH Command registers
> > + */
> > +union sfh_cmd_base {
> > + u32 ul;
> > + struct {
> > + u32 cmd_id : 8;
> > + u32 sensor_id : 8;
> > + u32 period : 16;
> > + } s; /*!< Structure used for bit access */
> > +};
> > +
> > +union sfh_command_parameter {
> > + u32 ul;
> > + struct {
> > + u32 buffer_layout : 2;
> > + u32 buffer_length : 6;
> > + u32 rsvd : 24;
> > + } s;
> > +};
> > +
> > +struct sfh_command_register {
> > + union sfh_cmd_base cmd_base;
> > + union sfh_command_parameter cmd_param;
> > + phys_addr_t phy_addr;
> > +};
> > +
> > +/*
> > + * SFH Response registers
> > + */
> > +enum response_type {
> > + non_operationevent,
> > + command_success,
> > + command_failed,
> > + sfi_dataready_event,
> > + invalid_response = 0xff,
> > +};
> > +
> > +enum status_type {
> > + cmd_success,
> > + invalid_data_payload,
> > + invalid_data_length,
> > + invalid_sensor_id,
> > + invalid_dram_addr,
> > + invalid_command,
> > + sensor_enabled,
> > + sensor_disabled,
> > + status_end,
> > +};
> > +
> > +enum command_id {
> > + non_operation = 0,
> > + enable_sensor = 1,
> > + disable_sensor = 2,
> > + dump_sensorinfo = 3,
> > + numberof_sensordiscovered = 4,
> > + who_am_i_regchipid = 5,
> > + set_dcd_data = 6,
> > + get_dcd_data = 7,
> > + stop_all_sensors = 8,
> > + invalid_cmd = 0xf,
> > +};
> > +
> > +union sfh_event_base {
> > + u32 ul;
> > + struct {
> > + u32 response : 4; /*!< bit: 0..3 SFI response_type */
> > + u32 status : 3; /*!< bit: 6..5 status_type */
> > + u32 out_in_c2p : 1; /*!< bit: 5 0- output in DRAM,1-in
> > C2PMsg */
> > + u32 length : 6; /*!< bit: 8..13 length */
> > + u32 dbg : 2; /*!< bit: 14.15 dbg msg include in p2c msg
> > 1-2 */
> > + u32 sensor_id : 8; /*!< bit: 16..23 Sensor ID */
> > + u32 rsvd : 8; /*!< bit: 24..31 Reservered for future
> > use */
> > + } s;
> > +};
> > +
> > +struct sfi_event_register {
> > + union sfh_event_base evtbase;
> > + u32 debuginfo1;
> > + u32 debuginfo2;
> > + u32 activecontrolstatus;
> > +};
> > +
> > +enum sensor_idx {
> > + ACCEL_IDX = 0,
> > + GYRO_IDX = 1,
> > + MAG_IDX = 2,
> > + AMBIENT_LIGHT_IDX = 19,
> > + NUM_ALL_SENSOR_CONSUMERS
> > +};
> > +
> > +struct amd_mp2_dev {
> > + struct pci_dev *pdev;
> > + struct dentry *debugfs_dir;
> > + void __iomem *mmio;
> > + union sfh_event_base eventval;
> > + struct sfi_event_register eventreg;
> > + struct delayed_work work;
> > + void *ctx;
> > + void *cl_data;
> > +};
> > +
> > +struct amd_mp2_sensor_info {
> > + u8 sensor_idx;
> > + u32 period;
> > + phys_addr_t phy_address;
> > +};
> > +
> > +int amd_start_sensor(struct pci_dev *pdev, struct
> > amd_mp2_sensor_info info);
> > +int amd_stop_sensor(struct pci_dev *pdev, u16 sensor_idx);
> > +int amd_stop_all_sensors(struct pci_dev *pdev);
> > +int amd_mp2_get_sensor_num(struct pci_dev *dev, u8 *sensor_id);
> > +#define ndev_pdev(ndev) ((ndev)->pdev)
> > +#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
> > +#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
> > +#endif
> >
>
> any update on this?
>
> Thanks
>
> Nehal Shah
On Wed, 2020-01-29 at 09:57 +0530, Sandeep Singh wrote:
> From: Sandeep Singh <[email protected]>
>
> Add Maintainer list for AMD SFH
SFH (SENSOR FUSION HUB)
This way it will be clear what is SFH.
> Solution and work flow
> document.
>
> Signed-off-by: Nehal Shah <[email protected]>
> Signed-off-by: Sandeep Singh <[email protected]>
> ---
> Documentation/hid/amd-sfh-hid.rst | 159
> ++++++++++++++++++++++++++++++++++++++
> MAINTAINERS | 8 ++
> 2 files changed, 167 insertions(+)
> create mode 100644 Documentation/hid/amd-sfh-hid.rst
>
> diff --git a/Documentation/hid/amd-sfh-hid.rst
> b/Documentation/hid/amd-sfh-hid.rst
> new file mode 100644
> index 0000000..1183350
> --- /dev/null
> +++ b/Documentation/hid/amd-sfh-hid.rst
> @@ -0,0 +1,159 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +AMD Sensor Fusion Hub:-
> +======================
> +AMD sensor fushion Hub is part of a SOC starting from ryzon based
> platforms.
> +The solution is working well on windows OS in several
> +OEM products. AMD SFH uses HID over PCIe bus. In terms of
> architecture
> +it is much more resmebles like ISH .However the major diffrence is
> all
> +The hid reports are generated as part of kernel driver.
> +
> +Block Diagram:-
> +=============
> + -------------------------------
> + | HID User Space Applications |
> + -------------------------------
> +---------------------------------------------
> + ---------------------------------
> + | HID Core |
> + ---------------------------------
> +
> + ---------------------------------
> + | AMD HID Transport Driver |
> + ---------------------------------
> +
> + --------------------------------
> + | AMD HID Client Driver |
> + | with HID Report Generator|
> + --------------------------------
> +
> + --------------------------------
> + | AMD MP2 PCIe Driver |
> + --------------------------------
> +---------------------------------------------
> + -------------------------------
> + | 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.
> +The driver, which binds each device (AMD SFH HID driver) identifies
> +the device type and registers with the hid core. Transport drivers
> +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 driver implements the synchronous calls.
> +
> +AMD HID Client Driver:-
> +**********************
> +This driver is responsible to implement HID request and descriptors.
> +As firmware is OS agnostic, HID client driver fills the HID request
> +structure and descriptors. HID client driver is in complex in nature
> +as it is interface between MP2 PCIe driver and HID. HID client
> driver
> +initialized the MP2 PCIe driver and holds the instance of MP2
> driver.
> +It identified the number of sensors connected using MP2- PCIe driver
> and
> +based on that allocate the DRAM address for each and every sensor
> and
> +pass it to MP2-PCIe driver.
> +On enumeration of each sensor, client driver fills out the HID
> Descriptor
> +structure and HID input report structure. HID Feature report
> structure can
> +be optional. The report descriptor structure varies sensor to
> sensor.
> +Now on enumeration client driver does two major things
> +1. Register the HID sensor client to virtual bus (Platform driver)
> and bind it.
> +2. Probes the AMD HID transport driver. Which in turns register
> device to the core.
> +
> +AMD MP2 PCIe Driver:-
> +********************
> +MP2 PCIe driver is responsible for making all transaction with the
> firmware over
> +PCIe.The connection establishment between firmware and MP2 PCIe
> driver happens here.
> +
> +The communication between X86 and MP2 is spilt into three parts.
> +1. Command Transfer => C2P Mailbox Register are used
> +2. Data Transfer => DRAM
> +
> +Commands are sent to MP2 using C2P Mail Box registers. These
> C2P registers
> +are mapped in PCIe address space.Writing into C2P Message register
> generate
> +interrupt to MP2. The client driver allocates the physical memory
> and send
> +the same to MP2 for data transfer. MP2 firmware uses DRAM interface
> registers
> +to indirectly access DRAM memory. For Firmware always write minimum
> 32 bytes
> +into DRAM.So it is expected that driver shall allocate minimum 32
> bytes DRAM space.
> +
> +Enumeration and Probing flow:-
> +*****************************
> + HID AMD AMD AMD
> -PCIe MP2
> + Core Transport Client
> Driver Driver 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:-
> +*************************************************
> +
> + | | | |
> |
> +Get | | | |
> |
> +Input | | | |
> |
> +Report | | |
> | |
> +---> | | |
> | |
> + |HID_req | | |
> |
> + |get_report | | |
> |
> + |-------------
> >| | | |
> + | |
> HID_get_input| | |
> + | | report | |
> |
> + | |------------->|----------------------
> --| | |
> + | | | Read the DRAM data
> for| | |
> + | | | requsted sensor
> and | | |
> + | | | create the HID
> input | | |
> + | | | report | |
> |
> + | | |----------------------
> --| | |
> + | |Data received
> | | |
> + | | in HID
> report| | |
> + To |<-------------|<-------------
> | | |
> +Applications | | |
> |
> +<-------
> | | | |
> |
> +
> +
> +Data Flow from AMD SFH Driver to Application:-
> +**********************************************
> + | | |
> | |
> + | | |----------------------
> --| | |
> + | | |Periodically
> Read | | |
> + | | |the data for
> all | | |
> + | | |enumerated
> sensors | | |
> + | | |from the dram and
> create| | |
> + | | | HID Input
> reports | | |
> + | | |----------------------
> --| | |
> + | |HID
> Input | | |
> + | |Input
> report | | |
> + <----submit to Application-----
> | | |
> + | | | |
> |
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 56765f5..7cfeb5a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -884,6 +884,14 @@ S: Supported
> F: drivers/net/ethernet/amd/xgbe/
> F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
>
> +AMD SENSOR FUSION HUB DRIVER
> +M: Nehal Shah <[email protected]>
> +M: Sandeep Singh <[email protected]>
> +L: [email protected]
> +S: Maintained
> +F: Documentation/hid/amd-sfh*
> +F: drivers/hid/amd-sfh-hid/
> +
> ANALOG DEVICES INC AD5686 DRIVER
> M: Stefan Popa <[email protected]>
> L: [email protected]
On Wed, 2020-01-29 at 09:57 +0530, Sandeep Singh wrote:
> From: Sandeep Singh <[email protected]>
>
> AMD SFH uses HID over PCIe bus.SFH fw is part of MP2
> processor and it runs on MP2
First time explain MP2 means.
> where in driver resides
> on X86.This part of module will communicate with MP2 FW and
> provide that data into DRAM
Some minor comments below.
>
> Signed-off-by: Sandeep Singh <[email protected]>
> Signed-off-by: Nehal Shah <[email protected]>
> Reported-by: kbuild test robot <[email protected]>
> ---
> drivers/hid/Kconfig | 2 +
> drivers/hid/Makefile | 1 +
> drivers/hid/amd-sfh-hid/Kconfig | 17 +++
> drivers/hid/amd-sfh-hid/Makefile | 17 +++
> drivers/hid/amd-sfh-hid/amd_mp2_pcie.c | 256
> +++++++++++++++++++++++++++++++++
> drivers/hid/amd-sfh-hid/amd_mp2_pcie.h | 169 ++++++++++++++++++++++
> 6 files changed, 462 insertions(+)
> create mode 100644 drivers/hid/amd-sfh-hid/Kconfig
> create mode 100644 drivers/hid/amd-sfh-hid/Makefile
> create mode 100644 drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> create mode 100644 drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
>
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index 494a39e..b253ad1 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -1155,4 +1155,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 bfefa36..15a08e8 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -139,3 +139,4 @@ 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 0000000..e2dee39
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/Kconfig
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +menu "AMD SFH HID support"
> + depends on (X86_64 || COMPILE_TEST) && PCI
> +
> +config AMD_SFH_HID
> + tristate "AMD Sensor Fusion Hub"
> + default n
By default is "n" anyway, so don't need this line.
> + select HID
> + help
> + If you say yes to this option, support will be included for
> the AMD
> + Sensor Fusion Hub.
Better to explain, what user will get benefit. This way user will make
sure that they will include this option.
> +
> + This driver can also be built as modules. If so, the modules
> will
> + be called amd-mp2-pcie and amd-sfhtp-hid.
What is mp2?
> + 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 0000000..5aae934
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/Makefile
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Makefile - AMD SFH HID drivers
> +# Copyright (c) 2019-2020, Advanced Micro Devices, Inc.
> +#
> +#
> +ccflags-m := -Werror
> +obj-$(CONFIG_AMD_SFH_HID) += amd-mp2-pcie.o
> +amd-mp2-pcie-objs := amd_mp2_pcie.o
> +
> +obj-$(CONFIG_AMD_SFH_HID) +=amd-sfhtp-hid.o
> +amd-sfhtp-hid-objs := amdsfh-hid.o
> +amd-sfhtp-hid-objs+= amdsfh-hid-client.o
> +amd-sfhtp-hid-objs+= amdsfh-debugfs.o
> +amd-sfhtp-hid-objs+= hid_descriptor/amd_sfh_hid_descriptor.o
> +
> +ccflags-y += -I$(srctree)/$(src)/
> diff --git a/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> new file mode 100644
> index 0000000..f264d60
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.c
> @@ -0,0 +1,256 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * AMD MP2 PCIe communication driver
> + *
> + * Authors: Shyam Sundar S K <[email protected]>
> + * Nehal Bakulchandra Shah <[email protected]
> >
> + */
> +
> +#include "amd_mp2_pcie.h"
This should be at the end.
First standard include for <linux/*> then local includes
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +
> +#define DRIVER_NAME "pcie_mp2_amd"
> +#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
> +#define DRIVER_VER "1.0"
Do you think you will keep updating this version number for changes?
> +
> +#define ACEL_EN BIT(ACCEL_IDX)
> +#define GYRO_EN BIT(GYRO_IDX)
> +#define MAGNO_EN BIT(MAG_IDX)
> +#define ALS_EN BIT(AMBIENT_LIGHT_IDX)
> +
> +int amd_start_sensor(struct pci_dev *pdev, struct
> amd_mp2_sensor_info info)
> +{
> + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> + union sfh_cmd_base cmd_base;
> + union sfh_command_parameter cmd_param;
> +
Generally better to define local variable in the order, for example for
the above. Same for other functions.
struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
union sfh_command_parameter cmd_param;
union sfh_cmd_base cmd_base;
> + /*fill up command register*/
> + cmd_base.ul = 0;
> + 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*/
> + cmd_param.ul = 0;
> + cmd_param.s.buffer_layout = 1;
> + cmd_param.s.buffer_length = 16;
> +
> + write64((u64)info.phy_address, privdata->mmio + AMD_C2P_MSG2);
> + writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
> + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
> + return 0;
Can this function be void(). There is no error return anywhere?
Same for the function below.
> +}
> +EXPORT_SYMBOL_GPL(amd_start_sensor);
> +
> +int amd_stop_sensor(struct pci_dev *pdev, u16 sensor_idx)
> +{
> + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> + union sfh_cmd_base cmd_base;
> +
> + /* fill up command register */
> + cmd_base.ul = 0;
> + cmd_base.s.cmd_id = disable_sensor;
> + cmd_base.s.period = 0;
> + cmd_base.s.sensor_id = sensor_idx;
> +
> + write64(0x0, privdata->mmio + AMD_C2P_MSG2);
> + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(amd_stop_sensor);
> +
> +int amd_stop_all_sensors(struct pci_dev *pdev)
> +{
> + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> + union sfh_cmd_base cmd_base;
> +
> + /*fill up command register */
> + cmd_base.ul = 0;
> + 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);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(amd_stop_all_sensors);
> +
> +int amd_mp2_get_sensor_num(struct pci_dev *dev, u8 *sensor_id)
> +{
> + struct amd_mp2_dev *privdata = pci_get_drvdata(dev);
> + int activestatus;
> + int num_of_sensors = 0;
> +
> + if (!sensor_id)
> + return -ENOMEM;
> +
> + privdata->eventreg.activecontrolstatus =
> + readl(privdata->mmio + AMD_P2C_MSG3);
> + activestatus = privdata->eventreg.activecontrolstatus >> 4;
> +
> + if (ACEL_EN & activestatus) {
> + sensor_id[num_of_sensors] = ACCEL_IDX;
> + num_of_sensors++;
> + }
> + if (GYRO_EN & activestatus) {
> + sensor_id[num_of_sensors] = GYRO_IDX;
> + num_of_sensors++;
> + }
> + if (MAGNO_EN & activestatus) {
> + sensor_id[num_of_sensors] = MAG_IDX;
> + num_of_sensors++;
> + }
> +
> + if (ALS_EN & activestatus) {
> + sensor_id[num_of_sensors] = AMBIENT_LIGHT_IDX;
> + num_of_sensors++;
> + }
> +
> + return num_of_sensors;
> +}
> +EXPORT_SYMBOL_GPL(amd_mp2_get_sensor_num);
> +
> +static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, struct
> pci_dev *pdev)
> +{
> + int rc;
> + int bar_index = 2;
> + resource_size_t size, base;
> +
> + pci_set_drvdata(pdev, privdata);
> +
> + rc = pci_enable_device(pdev);
> + if (rc)
> + goto err_pci_enable;
> +
> + rc = pci_request_regions(pdev, DRIVER_NAME);
> + if (rc)
> + goto err_pci_regions;
> +
> + 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));
> + if (rc)
> + goto err_dma_mask;
> + dev_warn(ndev_dev(privdata), "Cannot DMA highmem\n");
If rc, you are returning from the function. Why dev_Warn?
> + }
> +
> + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
> + if (rc) {
> + rc = pci_set_consistent_dma_mask(pdev,
> DMA_BIT_MASK(32));
> + if (rc)
> + goto err_dma_mask;
> + dev_warn(ndev_dev(privdata), "Cannot DMA consistent
> highmem\n");
Why dev_warn?
> + }
> +
> + base = pci_resource_start(pdev, bar_index);
> + size = pci_resource_len(pdev, bar_index);
> + dev_dbg(ndev_dev(privdata), "Base addr:%llx size:%llx\n",
> + (unsigned long long)base, (unsigned long long)size);
> + privdata->mmio = ioremap(base, size);
> + if (!privdata->mmio) {
> + rc = -EIO;
> + goto err_dma_mask;
> + }
> +
> + return 0;
> +
> +err_dma_mask:
> + pci_clear_master(pdev);
> + pci_release_regions(pdev);
> +err_pci_regions:
> + pci_disable_device(pdev);
> +err_pci_enable:
> + pci_set_drvdata(pdev, NULL);
> + return rc;
> +}
> +
> +static void amd_mp2_pci_deinit(struct amd_mp2_dev *privdata)
> +{
> + struct pci_dev *pdev = ndev_pdev(privdata);
> +
> + amd_stop_all_sensors(pdev);
> + pci_iounmap(pdev, privdata->mmio);
> +
> + pci_clear_master(pdev);
> + pci_release_regions(pdev);
> + pci_disable_device(pdev);
> + pci_set_drvdata(pdev, NULL);
> +}
> +
> +static int amd_mp2_pci_probe(struct pci_dev *pdev,
> + const struct pci_device_id *id)
> +{
> + struct amd_mp2_dev *privdata;
> + int rc;
> +
> + dev_info(&pdev->dev, "MP2 device found [%04x:%04x] (rev %x)\n",
> + (int)pdev->vendor, (int)pdev->device, (int)pdev-
> >revision);
Better dev_dbg. On the most of the distro kernel, you will see this
message in dmesg, even if you don't need unless debugging.
> +
> + privdata = kzalloc(sizeof(*privdata), GFP_KERNEL);
>
> +
> + if (!privdata) {
> + rc = -ENOMEM;
> + goto err_dev;
> + }
> +
> + privdata->pdev = pdev;
> +
> + rc = amd_mp2_pci_init(privdata, pdev);
> + if (rc)
> + goto err_pci_init;
> +
> + return 0;
> +
> +err_pci_init:
> + kfree(privdata);
> +err_dev:
> + dev_err(&pdev->dev, "Memory Allocation Failed\n");
You don't need memory allocation failure error, there are other prints
will show this.
> + return rc;
> +}
> +
> +static void amd_mp2_pci_remove(struct pci_dev *pdev)
> +{
> + struct amd_mp2_dev *privdata = pci_get_drvdata(pdev);
> +
> + amd_mp2_pci_deinit(privdata);
> + kfree(privdata);
> +}
> +
> +static const struct pci_device_id amd_mp2_pci_tbl[] = {
> + {PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2)},
> + {0}
> +};
> +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,
> + .remove = amd_mp2_pci_remove,
> +};
> +
> +static int __init amd_mp2_pci_driver_init(void)
> +{
> + return pci_register_driver(&amd_mp2_pci_driver);
> +}
> +module_init(amd_mp2_pci_driver_init);
> +
> +static void __exit amd_mp2_pci_driver_exit(void)
> +{
> + pci_unregister_driver(&amd_mp2_pci_driver);
> +}
> +module_exit(amd_mp2_pci_driver_exit);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_VERSION(DRIVER_VER);
> +MODULE_LICENSE("Dual BSD/GPL");
> +MODULE_AUTHOR("Shyam Sundar S K <[email protected]>");
> +MODULE_AUTHOR("Nehal Bakulchandra Shah <
> [email protected]>");
> diff --git a/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
> b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
> new file mode 100644
> index 0000000..2bfd2de
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/amd_mp2_pcie.h
> @@ -0,0 +1,169 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * AMD MP2 PCIe communication driver
> + *
> + * Authors: Shyam Sundar S K <[email protected]>
> + * Nehal Bakulchandra Shah <[email protected]
> >
> + */
> +
> +#ifndef PCIE_MP2_AMD_H
> +#define PCIE_MP2_AMD_H
> +
> +#include <linux/pci.h>
> +#define PCI_DEVICE_ID_AMD_MP2 0x15E4
> +
> +#define write64 _write64
When you are defining a special write64, better to prefix with
something. This way this will not be confused with some API.
Same for read64.
> +static inline void _write64(u64 val, void __iomem *mmio)
> +{
> + writel(val, mmio);
> + writel(val >> 32, mmio + sizeof(u32));
> +}
> +
> +#define read64 _read64
> +static inline u64 _read64(void __iomem *mmio)
> +{
> + u64 low, high;
> +
> + low = readl(mmio);
> + high = readl(mmio + sizeof(u32));
> + return low | (high << 32);
> +}
> +
> +enum {
> + /* MP2 C2P Message Registers */
> + AMD_C2P_MSG0 = 0x10500,
> + AMD_C2P_MSG1 = 0x10504,
> + AMD_C2P_MSG2 = 0x10508,
> + AMD_C2P_MSG3 = 0x1050c,
> + AMD_C2P_MSG4 = 0x10510,
> + AMD_C2P_MSG5 = 0x10514,
> + AMD_C2P_MSG6 = 0x10518,
> + AMD_C2P_MSG7 = 0x1051c,
> + AMD_C2P_MSG8 = 0x10520,
> + AMD_C2P_MSG9 = 0x10524,
> +
> + /* MP2 P2C Message Registers */
> + AMD_P2C_MSG0 = 0x10680, /*Do not use*/
> + AMD_P2C_MSG1 = 0x10684,
> + AMD_P2C_MSG2 = 0x10688,
> + AMD_P2C_MSG3 = 0x1068C, /*MP2 debug info*/
> + AMD_P2C_MSG_INTEN = 0x10690, /*MP2 int gen register*/
> + AMD_P2C_MSG_INTSTS = 0x10694, /*Interrupt sts*/
> +};
Why not #define, when you are overriding every enum?
> +
> +/*
> + * SFH Command registers
> + */
> +union sfh_cmd_base {
> + u32 ul;
> + struct {
> + u32 cmd_id : 8;
> + u32 sensor_id : 8;
> + u32 period : 16;
> + } s; /*!< Structure used for bit access */
> +};
> +
> +union sfh_command_parameter {
> + u32 ul;
> + struct {
> + u32 buffer_layout : 2;
> + u32 buffer_length : 6;
> + u32 rsvd : 24;
> + } s;
> +};
> +
> +struct sfh_command_register {
> + union sfh_cmd_base cmd_base;
> + union sfh_command_parameter cmd_param;
> + phys_addr_t phy_addr;
> +};
> +
> +/*
> + * SFH Response registers
> + */
> +enum response_type {
> + non_operationevent,
> + command_success,
> + command_failed,
> + sfi_dataready_event,
> + invalid_response = 0xff,
> +};
> +
> +enum status_type {
> + cmd_success,
> + invalid_data_payload,
> + invalid_data_length,
> + invalid_sensor_id,
> + invalid_dram_addr,
> + invalid_command,
> + sensor_enabled,
> + sensor_disabled,
> + status_end,
> +};
> +
> +enum command_id {
> + non_operation = 0,
> + enable_sensor = 1,
> + disable_sensor = 2,
> + dump_sensorinfo = 3,
> + numberof_sensordiscovered = 4,
> + who_am_i_regchipid = 5,
> + set_dcd_data = 6,
> + get_dcd_data = 7,
> + stop_all_sensors = 8,
> + invalid_cmd = 0xf,
> +};
> +
> +union sfh_event_base {
> + u32 ul;
> + struct {
Since you are explaining every member, better to use kerneldoc style
Thanks,
Srinivas
> + u32 response : 4; /*!< bit: 0..3 SFI response_type */
> + u32 status : 3; /*!< bit: 6..5 status_type */
> + u32 out_in_c2p : 1; /*!< bit: 5 0- output in DRAM,1-in
> C2PMsg */
> + u32 length : 6; /*!< bit: 8..13 length */
> + u32 dbg : 2; /*!< bit: 14.15 dbg msg include in p2c msg
> 1-2 */
> + u32 sensor_id : 8; /*!< bit: 16..23 Sensor ID */
> + u32 rsvd : 8; /*!< bit: 24..31 Reservered for future
> use */
> + } s;
> +};
> +
> +struct sfi_event_register {
> + union sfh_event_base evtbase;
> + u32 debuginfo1;
> + u32 debuginfo2;
> + u32 activecontrolstatus;
> +};
> +
> +enum sensor_idx {
> + ACCEL_IDX = 0,
> + GYRO_IDX = 1,
> + MAG_IDX = 2,
> + AMBIENT_LIGHT_IDX = 19,
> + NUM_ALL_SENSOR_CONSUMERS
> +};
> +
> +struct amd_mp2_dev {
> + struct pci_dev *pdev;
> + struct dentry *debugfs_dir;
> + void __iomem *mmio;
> + union sfh_event_base eventval;
> + struct sfi_event_register eventreg;
> + struct delayed_work work;
> + void *ctx;
> + void *cl_data;
> +};
> +
> +struct amd_mp2_sensor_info {
> + u8 sensor_idx;
> + u32 period;
> + phys_addr_t phy_address;
> +};
> +
> +int amd_start_sensor(struct pci_dev *pdev, struct
> amd_mp2_sensor_info info);
> +int amd_stop_sensor(struct pci_dev *pdev, u16 sensor_idx);
> +int amd_stop_all_sensors(struct pci_dev *pdev);
> +int amd_mp2_get_sensor_num(struct pci_dev *dev, u8 *sensor_id);
> +#define ndev_pdev(ndev) ((ndev)->pdev)
> +#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
> +#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
> +#endif
On Wed, 2020-01-29 at 09:57 +0530, Sandeep Singh wrote:
> From: Sandeep Singh <[email protected]>
>
> This part of module will provide the interaction between HID
> framework
> and client driver.This modules will registered client driver with
> HID framework.
>
Better to have two patches. One for debugfs specific and one client
driver.
> Signed-off-by: Sandeep Singh <[email protected]>
> Signed-off-by: Nehal Shah <[email protected]>
> Reported-by: kbuild test robot <[email protected]>
> Reported-by: Dan Carpenter <[email protected]>
> ---
> drivers/hid/amd-sfh-hid/amdsfh-debugfs.c | 251
> ++++++++++++++++++++++++++
> drivers/hid/amd-sfh-hid/amdsfh-debugfs.h | 14 ++
> drivers/hid/amd-sfh-hid/amdsfh-hid-client.c | 261
> ++++++++++++++++++++++++++++
> drivers/hid/amd-sfh-hid/amdsfh-hid.c | 179
> +++++++++++++++++++
> drivers/hid/amd-sfh-hid/amdsfh-hid.h | 85 +++++++++
> 5 files changed, 790 insertions(+)
> create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-debugfs.c
> create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-debugfs.h
> create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-hid-client.c
> create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-hid.c
> create mode 100644 drivers/hid/amd-sfh-hid/amdsfh-hid.h
>
> diff --git a/drivers/hid/amd-sfh-hid/amdsfh-debugfs.c
> b/drivers/hid/amd-sfh-hid/amdsfh-debugfs.c
> new file mode 100644
> index 0000000..20859d4
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/amdsfh-debugfs.c
> @@ -0,0 +1,251 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * AMD SFH DebugFS
> + * This part of module will provide sensors raw value data
> + * for AMD SFH debugging.
> + * cat /sys/kernel/debug/amd_sfhtp_hid
> + * Author: Nehal Bakulchandra Shah <[email protected]
> >
> + */
> +
> +#include <linux/slab.h>
> +#include "amd_mp2_pcie.h"
> +#include "amdsfh-debugfs.h"
> +
> +/* DebugFS helpers */
> +#define OBUFP (obuf + oboff)
> +#define OBUFLEN 512
> +#define OBUFSPC (OBUFLEN - oboff)
> +#define OSCNPRINTF(fmt, ...) \
> + scnprintf(OBUFP, OBUFSPC, fmt, ## __VA_ARGS__)
> +
> +static ssize_t amdsfh_debugfs_accel_read(struct file *filp, char
> __user *ubuf,
> + size_t count, loff_t *offp)
> +{
> + unsigned int oboff = 0, i;
> + struct amdtp_cl_data *cl_data = filp->private_data;
> + bool found = false;
> + ssize_t ret;
> + char *obuf;
> +
> + for (i = 0; i < cl_data->num_hid_devices; i++) {
> + if (cl_data->sensor_idx[i] == ACCEL_IDX) {
> + found = true;
> + break;
> + }
> + }
> +
> + if (!found)
> + return -1;
> +
> + obuf = kmalloc(OBUFLEN, GFP_KERNEL);
> + if (!obuf)
> + return -ENOMEM;
> +
> + oboff += OSCNPRINTF("Accel_X_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][0]);
> + oboff += OSCNPRINTF("Accel_Y_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][1]);
> + oboff += OSCNPRINTF("Accel_Z_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][2]);
> + ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
> +
> + kfree(obuf);
> +
> + return ret;
> +}
> +
> +static ssize_t amdsfh_debugfs_gyro_read(struct file *filp, char
> __user *ubuf,
> + size_t count, loff_t *offp)
> +{
> + unsigned int oboff = 0, i;
> + bool found = false;
> + struct amdtp_cl_data *cl_data = filp->private_data;
> + ssize_t ret;
> + char *obuf;
> +
> + for (i = 0; i < cl_data->num_hid_devices; i++) {
> + if (cl_data->sensor_idx[i] == GYRO_IDX) {
> + found = true;
> + break;
> + }
> + }
> +
> + if (!found)
> + return -1;
> +
> + obuf = kmalloc(OBUFLEN, GFP_KERNEL);
> + if (!obuf)
> + return -ENOMEM;
> +
> + oboff += OSCNPRINTF("Gyro_X_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][0]);
> + oboff += OSCNPRINTF("Gyro_Y_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][1]);
> + oboff += OSCNPRINTF("Gyro_Z_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][2]);
> + ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
> +
> + kfree(obuf);
> +
> + return ret;
> +}
> +
> +static ssize_t amdsfh_debugfs_mag_read(struct file *filp, char
> __user *ubuf,
> + size_t count, loff_t *offp)
> +{
> + unsigned int oboff = 0, i;
> + bool found = false;
> + ssize_t ret;
> + char *obuf;
> + struct amdtp_cl_data *cl_data = filp->private_data;
> +
> + for (i = 0; i < cl_data->num_hid_devices; i++) {
> + if (cl_data->sensor_idx[i] == MAG_IDX) {
> + found = true;
> + break;
> + }
> + }
> +
> + if (!found)
> + return -1;
> +
> + obuf = kmalloc(OBUFLEN, GFP_KERNEL);
> + if (!obuf)
> + return -ENOMEM;
> +
> + oboff += OSCNPRINTF("Mag_X_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][0]);
> + oboff += OSCNPRINTF("Mag_Y_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][1]);
> + oboff += OSCNPRINTF("Mag_Z_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][2]);
> + ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
> +
> + kfree(obuf);
> +
> + return ret;
> +}
> +
> +static ssize_t amdsfh_debugfs_als_read(struct file *filp, char
> __user *ubuf,
> + size_t count, loff_t *offp)
> +{
> + unsigned int oboff = 0, i;
> + bool found = false;
> + ssize_t ret;
> + char *obuf;
> + struct amdtp_cl_data *cl_data = filp->private_data;
> +
> + for (i = 0; i < cl_data->num_hid_devices; i++) {
> + if (cl_data->sensor_idx[i] == AMBIENT_LIGHT_IDX) {
> + found = true;
> + break;
> + }
> + }
> +
> + if (!found)
> + return -1;
> +
> + obuf = kmalloc(OBUFLEN, GFP_KERNEL);
> + if (!obuf)
> + return -ENOMEM;
> +
> + oboff += OSCNPRINTF("Gyro_X_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][0]);
> + oboff += OSCNPRINTF("Gyro_Y_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][1]);
> + oboff += OSCNPRINTF("Gyro_Z_Raw:%d\n",
> + (int)cl_data->sensor_virt_addr[i][2]);
> + ret = simple_read_from_buffer(ubuf, count, offp, obuf, oboff);
> +
> + kfree(obuf);
> +
> + return ret;
> +}
> +
> +static const struct file_operations amdsfh_debugfs_accel_ops = {
> + .owner = THIS_MODULE,
> + .open = simple_open,
> + .read = amdsfh_debugfs_accel_read,
> +};
> +
> +static const struct file_operations amdsfh_debugfs_gyro_ops = {
> + .owner = THIS_MODULE,
> + .open = simple_open,
> + .read = amdsfh_debugfs_gyro_read,
> +};
> +
> +static const struct file_operations amdsfh_debugfs_mag_ops = {
> + .owner = THIS_MODULE,
> + .open = simple_open,
> + .read = amdsfh_debugfs_mag_read,
> +};
> +
> +static const struct file_operations amdsfh_debugfs_als_ops = {
> + .owner = THIS_MODULE,
> + .open = simple_open,
> + .read = amdsfh_debugfs_als_read,
> +};
> +
> +int amdsfh_debugfs_setup(struct amdtp_cl_data *cl_data)
> +{
> + /* DebugFS info */
> + struct dentry *dbgfs;
> + int i;
> +
> + if (!debugfs_initialized())
> + return -1;
> +
> + if (!cl_data->amd_debugfs_dir)
> + cl_data->amd_debugfs_dir = debugfs_create_dir
> + (KBUILD_MODNAME, NULL);
> +
> + if (!cl_data->amd_debugfs_dir)
> + return -1;
> +
> + for (i = 0; i < cl_data->num_hid_devices; i++) {
> + switch (cl_data->sensor_idx[i]) {
> + case ACCEL_IDX:
> + dbgfs = debugfs_create_dir("accel",
> + cl_data-
> >amd_debugfs_dir);
> + debugfs_create_file("raw_value", 0400,
> + dbgfs, cl_data,
> + &amdsfh_debugfs_accel_ops);
> + break;
> +
> + case GYRO_IDX:
> + dbgfs = debugfs_create_dir("gyro",
> + cl_data-
> >amd_debugfs_dir);
> + debugfs_create_file("raw_value", 0400,
> + dbgfs, cl_data,
> + &amdsfh_debugfs_gyro_ops);
> + break;
> +
> + case MAG_IDX:
> + dbgfs = debugfs_create_dir("magnetometer",
> + cl_data-
> >amd_debugfs_dir);
> + debugfs_create_file("raw_value", 0400,
> + dbgfs, cl_data,
> + &amdsfh_debugfs_mag_ops);
> + break;
> +
> + case AMBIENT_LIGHT_IDX:
> + dbgfs = debugfs_create_dir("als",
> + cl_data-
> >amd_debugfs_dir);
> + debugfs_create_file("raw_value", 0400,
> + dbgfs, cl_data,
> + &amdsfh_debugfs_als_ops);
> + break;
> +
> + default:
> + return 0;
> + }
> + }
> + return 0;
> +}
> +EXPORT_SYMBOL(amdsfh_debugfs_setup);
> +
> +void amdsfh_debugfs_destroy(struct amdtp_cl_data *cl_data)
> +{
> + debugfs_remove_recursive(cl_data->amd_debugfs_dir);
> +}
> +EXPORT_SYMBOL(amdsfh_debugfs_destroy);
> diff --git a/drivers/hid/amd-sfh-hid/amdsfh-debugfs.h
> b/drivers/hid/amd-sfh-hid/amdsfh-debugfs.h
> new file mode 100644
> index 0000000..470f1f12
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/amdsfh-debugfs.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * AMD SFH DebugFS
> + * Author: Nehal Bakulchandra Shah <[email protected]
> >
> + */
> +#include "amdsfh-hid.h"
> +
> +#ifndef AMDSFH_DEBUGFS_H
> +#define AMDSFH_DEBUGFS_H
> +
> +int amdsfh_debugfs_setup(struct amdtp_cl_data *cl_data);
> +void amdsfh_debugfs_destroy(struct amdtp_cl_data *cl_data);
> +
> +#endif
> diff --git a/drivers/hid/amd-sfh-hid/amdsfh-hid-client.c
> b/drivers/hid/amd-sfh-hid/amdsfh-hid-client.c
> new file mode 100644
> index 0000000..b59cb2f
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/amdsfh-hid-client.c
> @@ -0,0 +1,261 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +/*
> + * AMD SFH Client Driver
> + * Author: Nehal Bakulchandra Shah <[email protected]
> >
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +#include <linux/hid.h>
> +#include <linux/list.h>
> +#include <linux/platform_device.h>
> +#include <linux/acpi.h>
> +#include <linux/dma-mapping.h>
> +#include "amdsfh-hid.h"
> +#include "amd_mp2_pcie.h"
> +#include "hid_descriptor/amd_sfh_hid_descriptor.h"
> +#include "amdsfh-debugfs.h"
> +
> +#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Client Driver"
> +#define DRIVER_VER "1.0"
> +#define DRIVER_NAME "AMD_SFH_HID_CLIENT"
> +#define PERIOD 200
> +
> +struct request_list {
> + u8 report_id;
> + u8 sensor_idx;
> + u8 report_type;
> + u8 current_index;
> + struct hid_device *hid;
> + struct list_head list;
> +};
> +
> +static struct request_list req_list;
> +static struct amdtp_cl_data *cl_data_context;
> +
> +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);
> +}
> +EXPORT_SYMBOL(amd_sfh_set_report);
> +
> +void 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_request = kzalloc
> + (sizeof(*new_request), GFP_KERNEL);
> + new_request->current_index = i;
> + new_request->sensor_idx = cli_data-
> >sensor_idx[i];
> + new_request->hid = hid;
> + new_request->report_type = report_type;
> + new_request->report_id = report_id;
> + cli_data->report_id[i] = report_id;
> + cli_data->request_done[i] = false;
> + list_add(&new_request->list, &req_list.list);
> + break;
> + }
> + }
> + schedule_delayed_work(&cli_data->work, 0);
> +}
> +EXPORT_SYMBOL(amd_sfh_get_report);
> +
> +static void amd_sfh_work(struct work_struct *work)
> +{
> + struct amdtp_cl_data *cli_data = amd_sfh_cldata(work);
> + struct request_list *req_node;
> + u8 report_size = 0;
> + u8 current_index;
> + u8 sensor_index;
> + u8 report_id;
> + u8 node_type;
> +
> + 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->current_index;
> + 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]);
> + } 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]);
> + }
> +
> + 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);
> + cli_data->cur_hid_dev = current_index;
> + cli_data->sensor_requested_cnt[current_index] = 0;
> + kfree(req_node);
> + 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 = cl_data_context;
> + unsigned int i;
> + u8 report_size = 0;
> +
> + 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, PERIOD);
> +}
> +
> +static int amd_sfh_hid_client_probe(struct platform_device *pdev)
> +{
> + struct amd_mp2_sensor_info info;
> + int rc = 0;
> + int i;
> + struct amdtp_cl_device *cl_dev;
> + struct amdtp_cl_data *cl_data;
> + u32 feature_report_size = 0;
> + u32 input_report_size = 0;
> +
> + cl_dev = devm_kzalloc(&pdev->dev, sizeof(*cl_dev), GFP_KERNEL);
> + if (!cl_dev)
> + return -ENOMEM;
Here you are using devm_ call. So better to be consistant and use
everywhere devm_
> +
> + cl_dev->pdev = pci_get_device(PCI_VENDOR_ID_AMD,
> + PCI_DEVICE_ID_AMD_MP2, NULL);
> + if (!cl_dev->pdev)
> + return -ENOMEM;
> +
> + cl_data = kzalloc(sizeof(*cl_data), GFP_KERNEL);
> + cl_data->num_hid_devices = amd_mp2_get_sensor_num
> + (cl_dev->pdev, &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);
> +
> + amdsfh_debugfs_setup(cl_data);
> +
> + for (i = 0; i < cl_data->num_hid_devices; i++) {
> + cl_data->sensor_virt_addr[i] = dma_alloc_coherent
> + (&pdev->dev, sizeof(int) * 8,
> + &cl_data->sensor_phy_addr[i], GFP_KERNEL);
> + cl_data->sensor_sts[i] = 0;
> + cl_data->sensor_requested_cnt[i] = 0;
> + cl_data->cur_hid_dev = i;
> +
> + cl_data->report_descr_size[i] = get_descriptor_size
> + (cl_data->sensor_idx[i], descr_size);
> +
> + feature_report_size = get_descriptor_size
> + (cl_data->sensor_idx[i], feature_size);
> +
> + input_report_size = get_descriptor_size
> + (cl_data->sensor_idx[i], input_size);
> +
> + cl_data->feature_report[i] =
> kzalloc(feature_report_size,
> + GFP_KERNEL);
> + cl_data->input_report[i] = kzalloc(input_report_size,
> + GFP_KERNEL);
> + info.period = PERIOD;
> + info.sensor_idx = cl_data->sensor_idx[i];
> + info.phy_address = cl_data->sensor_phy_addr[i];
> + cl_data->report_descr[i] = kzalloc
> + (cl_data->report_descr_size[i], GFP_KERNEL);
> + if (!cl_data->report_descr[i])
> + return -ENOMEM;
> + rc = get_report_descriptor(cl_data->sensor_idx[i],
> + cl_data->report_descr[i]);
> + rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
> + rc = amd_start_sensor(cl_dev->pdev, info);
> + cl_data->sensor_sts[i] = 1;
> + }
> +
> + cl_dev->cl_data = cl_data;
> + cl_data_context = cl_data;
> + platform_set_drvdata(pdev, cl_dev);
> + schedule_delayed_work(&cl_data->work_buffer, PERIOD);
> + return 0;
> +}
> +
> +static int amd_sfh_hid_client_remove(struct platform_device *pdev)
> +{
> + int i;
> + struct amdtp_cl_device *cl_dev;
> + struct amdtp_cl_data *cl_data;
> +
> + cl_dev = platform_get_drvdata(pdev);
> + if (!(cl_dev))
> + return -EINVAL;
> +
> + cl_data = cl_dev->cl_data;
> + if (!(cl_data))
> + return -EINVAL;
> +
> + for (i = 0; i < cl_data->num_hid_devices; i++)
> + amd_stop_sensor(cl_dev->pdev, i);
one space
Thanks,
Srinivas
> + cancel_delayed_work_sync(&cl_data->work);
> + cancel_delayed_work_sync(&cl_data->work_buffer);
> + amdsfh_debugfs_destroy(cl_data);
> + 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(&pdev->dev, 8 * sizeof(int),
> + cl_data->sensor_virt_addr[i],
> + cl_data->sensor_phy_addr[i]);
> + }
> +
> + kfree(cl_data);
> + pr_info("%s:%s Exit\n", DRIVER_NAME, __func__);
> + return 0;
> +}
> +
> +static const struct acpi_device_id amd_sfh_acpi_match[] = { {
> + "AMDI0080" },
> + { },
> +};
> +
> +MODULE_DEVICE_TABLE(acpi, amd_sfh_acpi_match);
> +static struct platform_driver amd_sfh_plat_driver = {
> + .probe = amd_sfh_hid_client_probe,
> + .remove = amd_sfh_hid_client_remove,
> + .driver = {
> + .name = "amd_sfh_platform",
> + .acpi_match_table =
> ACPI_PTR(amd_sfh_acpi_match),
> + },
> +};
> +module_platform_driver(amd_sfh_plat_driver);
> +MODULE_DESCRIPTION("AMD(R) SFH Client Driver");
> +MODULE_AUTHOR("Nehal Shah <[email protected]>");
> +MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/hid/amd-sfh-hid/amdsfh-hid.c b/drivers/hid/amd-
> sfh-hid/amdsfh-hid.c
> new file mode 100644
> index 0000000..89fe35a8
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/amdsfh-hid.c
> @@ -0,0 +1,179 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +/*
> + * AMD MP2 Sensors transport driver
> + *
> + * Authors: Sandeep Singh <[email protected]>
> + * Nehal Bakulchandra Shah <[email protected]
> >
> + */
> +#include <linux/hid.h>
> +#include <linux/wait.h>
> +#include <linux/sched.h>
> +#include "amdsfh-hid.h"
> +
> +#define DRIVER_NAME "AMD_MP2_SENSORS_TRANSPORT"
> +
> +/**
> + * 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;
> + int rc;
> +
> + rc = hid_parse_report(hid, cli_data->report_descr[hid_data-
> >index],
> + cli_data->report_descr_size[hid_data-
> >index]);
> + if (rc)
> + return rc;
> + return 0;
> +}
> +
> +/* 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, unsigned char
> reportnum,
> + u8 *buf, size_t len, unsigned char rtype,
> + int reqtype)
> +{
> + return 0;
> +}
> +
> +static void amdtp_hid_request(struct hid_device *hid, struct
> hid_report *rep,
> + int reqtype)
> +{
> + switch (reqtype) {
> + case HID_REQ_GET_REPORT:
> + amd_sfh_get_report(hid, rep->id, rep->type);
> + break;
> + case HID_REQ_SET_REPORT:
> + amd_sfh_set_report(hid, rep->id, reqtype);
> + 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 = 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])
> + wait_event_interruptible_timeout(hid_data->hid_wait,
> + cli_data-
> >request_done[i],
> + 1500);
> + if (!cli_data->request_done[i]) {
> + hid_err(hid,
> + "timeout waiting for response from device\n");
> + return -ETIMEDOUT;
> + }
> + cli_data->request_done[i] = false;
> +
> + 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(unsigned int cur_hid_dev,
> + struct amdtp_cl_data *cli_data)
> +{
> + int rc;
> + struct hid_device *hid;
> + struct amdtp_hid_data *hid_data;
> +
> + hid = hid_allocate_device();
> + if (IS_ERR(hid)) {
> + rc = PTR_ERR(hid);
> + return -ENOMEM;
> + }
> +
> + 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->version = AMD_SFH_HID_VERSION;
> + 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/amdsfh-hid.h b/drivers/hid/amd-
> sfh-hid/amdsfh-hid.h
> new file mode 100644
> index 0000000..8bbe40c
> --- /dev/null
> +++ b/drivers/hid/amd-sfh-hid/amdsfh-hid.h
> @@ -0,0 +1,85 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * AMD MP2 Sensors transport driver
> + *
> + * Authors: Sandeep Singh <[email protected]>
> + * Nehal Bakulchandra Shah <[email protected]
> >
> + */
> +
> +#ifndef AMDSFH_HID_H
> +#define AMDSFH_HID_H
> +#include <linux/debugfs.h>
> +
> +#define MAX_HID_DEVICES 4
> +#define DCD_DATA_SIZE_CHAR 512
> +#define BUS_AMD_AMDTP 0x20
> +#define AMD_SFH_HID_VENDOR 1022
> +#define AMD_SFH_HID_PRODUCT 0x0001
> +#define AMD_SFH_HID_VERSION 0x0001
> +
> +struct amdtp_cl_device {
> + struct pci_dev *pdev;
> + struct amdtp_cl_data *cl_data;
> +};
> +
> +struct amdtp_cl_data {
> + u8 init_done;
> + unsigned int cur_hid_dev;
> + unsigned int hid_dev_count;
> + unsigned int num_hid_devices;
> + struct device_info *hid_devices;
> + unsigned char *report_descr[MAX_HID_DEVICES];
> + int report_descr_size[MAX_HID_DEVICES];
> + struct hid_device *hid_sensor_hubs[MAX_HID_DEVICES];
> + unsigned char *hid_descr[MAX_HID_DEVICES];
> + int hid_descr_size[MAX_HID_DEVICES];
> + phys_addr_t phy_addr_base;
> + u32 *sensor_virt_addr[MAX_HID_DEVICES];
> + phys_addr_t sensor_phy_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 dentry *amd_debugfs_dir;
> +
> +};
> +
> +/**
> + * 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 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,
> unsigned int len,
> + int report_id);
> +void hid_amdtp_get_report(struct hid_device *hid, int report_id,
> + int report_type);
> +int amdtp_hid_probe(unsigned int cur_hid_dev,
> + struct amdtp_cl_data *cli_data);
> +void amdtp_hid_remove(struct amdtp_cl_data *cli_data);
> +void 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);
> +
> +#define amd_sfh_cldata(__work) container_of(__work,\
> + struct amdtp_cl_data,
> work.work)
> +#endif /* AMDSFH_HID */