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