1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * AMD MP2 Sensors transport driver 4 * 5 * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com> 6 * Sandeep Singh <sandeep.singh@amd.com> 7 */ 8 #include <linux/hid.h> 9 #include <linux/wait.h> 10 #include <linux/sched.h> 11 12 #include "amd_sfh_hid.h" 13 14 #define AMD_SFH_RESPONSE_TIMEOUT 1500 15 16 /** 17 * amdtp_hid_parse() - hid-core .parse() callback 18 * @hid: hid device instance 19 * 20 * This function gets called during call to hid_add_device 21 * 22 * Return: 0 on success and non zero on error 23 */ 24 static int amdtp_hid_parse(struct hid_device *hid) 25 { 26 struct amdtp_hid_data *hid_data = hid->driver_data; 27 struct amdtp_cl_data *cli_data = hid_data->cli_data; 28 29 return hid_parse_report(hid, cli_data->report_descr[hid_data->index], 30 cli_data->report_descr_sz[hid_data->index]); 31 } 32 33 /* Empty callbacks with success return code */ 34 static int amdtp_hid_start(struct hid_device *hid) 35 { 36 return 0; 37 } 38 39 static void amdtp_hid_stop(struct hid_device *hid) 40 { 41 } 42 43 static int amdtp_hid_open(struct hid_device *hid) 44 { 45 return 0; 46 } 47 48 static void amdtp_hid_close(struct hid_device *hid) 49 { 50 } 51 52 static int amdtp_raw_request(struct hid_device *hdev, u8 reportnum, 53 u8 *buf, size_t len, u8 rtype, int reqtype) 54 { 55 return 0; 56 } 57 58 static void amdtp_hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype) 59 { 60 int rc; 61 62 switch (reqtype) { 63 case HID_REQ_GET_REPORT: 64 rc = amd_sfh_get_report(hid, rep->id, rep->type); 65 if (rc) 66 dev_err(&hid->dev, "AMDSFH get report error\n"); 67 break; 68 case HID_REQ_SET_REPORT: 69 amd_sfh_set_report(hid, rep->id, reqtype); 70 break; 71 default: 72 break; 73 } 74 } 75 76 static int amdtp_wait_for_response(struct hid_device *hid) 77 { 78 struct amdtp_hid_data *hid_data = hid->driver_data; 79 struct amdtp_cl_data *cli_data = hid_data->cli_data; 80 int i, ret = 0; 81 82 for (i = 0; i < cli_data->num_hid_devices; i++) { 83 if (cli_data->hid_sensor_hubs[i] == hid) 84 break; 85 } 86 87 if (!cli_data->request_done[i]) 88 ret = wait_event_interruptible_timeout(hid_data->hid_wait, 89 cli_data->request_done[i], 90 msecs_to_jiffies(AMD_SFH_RESPONSE_TIMEOUT)); 91 if (ret == -ERESTARTSYS) 92 return -ERESTARTSYS; 93 else if (ret < 0) 94 return -ETIMEDOUT; 95 else 96 return 0; 97 } 98 99 void amdtp_hid_wakeup(struct hid_device *hid) 100 { 101 struct amdtp_hid_data *hid_data = hid->driver_data; 102 struct amdtp_cl_data *cli_data = hid_data->cli_data; 103 104 cli_data->request_done[cli_data->cur_hid_dev] = true; 105 wake_up_interruptible(&hid_data->hid_wait); 106 } 107 108 static struct hid_ll_driver amdtp_hid_ll_driver = { 109 .parse = amdtp_hid_parse, 110 .start = amdtp_hid_start, 111 .stop = amdtp_hid_stop, 112 .open = amdtp_hid_open, 113 .close = amdtp_hid_close, 114 .request = amdtp_hid_request, 115 .wait = amdtp_wait_for_response, 116 .raw_request = amdtp_raw_request, 117 }; 118 119 int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data) 120 { 121 struct hid_device *hid; 122 struct amdtp_hid_data *hid_data; 123 int rc; 124 125 hid = hid_allocate_device(); 126 if (IS_ERR(hid)) 127 return PTR_ERR(hid); 128 129 hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL); 130 if (!hid_data) { 131 rc = -ENOMEM; 132 goto err_hid_data; 133 } 134 135 hid->ll_driver = &amdtp_hid_ll_driver; 136 hid_data->index = cur_hid_dev; 137 hid_data->cli_data = cli_data; 138 init_waitqueue_head(&hid_data->hid_wait); 139 140 hid->driver_data = hid_data; 141 cli_data->hid_sensor_hubs[cur_hid_dev] = hid; 142 hid->bus = BUS_AMD_AMDTP; 143 hid->vendor = AMD_SFH_HID_VENDOR; 144 hid->product = AMD_SFH_HID_PRODUCT; 145 snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-amdtp", 146 hid->vendor, hid->product); 147 148 rc = hid_add_device(hid); 149 if (rc) 150 goto err_hid_device; 151 return 0; 152 153 err_hid_device: 154 kfree(hid_data); 155 err_hid_data: 156 hid_destroy_device(hid); 157 return rc; 158 } 159 160 void amdtp_hid_remove(struct amdtp_cl_data *cli_data) 161 { 162 int i; 163 164 for (i = 0; i < cli_data->num_hid_devices; ++i) { 165 if (cli_data->hid_sensor_hubs[i]) { 166 kfree(cli_data->hid_sensor_hubs[i]->driver_data); 167 hid_destroy_device(cli_data->hid_sensor_hubs[i]); 168 cli_data->hid_sensor_hubs[i] = NULL; 169 } 170 } 171 } 172