File Index
Files and directories
Sign in
FILE

amd_sfh_init.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * AMD MP2 1.1 communication driver
  4 *
  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 SRA_IDX:
 34		case ALS_IDX:
 35		case HPD_IDX:
 36			if (BIT(i) & slist->sl.sensors)
 37				sensor_id[num_of_sensors++] = i;
 38			break;
 39		}
 40	}
 41
 42	return num_of_sensors;
 43}
 44
 45static u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)
 46{
 47	if (mp2->mp2_ops->response)
 48		return mp2->mp2_ops->response(mp2, sid, cmd_id);
 49
 50	return 0;
 51}
 52
 53static const char *get_sensor_name(int idx)
 54{
 55	switch (idx) {
 56	case ACCEL_IDX:
 57		return "accelerometer";
 58	case GYRO_IDX:
 59		return "gyroscope";
 60	case MAG_IDX:
 61		return "magnetometer";
 62	case SRA_IDX:
 63		return "SRA";
 64	case ALS_IDX:
 65		return "ALS";
 66	case HPD_IDX:
 67		return "HPD";
 68	default:
 69		return "unknown sensor type";
 70	}
 71}
 72
 73static int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
 74{
 75	struct amdtp_cl_data *cl_data = privdata->cl_data;
 76	int i, status;
 77
 78	for (i = 0; i < cl_data->num_hid_devices; i++) {
 79		switch (cl_data->sensor_idx[i]) {
 80		case HPD_IDX:
 81			privdata->dev_en.is_hpd_present = false;
 82			break;
 83		case ALS_IDX:
 84			privdata->dev_en.is_als_present = false;
 85			break;
 86		case SRA_IDX:
 87			privdata->dev_en.is_sra_present = false;
 88			break;
 89		}
 90
 91		if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
 92			privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]);
 93			status = amd_sfh_wait_for_response
 94					(privdata, cl_data->sensor_idx[i], DISABLE_SENSOR);
 95			if (status == 0)
 96				cl_data->sensor_sts[i] = SENSOR_DISABLED;
 97			dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x (%s) status 0x%x\n",
 98				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
 99				cl_data->sensor_sts[i]);
