Commit ba38d7f8 authored by Even Xu's avatar Even Xu Committed by Jiri Kosina
Browse files

HID: intel-thc-hid: intel-quicki2c: Add THC QuickI2C driver hid layer



Add HID Low level driver callbacks and hid probe function to register
QucikI2C as a HID driver, and external touch device as a HID device.

Co-developed-by: default avatarXinpeng Sun <xinpeng.sun@intel.com>
Signed-off-by: default avatarXinpeng Sun <xinpeng.sun@intel.com>
Signed-off-by: default avatarEven Xu <even.xu@intel.com>
Tested-by: default avatarRui Zhang <rui1.zhang@intel.com>
Tested-by: default avatarMark Pearson <mpearson-lenovo@squebb.ca>
Reviewed-by: default avatarSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Reviewed-by: default avatarMark Pearson <mpearson-lenovo@squebb.ca>
Tested-by: default avatarAaron Ma <aaron.ma@canonical.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.com>
parent 61bb2714
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -16,5 +16,6 @@ intel-quickspi-objs += intel-quickspi/quickspi-protocol.o

obj-$(CONFIG_INTEL_QUICKI2C) += intel-quicki2c.o
intel-quicki2c-objs += intel-quicki2c/pci-quicki2c.o
intel-quicki2c-objs += intel-quicki2c/quicki2c-hid.o

ccflags-y += -I $(src)/intel-thc
+11 −0
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@
#ifndef _QUICKI2C_DEV_H_
#define _QUICKI2C_DEV_H_

#include <linux/hid-over-i2c.h>

#define THC_LNL_DEVICE_ID_I2C_PORT1	0xA848
#define THC_LNL_DEVICE_ID_I2C_PORT2	0xA84A
#define THC_PTL_H_DEVICE_ID_I2C_PORT1	0xE348
@@ -26,23 +28,32 @@ enum quicki2c_dev_state {
struct device;
struct pci_dev;
struct thc_device;
struct hid_device;

/**
 * struct quicki2c_device -  THC QuickI2C device struct
 * @dev: point to kernel device
 * @pdev: point to PCI device
 * @thc_hw: point to THC device
 * @hid_dev: point to hid device
 * @driver_data: point to quicki2c specific driver data
 * @state: THC I2C device state
 * @mem_addr: MMIO memory address
 * @dev_desc: device descriptor for HIDI2C protocol
 * @report_descriptor: store a copy of device report descriptor
 */
struct quicki2c_device {
	struct device *dev;
	struct pci_dev *pdev;
	struct thc_device *thc_hw;
	struct hid_device *hid_dev;
	enum quicki2c_dev_state state;

	void __iomem *mem_addr;

	struct hidi2c_dev_descriptor dev_desc;

	u8 *report_descriptor;
};

#endif /* _QUICKI2C_DEV_H_ */
+142 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2024 Intel Corporation */

#include <linux/hid.h>
#include <linux/input.h>

#include "quicki2c-dev.h"
#include "quicki2c-hid.h"

/**
 * quicki2c_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 quicki2c_hid_parse(struct hid_device *hid)
{
	struct quicki2c_device *qcdev = hid->driver_data;

	if (qcdev->report_descriptor)
		return hid_parse_report(hid, qcdev->report_descriptor,
					le16_to_cpu(qcdev->dev_desc.report_desc_len));

	dev_err_once(qcdev->dev, "invalid report descriptor\n");
	return -EINVAL;
}

static int quicki2c_hid_start(struct hid_device *hid)
{
	return 0;
}

static void quicki2c_hid_stop(struct hid_device *hid)
{
}

static int quicki2c_hid_open(struct hid_device *hid)
{
	return 0;
}

static void quicki2c_hid_close(struct hid_device *hid)
{
}

static int quicki2c_hid_raw_request(struct hid_device *hid,
				    unsigned char reportnum,
				    __u8 *buf, size_t len,
				    unsigned char rtype, int reqtype)
{
	return 0;
}

static int quicki2c_hid_power(struct hid_device *hid, int lvl)
{
	return 0;
}

static struct hid_ll_driver quicki2c_hid_ll_driver = {
	.parse = quicki2c_hid_parse,
	.start = quicki2c_hid_start,
	.stop = quicki2c_hid_stop,
	.open = quicki2c_hid_open,
	.close = quicki2c_hid_close,
	.power = quicki2c_hid_power,
	.raw_request = quicki2c_hid_raw_request,
};

/**
 * quicki2c_hid_probe() - Register HID low level driver
 *
 * @qcdev: point to quicki2c device
 *
 * This function is used to allocate and add HID device.
 *
 * Return: 0 on success, non zero on error.
 */
int quicki2c_hid_probe(struct quicki2c_device *qcdev)
{
	struct hid_device *hid;
	int ret;

	hid = hid_allocate_device();
	if (IS_ERR(hid))
		return PTR_ERR(hid);

	hid->ll_driver = &quicki2c_hid_ll_driver;
	hid->bus = BUS_PCI;
	hid->dev.parent = qcdev->dev;
	hid->driver_data = qcdev;
	hid->version = le16_to_cpu(qcdev->dev_desc.version_id);
	hid->vendor = le16_to_cpu(qcdev->dev_desc.vendor_id);
	hid->product = le16_to_cpu(qcdev->dev_desc.product_id);
	snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "quicki2c-hid",
		 hid->vendor, hid->product);

	ret = hid_add_device(hid);
	if (ret) {
		hid_destroy_device(hid);
		return ret;
	}

	qcdev->hid_dev = hid;

	return 0;
}

