Commit 9f2975f1 authored by Jiri Kosina's avatar Jiri Kosina
Browse files

Merge branch 'for-6.20/intel-thc' into for-linus

- support for HID output reports in the Quicki2c (Even Xu)
parents 05bc4583 6761f9cc
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -807,6 +807,12 @@ static int quicki2c_suspend(struct device *device)
	if (!qcdev)
		return -ENODEV;

	if (!device_may_wakeup(qcdev->dev)) {
		ret = quicki2c_set_power(qcdev, HIDI2C_SLEEP);
		if (ret)
			return ret;
	}

	/*
	 * As I2C is THC subsystem, no register auto save/restore support,
	 * need driver to do that explicitly for every D3 case.
@@ -856,6 +862,9 @@ static int quicki2c_resume(struct device *device)
	if (ret)
		return ret;

	if (!device_may_wakeup(qcdev->dev))
		return quicki2c_set_power(qcdev, HIDI2C_ON);

	return 0;
}

@@ -913,6 +922,9 @@ static int quicki2c_poweroff(struct device *device)
	if (!qcdev)
		return -ENODEV;

	/* Ignore the return value as platform will be poweroff soon */
	quicki2c_set_power(qcdev, HIDI2C_SLEEP);

	ret = thc_interrupt_quiesce(qcdev->thc_hw, true);
	if (ret)
		return ret;
@@ -966,7 +978,7 @@ static int quicki2c_restore(struct device *device)

	thc_change_ltr_mode(qcdev->thc_hw, THC_LTR_MODE_ACTIVE);

	return 0;
	return quicki2c_set_power(qcdev, HIDI2C_ON);
}

static int quicki2c_runtime_suspend(struct device *device)
+1 −1
Original line number Diff line number Diff line
@@ -213,7 +213,7 @@ struct quicki2c_device {
	u8 *report_descriptor;
	u8 *input_buf;
	u8 *report_buf;
	u32 report_len;
	size_t report_len;

	wait_queue_head_t reset_ack_wq;
	bool reset_ack;
+8 −0
Original line number Diff line number Diff line
@@ -82,6 +82,13 @@ static int quicki2c_hid_power(struct hid_device *hid, int lvl)
	return 0;
}

static int quicki2c_hid_output_report(struct hid_device *hid, u8 *buf, size_t count)
{
	struct quicki2c_device *qcdev = hid->driver_data;

	return quicki2c_output_report(qcdev, buf, count);
}

