brintos

brintos / linux-shallow public Read only

0
0
Text · 9.1 KiB · db36d87 Raw
357 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * AMD MP2 1.1 communication driver4 *5 * Copyright (c) 2022, Advanced Micro Devices, Inc.6 * All Rights Reserved.7 *8 * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com>9 */10 11#include <linux/delay.h>12#include <linux/hid.h>13 14#include "amd_sfh_init.h"15#include "amd_sfh_interface.h"16#include "../hid_descriptor/amd_sfh_hid_desc.h"17 18static int amd_sfh_get_sensor_num(struct amd_mp2_dev *mp2, u8 *sensor_id)19{20	struct sfh_sensor_list *slist;21	struct sfh_base_info binfo;22	int num_of_sensors = 0;23	int i;24 25	memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info));26	slist = &binfo.sbase.s_list;27 28	for (i = 0; i < MAX_IDX; i++) {29		switch (i) {30		case ACCEL_IDX:31		case GYRO_IDX:32		case MAG_IDX:33		case ALS_IDX:34		case HPD_IDX:35			if (BIT(i) & slist->sl.sensors)36				sensor_id[num_of_sensors++] = i;37			break;38		}39	}40 41	return num_of_sensors;42}43 44static u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)45{46	if (mp2->mp2_ops->response)47		return mp2->mp2_ops->response(mp2, sid, cmd_id);48 49	return 0;50}51 52static const char *get_sensor_name(int idx)53{54	switch (idx) {55	case ACCEL_IDX:56		return "accelerometer";57	case GYRO_IDX:58		return "gyroscope";59	case MAG_IDX:60		return "magnetometer";61	case ALS_IDX:62		return "ALS";63	case HPD_IDX:64		return "HPD";65	default:66		return "unknown sensor type";67	}68}69 70static int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)71{72	struct amdtp_cl_data *cl_data = privdata->cl_data;73	int i, status;74 75	for (i = 0; i < cl_data->num_hid_devices; i++) {76		switch (cl_data->sensor_idx[i]) {77		case HPD_IDX:78			privdata->dev_en.is_hpd_present = false;79			break;80		case ALS_IDX:81			privdata->dev_en.is_als_present = false;82			break;83		}84 85		if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {86			privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]);87			status = amd_sfh_wait_for_response88					(privdata, cl_data->sensor_idx[i], DISABLE_SENSOR);89			if (status == 0)90				cl_data->sensor_sts[i] = SENSOR_DISABLED;91			dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x (%s) status 0x%x\n",92				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),93				cl_data->sensor_sts[i]);94		}95	}96 97	cancel_delayed_work_sync(&cl_data->work);98	cancel_delayed_work_sync(&cl_data->work_buffer);99	amdtp_hid_remove(cl_data);100 101	return 0;102}103 104static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata)105{106	struct amd_input_data *in_data = &privdata->in_data;107	struct amdtp_cl_data *cl_data = privdata->cl_data;108	struct amd_mp2_ops *mp2_ops = privdata->mp2_ops;109	struct amd_mp2_sensor_info info;110	struct request_list *req_list;111	u32 feature_report_size;112	u32 input_report_size;113	struct device *dev;114	int rc, i, status;115	u8 cl_idx;116 117	req_list = &cl_data->req_list;118	dev = &privdata->pdev->dev;119	amd_sfh1_1_set_desc_ops(mp2_ops);120 121	cl_data->num_hid_devices = amd_sfh_get_sensor_num(privdata, &cl_data->sensor_idx[0]);122	if (cl_data->num_hid_devices == 0)123		return -ENODEV;124	cl_data->is_any_sensor_enabled = false;125 126	INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);127	INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);128	INIT_LIST_HEAD(&req_list->list);129	cl_data->in_data = in_data;130 131	for (i = 0; i < cl_data->num_hid_devices; i++) {132		cl_data->sensor_sts[i] = SENSOR_DISABLED;133		cl_data->sensor_requested_cnt[i] = 0;134		cl_data->cur_hid_dev = i;135		cl_idx = cl_data->sensor_idx[i];136 137		cl_data->report_descr_sz[i] = mp2_ops->get_desc_sz(cl_idx, descr_size);138		if (!cl_data->report_descr_sz[i]) {139			rc = -EINVAL;140			goto cleanup;141		}142		feature_report_size = mp2_ops->get_desc_sz(cl_idx, feature_size);143		if (!feature_report_size) {144			rc = -EINVAL;145			goto cleanup;146		}147		input_report_size =  mp2_ops->get_desc_sz(cl_idx, input_size);148		if (!input_report_size) {149			rc = -EINVAL;150			goto cleanup;151		}152		cl_data->feature_report[i] = devm_kzalloc(dev, feature_report_size, GFP_KERNEL);153		if (!cl_data->feature_report[i]) {154			rc = -ENOMEM;155			goto cleanup;156		}157		in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);158		if (!in_data->input_report[i]) {159			rc = -ENOMEM;160			goto cleanup;161		}162 163		info.sensor_idx = cl_idx;164 165		cl_data->report_descr[i] =166			devm_kzalloc(dev, cl_data->report_descr_sz[i], GFP_KERNEL);167		if (!cl_data->report_descr[i]) {168			rc = -ENOMEM;169			goto cleanup;170		}171		rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]);172		if (rc)173			goto cleanup;174 175		writel(0, privdata->mmio + amd_get_p2c_val(privdata, 0));176		mp2_ops->start(privdata, info);177		status = amd_sfh_wait_for_response178				(privdata, cl_data->sensor_idx[i], ENABLE_SENSOR);179 180		cl_data->sensor_sts[i] = (status == 0) ? SENSOR_ENABLED : SENSOR_DISABLED;181	}182 183	for (i = 0; i < cl_data->num_hid_devices; i++) {184		cl_data->cur_hid_dev = i;185		if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {186			cl_data->is_any_sensor_enabled = true;187			rc = amdtp_hid_probe(i, cl_data);188			if (rc)189				goto cleanup;190			switch (cl_data->sensor_idx[i]) {191			case HPD_IDX:192				privdata->dev_en.is_hpd_present = true;193				break;194			case ALS_IDX:195				privdata->dev_en.is_als_present = true;196				break;197			}198		}199		dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",200			cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),201			cl_data->sensor_sts[i]);202	}203 204	if (!cl_data->is_any_sensor_enabled) {205		dev_warn(dev, "No sensor registered, sensors not enabled is %d\n",206			 cl_data->is_any_sensor_enabled);207		rc = -EOPNOTSUPP;208		goto cleanup;209	}210 211	schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));212	return 0;213 214cleanup:215	amd_sfh_hid_client_deinit(privdata);216	for (i = 0; i < cl_data->num_hid_devices; i++) {217		devm_kfree(dev, cl_data->feature_report[i]);218		devm_kfree(dev, in_data->input_report[i]);219		devm_kfree(dev, cl_data->report_descr[i]);220	}221	return rc;222}223 224static void amd_sfh_resume(struct amd_mp2_dev *mp2)225{226	struct amdtp_cl_data *cl_data = mp2->cl_data;227	struct amd_mp2_sensor_info info;228	int i, status;229 230	if (!cl_data->is_any_sensor_enabled) {231		amd_sfh_clear_intr(mp2);232		return;233	}234 235	for (i = 0; i < cl_data->num_hid_devices; i++) {236		if (cl_data->sensor_sts[i] == SENSOR_DISABLED) {237			info.sensor_idx = cl_data->sensor_idx[i];238			mp2->mp2_ops->start(mp2, info);239			status = amd_sfh_wait_for_response240					(mp2, cl_data->sensor_idx[i], ENABLE_SENSOR);241			if (status == 0)242				status = SENSOR_ENABLED;243			if (status == SENSOR_ENABLED)244				cl_data->sensor_sts[i] = SENSOR_ENABLED;245			dev_dbg(&mp2->pdev->dev, "resume sid 0x%x (%s) status 0x%x\n",246				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),247				cl_data->sensor_sts[i]);248		}249	}250 251	schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));252	amd_sfh_clear_intr(mp2);253}254 255static void amd_sfh_suspend(struct amd_mp2_dev *mp2)256{257	struct amdtp_cl_data *cl_data = mp2->cl_data;258	int i, status;259 260	if (!cl_data->is_any_sensor_enabled) {261		amd_sfh_clear_intr(mp2);262		return;263	}264 265	for (i = 0; i < cl_data->num_hid_devices; i++) {266		if (cl_data->sensor_idx[i] != HPD_IDX &&267		    cl_data->sensor_sts[i] == SENSOR_ENABLED) {268			mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);269			status = amd_sfh_wait_for_response270					(mp2, cl_data->sensor_idx[i], DISABLE_SENSOR);271			if (status == 0)272				status = SENSOR_DISABLED;273			if (status != SENSOR_ENABLED)274				cl_data->sensor_sts[i] = SENSOR_DISABLED;275			dev_dbg(&mp2->pdev->dev, "suspend sid 0x%x (%s) status 0x%x\n",276				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),277				cl_data->sensor_sts[i]);278		}279	}280 281	cancel_delayed_work_sync(&cl_data->work_buffer);282	amd_sfh_clear_intr(mp2);283}284 285static void amd_mp2_pci_remove(void *privdata)286{287	struct amd_mp2_dev *mp2 = privdata;288 289	sfh_deinit_emp2();290	amd_sfh_hid_client_deinit(privdata);291	mp2->mp2_ops->stop_all(mp2);292	pci_intx(mp2->pdev, false);293	amd_sfh_clear_intr(mp2);294}295 296static void amd_sfh_set_ops(struct amd_mp2_dev *mp2)297{298	struct amd_mp2_ops *mp2_ops;299 300	sfh_interface_init(mp2);301	mp2_ops = mp2->mp2_ops;302	mp2_ops->clear_intr = amd_sfh_clear_intr_v2;303	mp2_ops->init_intr = amd_sfh_irq_init_v2;304	mp2_ops->suspend = amd_sfh_suspend;305	mp2_ops->resume = amd_sfh_resume;306	mp2_ops->remove = amd_mp2_pci_remove;307}308 309int amd_sfh1_1_init(struct amd_mp2_dev *mp2)310{311	u32 phy_base = readl(mp2->mmio + amd_get_c2p_val(mp2, 22));312	struct device *dev = &mp2->pdev->dev;313	struct sfh_base_info binfo;314	int rc;315 316	phy_base <<= 21;317	if (!devm_request_mem_region(dev, phy_base, 128 * 1024, "amd_sfh")) {318		dev_dbg(dev, "can't reserve mmio registers\n");319		return -ENOMEM;320	}321 322	mp2->vsbase = devm_ioremap(dev, phy_base, 128 * 1024);323	if (!mp2->vsbase) {324		dev_dbg(dev, "failed to remap vsbase\n");325		return -ENOMEM;326	}327 328	/* Before accessing give time for SFH firmware for processing configuration */329	msleep(5000);330 331	memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info));332	if (binfo.sbase.fw_info.fw_ver == 0 || binfo.sbase.s_list.sl.sensors == 0) {333		dev_dbg(dev, "No sensor registered\n");334		return -EOPNOTSUPP;335	}336	dev_dbg(dev, "firmware version 0x%x\n", binfo.sbase.fw_info.fw_ver);337 338	amd_sfh_set_ops(mp2);339 340	rc = amd_sfh_irq_init(mp2);341	if (rc) {342		sfh_deinit_emp2();343		dev_err(dev, "amd_sfh_irq_init failed\n");344		return rc;345	}346 347	rc = amd_sfh1_1_hid_client_init(mp2);348	if (rc) {349		sfh_deinit_emp2();350		if ((rc != -ENODEV) && (rc != -EOPNOTSUPP))351			dev_err(dev, "amd_sfh1_1_hid_client_init failed\n");352		return rc;353	}354 355	return rc;356}357