Linux Input/HID development
 help / color / mirror / Atom feed
From: Helge Bahmann <hcb@chaoticmind.net>
To: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com>,
	Sandeep Singh <Sandeep.singh@amd.com>,
	Basavaraj Natikar <Basavaraj.Natikar@amd.com>,
	jikos@kernel.org, bentiss@kernel.org
Cc: linux-hid@vger.kernel.org, linux-input@vger.kernel.org
Subject: [PATCH] amd-sfh-hid: tablet mode switch and asus quirk
Date: Mon, 27 Apr 2026 08:22:54 +0200	[thread overview]
Message-ID: <6879487.lOV4Wx5bFT@lothlorien> (raw)

Add an input driver that interprets the "operation mode" sensor offered
by the amd sfh on some laptop models.

Add a quirk to make the driver work again with the Asus VivoBook
VivoBook (turn off the "disable interrupts" flag).

Expose the intr_disable flag as a module parameter in case it turns out
to be needed on further laptop models.

Signed-off-by: Helge Bahmann <hcb@chaoticmind.net>
---
 drivers/hid/amd-sfh-hid/amd_sfh_client.c | 25 ++++++++------
 drivers/hid/amd-sfh-hid/amd_sfh_hid.c    | 43 ++++++++++++++++++++++++
 drivers/hid/amd-sfh-hid/amd_sfh_hid.h    |  6 ++++
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c   |  9 +++++
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.h   |  3 ++
 5 files changed, 75 insertions(+), 11 deletions(-)

diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
index 7017bfa59093..a24757c5a203 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
@@ -128,10 +128,16 @@ void amd_sfh_work_buffer(struct work_struct *work)
 	guard(mutex)(&mp2->lock);
 	for (i = 0; i < cli_data->num_hid_devices; i++) {
 		if (cli_data->sensor_sts[i] == SENSOR_ENABLED) {
-			report_size = mp2->mp2_ops->get_in_rep(i, cli_data->sensor_idx[i],
-							       cli_data->report_id[i], in_data);
-			hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
-					 in_data->input_report[i], report_size, 0);
+			if (cli_data->hid_sensor_hubs[i]) {
+				report_size = mp2->mp2_ops->get_in_rep(i, cli_data->sensor_idx[i],
+								       cli_data->report_id[i],
+								       in_data);
+				hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
+						 in_data->input_report[i], report_size, 0);
+			} else if (cli_data->sensor_idx[i] == op_idx &&
+				   cli_data->modeswitch_input) {
+				amdtp_modeswitch_report(i, cli_data->modeswitch_input, in_data);
+			}
 		}
 	}
 	schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
@@ -327,15 +333,12 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)

 	for (i = 0; i < cl_data->num_hid_devices; i++) {
 		cl_data->cur_hid_dev = i;
-		if (cl_data->sensor_idx[i] == op_idx) {
-			dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
-				cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
-				cl_data->sensor_sts[i]);
-			continue;
-		}

 		if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
-			rc = amdtp_hid_probe(i, cl_data);
+			if (cl_data->sensor_idx[i] != op_idx)
+				rc = amdtp_hid_probe(i, cl_data);
+			else
+				rc = amdtp_modeswitch_probe(i, cl_data);
 			if (rc)
 				goto cleanup;
 		} else {
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
index 81f3024b7b1b..44008c02b63c 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c
@@ -181,4 +181,47 @@ void amdtp_hid_remove(struct amdtp_cl_data *cli_data)
 			cli_data->hid_sensor_hubs[i] = NULL;
 		}
 	}