static struct hid_ll_driver quicki2c_hid_ll_driver = {
	.parse = quicki2c_hid_parse,
	.start = quicki2c_hid_start,
@@ -90,6 +97,7 @@ static struct hid_ll_driver quicki2c_hid_ll_driver = {
	.close = quicki2c_hid_close,
	.power = quicki2c_hid_power,
	.raw_request = quicki2c_hid_raw_request,
	.output_report = quicki2c_hid_output_report,
};

/**
+56 −39
Original line number Diff line number Diff line
@@ -13,11 +13,11 @@
#include "quicki2c-hid.h"
#include "quicki2c-protocol.h"

static int quicki2c_init_write_buf(struct quicki2c_device *qcdev, u32 cmd, int cmd_len,
				   bool append_data_reg, u8 *data, int data_len,
				   u8 *write_buf, int write_buf_len)
static ssize_t quicki2c_init_write_buf(struct quicki2c_device *qcdev, u32 cmd, size_t cmd_len,
				       bool append_data_reg, u8 *data, size_t data_len,
				       u8 *write_buf, size_t write_buf_len)
{
	int buf_len, offset = 0;
	size_t buf_len, offset = 0;

	buf_len = HIDI2C_REG_LEN + cmd_len;

@@ -30,6 +30,7 @@ static int quicki2c_init_write_buf(struct quicki2c_device *qcdev, u32 cmd, int c
	if (buf_len > write_buf_len)
		return -EINVAL;

	if (cmd_len) {
		memcpy(write_buf, &qcdev->dev_desc.cmd_reg, HIDI2C_REG_LEN);
		offset += HIDI2C_REG_LEN;
		memcpy(write_buf + offset, &cmd, cmd_len);
@@ -39,11 +40,13 @@ static int quicki2c_init_write_buf(struct quicki2c_device *qcdev, u32 cmd, int c
			memcpy(write_buf + offset, &qcdev->dev_desc.data_reg, HIDI2C_REG_LEN);
			offset += HIDI2C_REG_LEN;
		}
	} else {
		memcpy(write_buf, &qcdev->dev_desc.output_reg, HIDI2C_REG_LEN);
		offset += HIDI2C_REG_LEN;
	}

	if (data && data_len) {
		__le16 len = cpu_to_le16(data_len + HIDI2C_LENGTH_LEN);

		memcpy(write_buf + offset, &len, HIDI2C_LENGTH_LEN);
		put_unaligned_le16(data_len + HIDI2C_LENGTH_LEN, write_buf + offset);
		offset += HIDI2C_LENGTH_LEN;
		memcpy(write_buf + offset, data, data_len);
	}
@@ -51,10 +54,10 @@ static int quicki2c_init_write_buf(struct quicki2c_device *qcdev, u32 cmd, int c
	return buf_len;
}

static int quicki2c_encode_cmd(struct quicki2c_device *qcdev, u32 *cmd_buf,
static size_t quicki2c_encode_cmd(struct quicki2c_device *qcdev, u32 *cmd_buf,
				  u8 opcode, u8 report_type, u8 report_id)
{
	int cmd_len;
	size_t cmd_len;

	*cmd_buf = FIELD_PREP(HIDI2C_CMD_OPCODE, opcode) |
		   FIELD_PREP(HIDI2C_CMD_REPORT_TYPE, report_type);
@@ -72,22 +75,20 @@ static int quicki2c_encode_cmd(struct quicki2c_device *qcdev, u32 *cmd_buf,
}

static int write_cmd_to_txdma(struct quicki2c_device *qcdev, int opcode,
			      int report_type, int report_id, u8 *buf, int buf_len)
			      int report_type, int report_id, u8 *buf, size_t buf_len)
{
	size_t write_buf_len;
	int cmd_len, ret;
	size_t cmd_len;
	ssize_t len;
	u32 cmd;

	cmd_len = quicki2c_encode_cmd(qcdev, &cmd, opcode, report_type, report_id);

	ret = quicki2c_init_write_buf(qcdev, cmd, cmd_len, buf ? true : false, buf,
	len = quicki2c_init_write_buf(qcdev, cmd, cmd_len, buf ? true : false, buf,
				      buf_len, qcdev->report_buf, qcdev->report_len);
	if (ret < 0)
		return ret;

	write_buf_len = ret;
	if (len < 0)
		return len;

	return thc_dma_write(qcdev->thc_hw, qcdev->report_buf, write_buf_len);
	return thc_dma_write(qcdev->thc_hw, qcdev->report_buf, len);
}

int quicki2c_set_power(struct quicki2c_device *qcdev, enum hidi2c_power_state power_state)
@@ -126,13 +127,13 @@ int quicki2c_get_report_descriptor(struct quicki2c_device *qcdev)
}

int quicki2c_get_report(struct quicki2c_device *qcdev, u8 report_type,
			unsigned int reportnum, void *buf, u32 buf_len)
			unsigned int reportnum, void *buf, size_t buf_len)
{
	struct hidi2c_report_packet *rpt;
	size_t write_buf_len, read_len = 0;
	int cmd_len, rep_type;
	size_t cmd_len, read_len = 0;
	int rep_type, ret;
	ssize_t len;
	u32 cmd;
	int ret;

	if (report_type == HID_INPUT_REPORT) {
		rep_type = HIDI2C_INPUT;
@@ -145,25 +146,22 @@ int quicki2c_get_report(struct quicki2c_device *qcdev, u8 report_type,

	cmd_len = quicki2c_encode_cmd(qcdev, &cmd, HIDI2C_GET_REPORT, rep_type, reportnum);

	ret = quicki2c_init_write_buf(qcdev, cmd, cmd_len, true, NULL, 0,
	len = quicki2c_init_write_buf(qcdev, cmd, cmd_len, true, NULL, 0,
				      qcdev->report_buf, qcdev->report_len);
	if (ret < 0)
		return ret;

	write_buf_len = ret;
	if (len < 0)
		return len;

	rpt = (struct hidi2c_report_packet *)qcdev->input_buf;

	ret = thc_swdma_read(qcdev->thc_hw, qcdev->report_buf, write_buf_len,
			     NULL, rpt, &read_len);
	ret = thc_swdma_read(qcdev->thc_hw, qcdev->report_buf, len, NULL, rpt, &read_len);
	if (ret) {
		dev_err_once(qcdev->dev, "Get report failed, ret %d, read len (%zu vs %d)\n",
		dev_err_once(qcdev->dev, "Get report failed, ret %d, read len (%zu vs %zu)\n",
			     ret, read_len, buf_len);
		return ret;
	}

	if (HIDI2C_DATA_LEN(le16_to_cpu(rpt->len)) != buf_len || rpt->data[0] != reportnum) {
		dev_err_once(qcdev->dev, "Invalid packet, len (%d vs %d) report id (%d vs %d)\n",
		dev_err_once(qcdev->dev, "Invalid packet, len (%d vs %zu) report id (%d vs %d)\n",
			     le16_to_cpu(rpt->len), buf_len, rpt->data[0], reportnum);
		return -EINVAL;
	}
@@ -174,7 +172,7 @@ int quicki2c_get_report(struct quicki2c_device *qcdev, u8 report_type,
}

int quicki2c_set_report(struct quicki2c_device *qcdev, u8 report_type,
			unsigned int reportnum, void *buf, u32 buf_len)
			unsigned int reportnum, void *buf, size_t buf_len)
{
	int rep_type;
	int ret;
@@ -197,6 +195,25 @@ int quicki2c_set_report(struct quicki2c_device *qcdev, u8 report_type,
	return buf_len;
}

int quicki2c_output_report(struct quicki2c_device *qcdev, void *buf, size_t buf_len)
{
	ssize_t len;
	int ret;

	len = quicki2c_init_write_buf(qcdev, 0, 0, false, buf, buf_len,
				      qcdev->report_buf, qcdev->report_len);
	if (len < 0)
		return -EINVAL;

	ret = thc_dma_write(qcdev->thc_hw, qcdev->report_buf, len);
	if (ret) {
		dev_err(qcdev->dev, "Output Report failed, ret %d\n", ret);
		return ret;
	}

	return buf_len;
}

#define HIDI2C_RESET_TIMEOUT		5

int quicki2c_reset(struct quicki2c_device *qcdev)
+3 −2
Original line number Diff line number Diff line
@@ -10,9 +10,10 @@ struct quicki2c_device;

int quicki2c_set_power(struct quicki2c_device *qcdev, enum hidi2c_power_state power_state);
int quicki2c_get_report(struct quicki2c_device *qcdev, u8 report_type,
			unsigned int reportnum, void *buf, u32 buf_len);
			unsigned int reportnum, void *buf, size_t buf_len);
int quicki2c_set_report(struct quicki2c_device *qcdev, u8 report_type,
			unsigned int reportnum, void *buf, u32 buf_len);
			unsigned int reportnum, void *buf, size_t buf_len);
int quicki2c_output_report(struct quicki2c_device *qcdev, void *buf, size_t buf_len);
int quicki2c_get_device_descriptor(struct quicki2c_device *qcdev);
int quicki2c_get_report_descriptor(struct quicki2c_device *qcdev);
int quicki2c_reset(struct quicki2c_device *qcdev);