xref: /linux/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c (revision 8a20830f2dd180064f25254d9c55beb243fe9223)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /* Copyright (c) 2024 Intel Corporation */
3 
4 #include <linux/bitfield.h>
5 #include <linux/hid.h>
6 #include <linux/hid-over-i2c.h>
7 #include <linux/unaligned.h>
8 
9 #include "intel-thc-dev.h"
10 #include "intel-thc-dma.h"
11 
12 #include "quicki2c-dev.h"
13 #include "quicki2c-hid.h"
14 #include "quicki2c-protocol.h"
15 
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)16 static int quicki2c_init_write_buf(struct quicki2c_device *qcdev, u32 cmd, int cmd_len,
17 				   bool append_data_reg, u8 *data, int data_len,
18 				   u8 *write_buf, int write_buf_len)
19 {
20 	int buf_len, offset = 0;
21 
22 	buf_len = HIDI2C_REG_LEN + cmd_len;
23 
24 	if (append_data_reg)
25 		buf_len += HIDI2C_REG_LEN;
26 
27 	if (data && data_len)
28 		buf_len += data_len + HIDI2C_LENGTH_LEN;
29 
30 	if (buf_len > write_buf_len)
31 		return -EINVAL;
32 
33 	memcpy(write_buf, &qcdev->dev_desc.cmd_reg, HIDI2C_REG_LEN);
34 	offset += HIDI2C_REG_LEN;
35 	memcpy(write_buf + offset, &cmd, cmd_len);
36 	offset += cmd_len;
37 
38 	if (append_data_reg) {
39 		memcpy(write_buf + offset, &qcdev->dev_desc.data_reg, HIDI2C_REG_LEN);
40 		offset += HIDI2C_REG_LEN;
41 	}
42 
43 	if (data && data_len) {
44 		__le16 len = cpu_to_le16(data_len + HIDI2C_LENGTH_LEN);
45 
46 		memcpy(write_buf + offset, &len, HIDI2C_LENGTH_LEN);
47 		offset += HIDI2C_LENGTH_LEN;
48 		memcpy(write_buf + offset, data, data_len);
49 	}
50 
51 	return buf_len;
52 }
53 
quicki2c_encode_cmd(struct quicki2c_device * qcdev,u32 * cmd_buf,u8 opcode,u8 report_type,u8 report_id)54 static int quicki2c_encode_cmd(struct quicki2c_device *qcdev, u32 *cmd_buf,
55 			       u8 opcode, u8 report_type, u8 report_id)
56 {
57 	int cmd_len;
58 
59 	*cmd_buf = FIELD_PREP(HIDI2C_CMD_OPCODE, opcode) |
60 		   FIELD_PREP(HIDI2C_CMD_REPORT_TYPE, report_type);
61 
62 	if (report_id < HIDI2C_CMD_MAX_RI) {
63 		*cmd_buf |= FIELD_PREP(HIDI2C_CMD_REPORT_ID, report_id);
64 		cmd_len = HIDI2C_CMD_LEN;
65 	} else {
66 		*cmd_buf |= FIELD_PREP(HIDI2C_CMD_REPORT_ID, HIDI2C_CMD_MAX_RI) |
67 			    FIELD_PREP(HIDI2C_CMD_3RD_BYTE, report_id);
68 		cmd_len = HIDI2C_CMD_LEN_OPT;
69 	}
70 
71 	return cmd_len;
72 }
73 
write_cmd_to_txdma(struct quicki2c_device * qcdev,int opcode,int report_type,int report_id,u8 * buf,int buf_len)74 static int write_cmd_to_txdma(struct quicki2c_device *qcdev, int opcode,
75 			      int report_type, int report_id, u8 *buf, int buf_len)
76 {
77 	size_t write_buf_len;
78 	int cmd_len, ret;
79 	u32 cmd;
80 
81 	cmd_len = quicki2c_encode_cmd(qcdev, &cmd, opcode, report_type, report_id);
82 
83 	ret = quicki2c_init_write_buf(qcdev, cmd, cmd_len, buf ? true : false, buf,
84 				      buf_len, qcdev->report_buf, qcdev->report_len);
85 	if (ret < 0)
86 		return ret;
87 
88 	write_buf_len = ret;
89 
90 	return thc_dma_write(qcdev->thc_hw, qcdev->report_buf, write_buf_len);
91 }
92 
quicki2c_set_power(struct quicki2c_device * qcdev,enum hidi2c_power_state power_state)93 int quicki2c_set_power(struct quicki2c_device *qcdev, enum hidi2c_power_state power_state)
94 {
95 	return write_cmd_to_txdma(qcdev, HIDI2C_SET_POWER, HIDI2C_RESERVED, power_state, NULL, 0);
96 }
97 
quicki2c_get_device_descriptor(struct quicki2c_device * qcdev)98 int quicki2c_get_device_descriptor(struct quicki2c_device *qcdev)
99 {
100 	u32 read_len = 0;
101 	int ret;
102 
103 	ret = thc_tic_pio_write_and_read(qcdev->thc_hw, qcdev->hid_desc_addr,
104 					 HIDI2C_REG_LEN, NULL, HIDI2C_DEV_DESC_LEN,
105 					 &read_len, (u32 *)&qcdev->dev_desc);
106 	if (ret || HIDI2C_DEV_DESC_LEN != read_len) {
107 		dev_err_once(qcdev->dev, "Get device descriptor failed, ret %d, read len %u\n",
108 			     ret, read_len);
109 		return -EIO;
110 	}
111 
112 	if (le16_to_cpu(qcdev->dev_desc.bcd_ver) != HIDI2C_HID_DESC_BCDVERSION)
113 		return -EOPNOTSUPP;
114 
115 	return 0;
116 }
117 
quicki2c_get_report_descriptor(struct quicki2c_device * qcdev)118 int quicki2c_get_report_descriptor(struct quicki2c_device *qcdev)
119 {
120 	u16 desc_reg = le16_to_cpu(qcdev->dev_desc.report_desc_reg);
121 	size_t read_len = le16_to_cpu(qcdev->dev_desc.report_desc_len);
122 	u32 prd_len = read_len;
123 
124 	return thc_swdma_read(qcdev->thc_hw, (u8 *)&desc_reg, HIDI2C_REG_LEN,
125 			      &prd_len, qcdev->report_descriptor, &read_len);
126 }
127 
quicki2c_get_report(struct quicki2c_device * qcdev,u8 report_type,unsigned int reportnum,void * buf,u32 buf_len)128 int quicki2c_get_report(struct quicki2c_device *qcdev, u8 report_type,
129 			unsigned int reportnum, void *buf, u32 buf_len)
130 {
131 	struct hidi2c_report_packet *rpt;
132 	size_t write_buf_len, read_len = 0;
133 	int cmd_len, rep_type;
134 	u32 cmd;
135 	int ret;
136 
137 	if (report_type == HID_INPUT_REPORT) {
138 		rep_type = HIDI2C_INPUT;
139 	} else if (report_type == HID_FEATURE_REPORT) {
140 		rep_type = HIDI2C_FEATURE;
141 	} else {
142 		dev_err(qcdev->dev, "Unsupported report type for GET REPORT: %d\n", report_type);
143 		return -EINVAL;
144 	}
145 
146 	cmd_len = quicki2c_encode_cmd(qcdev, &cmd, HIDI2C_GET_REPORT, rep_type, reportnum);
147 
148 	ret = quicki2c_init_write_buf(qcdev, cmd, cmd_len, true, NULL, 0,
149 				      qcdev->report_buf, qcdev->report_len);
150 	if (ret < 0)
151 		return ret;
152 
153 	write_buf_len = ret;
154 
155 	rpt = (struct hidi2c_report_packet *)qcdev->input_buf;
156 
157 	ret = thc_swdma_read(qcdev->thc_hw, qcdev->report_buf, write_buf_len,
158 			     NULL, rpt, &read_len);
159 	if (ret) {
160 		dev_err_once(qcdev->dev, "Get report failed, ret %d, read len (%zu vs %d)\n",
161 			     ret, read_len, buf_len);
162 		return ret;
163 	}
164 
165 	if (HIDI2C_DATA_LEN(le16_to_cpu(rpt->len)) != buf_len || rpt->data[0] != reportnum) {
166 		dev_err_once(qcdev->dev, "Invalid packet, len (%d vs %d) report id (%d vs %d)\n",
167 			     le16_to_cpu(rpt->len), buf_len, rpt->data[0], reportnum);
168 		return -EINVAL;
169 	}
170 
171 	memcpy(buf, rpt->data, buf_len);
172 
173 	return buf_len;
174 }
175 
quicki2c_set_report(struct quicki2c_device * qcdev,u8 report_type,unsigned int reportnum,void * buf,u32 buf_len)176 int quicki2c_set_report(struct quicki2c_device *qcdev, u8 report_type,
177 			unsigned int reportnum, void *buf, u32 buf_len)
178 {
179 	int rep_type;
180 	int ret;
181 
182 	if (report_type == HID_OUTPUT_REPORT) {
183 		rep_type = HIDI2C_OUTPUT;
184 	} else if (report_type == HID_FEATURE_REPORT) {
185 		rep_type = HIDI2C_FEATURE;
186 	} else {
187 		dev_err(qcdev->dev, "Unsupported report type for SET REPORT: %d\n", report_type);
188 		return -EINVAL;
189 	}
190 
191 	ret = write_cmd_to_txdma(qcdev, HIDI2C_SET_REPORT, rep_type, reportnum, buf, buf_len);
192 	if (ret) {
193 		dev_err_once(qcdev->dev, "Set Report failed, ret %d\n", ret);
194 		return ret;
195 	}
196 
197 	return buf_len;
198 }
199 
200 #define HIDI2C_RESET_TIMEOUT		5
201 
quicki2c_reset(struct quicki2c_device * qcdev)202 int quicki2c_reset(struct quicki2c_device *qcdev)
203 {
204 	u16 input_reg = le16_to_cpu(qcdev->dev_desc.input_reg);
205 	size_t read_len = HIDI2C_LENGTH_LEN;
206 	u32 prd_len = read_len;
207 	int ret;
208 
209 	qcdev->reset_ack = false;
210 	qcdev->state = QUICKI2C_RESETING;
211 
212 	ret = write_cmd_to_txdma(qcdev, HIDI2C_RESET, HIDI2C_RESERVED, 0, NULL, 0);
213 	if (ret) {
214 		dev_err_once(qcdev->dev, "Send reset command failed, ret %d\n", ret);
215 		return ret;
216 	}
217 
218 	ret = wait_event_interruptible_timeout(qcdev->reset_ack_wq, qcdev->reset_ack,
219 					       HIDI2C_RESET_TIMEOUT * HZ);
220 	if (qcdev->reset_ack)
221 		return 0;
222 
223 	/*
224 	 * Manually read reset response if it wasn't received, in case reset interrupt
225 	 * was missed by touch device or THC hardware.
226 	 */
227 	ret = thc_tic_pio_read(qcdev->thc_hw, input_reg, read_len, &prd_len,
228 			       (u32 *)qcdev->input_buf);
229 	if (ret) {
230 		dev_err_once(qcdev->dev, "Read Reset Response failed, ret %d\n", ret);
231 		return ret;
232 	}
233 
234 	/*
235 	 * Check response packet length, it's first 16 bits of packet.
236 	 * If response packet length is zero, it's reset response, otherwise not.
237 	 */
238 	if (get_unaligned_le16(qcdev->input_buf)) {
239 		dev_err_once(qcdev->dev,
240 			     "Wait reset response timed out ret:%d timeout:%ds\n",
241 			     ret, HIDI2C_RESET_TIMEOUT);
242 		return -ETIMEDOUT;
243 	}
244 
245 	qcdev->reset_ack = true;
246 
247 	return 0;
248 }
249