/**
 * quicki2c_hid_remove() - Destroy HID device
 *
 * @qcdev: point to quicki2c device
 *
 * Return: 0 on success, non zero on error.
 */
void quicki2c_hid_remove(struct quicki2c_device *qcdev)
{
	hid_destroy_device(qcdev->hid_dev);
}

/**
 * quicki2c_hid_send_report() - Send HID input report data to HID core
 *
 * @qcdev: point to quicki2c 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 quicki2c_hid_send_report(struct quicki2c_device *qcdev,
			     void *data, size_t data_len)
{
	int ret;

	ret = hid_input_report(qcdev->hid_dev, HID_INPUT_REPORT, data, data_len, 1);
	if (ret)
		dev_err(qcdev->dev, "Failed to send HID input report, ret = %d.\n", ret);

	return ret;
}
+14 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2024 Intel Corporation */

#ifndef _QUICKI2C_HID_H_
#define _QUICKI2C_HID_H_

struct quicki2c_device;

int quicki2c_hid_send_report(struct quicki2c_device *qcdev,
			     void *data, size_t data_size);
int quicki2c_hid_probe(struct quicki2c_device *qcdev);
void quicki2c_hid_remove(struct quicki2c_device *qcdev);

#endif /* _QUICKI2C_HID_H_ */
+44 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright 2024 Intel Corporation */

#ifndef _HID_OVER_I2C_H_
#define _HID_OVER_I2C_H_

/**
 * struct hidi2c_dev_descriptor - HIDI2C device descriptor definition
 * @dev_desc_len: The length of the complete device descriptor, fixed to 0x1E (30).
 * @bcd_ver: The version number of the HIDI2C protocol supported.
 *           In binary coded decimal (BCD) format.
 * @report_desc_len: The length of the report descriptor
 * @report_desc_reg: The register address to retrieve report descriptor
 * @input_reg: the register address to retrieve input report
 * @max_input_len: The length of the largest possible HID input (or feature) report
 * @output_reg: the register address to send output report
 * @max_output_len: The length of the largest output (or feature) report
 * @cmd_reg: the register address to send command
 * @data_reg: the register address to send command data
 * @vendor_id: Device manufacturers vendor ID
 * @product_id: Device unique model/product ID
 * @version_id: Device’s unique version
 * @reserved0: Reserved and should be 0
 * @reserved1: Reserved and should be 0
 */
struct hidi2c_dev_descriptor {
	__le16 dev_desc_len;
	__le16 bcd_ver;
	__le16 report_desc_len;
	__le16 report_desc_reg;
	__le16 input_reg;
	__le16 max_input_len;
	__le16 output_reg;
	__le16 max_output_len;
	__le16 cmd_reg;
	__le16 data_reg;
	__le16 vendor_id;
	__le16 product_id;
	__le16 version_id;
	__le16 reserved0;
	__le16 reserved1;
} __packed;

#endif /* _HID_OVER_I2C_H_ */