Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,178 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2024 Intel Corporation */
#ifndef _QUICKSPI_DEV_H_
#define _QUICKSPI_DEV_H_
#include <linux/bits.h>
#include <linux/hid-over-spi.h>
#include <linux/sizes.h>
#include <linux/wait.h>
#include "quickspi-protocol.h"
#define PCI_DEVICE_ID_INTEL_THC_MTL_DEVICE_ID_SPI_PORT1 0x7E49
#define PCI_DEVICE_ID_INTEL_THC_MTL_DEVICE_ID_SPI_PORT2 0x7E4B
#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_SPI_PORT1 0xA849
#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_SPI_PORT2 0xA84B
#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_SPI_PORT1 0xE349
#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_SPI_PORT2 0xE34B
#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_SPI_PORT1 0xE449
#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_SPI_PORT2 0xE44B
#define PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_SPI_PORT1 0x4D49
#define PCI_DEVICE_ID_INTEL_THC_WCL_DEVICE_ID_SPI_PORT2 0x4D4B
#define PCI_DEVICE_ID_INTEL_THC_ARL_DEVICE_ID_SPI_PORT1 0x7749
#define PCI_DEVICE_ID_INTEL_THC_ARL_DEVICE_ID_SPI_PORT2 0x774B
#define PCI_DEVICE_ID_INTEL_THC_NVL_H_DEVICE_ID_SPI_PORT1 0xD349
#define PCI_DEVICE_ID_INTEL_THC_NVL_H_DEVICE_ID_SPI_PORT2 0xD34B
/* HIDSPI special ACPI parameters DSM methods */
#define ACPI_QUICKSPI_REVISION_NUM 2
#define ACPI_QUICKSPI_FUNC_NUM_INPUT_REP_HDR_ADDR 1
#define ACPI_QUICKSPI_FUNC_NUM_INPUT_REP_BDY_ADDR 2
#define ACPI_QUICKSPI_FUNC_NUM_OUTPUT_REP_ADDR 3
#define ACPI_QUICKSPI_FUNC_NUM_READ_OPCODE 4
#define ACPI_QUICKSPI_FUNC_NUM_WRITE_OPCODE 5
#define ACPI_QUICKSPI_FUNC_NUM_IO_MODE 6
/* QickSPI device special ACPI parameters DSM methods */
#define ACPI_QUICKSPI_FUNC_NUM_CONNECTION_SPEED 1
#define ACPI_QUICKSPI_FUNC_NUM_LIMIT_PACKET_SIZE 2
#define ACPI_QUICKSPI_FUNC_NUM_PERFORMANCE_LIMIT 3
/* Platform special ACPI parameters DSM methods */
#define ACPI_QUICKSPI_FUNC_NUM_ACTIVE_LTR 1
#define ACPI_QUICKSPI_FUNC_NUM_LP_LTR 2
#define SPI_WRITE_IO_MODE BIT(13)
#define SPI_IO_MODE_OPCODE GENMASK(15, 14)
#define PERFORMANCE_LIMITATION GENMASK(15, 0)
/* Packet size value, the unit is 16 bytes */
#define DEFAULT_MIN_PACKET_SIZE_VALUE 4
#define MAX_PACKET_SIZE_VALUE_MTL 128
#define MAX_PACKET_SIZE_VALUE_LNL 256
/*
* THC uses runtime auto suspend to dynamically switch between THC active LTR
* and low power LTR to save CPU power.
* Default value is 5000ms, that means if no touch event in this time, THC will
* change to low power LTR mode.
*/
#define DEFAULT_AUTO_SUSPEND_DELAY_MS 5000
enum quickspi_dev_state {
QUICKSPI_NONE,
QUICKSPI_INITIATED,
QUICKSPI_RESETING,
QUICKSPI_RESET,
QUICKSPI_ENABLED,
QUICKSPI_DISABLED,
};
/**
* struct quickspi_driver_data - Driver specific data for quickspi device
* @max_packet_size_value: identify max packet size, unit is 16 bytes
*/
struct quickspi_driver_data {
u32 max_packet_size_value;
};
struct device;
struct pci_dev;
struct thc_device;
struct hid_device;
struct acpi_device;
/**
* struct quickspi_device - THC QuickSpi device struct
* @dev: point to kernel device
* @pdev: point to PCI device
* @thc_hw: point to THC device
* @hid_dev: point to hid device
* @acpi_dev: point to ACPI device
* @driver_data: point to quickspi specific driver data
* @state: THC SPI device state
* @mem_addr: MMIO memory address
* @dev_desc: device descriptor for HIDSPI protocol
* @input_report_hdr_addr: device input report header address
* @input_report_bdy_addr: device input report body address
* @output_report_bdy_addr: device output report address
* @spi_freq_val: device supported max SPI frequnecy, in Hz
* @spi_read_io_mode: device supported SPI read io mode
* @spi_write_io_mode: device supported SPI write io mode
* @spi_read_opcode: device read opcode
* @spi_write_opcode: device write opcode
* @limit_packet_size: 1 - limit read/write packet to 64Bytes
* 0 - device no packet size limiation for read/write
* @performance_limit: delay time, in ms.
* if device has performance limitation, must give a delay
* before write operation after a read operation.
* @active_ltr_val: THC active LTR value
* @low_power_ltr_val: THC low power LTR value
* @report_descriptor: store a copy of device report descriptor
* @input_buf: store a copy of latest input report data
* @report_buf: store a copy of latest input/output report packet from set/get feature
* @report_len: the length of input/output report packet
* @reset_ack_wq: workqueue for waiting reset response from device
* @reset_ack: indicate reset response received or not
* @nondma_int_received_wq: workqueue for waiting THC non-DMA interrupt
* @nondma_int_received: indicate THC non-DMA interrupt received or not
* @report_desc_got_wq: workqueue for waiting device report descriptor
* @report_desc_got: indicate device report descritor received or not
* @set_power_on_wq: workqueue for waiting set power on response from device
* @set_power_on: indicate set power on response received or not
* @get_feature_cmpl_wq: workqueue for waiting get feature response from device
* @get_feature_cmpl: indicate get feature received or not
* @set_feature_cmpl_wq: workqueue for waiting set feature to device
* @set_feature_cmpl: indicate set feature send complete or not
*/
struct quickspi_device {
struct device *dev;
struct pci_dev *pdev;
struct thc_device *thc_hw;
struct hid_device *hid_dev;
struct acpi_device *acpi_dev;
struct quickspi_driver_data *driver_data;
enum quickspi_dev_state state;
void __iomem *mem_addr;
struct hidspi_dev_descriptor dev_desc;
u32 input_report_hdr_addr;
u32 input_report_bdy_addr;
u32 output_report_addr;
u32 spi_freq_val;
u32 spi_read_io_mode;
u32 spi_write_io_mode;
u32 spi_read_opcode;
u32 spi_write_opcode;
u32 limit_packet_size;
u32 spi_packet_size;
u32 performance_limit;
u32 active_ltr_val;
u32 low_power_ltr_val;
u8 *report_descriptor;
u8 *input_buf;
u8 *report_buf;
u32 report_len;
wait_queue_head_t reset_ack_wq;
bool reset_ack;
wait_queue_head_t nondma_int_received_wq;
bool nondma_int_received;
wait_queue_head_t report_desc_got_wq;
bool report_desc_got;
wait_queue_head_t get_report_cmpl_wq;
bool get_report_cmpl;
wait_queue_head_t set_report_cmpl_wq;
bool set_report_cmpl;
};
#endif /* _QUICKSPI_DEV_H_ */
@@ -0,0 +1,165 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2024 Intel Corporation */
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/pm_runtime.h>
#include "quickspi-dev.h"
#include "quickspi-hid.h"
/**
* quickspi_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 quickspi_hid_parse(struct hid_device *hid)
{
struct quickspi_device *qsdev = hid->driver_data;
if (qsdev->report_descriptor)
return hid_parse_report(hid, qsdev->report_descriptor,
le16_to_cpu(qsdev->dev_desc.rep_desc_len));
dev_err(qsdev->dev, "invalid report descriptor\n");
return -EINVAL;
}
static int quickspi_hid_start(struct hid_device *hid)
{
return 0;
}
static void quickspi_hid_stop(struct hid_device *hid)
{
}
static int quickspi_hid_open(struct hid_device *hid)
{
return 0;
}
static void quickspi_hid_close(struct hid_device *hid)
{
}
static int quickspi_hid_raw_request(struct hid_device *hid,
unsigned char reportnum,
__u8 *buf, size_t len,
unsigned char rtype, int reqtype)
{
struct quickspi_device *qsdev = hid->driver_data;
int ret = 0;
ret = pm_runtime_resume_and_get(qsdev->dev);
if (ret)
return ret;
switch (reqtype) {
case HID_REQ_GET_REPORT:
ret = quickspi_get_report(qsdev, rtype, reportnum, buf);
break;
case HID_REQ_SET_REPORT:
ret = quickspi_set_report(qsdev, rtype, reportnum, buf, len);
break;
default:
dev_err_once(qsdev->dev, "Not supported request type %d\n", reqtype);
break;
}
pm_runtime_put_autosuspend(qsdev->dev);
return ret;
}
static int quickspi_hid_power(struct hid_device *hid, int lvl)
{
return 0;
}
static struct hid_ll_driver quickspi_hid_ll_driver = {
.parse = quickspi_hid_parse,
.start = quickspi_hid_start,
.stop = quickspi_hid_stop,
.open = quickspi_hid_open,
.close = quickspi_hid_close,
.power = quickspi_hid_power,
.raw_request = quickspi_hid_raw_request,
};
/**
* quickspi_hid_probe() - Register HID low level driver
*
* @qsdev: point to quickspi device
*
* This function is used to allocate and add HID device.
*
* Return: 0 on success, non zero on error.
*/
int quickspi_hid_probe(struct quickspi_device *qsdev)
{
struct hid_device *hid;
int ret;
hid = hid_allocate_device();
if (IS_ERR(hid))
return PTR_ERR(hid);
hid->ll_driver = &quickspi_hid_ll_driver;
hid->bus = BUS_PCI;
hid->dev.parent = qsdev->dev;
hid->driver_data = qsdev;
hid->version = le16_to_cpu(qsdev->dev_desc.version_id);
hid->vendor = le16_to_cpu(qsdev->dev_desc.vendor_id);
hid->product = le16_to_cpu(qsdev->dev_desc.product_id);
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "quickspi-hid",
hid->vendor, hid->product);
strscpy(hid->phys, dev_name(qsdev->dev), sizeof(hid->phys));
ret = hid_add_device(hid);
if (ret) {
hid_destroy_device(hid);
return ret;
}
qsdev->hid_dev = hid;
return 0;
}
/**
* quickspi_hid_remove() - Destroy HID device
*
* @qsdev: point to quickspi device
*
* Return: 0 on success, non zero on error.
*/
void quickspi_hid_remove(struct quickspi_device *qsdev)
{
hid_destroy_device(qsdev->hid_dev);
}
/**
* quickspi_hid_send_report() - Send HID input report data to HID core
*
* @qsdev: point to quickspi device
* @data: point to input report data buffer
* @data_len: the length of input report data
*
* Return: 0 on success, non zero on error.
*/
int quickspi_hid_send_report(struct quickspi_device *qsdev,
void *data, size_t data_len)
{
int ret;
ret = hid_input_report(qsdev->hid_dev, HID_INPUT_REPORT, data, data_len, 1);
if (ret)
dev_err(qsdev->dev, "Failed to send HID input report, ret = %d.\n", ret);
return ret;
}
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2024 Intel Corporation */
#ifndef _QUICKSPI_HID_H_
#define _QUICKSPI_HID_H_
struct quickspi_device;
int quickspi_hid_send_report(struct quickspi_device *qsdev,
void *data, size_t data_size);
int quickspi_hid_probe(struct quickspi_device *qsdev);
void quickspi_hid_remove(struct quickspi_device *qsdev);
#endif /* _QUICKSPI_HID_H_ */
@@ -0,0 +1,413 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright © 2024 Intel Corporation */
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/hid.h>
#include "intel-thc-dev.h"
#include "intel-thc-dma.h"
#include "quickspi-dev.h"
#include "quickspi-hid.h"
#include "quickspi-protocol.h"
/* THC uses HW to accelerate HID over SPI protocol, THC_M_PRT_DEV_INT_CAUSE
* register is used to store message header and body header, below definition
* let driver retrieve needed data filed easier from THC_M_PRT_DEV_INT_CAUSE
* register.
*/
#define HIDSPI_IN_REP_BDY_HDR_REP_TYPE GENMASK(7, 0)
static int write_cmd_to_txdma(struct quickspi_device *qsdev,
int report_type, int report_id,
u8 *report_buf, const int report_buf_len)
{
struct output_report *write_buf;
int write_buf_len;
int ret;
write_buf = (struct output_report *)qsdev->report_buf;
write_buf->output_hdr.report_type = report_type;
write_buf->output_hdr.content_len = cpu_to_le16(report_buf_len);
write_buf->output_hdr.content_id = report_id;
if (report_buf && report_buf_len > 0)
memcpy(write_buf->content, report_buf, report_buf_len);
write_buf_len = HIDSPI_OUTPUT_REPORT_SIZE(report_buf_len);
ret = thc_dma_write(qsdev->thc_hw, write_buf, write_buf_len);
if (ret)
dev_err_once(qsdev->dev, "DMA write failed, ret = %d\n", ret);
return ret;
}
static int quickspi_get_device_descriptor(struct quickspi_device *qsdev)
{
u8 read_buf[HIDSPI_INPUT_DEVICE_DESCRIPTOR_SIZE];
struct output_report output_rep;
u32 input_len, read_len = 0;
u32 int_cause_val;
u8 input_rep_type;
int ret;
output_rep.output_hdr.report_type = DEVICE_DESCRIPTOR;
output_rep.output_hdr.content_len = 0;
output_rep.output_hdr.content_id = 0;
qsdev->nondma_int_received = false;
ret = thc_tic_pio_write(qsdev->thc_hw, qsdev->output_report_addr,
HIDSPI_OUTPUT_REPORT_SIZE(0), (u32 *)&output_rep);
if (ret) {
dev_err_once(qsdev->dev,
"Write DEVICE_DESCRIPTOR command failed, ret = %d\n", ret);
return ret;
}
ret = wait_event_interruptible_timeout(qsdev->nondma_int_received_wq,
qsdev->nondma_int_received,
QUICKSPI_ACK_WAIT_TIMEOUT * HZ);
if (ret <= 0 || !qsdev->nondma_int_received) {
dev_err_once(qsdev->dev, "Wait DEVICE_DESCRIPTOR timeout, ret:%d\n", ret);
return -ETIMEDOUT;
}
qsdev->nondma_int_received = false;
int_cause_val = thc_int_cause_read(qsdev->thc_hw);
input_len = FIELD_GET(HIDSPI_INPUT_HEADER_REPORT_LEN, int_cause_val);
input_len = input_len * sizeof(u32);
if (input_len != HIDSPI_INPUT_DEVICE_DESCRIPTOR_SIZE) {
dev_err_once(qsdev->dev, "Receive wrong DEVICE_DESCRIPTOR length, len = %u\n",
input_len);
return -EINVAL;
}
ret = thc_tic_pio_read(qsdev->thc_hw, qsdev->input_report_bdy_addr,
input_len, &read_len, (u32 *)read_buf);
if (ret || read_len != input_len) {
dev_err_once(qsdev->dev, "Read DEVICE_DESCRIPTOR failed, ret = %d\n", ret);
dev_err_once(qsdev->dev, "DEVICE_DESCRIPTOR expected len = %u, actual read = %u\n",
input_len, read_len);
return ret ?: -EINVAL;
}
input_rep_type = ((struct input_report_body_header *)read_buf)->input_report_type;
if (input_rep_type == DEVICE_DESCRIPTOR_RESPONSE) {
memcpy(&qsdev->dev_desc,
read_buf + HIDSPI_INPUT_BODY_HEADER_SIZE,
HIDSPI_DEVICE_DESCRIPTOR_SIZE);
return 0;
}
dev_err_once(qsdev->dev, "Unexpected input report type: %d\n", input_rep_type);
return -EINVAL;
}
int quickspi_get_report_descriptor(struct quickspi_device *qsdev)
{
int ret;
ret = write_cmd_to_txdma(qsdev, REPORT_DESCRIPTOR, 0, NULL, 0);
if (ret) {
dev_err_once(qsdev->dev,
"Write REPORT_DESCRIPTOR command failed, ret = %d\n", ret);
return ret;
}
ret = wait_event_interruptible_timeout(qsdev->report_desc_got_wq,
qsdev->report_desc_got,
QUICKSPI_ACK_WAIT_TIMEOUT * HZ);
if (ret <= 0 || !qsdev->report_desc_got) {
dev_err_once(qsdev->dev, "Wait Report Descriptor timeout, ret:%d\n", ret);
return -ETIMEDOUT;
}
qsdev->report_desc_got = false;
return 0;
}
int quickspi_set_power(struct quickspi_device *qsdev,
enum hidspi_power_state power_state)
{
u8 cmd_content = power_state;
int ret;
ret = write_cmd_to_txdma(qsdev, COMMAND_CONTENT,
HIDSPI_SET_POWER_CMD_ID,
&cmd_content,
sizeof(cmd_content));
if (ret) {
dev_err_once(qsdev->dev, "Write SET_POWER command failed, ret = %d\n", ret);
return ret;
}
return 0;
}
void quickspi_handle_input_data(struct quickspi_device *qsdev, u32 buf_len)
{
struct input_report_body_header *body_hdr;
struct input_report_body *input_body;
u8 *input_report;
u32 input_len;
int ret = 0;
input_body = (struct input_report_body *)qsdev->input_buf;
body_hdr = &input_body->body_hdr;
input_len = le16_to_cpu(body_hdr->content_len);
if (HIDSPI_INPUT_BODY_SIZE(input_len) > buf_len) {
dev_err_once(qsdev->dev, "Wrong input report length: %u",
input_len);
return;
}
switch (body_hdr->input_report_type) {
case REPORT_DESCRIPTOR_RESPONSE:
if (input_len != le16_to_cpu(qsdev->dev_desc.rep_desc_len)) {
dev_err_once(qsdev->dev, "Unexpected report descriptor length: %u\n",
input_len);
return;
}
memcpy(qsdev->report_descriptor, input_body->content, input_len);
qsdev->report_desc_got = true;
wake_up_interruptible(&qsdev->report_desc_got_wq);
break;
case COMMAND_RESPONSE:
if (body_hdr->content_id == HIDSPI_SET_POWER_CMD_ID) {
dev_dbg(qsdev->dev, "Receive set power on response\n");
} else {
dev_err_once(qsdev->dev, "Unknown command response type: %u\n",
body_hdr->content_id);
}
break;
case RESET_RESPONSE:
if (qsdev->state == QUICKSPI_RESETING) {
qsdev->reset_ack = true;
wake_up_interruptible(&qsdev->reset_ack_wq);
dev_dbg(qsdev->dev, "Receive HIR reset response\n");
} else {
dev_info(qsdev->dev, "Receive DIR\n");
}
break;
case GET_FEATURE_RESPONSE:
case GET_INPUT_REPORT_RESPONSE:
qsdev->report_len = sizeof(body_hdr->content_id) + input_len;
input_report = input_body->content - sizeof(body_hdr->content_id);
memcpy(qsdev->report_buf, input_report, qsdev->report_len);
qsdev->get_report_cmpl = true;
wake_up_interruptible(&qsdev->get_report_cmpl_wq);
break;
case SET_FEATURE_RESPONSE:
case OUTPUT_REPORT_RESPONSE:
qsdev->set_report_cmpl = true;
wake_up_interruptible(&qsdev->set_report_cmpl_wq);
break;
case DATA:
if (qsdev->state != QUICKSPI_ENABLED)
return;
if (input_len > le16_to_cpu(qsdev->dev_desc.max_input_len)) {
dev_err_once(qsdev->dev, "Unexpected too large input report length: %u\n",
input_len);
return;
}
input_len = sizeof(body_hdr->content_id) + input_len;
input_report = input_body->content - sizeof(body_hdr->content_id);
ret = quickspi_hid_send_report(qsdev, input_report, input_len);
if (ret)
dev_err_once(qsdev->dev, "Failed to send HID input report: %d\n", ret);
break;
default:
dev_err_once(qsdev->dev, "Unsupported input report type: %u\n",
body_hdr->input_report_type);
break;
}
}
static int acpi_tic_reset(struct quickspi_device *qsdev)
{
acpi_status status = 0;
acpi_handle handle;
if (!qsdev->acpi_dev)
return -ENODEV;
handle = acpi_device_handle(qsdev->acpi_dev);
status = acpi_execute_simple_method(handle, "_RST", 0);
if (ACPI_FAILURE(status)) {
dev_err_once(qsdev->dev,
"Failed to reset device through ACPI method, ret = %d\n", status);
return -EIO;
}
return 0;
}
int reset_tic(struct quickspi_device *qsdev)
{
u32 actual_read_len, read_len = 0;
u32 input_report_len, reset_response, int_cause_val;
u8 input_rep_type;
int ret;
qsdev->state = QUICKSPI_RESETING;
qsdev->reset_ack = false;
thc_int_trigger_type_select(qsdev->thc_hw, true);
ret = acpi_tic_reset(qsdev);
if (ret)
return ret;
ret = thc_interrupt_quiesce(qsdev->thc_hw, false);
if (ret)
return ret;
ret = wait_event_interruptible_timeout(qsdev->reset_ack_wq,
qsdev->reset_ack,
QUICKSPI_ACK_WAIT_TIMEOUT * HZ);
if (ret <= 0 || !qsdev->reset_ack) {
dev_err_once(qsdev->dev, "Wait RESET_RESPONSE timeout, ret:%d\n", ret);
return -ETIMEDOUT;
}
int_cause_val = thc_int_cause_read(qsdev->thc_hw);
input_report_len = FIELD_GET(HIDSPI_INPUT_HEADER_REPORT_LEN, int_cause_val);
read_len = input_report_len * sizeof(u32);
if (read_len != HIDSPI_INPUT_BODY_SIZE(0)) {
dev_err_once(qsdev->dev, "Receive wrong RESET_RESPONSE, len = %u\n",
read_len);
return -EINVAL;
}
/* Switch to edge trigger matching with HIDSPI protocol definition */
thc_int_trigger_type_select(qsdev->thc_hw, true);
ret = thc_tic_pio_read(qsdev->thc_hw, qsdev->input_report_bdy_addr,
read_len, &actual_read_len,
(u32 *)&reset_response);
if (ret || actual_read_len != read_len) {
dev_err_once(qsdev->dev, "Read RESET_RESPONSE body failed, ret = %d\n", ret);
dev_err_once(qsdev->dev, "RESET_RESPONSE body expected len = %u, actual = %u\n",
read_len, actual_read_len);
return ret ?: -EINVAL;
}
input_rep_type = FIELD_GET(HIDSPI_IN_REP_BDY_HDR_REP_TYPE, reset_response);
if (input_rep_type == RESET_RESPONSE) {
dev_dbg(qsdev->dev, "RESET_RESPONSE received\n");
} else {
dev_err_once(qsdev->dev,
"Unexpected input report type: %d, expect RESET_RESPONSE\n",
input_rep_type);
return -EINVAL;
}
qsdev->state = QUICKSPI_RESET;
ret = quickspi_get_device_descriptor(qsdev);
if (ret)
return ret;
return 0;
}
int quickspi_get_report(struct quickspi_device *qsdev,
u8 report_type, unsigned int report_id, void *buf)
{
int rep_type;
int ret;
if (report_type == HID_INPUT_REPORT) {
rep_type = GET_INPUT_REPORT;
} else if (report_type == HID_FEATURE_REPORT) {
rep_type = GET_FEATURE;
} else {
dev_err_once(qsdev->dev, "Unsupported report type for GET REPORT: %d\n",
report_type);
return -EINVAL;
}
ret = write_cmd_to_txdma(qsdev, rep_type, report_id, NULL, 0);
if (ret) {
dev_err_once(qsdev->dev, "Write GET_REPORT command failed, ret = %d\n", ret);
return ret;
}
ret = wait_event_interruptible_timeout(qsdev->get_report_cmpl_wq,
qsdev->get_report_cmpl,
QUICKSPI_ACK_WAIT_TIMEOUT * HZ);
if (ret <= 0 || !qsdev->get_report_cmpl) {
dev_err_once(qsdev->dev, "Wait Get Report Response timeout, ret:%d\n", ret);
return -ETIMEDOUT;
}
qsdev->get_report_cmpl = false;
memcpy(buf, qsdev->report_buf, qsdev->report_len);
return qsdev->report_len;
}
int quickspi_set_report(struct quickspi_device *qsdev,
u8 report_type, unsigned int report_id,
void *buf, u32 buf_len)
{
int rep_type;
int ret;
if (report_type == HID_OUTPUT_REPORT) {
rep_type = OUTPUT_REPORT;
} else if (report_type == HID_FEATURE_REPORT) {
rep_type = SET_FEATURE;
} else {
dev_err_once(qsdev->dev, "Unsupported report type for SET REPORT: %d\n",
report_type);
return -EINVAL;
}
ret = write_cmd_to_txdma(qsdev, rep_type, report_id, buf + 1, buf_len - 1);
if (ret) {
dev_err_once(qsdev->dev, "Write SET_REPORT command failed, ret = %d\n", ret);
return ret;
}
ret = wait_event_interruptible_timeout(qsdev->set_report_cmpl_wq,
qsdev->set_report_cmpl,
QUICKSPI_ACK_WAIT_TIMEOUT * HZ);
if (ret <= 0 || !qsdev->set_report_cmpl) {
dev_err_once(qsdev->dev, "Wait Set Report Response timeout, ret:%d\n", ret);
return -ETIMEDOUT;
}
qsdev->set_report_cmpl = false;
return buf_len;
}
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2024 Intel Corporation */
#ifndef _QUICKSPI_PROTOCOL_H_
#define _QUICKSPI_PROTOCOL_H_
#include <linux/hid-over-spi.h>
#define QUICKSPI_ACK_WAIT_TIMEOUT 5
struct quickspi_device;
void quickspi_handle_input_data(struct quickspi_device *qsdev, u32 buf_len);
int quickspi_get_report(struct quickspi_device *qsdev, u8 report_type,
unsigned int report_id, void *buf);
int quickspi_set_report(struct quickspi_device *qsdev, u8 report_type,
unsigned int report_id, void *buf, u32 buf_len);
int quickspi_get_report_descriptor(struct quickspi_device *qsdev);
int quickspi_set_power(struct quickspi_device *qsdev,
enum hidspi_power_state power_state);
int reset_tic(struct quickspi_device *qsdev);
#endif /* _QUICKSPI_PROTOCOL_H_ */