100		}
101	}
102
103	cancel_delayed_work_sync(&cl_data->work);
104	cancel_delayed_work_sync(&cl_data->work_buffer);
105	amdtp_hid_remove(cl_data);
106
107	return 0;
108}
109
110static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata)
111{
112	struct amd_input_data *in_data = &privdata->in_data;
113	struct amdtp_cl_data *cl_data = privdata->cl_data;
114	struct amd_mp2_ops *mp2_ops = privdata->mp2_ops;
115	struct amd_mp2_sensor_info info;
116	struct request_list *req_list;
117	u32 feature_report_size;
118	u32 input_report_size;
119	struct device *dev;
120	int rc, i, status;
121	u8 cl_idx;
122
123	req_list = &cl_data->req_list;
124	dev = &privdata->pdev->dev;
125	amd_sfh1_1_set_desc_ops(mp2_ops);
126
127	cl_data->num_hid_devices = amd_sfh_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
128	if (cl_data->num_hid_devices == 0)
129		return -ENODEV;
130	cl_data->is_any_sensor_enabled = false;
131
132	INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
133	INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
134	INIT_LIST_HEAD(&req_list->list);
135	cl_data->in_data = in_data;
136
137	for (i = 0; i < cl_data->num_hid_devices; i++) {
138		cl_data->sensor_sts[i] = SENSOR_DISABLED;
139
140		if (cl_data->sensor_idx[i] == SRA_IDX) {
141			info.sensor_idx = cl_data->sensor_idx[i];
142			writel(0, privdata->mmio + amd_get_p2c_val(privdata, 0));
143			mp2_ops->start(privdata, info);
144			status = amd_sfh_wait_for_response
145				(privdata, cl_data->sensor_idx[i], ENABLE_SENSOR);
146
147			cl_data->sensor_sts[i] = (status == 0) ? SENSOR_ENABLED : SENSOR_DISABLED;
148			if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
149				cl_data->is_any_sensor_enabled = true;
150				privdata->dev_en.is_sra_present = true;
151			}
152			continue;
153		}
154
155		cl_data->sensor_requested_cnt[i] = 0;
156		cl_data->cur_hid_dev = i;
157		cl_idx = cl_data->sensor_idx[i];
158
159		cl_data->report_descr_sz[i] = mp2_ops->get_desc_sz(cl_idx, descr_size);
160		if (!cl_data->report_descr_sz[i]) {
161			rc = -EINVAL;
162			goto cleanup;
163		}
164		feature_report_size = mp2_ops->get_desc_sz(cl_idx, feature_size);
165		if (!feature_report_size) {
166			rc = -EINVAL;
167			goto cleanup;
168		}
169		input_report_size =  mp2_ops->get_desc_sz(cl_idx, input_size);
170		if (!input_report_size) {
171			rc = -EINVAL;
172			goto cleanup;
173		}
174		cl_data->feature_report[i] = devm_kzalloc(dev, feature_report_size, GFP_KERNEL);
175		if (!cl_data->feature_report[i]) {
176			rc = -ENOMEM;
177			goto cleanup;
178		}
179		in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
180		if (!in_data->input_report[i]) {
181			rc = -ENOMEM;
182			goto cleanup;
183		}
184
185		info.sensor_idx = cl_idx;
186
187		cl_data->report_descr[i] =
188			devm_kzalloc(dev, cl_data->report_descr_sz[i], GFP_KERNEL);
189		if (!cl_data->report_descr[i]) {
190			rc = -ENOMEM;
191			goto cleanup;
192		}
193		rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]);
194		if (rc)
195			goto cleanup;
196
197		mp2_ops->stop(privdata, cl_data->sensor_idx[i]);
198		amd_sfh_wait_for_response(privdata, cl_data->sensor_idx[i], DISABLE_SENSOR);
199		writel(0, privdata->mmio + amd_get_p2c_val(privdata, 0));
200		mp2_ops->start(privdata, info);
201		status = amd_sfh_wait_for_response
202				(privdata, cl_data->sensor_idx[i], ENABLE_SENSOR);
203
204		cl_data->sensor_sts[i] = (status == 0) ? SENSOR_ENABLED : SENSOR_DISABLED;
205	}
206
207	for (i = 0; i < cl_data->num_hid_devices; i++) {
208		if (cl_data->sensor_idx[i] == SRA_IDX)
209			continue;
210		cl_data->cur_hid_dev = i;
211		if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
212			cl_data->is_any_sensor_enabled = true;
213			rc = amdtp_hid_probe(i, cl_data);
214			if (rc)
215				goto cleanup;
216			switch (cl_data->sensor_idx[i]) {
217			case HPD_IDX:
218				privdata->dev_en.is_hpd_present = true;
219				privdata->dev_en.is_hpd_enabled = true;
220				amd_sfh_toggle_hpd(privdata, false);
221				break;
222			case ALS_IDX:
223				privdata->dev_en.is_als_present = true;
224				break;
225			}
226		}
227		dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
228			cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
229			cl_data->sensor_sts[i]);
230	}
231
232	if (!cl_data->is_any_sensor_enabled) {
233		dev_warn(dev, "No sensor registered, sensors not enabled is %d\n",
234			 cl_data->is_any_sensor_enabled);
235		rc = -EOPNOTSUPP;
236		goto cleanup;
237	}
238
239	schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
240	return 0;
241
242cleanup:
243	amd_sfh_hid_client_deinit(privdata);
244	for (i = 0; i < cl_data->num_hid_devices; i++) {
245		if (cl_data->sensor_idx[i] == SRA_IDX)
246			continue;
247		devm_kfree(dev, cl_data->feature_report[i]);
248		devm_kfree(dev, in_data->input_report[i]);
249		devm_kfree(dev, cl_data->report_descr[i]);
250	}
251	return rc;
252}
253
254static void amd_sfh_resume(struct amd_mp2_dev *mp2)
255{
256	struct amdtp_cl_data *cl_data = mp2->cl_data;
257	struct amd_mp2_sensor_info info;
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		/* leave HPD alone; policy is controlled by sysfs */
267		if (cl_data->sensor_idx[i] == HPD_IDX)
268			continue;
269
270		if (cl_data->sensor_sts[i] == SENSOR_DISABLED) {
271			info.sensor_idx = cl_data->sensor_idx[i];
272			mp2->mp2_ops->start(mp2, info);
273			status = amd_sfh_wait_for_response
274					(mp2, cl_data->sensor_idx[i], ENABLE_SENSOR);
275			if (status == 0)
276				status = SENSOR_ENABLED;
277			if (status == SENSOR_ENABLED)
278				cl_data->sensor_sts[i] = SENSOR_ENABLED;
279			dev_dbg(&mp2->pdev->dev, "resume sid 0x%x (%s) status 0x%x\n",
280				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
281				cl_data->sensor_sts[i]);
282		}
283	}
284
285	schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
286	amd_sfh_clear_intr(mp2);
287}
288
289static void amd_sfh_suspend(struct amd_mp2_dev *mp2)
290{
291	struct amdtp_cl_data *cl_data = mp2->cl_data;
292	int i, status;
293
294	if (!cl_data->is_any_sensor_enabled) {
295		amd_sfh_clear_intr(mp2);
296		return;
297	}
298
299	for (i = 0; i < cl_data->num_hid_devices; i++) {
300		/* leave HPD alone; policy is controlled by sysfs */
301		if (cl_data->sensor_idx[i] == HPD_IDX)
302			continue;
303		if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
304			mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
305			status = amd_sfh_wait_for_response
306					(mp2, cl_data->sensor_idx[i], DISABLE_SENSOR);
307			if (status == 0)
308				status = SENSOR_DISABLED;
309			if (status != SENSOR_ENABLED)
310				cl_data->sensor_sts[i] = SENSOR_DISABLED;
311			dev_dbg(&mp2->pdev->dev, "suspend sid 0x%x (%s) status 0x%x\n",
312				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
313				cl_data->sensor_sts[i]);
314		}
315	}
316
317	cancel_delayed_work_sync(&cl_data->work_buffer);
318	amd_sfh_clear_intr(mp2);
319}
320
321void amd_sfh_toggle_hpd(struct amd_mp2_dev *mp2, bool enabled)
322{
323	struct amdtp_cl_data *cl_data = mp2->cl_data;
324	struct amd_mp2_sensor_info info;
325	int i, status;
326
327	if (mp2->dev_en.is_hpd_enabled == enabled)
328		return;
329
330	for (i = 0; i < cl_data->num_hid_devices; i++) {
331		if (cl_data->sensor_idx[i] != HPD_IDX)
332			continue;
333		info.sensor_idx = cl_data->sensor_idx[i];
334		if (enabled) {
335			mp2->mp2_ops->start(mp2, info);
336			status = amd_sfh_wait_for_response
337					(mp2, cl_data->sensor_idx[i], ENABLE_SENSOR);
338			if (status == 0)
339				status = SENSOR_ENABLED;
340			if (status == SENSOR_ENABLED)
341				cl_data->sensor_sts[i] = SENSOR_ENABLED;
342		} else {
343			mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
344			status = amd_sfh_wait_for_response
345					(mp2, cl_data->sensor_idx[i], DISABLE_SENSOR);
346			if (status == 0)
347				status = SENSOR_DISABLED;
348			if (status != SENSOR_ENABLED)
349				cl_data->sensor_sts[i] = SENSOR_DISABLED;
350		}
351		dev_dbg(&mp2->pdev->dev, "toggle sid 0x%x (%s) status 0x%x\n",
352			cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
353			cl_data->sensor_sts[i]);
354		break;
355	}
356	mp2->dev_en.is_hpd_enabled = enabled;
357}
358
359static void amd_mp2_pci_remove(void *privdata)
360{
361	struct amd_mp2_dev *mp2 = privdata;
362
363	sfh_deinit_emp2();
364	amd_sfh_hid_client_deinit(privdata);
365	mp2->mp2_ops->stop_all(mp2);
366	pcim_intx(mp2->pdev, false);
367	amd_sfh_clear_intr(mp2);
368}
369
370static void amd_sfh_set_ops(struct amd_mp2_dev *mp2)
371{
372	struct amd_mp2_ops *mp2_ops;
373
374	sfh_interface_init(mp2);
375	mp2_ops = mp2->mp2_ops;
376	mp2_ops->clear_intr = amd_sfh_clear_intr_v2;
377	mp2_ops->init_intr = amd_sfh_irq_init_v2;
378	mp2_ops->suspend = amd_sfh_suspend;
379	mp2_ops->resume = amd_sfh_resume;
380	mp2_ops->remove = amd_mp2_pci_remove;
381}
382
383int amd_sfh1_1_init(struct amd_mp2_dev *mp2)
384{
385	u32 phy_base = readl(mp2->mmio + amd_get_c2p_val(mp2, 22));
386	struct device *dev = &mp2->pdev->dev;
387	struct sfh_base_info binfo;
388	int rc;
389
390	phy_base <<= 21;
391	if (!devm_request_mem_region(dev, phy_base, 128 * 1024, "amd_sfh")) {
392		dev_dbg(dev, "can't reserve mmio registers\n");
393		return -ENOMEM;
394	}
395
396	mp2->vsbase = devm_ioremap(dev, phy_base, 128 * 1024);
397	if (!mp2->vsbase) {
398		dev_dbg(dev, "failed to remap vsbase\n");
399		return -ENOMEM;
400	}
401
402	/* Before accessing give time for SFH firmware for processing configuration */
403	msleep(5000);
404
405	memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info));
406	if (binfo.sbase.fw_info.fw_ver == 0 || binfo.sbase.s_list.sl.sensors == 0) {
407		dev_dbg(dev, "No sensor registered\n");
408		return -EOPNOTSUPP;
409	}
410	dev_dbg(dev, "firmware version 0x%x\n", binfo.sbase.fw_info.fw_ver);
411
412	amd_sfh_set_ops(mp2);
413
414	rc = amd_sfh_irq_init(mp2);
415	if (rc) {
416		sfh_deinit_emp2();
417		dev_err(dev, "amd_sfh_irq_init failed\n");
418		return rc;
419	}
420
421	rc = amd_sfh1_1_hid_client_init(mp2);
422	if (rc) {
423		sfh_deinit_emp2();
424		if ((rc != -ENODEV) && (rc != -EOPNOTSUPP))
425			dev_err(dev, "amd_sfh1_1_hid_client_init failed\n");
426		return rc;
427	}
428
429	return rc;
430}
~/ Read-only file preview.