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