File Index
Files and directories
Sign in
FILE

amd_sfh_interface.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * AMD MP2 1.1 communication interfaces
  4 *
  5 * Copyright (c) 2022, Advanced Micro Devices, Inc.
  6 * All Rights Reserved.
  7 *
  8 * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
  9 */
 10#include <linux/amd-pmf-io.h>
 11#include <linux/io-64-nonatomic-lo-hi.h>
 12#include <linux/iopoll.h>
 13
 14#include "amd_sfh_interface.h"
 15
 16static struct amd_mp2_dev *emp2;
 17
 18static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)
 19{
 20	struct sfh_cmd_response cmd_resp;
 21
 22	/* Get response with status within a max of 10000 ms timeout */
 23	if (!readl_poll_timeout(mp2->mmio + amd_get_p2c_val(mp2, 0), cmd_resp.resp,
 24				(cmd_resp.response.response == 0 &&
 25				cmd_resp.response.cmd_id == cmd_id && (sid == 0xff ||
 26				cmd_resp.response.sensor_id == sid)), 500, 10000000))
 27		return cmd_resp.response.response;
 28
 29	return -1;
 30}
 31
 32static void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
 33{
 34	struct sfh_cmd_base cmd_base;
 35
 36	cmd_base.ul = 0;
 37	cmd_base.cmd.cmd_id = ENABLE_SENSOR;
 38	cmd_base.cmd.intr_disable = 0;
 39	cmd_base.cmd.sub_cmd_value = 1;
 40	cmd_base.cmd.sensor_id = info.sensor_idx;
 41
 42	writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
 43}
 44
 45static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
 46{
 47	struct sfh_cmd_base cmd_base;
 48
 49	cmd_base.ul = 0;
 50	cmd_base.cmd.cmd_id = DISABLE_SENSOR;
 51	cmd_base.cmd.intr_disable = 0;
 52	cmd_base.cmd.sub_cmd_value = 1;
 53	cmd_base.cmd.sensor_id = sensor_idx;
 54
 55	writeq(0x0, privdata->mmio + amd_get_c2p_val(privdata, 1));
 56	writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
 57}
 58
 59static void amd_stop_all_sensor(struct amd_mp2_dev *privdata)
 60{
 61	struct sfh_cmd_base cmd_base;
 62
 63	cmd_base.ul = 0;
 64	cmd_base.cmd.cmd_id = DISABLE_SENSOR;
 65	cmd_base.cmd.intr_disable = 0;
 66	/* 0xf indicates all sensors */
 67	cmd_base.cmd.sensor_id = 0xf;
 68
 69	writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
 70}
 71
 72static struct amd_mp2_ops amd_sfh_ops = {
 73	.start = amd_start_sensor,
 74	.stop = amd_stop_sensor,
 75	.stop_all = amd_stop_all_sensor,
 76	.response = amd_sfh_wait_response,
 77};
 78
 79void sfh_deinit_emp2(void)
 80{
 81	emp2 = NULL;
 82}
 83
 84void sfh_interface_init(struct amd_mp2_dev *mp2)
 85{
 86	mp2->mp2_ops = &amd_sfh_ops;
 87	emp2 = mp2;
 88}
 89
 90static int amd_sfh_mode_info(u32 *platform_type, u32 *laptop_placement)
 91{
 92	struct sfh_op_mode mode;
 93
 94	if (!platform_type || !laptop_placement)
 95		return -EINVAL;
 96
 97	if (!emp2 || !emp2->dev_en.is_sra_present)
 98		return -ENODEV;
 99
100	mode.val = readl(emp2->mmio + amd_get_c2p_val(emp2, 3));
101
102	*platform_type = mode.op_mode.devicemode;
103
104	if (mode.op_mode.ontablestate == 1) {
105		*laptop_placement = ON_TABLE;
106	} else if (mode.op_mode.ontablestate == 2) {
107		*laptop_placement = ON_LAP_MOTION;
108	} else if (mode.op_mode.inbagstate == 1) {
109		*laptop_placement = IN_BAG;
110	} else if (mode.op_mode.outbagstate == 1) {
111		*laptop_placement = OUT_OF_BAG;
112	} else if (mode.op_mode.ontablestate == 0 || mode.op_mode.inbagstate == 0 ||
113		 mode.op_mode.outbagstate == 0) {
114		*laptop_placement = LP_UNKNOWN;
115		pr_warn_once("Unknown laptop placement\n");
116	} else if (mode.op_mode.ontablestate == 3 || mode.op_mode.inbagstate == 3 ||
117		 mode.op_mode.outbagstate == 3) {
118		*laptop_placement = LP_UNDEFINED;
119		pr_warn_once("Undefined laptop placement\n");
120	}
121
122	return 0;
123}
124
125static int amd_sfh_hpd_info(u8 *user_present)
126{
127	struct hpd_status hpdstatus;
128
129	if (!user_present)
130		return -EINVAL;
131
132	if (!emp2 || !emp2->dev_en.is_hpd_present || !emp2->dev_en.is_hpd_enabled)
133		return -ENODEV;
134
135	hpdstatus.val = readl(emp2->mmio + amd_get_c2p_val(emp2, 4));
136	*user_present = hpdstatus.shpd.presence;
137
138	return 0;
139}
140
141static int amd_sfh_als_info(u32 *ambient_light)
142{
143	struct sfh_als_data als_data;
144	void __iomem *sensoraddr;
145
146	if (!ambient_light)
147		return -EINVAL;
148
149	if (!emp2 || !emp2->dev_en.is_als_present)
150		return -ENODEV;
151
152	sensoraddr = emp2->vsbase +
153		(ALS_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) +
154		OFFSET_SENSOR_DATA_DEFAULT;
155	memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data));
156	*ambient_light = amd_sfh_float_to_int(als_data.lux);
157
158	return 0;
159}
160
161int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op)
162{
163	if (sfh_info) {
164		switch (op) {
165		case MT_HPD:
166			return amd_sfh_hpd_info(&sfh_info->user_present);
167		case MT_ALS:
168			return amd_sfh_als_info(&sfh_info->ambient_light);
169		case MT_SRA:
170			return amd_sfh_mode_info(&sfh_info->platform_type,
171						 &sfh_info->laptop_placement);
172		}
173	}
174	return -EINVAL;
175}
176EXPORT_SYMBOL_GPL(amd_get_sfh_info);
~/ Read-only file preview.