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 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 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 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 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 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 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 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 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 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