162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AMD SFH Client Layer 462306a36Sopenharmony_ci * Copyright 2020-2021 Advanced Micro Devices, Inc. 562306a36Sopenharmony_ci * Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com> 662306a36Sopenharmony_ci * Sandeep Singh <Sandeep.singh@amd.com> 762306a36Sopenharmony_ci * Basavaraj Natikar <Basavaraj.Natikar@amd.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1162306a36Sopenharmony_ci#include <linux/hid.h> 1262306a36Sopenharmony_ci#include <linux/list.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/workqueue.h> 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "hid_descriptor/amd_sfh_hid_desc.h" 1862306a36Sopenharmony_ci#include "amd_sfh_pcie.h" 1962306a36Sopenharmony_ci#include "amd_sfh_hid.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_civoid amd_sfh_set_report(struct hid_device *hid, int report_id, 2262306a36Sopenharmony_ci int report_type) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct amdtp_hid_data *hid_data = hid->driver_data; 2562306a36Sopenharmony_ci struct amdtp_cl_data *cli_data = hid_data->cli_data; 2662306a36Sopenharmony_ci int i; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci for (i = 0; i < cli_data->num_hid_devices; i++) { 2962306a36Sopenharmony_ci if (cli_data->hid_sensor_hubs[i] == hid) { 3062306a36Sopenharmony_ci cli_data->cur_hid_dev = i; 3162306a36Sopenharmony_ci break; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci amdtp_hid_wakeup(hid); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciint amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct amdtp_hid_data *hid_data = hid->driver_data; 4062306a36Sopenharmony_ci struct amdtp_cl_data *cli_data = hid_data->cli_data; 4162306a36Sopenharmony_ci struct request_list *req_list = &cli_data->req_list; 4262306a36Sopenharmony_ci int i; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci for (i = 0; i < cli_data->num_hid_devices; i++) { 4562306a36Sopenharmony_ci if (cli_data->hid_sensor_hubs[i] == hid) { 4662306a36Sopenharmony_ci struct request_list *new = kzalloc(sizeof(*new), GFP_KERNEL); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (!new) 4962306a36Sopenharmony_ci return -ENOMEM; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci new->current_index = i; 5262306a36Sopenharmony_ci new->sensor_idx = cli_data->sensor_idx[i]; 5362306a36Sopenharmony_ci new->hid = hid; 5462306a36Sopenharmony_ci new->report_type = report_type; 5562306a36Sopenharmony_ci new->report_id = report_id; 5662306a36Sopenharmony_ci cli_data->report_id[i] = report_id; 5762306a36Sopenharmony_ci cli_data->request_done[i] = false; 5862306a36Sopenharmony_ci list_add(&new->list, &req_list->list); 5962306a36Sopenharmony_ci break; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci schedule_delayed_work(&cli_data->work, 0); 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_civoid amd_sfh_work(struct work_struct *work) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work); 6962306a36Sopenharmony_ci struct request_list *req_list = &cli_data->req_list; 7062306a36Sopenharmony_ci struct amd_input_data *in_data = cli_data->in_data; 7162306a36Sopenharmony_ci struct request_list *req_node; 7262306a36Sopenharmony_ci u8 current_index, sensor_index; 7362306a36Sopenharmony_ci struct amd_mp2_ops *mp2_ops; 7462306a36Sopenharmony_ci struct amd_mp2_dev *mp2; 7562306a36Sopenharmony_ci u8 report_id, node_type; 7662306a36Sopenharmony_ci u8 report_size = 0; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci req_node = list_last_entry(&req_list->list, struct request_list, list); 7962306a36Sopenharmony_ci list_del(&req_node->list); 8062306a36Sopenharmony_ci current_index = req_node->current_index; 8162306a36Sopenharmony_ci sensor_index = req_node->sensor_idx; 8262306a36Sopenharmony_ci report_id = req_node->report_id; 8362306a36Sopenharmony_ci node_type = req_node->report_type; 8462306a36Sopenharmony_ci kfree(req_node); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci mp2 = container_of(in_data, struct amd_mp2_dev, in_data); 8762306a36Sopenharmony_ci mp2_ops = mp2->mp2_ops; 8862306a36Sopenharmony_ci if (node_type == HID_FEATURE_REPORT) { 8962306a36Sopenharmony_ci report_size = mp2_ops->get_feat_rep(sensor_index, report_id, 9062306a36Sopenharmony_ci cli_data->feature_report[current_index]); 9162306a36Sopenharmony_ci if (report_size) 9262306a36Sopenharmony_ci hid_input_report(cli_data->hid_sensor_hubs[current_index], 9362306a36Sopenharmony_ci cli_data->report_type[current_index], 9462306a36Sopenharmony_ci cli_data->feature_report[current_index], report_size, 0); 9562306a36Sopenharmony_ci else 9662306a36Sopenharmony_ci pr_err("AMDSFH: Invalid report size\n"); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci } else if (node_type == HID_INPUT_REPORT) { 9962306a36Sopenharmony_ci report_size = mp2_ops->get_in_rep(current_index, sensor_index, report_id, in_data); 10062306a36Sopenharmony_ci if (report_size) 10162306a36Sopenharmony_ci hid_input_report(cli_data->hid_sensor_hubs[current_index], 10262306a36Sopenharmony_ci cli_data->report_type[current_index], 10362306a36Sopenharmony_ci in_data->input_report[current_index], report_size, 0); 10462306a36Sopenharmony_ci else 10562306a36Sopenharmony_ci pr_err("AMDSFH: Invalid report size\n"); 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci cli_data->cur_hid_dev = current_index; 10862306a36Sopenharmony_ci cli_data->sensor_requested_cnt[current_index] = 0; 10962306a36Sopenharmony_ci amdtp_hid_wakeup(cli_data->hid_sensor_hubs[current_index]); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_civoid amd_sfh_work_buffer(struct work_struct *work) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work); 11562306a36Sopenharmony_ci struct amd_input_data *in_data = cli_data->in_data; 11662306a36Sopenharmony_ci struct amd_mp2_dev *mp2; 11762306a36Sopenharmony_ci u8 report_size; 11862306a36Sopenharmony_ci int i; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci for (i = 0; i < cli_data->num_hid_devices; i++) { 12162306a36Sopenharmony_ci if (cli_data->sensor_sts[i] == SENSOR_ENABLED) { 12262306a36Sopenharmony_ci mp2 = container_of(in_data, struct amd_mp2_dev, in_data); 12362306a36Sopenharmony_ci report_size = mp2->mp2_ops->get_in_rep(i, cli_data->sensor_idx[i], 12462306a36Sopenharmony_ci cli_data->report_id[i], in_data); 12562306a36Sopenharmony_ci hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT, 12662306a36Sopenharmony_ci in_data->input_report[i], report_size, 0); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci if (mp2->mp2_ops->response) 13562306a36Sopenharmony_ci sensor_sts = mp2->mp2_ops->response(mp2, sid, sensor_sts); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return sensor_sts; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic const char *get_sensor_name(int idx) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci switch (idx) { 14362306a36Sopenharmony_ci case accel_idx: 14462306a36Sopenharmony_ci return "accelerometer"; 14562306a36Sopenharmony_ci case gyro_idx: 14662306a36Sopenharmony_ci return "gyroscope"; 14762306a36Sopenharmony_ci case mag_idx: 14862306a36Sopenharmony_ci return "magnetometer"; 14962306a36Sopenharmony_ci case als_idx: 15062306a36Sopenharmony_ci case ACS_IDX: /* ambient color sensor */ 15162306a36Sopenharmony_ci return "ALS"; 15262306a36Sopenharmony_ci case HPD_IDX: 15362306a36Sopenharmony_ci return "HPD"; 15462306a36Sopenharmony_ci default: 15562306a36Sopenharmony_ci return "unknown sensor type"; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic void amd_sfh_resume(struct amd_mp2_dev *mp2) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct amdtp_cl_data *cl_data = mp2->cl_data; 16262306a36Sopenharmony_ci struct amd_mp2_sensor_info info; 16362306a36Sopenharmony_ci int i, status; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci for (i = 0; i < cl_data->num_hid_devices; i++) { 16662306a36Sopenharmony_ci if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { 16762306a36Sopenharmony_ci info.period = AMD_SFH_IDLE_LOOP; 16862306a36Sopenharmony_ci info.sensor_idx = cl_data->sensor_idx[i]; 16962306a36Sopenharmony_ci info.dma_address = cl_data->sensor_dma_addr[i]; 17062306a36Sopenharmony_ci mp2->mp2_ops->start(mp2, info); 17162306a36Sopenharmony_ci status = amd_sfh_wait_for_response 17262306a36Sopenharmony_ci (mp2, cl_data->sensor_idx[i], SENSOR_ENABLED); 17362306a36Sopenharmony_ci if (status == SENSOR_ENABLED) 17462306a36Sopenharmony_ci cl_data->sensor_sts[i] = SENSOR_ENABLED; 17562306a36Sopenharmony_ci dev_dbg(&mp2->pdev->dev, "resume sid 0x%x (%s) status 0x%x\n", 17662306a36Sopenharmony_ci cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 17762306a36Sopenharmony_ci cl_data->sensor_sts[i]); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); 18262306a36Sopenharmony_ci amd_sfh_clear_intr(mp2); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic void amd_sfh_suspend(struct amd_mp2_dev *mp2) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct amdtp_cl_data *cl_data = mp2->cl_data; 18862306a36Sopenharmony_ci int i, status; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci for (i = 0; i < cl_data->num_hid_devices; i++) { 19162306a36Sopenharmony_ci if (cl_data->sensor_idx[i] != HPD_IDX && 19262306a36Sopenharmony_ci cl_data->sensor_sts[i] == SENSOR_ENABLED) { 19362306a36Sopenharmony_ci mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]); 19462306a36Sopenharmony_ci status = amd_sfh_wait_for_response 19562306a36Sopenharmony_ci (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED); 19662306a36Sopenharmony_ci if (status != SENSOR_ENABLED) 19762306a36Sopenharmony_ci cl_data->sensor_sts[i] = SENSOR_DISABLED; 19862306a36Sopenharmony_ci dev_dbg(&mp2->pdev->dev, "suspend sid 0x%x (%s) status 0x%x\n", 19962306a36Sopenharmony_ci cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 20062306a36Sopenharmony_ci cl_data->sensor_sts[i]); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci cancel_delayed_work_sync(&cl_data->work_buffer); 20562306a36Sopenharmony_ci amd_sfh_clear_intr(mp2); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciint amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct amd_input_data *in_data = &privdata->in_data; 21162306a36Sopenharmony_ci struct amdtp_cl_data *cl_data = privdata->cl_data; 21262306a36Sopenharmony_ci struct amd_mp2_ops *mp2_ops = privdata->mp2_ops; 21362306a36Sopenharmony_ci struct amd_mp2_sensor_info info; 21462306a36Sopenharmony_ci struct request_list *req_list; 21562306a36Sopenharmony_ci struct device *dev; 21662306a36Sopenharmony_ci u32 feature_report_size; 21762306a36Sopenharmony_ci u32 input_report_size; 21862306a36Sopenharmony_ci int rc, i; 21962306a36Sopenharmony_ci u8 cl_idx; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci req_list = &cl_data->req_list; 22262306a36Sopenharmony_ci dev = &privdata->pdev->dev; 22362306a36Sopenharmony_ci amd_sfh_set_desc_ops(mp2_ops); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci mp2_ops->suspend = amd_sfh_suspend; 22662306a36Sopenharmony_ci mp2_ops->resume = amd_sfh_resume; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]); 22962306a36Sopenharmony_ci if (cl_data->num_hid_devices == 0) 23062306a36Sopenharmony_ci return -ENODEV; 23162306a36Sopenharmony_ci cl_data->is_any_sensor_enabled = false; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); 23462306a36Sopenharmony_ci INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); 23562306a36Sopenharmony_ci INIT_LIST_HEAD(&req_list->list); 23662306a36Sopenharmony_ci cl_data->in_data = in_data; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci for (i = 0; i < cl_data->num_hid_devices; i++) { 23962306a36Sopenharmony_ci in_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8, 24062306a36Sopenharmony_ci &cl_data->sensor_dma_addr[i], 24162306a36Sopenharmony_ci GFP_KERNEL); 24262306a36Sopenharmony_ci if (!in_data->sensor_virt_addr[i]) { 24362306a36Sopenharmony_ci rc = -ENOMEM; 24462306a36Sopenharmony_ci goto cleanup; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci cl_data->sensor_sts[i] = SENSOR_DISABLED; 24762306a36Sopenharmony_ci cl_data->sensor_requested_cnt[i] = 0; 24862306a36Sopenharmony_ci cl_data->cur_hid_dev = i; 24962306a36Sopenharmony_ci cl_idx = cl_data->sensor_idx[i]; 25062306a36Sopenharmony_ci cl_data->report_descr_sz[i] = mp2_ops->get_desc_sz(cl_idx, descr_size); 25162306a36Sopenharmony_ci if (!cl_data->report_descr_sz[i]) { 25262306a36Sopenharmony_ci rc = -EINVAL; 25362306a36Sopenharmony_ci goto cleanup; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci feature_report_size = mp2_ops->get_desc_sz(cl_idx, feature_size); 25662306a36Sopenharmony_ci if (!feature_report_size) { 25762306a36Sopenharmony_ci rc = -EINVAL; 25862306a36Sopenharmony_ci goto cleanup; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci input_report_size = mp2_ops->get_desc_sz(cl_idx, input_size); 26162306a36Sopenharmony_ci if (!input_report_size) { 26262306a36Sopenharmony_ci rc = -EINVAL; 26362306a36Sopenharmony_ci goto cleanup; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci cl_data->feature_report[i] = devm_kzalloc(dev, feature_report_size, GFP_KERNEL); 26662306a36Sopenharmony_ci if (!cl_data->feature_report[i]) { 26762306a36Sopenharmony_ci rc = -ENOMEM; 26862306a36Sopenharmony_ci goto cleanup; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL); 27162306a36Sopenharmony_ci if (!in_data->input_report[i]) { 27262306a36Sopenharmony_ci rc = -ENOMEM; 27362306a36Sopenharmony_ci goto cleanup; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci info.period = AMD_SFH_IDLE_LOOP; 27662306a36Sopenharmony_ci info.sensor_idx = cl_idx; 27762306a36Sopenharmony_ci info.dma_address = cl_data->sensor_dma_addr[i]; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci cl_data->report_descr[i] = 28062306a36Sopenharmony_ci devm_kzalloc(dev, cl_data->report_descr_sz[i], GFP_KERNEL); 28162306a36Sopenharmony_ci if (!cl_data->report_descr[i]) { 28262306a36Sopenharmony_ci rc = -ENOMEM; 28362306a36Sopenharmony_ci goto cleanup; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]); 28662306a36Sopenharmony_ci if (rc) 28762306a36Sopenharmony_ci goto cleanup; 28862306a36Sopenharmony_ci mp2_ops->start(privdata, info); 28962306a36Sopenharmony_ci cl_data->sensor_sts[i] = amd_sfh_wait_for_response 29062306a36Sopenharmony_ci (privdata, cl_data->sensor_idx[i], SENSOR_ENABLED); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci for (i = 0; i < cl_data->num_hid_devices; i++) { 29462306a36Sopenharmony_ci cl_data->cur_hid_dev = i; 29562306a36Sopenharmony_ci if (cl_data->sensor_sts[i] == SENSOR_ENABLED) { 29662306a36Sopenharmony_ci cl_data->is_any_sensor_enabled = true; 29762306a36Sopenharmony_ci rc = amdtp_hid_probe(i, cl_data); 29862306a36Sopenharmony_ci if (rc) 29962306a36Sopenharmony_ci goto cleanup; 30062306a36Sopenharmony_ci } else { 30162306a36Sopenharmony_ci cl_data->sensor_sts[i] = SENSOR_DISABLED; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n", 30462306a36Sopenharmony_ci cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 30562306a36Sopenharmony_ci cl_data->sensor_sts[i]); 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (!cl_data->is_any_sensor_enabled || 30962306a36Sopenharmony_ci (mp2_ops->discovery_status && mp2_ops->discovery_status(privdata) == 0)) { 31062306a36Sopenharmony_ci dev_warn(dev, "Failed to discover, sensors not enabled is %d\n", cl_data->is_any_sensor_enabled); 31162306a36Sopenharmony_ci rc = -EOPNOTSUPP; 31262306a36Sopenharmony_ci goto cleanup; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); 31562306a36Sopenharmony_ci return 0; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cicleanup: 31862306a36Sopenharmony_ci amd_sfh_hid_client_deinit(privdata); 31962306a36Sopenharmony_ci for (i = 0; i < cl_data->num_hid_devices; i++) { 32062306a36Sopenharmony_ci devm_kfree(dev, cl_data->feature_report[i]); 32162306a36Sopenharmony_ci devm_kfree(dev, in_data->input_report[i]); 32262306a36Sopenharmony_ci devm_kfree(dev, cl_data->report_descr[i]); 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci return rc; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ciint amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct amdtp_cl_data *cl_data = privdata->cl_data; 33062306a36Sopenharmony_ci struct amd_input_data *in_data = cl_data->in_data; 33162306a36Sopenharmony_ci int i, status; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci for (i = 0; i < cl_data->num_hid_devices; i++) { 33462306a36Sopenharmony_ci if (cl_data->sensor_sts[i] == SENSOR_ENABLED) { 33562306a36Sopenharmony_ci privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]); 33662306a36Sopenharmony_ci status = amd_sfh_wait_for_response 33762306a36Sopenharmony_ci (privdata, cl_data->sensor_idx[i], SENSOR_DISABLED); 33862306a36Sopenharmony_ci if (status != SENSOR_ENABLED) 33962306a36Sopenharmony_ci cl_data->sensor_sts[i] = SENSOR_DISABLED; 34062306a36Sopenharmony_ci dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x (%s) status 0x%x\n", 34162306a36Sopenharmony_ci cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 34262306a36Sopenharmony_ci cl_data->sensor_sts[i]); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci cancel_delayed_work_sync(&cl_data->work); 34762306a36Sopenharmony_ci cancel_delayed_work_sync(&cl_data->work_buffer); 34862306a36Sopenharmony_ci amdtp_hid_remove(cl_data); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci for (i = 0; i < cl_data->num_hid_devices; i++) { 35162306a36Sopenharmony_ci if (in_data->sensor_virt_addr[i]) { 35262306a36Sopenharmony_ci dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int), 35362306a36Sopenharmony_ci in_data->sensor_virt_addr[i], 35462306a36Sopenharmony_ci cl_data->sensor_dma_addr[i]); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci return 0; 35862306a36Sopenharmony_ci} 359