+
+	/* note: cli_data->modeswitch_input implicitly cleaned by devres */
+}
+
+int amdtp_modeswitch_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data)
+{
+	struct amd_mp2_dev *mp2 = container_of(cli_data->in_data, struct amd_mp2_dev, in_data);
+	struct device *dev = &mp2->pdev->dev;
+	struct input_dev *input;
+	int rc;
+
+	input = devm_input_allocate_device(dev);
+	if (IS_ERR(input))
+		return PTR_ERR(input);
+
+	input->name = "AMD SFH tablet mode switch sensor";
+	input->id.bustype = BUS_PCI;
+
+	input_set_capability(input, EV_SW, SW_TABLET_MODE);
+
+	rc = input_register_device(input);
+	if (rc)
+		goto cleanup;
+
+	cli_data->modeswitch_input = input;
+
+	return 0;
+
+cleanup:
+	return rc;
+}
+
+void amdtp_modeswitch_report(u32 index, struct input_dev *input, struct amd_input_data *in_data)
+{
+	u32 *sensor_virt_addr = in_data->sensor_virt_addr[index];
+	u32 value = sensor_virt_addr[0];
+
+	if (value == AMD_SFH_OP_IDX_MODE_TABLET)
+		input_report_switch(input, SW_TABLET_MODE, 1);
+	else
+		input_report_switch(input, SW_TABLET_MODE, 0);
+
+	input_sync(input);
 }
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
index 7452b0302953..20aff7b75fbd 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
@@ -11,6 +11,8 @@
 #ifndef AMDSFH_HID_H
 #define AMDSFH_HID_H

+#include <linux/input.h>
+
 #define MAX_HID_DEVICES		7
 #define AMD_SFH_HID_VENDOR	0x1022
 #define AMD_SFH_HID_PRODUCT	0x0001
@@ -50,6 +52,7 @@ struct amdtp_cl_data {
 	u8 sensor_idx[MAX_HID_DEVICES];
 	u8 *feature_report[MAX_HID_DEVICES];
 	u8 request_done[MAX_HID_DEVICES];
+	struct input_dev *modeswitch_input;
 	struct amd_input_data *in_data;
 	struct delayed_work work;
 	struct delayed_work work_buffer;
@@ -78,4 +81,7 @@ void amdtp_hid_remove(struct amdtp_cl_data *cli_data);
 int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type);
 void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type);
 void amdtp_hid_wakeup(struct hid_device *hid);
+int amdtp_modeswitch_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data);
+void amdtp_modeswitch_report(u32 index, struct input_dev *input, struct amd_input_data *in_data);
+
 #endif
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
index 1d9f955573aa..cd9cff75f114 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
@@ -39,6 +39,8 @@ module_param_named(sensor_mask, sensor_mask_override, int, 0444);
 MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask");

 static bool intr_disable = true;
+module_param_named(intr_disable, intr_disable, bool, 0444);
+MODULE_PARM_DESC(intr_disable, "override the interrupt disable sensor bit");

 static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)
 {
@@ -317,6 +319,13 @@ static const struct dmi_system_id dmi_sfh_table[] = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook x360 435 G7"),
 		},
 	},
+	{
+		.callback = mp2_disable_intr,
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "VivoBook_ASUSLaptop TP420UA_TM420UA"),
+		}
+	},
 	{}
 };

diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
index 2eb61f4e8434..5e968894ebe4 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
@@ -83,6 +83,9 @@ enum sensor_idx {
 	als_idx = 19
 };

+#define AMD_SFH_OP_IDX_MODE_LAPTOP 1
+#define AMD_SFH_OP_IDX_MODE_TABLET 3
+
 enum mem_use_type {
 	USE_DRAM,
 	USE_C2P_REG,
--
2.47.3





             reply	other threads:[~2026-04-27  6:39 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-27  6:22 Helge Bahmann [this message]
2026-05-12 16:06 ` [PATCH] amd-sfh-hid: tablet mode switch and asus quirk Jiri Kosina
2026-05-12 17:09   ` Basavaraj Natikar
2026-05-14  7:59   ` Helge Bahmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6879487.lOV4Wx5bFT@lothlorien \
    --to=hcb@chaoticmind.net \
    --cc=Basavaraj.Natikar@amd.com \
    --cc=Nehal-Bakulchandra.Shah@amd.com \
    --cc=Sandeep.singh@amd.com \
    --cc=bentiss@kernel.org \
    --cc=jikos@kernel.org \
    --cc=linux-hid@vger.kernel.org \
    --cc=linux-input@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox