brintos

brintos / linux-shallow public Read only

0
0
Text · 10.5 KiB · 3438d39 Raw
355 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  AMD SFH Client Layer4 *  Copyright 2020-2021 Advanced Micro Devices, Inc.5 *  Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com>6 *	     Sandeep Singh <Sandeep.singh@amd.com>7 *	     Basavaraj Natikar <Basavaraj.Natikar@amd.com>8 */9 10#include <linux/dma-mapping.h>11#include <linux/hid.h>12#include <linux/list.h>13#include <linux/slab.h>14#include <linux/workqueue.h>15#include <linux/errno.h>16 17#include "hid_descriptor/amd_sfh_hid_desc.h"18#include "amd_sfh_pcie.h"19#include "amd_sfh_hid.h"20 21void amd_sfh_set_report(struct hid_device *hid, int report_id,22			int report_type)23{24	struct amdtp_hid_data *hid_data = hid->driver_data;25	struct amdtp_cl_data *cli_data = hid_data->cli_data;26	int i;27 28	for (i = 0; i < cli_data->num_hid_devices; i++) {29		if (cli_data->hid_sensor_hubs[i] == hid) {30			cli_data->cur_hid_dev = i;31			break;32		}33	}34	amdtp_hid_wakeup(hid);35}36 37int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type)38{39	struct amdtp_hid_data *hid_data = hid->driver_data;40	struct amdtp_cl_data *cli_data = hid_data->cli_data;41	struct request_list *req_list = &cli_data->req_list;42	int i;43 44	for (i = 0; i < cli_data->num_hid_devices; i++) {45		if (cli_data->hid_sensor_hubs[i] == hid) {46			struct request_list *new = kzalloc(sizeof(*new), GFP_KERNEL);47 48			if (!new)49				return -ENOMEM;50 51			new->current_index = i;52			new->sensor_idx = cli_data->sensor_idx[i];53			new->hid = hid;54			new->report_type = report_type;55			new->report_id = report_id;56			cli_data->report_id[i] = report_id;57			cli_data->request_done[i] = false;58			list_add(&new->list, &req_list->list);59			break;60		}61	}62	schedule_delayed_work(&cli_data->work, 0);63	return 0;64}65 66void amd_sfh_work(struct work_struct *work)67{68	struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work);69	struct request_list *req_list = &cli_data->req_list;70	struct amd_input_data *in_data = cli_data->in_data;71	struct request_list *req_node;72	u8 current_index, sensor_index;73	struct amd_mp2_ops *mp2_ops;74	struct amd_mp2_dev *mp2;75	u8 report_id, node_type;76	u8 report_size = 0;77 78	req_node = list_last_entry(&req_list->list, struct request_list, list);79	list_del(&req_node->list);80	current_index = req_node->current_index;81	sensor_index = req_node->sensor_idx;82	report_id = req_node->report_id;83	node_type = req_node->report_type;84	kfree(req_node);85 86	mp2 = container_of(in_data, struct amd_mp2_dev, in_data);87	mp2_ops = mp2->mp2_ops;88	if (node_type == HID_FEATURE_REPORT) {89		report_size = mp2_ops->get_feat_rep(sensor_index, report_id,90						    cli_data->feature_report[current_index]);91		if (report_size)92			hid_input_report(cli_data->hid_sensor_hubs[current_index],93					 cli_data->report_type[current_index],94					 cli_data->feature_report[current_index], report_size, 0);95		else96			pr_err("AMDSFH: Invalid report size\n");97 98	} else if (node_type == HID_INPUT_REPORT) {99		report_size = mp2_ops->get_in_rep(current_index, sensor_index, report_id, in_data);100		if (report_size)101			hid_input_report(cli_data->hid_sensor_hubs[current_index],102					 cli_data->report_type[current_index],103					 in_data->input_report[current_index], report_size, 0);104		else105			pr_err("AMDSFH: Invalid report size\n");106	}107	cli_data->cur_hid_dev = current_index;108	cli_data->sensor_requested_cnt[current_index] = 0;109	amdtp_hid_wakeup(cli_data->hid_sensor_hubs[current_index]);110}111 112void amd_sfh_work_buffer(struct work_struct *work)113{114	struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work);115	struct amd_input_data *in_data = cli_data->in_data;116	struct amd_mp2_dev *mp2;117	u8 report_size;118	int i;119 120	for (i = 0; i < cli_data->num_hid_devices; i++) {121		if (cli_data->sensor_sts[i] == SENSOR_ENABLED) {122			mp2 = container_of(in_data, struct amd_mp2_dev, in_data);123			report_size = mp2->mp2_ops->get_in_rep(i, cli_data->sensor_idx[i],124							       cli_data->report_id[i], in_data);125			hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,126					 in_data->input_report[i], report_size, 0);127		}128	}129	schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));130}131 132static u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)133{134	if (mp2->mp2_ops->response)135		sensor_sts = mp2->mp2_ops->response(mp2, sid, sensor_sts);136 137	return sensor_sts;138}139 140static const char *get_sensor_name(int idx)141{142	switch (idx) {143	case accel_idx:144		return "accelerometer";145	case gyro_idx:146		return "gyroscope";147	case mag_idx:148		return "magnetometer";149	case als_idx:150	case ACS_IDX: /* ambient color sensor */151		return "ALS";152	case HPD_IDX:153		return "HPD";154	default:155		return "unknown sensor type";156	}157}158 159static void amd_sfh_resume(struct amd_mp2_dev *mp2)160{161	struct amdtp_cl_data *cl_data = mp2->cl_data;162	struct amd_mp2_sensor_info info;163	int i, status;164 165	for (i = 0; i < cl_data->num_hid_devices; i++) {166		if (cl_data->sensor_sts[i] == SENSOR_DISABLED) {167			info.period = AMD_SFH_IDLE_LOOP;168			info.sensor_idx = cl_data->sensor_idx[i];169			info.dma_address = cl_data->sensor_dma_addr[i];170			mp2->mp2_ops->start(mp2, info);171			status = amd_sfh_wait_for_response172					(mp2, cl_data->sensor_idx[i], SENSOR_ENABLED);173			if (status == SENSOR_ENABLED)174				cl_data->sensor_sts[i] = SENSOR_ENABLED;175			dev_dbg(&mp2->pdev->dev, "resume sid 0x%x (%s) status 0x%x\n",176				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),177				cl_data->sensor_sts[i]);178		}179	}180 181	schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));182	amd_sfh_clear_intr(mp2);183}184 185static void amd_sfh_suspend(struct amd_mp2_dev *mp2)186{187	struct amdtp_cl_data *cl_data = mp2->cl_data;188	int i, status;189 190	for (i = 0; i < cl_data->num_hid_devices; i++) {191		if (cl_data->sensor_idx[i] != HPD_IDX &&192		    cl_data->sensor_sts[i] == SENSOR_ENABLED) {193			mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);194			status = amd_sfh_wait_for_response195					(mp2, cl_data->sensor_idx[i], SENSOR_DISABLED);196			if (status != SENSOR_ENABLED)197				cl_data->sensor_sts[i] = SENSOR_DISABLED;198			dev_dbg(&mp2->pdev->dev, "suspend sid 0x%x (%s) status 0x%x\n",199				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),200				cl_data->sensor_sts[i]);201		}202	}203 204	cancel_delayed_work_sync(&cl_data->work_buffer);205	amd_sfh_clear_intr(mp2);206}207 208int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)209{210	struct amd_input_data *in_data = &privdata->in_data;211	struct amdtp_cl_data *cl_data = privdata->cl_data;212	struct amd_mp2_ops *mp2_ops = privdata->mp2_ops;213	struct amd_mp2_sensor_info info;214	struct request_list *req_list;215	struct device *dev;216	u32 feature_report_size;217	u32 input_report_size;218	int rc, i;219	u8 cl_idx;220 221	req_list = &cl_data->req_list;222	dev = &privdata->pdev->dev;223	amd_sfh_set_desc_ops(mp2_ops);224 225	mp2_ops->suspend = amd_sfh_suspend;226	mp2_ops->resume = amd_sfh_resume;227 228	cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]);229	if (cl_data->num_hid_devices == 0)230		return -ENODEV;231	cl_data->is_any_sensor_enabled = false;232 233	INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);234	INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);235	INIT_LIST_HEAD(&req_list->list);236	cl_data->in_data = in_data;237 238	for (i = 0; i < cl_data->num_hid_devices; i++) {239		in_data->sensor_virt_addr[i] = dmam_alloc_coherent(dev, sizeof(int) * 8,240								   &cl_data->sensor_dma_addr[i],241								   GFP_KERNEL);242		if (!in_data->sensor_virt_addr[i]) {243			rc = -ENOMEM;244			goto cleanup;245		}246		cl_data->sensor_sts[i] = SENSOR_DISABLED;247		cl_data->sensor_requested_cnt[i] = 0;248		cl_data->cur_hid_dev = i;249		cl_idx = cl_data->sensor_idx[i];250		cl_data->report_descr_sz[i] = mp2_ops->get_desc_sz(cl_idx, descr_size);251		if (!cl_data->report_descr_sz[i]) {252			rc = -EINVAL;253			goto cleanup;254		}255		feature_report_size = mp2_ops->get_desc_sz(cl_idx, feature_size);256		if (!feature_report_size) {257			rc = -EINVAL;258			goto cleanup;259		}260		input_report_size =  mp2_ops->get_desc_sz(cl_idx, input_size);261		if (!input_report_size) {262			rc = -EINVAL;263			goto cleanup;264		}265		cl_data->feature_report[i] = devm_kzalloc(dev, feature_report_size, GFP_KERNEL);266		if (!cl_data->feature_report[i]) {267			rc = -ENOMEM;268			goto cleanup;269		}270		in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);271		if (!in_data->input_report[i]) {272			rc = -ENOMEM;273			goto cleanup;274		}275		info.period = AMD_SFH_IDLE_LOOP;276		info.sensor_idx = cl_idx;277		info.dma_address = cl_data->sensor_dma_addr[i];278 279		cl_data->report_descr[i] =280			devm_kzalloc(dev, cl_data->report_descr_sz[i], GFP_KERNEL);281		if (!cl_data->report_descr[i]) {282			rc = -ENOMEM;283			goto cleanup;284		}285		rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]);286		if (rc)287			goto cleanup;288		mp2_ops->start(privdata, info);289		cl_data->sensor_sts[i] = amd_sfh_wait_for_response290						(privdata, cl_data->sensor_idx[i], SENSOR_ENABLED);291 292		if (cl_data->sensor_sts[i] == SENSOR_ENABLED)293			cl_data->is_any_sensor_enabled = true;294	}295 296	if (!cl_data->is_any_sensor_enabled ||297	    (mp2_ops->discovery_status && mp2_ops->discovery_status(privdata) == 0)) {298		dev_warn(dev, "Failed to discover, sensors not enabled is %d\n",299			 cl_data->is_any_sensor_enabled);300		rc = -EOPNOTSUPP;301		goto cleanup;302	}303 304	for (i = 0; i < cl_data->num_hid_devices; i++) {305		cl_data->cur_hid_dev = i;306		if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {307			rc = amdtp_hid_probe(i, cl_data);308			if (rc)309				goto cleanup;310		} else {311			cl_data->sensor_sts[i] = SENSOR_DISABLED;312		}313		dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",314			cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),315			cl_data->sensor_sts[i]);316	}317 318	schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));319	return 0;320 321cleanup:322	amd_sfh_hid_client_deinit(privdata);323	for (i = 0; i < cl_data->num_hid_devices; i++) {324		devm_kfree(dev, cl_data->feature_report[i]);325		devm_kfree(dev, in_data->input_report[i]);326		devm_kfree(dev, cl_data->report_descr[i]);327	}328	return rc;329}330 331int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)332{333	struct amdtp_cl_data *cl_data = privdata->cl_data;334	int i, status;335 336	for (i = 0; i < cl_data->num_hid_devices; i++) {337		if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {338			privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]);339			status = amd_sfh_wait_for_response340					(privdata, cl_data->sensor_idx[i], SENSOR_DISABLED);341			if (status != SENSOR_ENABLED)342				cl_data->sensor_sts[i] = SENSOR_DISABLED;343			dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x (%s) status 0x%x\n",344				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),345				cl_data->sensor_sts[i]);346		}347	}348 349	cancel_delayed_work_sync(&cl_data->work);350	cancel_delayed_work_sync(&cl_data->work_buffer);351	amdtp_hid_remove(cl_data);352 353	return 0;354}355