Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH v2 0/5] Add SW_TABLET_MODE support for AMD SFH convertibles
@ 2026-08-03 14:57 Basavaraj Natikar
  2026-08-03 14:57 ` [PATCH v2 1/5] HID: amd_sfh: Track MP2 version explicitly Basavaraj Natikar
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Basavaraj Natikar @ 2026-08-03 14:57 UTC (permalink / raw)
  To: jikos, bentiss, dmitry.torokhov; +Cc: linux-input, Basavaraj Natikar

Add SW_TABLET_MODE support for AMD convertibles whose operating mode
(laptop or tablet) is reported by the Sensor Fusion Hub.

Patches 1 and 2 are preparation: the first tracks the MP2 version
explicitly and the second serializes access to the shared emp2 pointer.
The third adds a way to read the operating mode. The fourth registers an
auxiliary device when the sensor is present, and the fifth is a small
input driver that binds to it and reports the posture to userspace.
Keeping the input handling in its own driver avoids pulling input/evdev
into the sensor transport driver.

Changes in v2 (address the Sashiko review of v1):
- Read the operating-mode register only on confirmed MP2 v2, by tracking
  the MP2 version explicitly. On v1.0 that register overlaps the 64-bit
  DMA address programmed through C2P, so the earlier unconditional read
  could return DMA bits instead of the operating mode.
- Serialize the shared emp2 pointer and all exported readers under a
  mutex, so a concurrent unbind can no longer free the device while a
  reader is still dereferencing it.
- Publish emp2 only after initialization has populated the client data,
  and clear it early on the MP2 v2 remove path instead of from a
  prematurely registered devres action; this removes both the
  publish-before-init data race and the unconditional global clear on a
  probe failure.
- Destroy the tablet-mode auxiliary device and release its id on removal,
  and allocate the id dynamically so multiple instances cannot collide.
- Report the initial tablet-mode state before registering the input
  device, so userspace never observes a stale default posture.
- Rename the error variable from 'rc' to 'error' to follow the
  input-subsystem convention.

v1: https://lore.kernel.org/all/20260721174422.3109166-1-Basavaraj.Natikar@amd.com/

Basavaraj Natikar (5):
  HID: amd_sfh: Track MP2 version explicitly
  HID: amd_sfh: Serialize access to the shared emp2 pointer
  HID: amd_sfh: Add accessor to read the operating-mode sensor
  HID: amd_sfh: Register tablet-mode auxiliary device
  Input: misc: Add AMD SFH tablet-mode switch driver

 MAINTAINERS                                   |  1 +
 drivers/hid/amd-sfh-hid/Kconfig               |  1 +
 drivers/hid/amd-sfh-hid/amd_sfh_client.c      | 16 ++++
 drivers/hid/amd-sfh-hid/amd_sfh_common.h      | 13 +++
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c        | 61 +++++++++++++-
 .../amd-sfh-hid/sfh1_1/amd_sfh_interface.c    | 39 +++++++++
 .../amd-sfh-hid/sfh1_1/amd_sfh_interface.h    |  1 -
 drivers/input/misc/Kconfig                    | 15 ++++
 drivers/input/misc/Makefile                   |  1 +
 drivers/input/misc/amd_sfh_tabletmode.c       | 81 +++++++++++++++++++
 include/linux/amd-pmf-io.h                    | 14 ++++
 11 files changed, 238 insertions(+), 5 deletions(-)
 create mode 100644 drivers/input/misc/amd_sfh_tabletmode.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 1/5] HID: amd_sfh: Track MP2 version explicitly
  2026-08-03 14:57 [PATCH v2 0/5] Add SW_TABLET_MODE support for AMD SFH convertibles Basavaraj Natikar
@ 2026-08-03 14:57 ` Basavaraj Natikar
  2026-08-03 14:57 ` [PATCH v2 2/5] HID: amd_sfh: Serialize access to the shared emp2 pointer Basavaraj Natikar
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Basavaraj Natikar @ 2026-08-03 14:57 UTC (permalink / raw)
  To: jikos, bentiss, dmitry.torokhov; +Cc: linux-input, Basavaraj Natikar

The MP2 version is currently known only implicitly, from whether an ops
pointer was stored in the PCI driver_data. Subsequent changes need to
act on the MP2 version directly, for example to read the operating-mode
register only on confirmed MP2 v2.

Track the MP2 version explicitly so that version-specific behaviour can
be gated on it, and leave it unset for generations that do not require
such handling.

Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
---
 drivers/hid/amd-sfh-hid/amd_sfh_common.h | 6 ++++++
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c   | 9 +++++----
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h
index 78f830c133e5..68586f08ab23 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h
@@ -35,6 +35,11 @@ enum cmd_id {
 	STOP_ALL_SENSORS = 8,
 };
 
+enum amd_mp2_version {
+	MP2_VER_V2 = 1,
+	MP2_VER_1_1 = 2,
+};
+
 struct amd_mp2_sensor_info {
 	u8 sensor_idx;
 	u32 period;
@@ -64,6 +69,7 @@ struct amd_mp2_dev {
 	struct mutex lock;
 	u8 init_done;
 	u8 rver;
+	u8 mp2_ver;
 };
 
 struct amd_mp2_ops {
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
index 4b81cebdc335..92801ca38957 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
@@ -285,6 +285,7 @@ static void mp2_select_ops(struct amd_mp2_dev *privdata)
 	switch (acs) {
 	case V2_STATUS:
 		privdata->mp2_ops = &amd_sfh_ops_v2;
+		privdata->mp2_ver = MP2_VER_V2;
 		break;
 	default:
 		privdata->mp2_ops = &amd_sfh_ops;
@@ -471,8 +472,9 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
 	if (rc)
 		return rc;
 
-	privdata->sfh1_1_ops = (const struct amd_sfh1_1_ops *)id->driver_data;
-	if (privdata->sfh1_1_ops) {
+	privdata->mp2_ver = (enum amd_mp2_version)id->driver_data;
+	if (privdata->mp2_ver >= MP2_VER_1_1) {
+		privdata->sfh1_1_ops = &sfh1_1_ops;
 		if (boot_cpu_data.x86 >= 0x1A)
 			privdata->rver = 1;
 
@@ -540,8 +542,7 @@ static SIMPLE_DEV_PM_OPS(amd_mp2_pm_ops, amd_mp2_pci_suspend,
 
 static const struct pci_device_id amd_mp2_pci_tbl[] = {
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) },
-	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2_1_1),
-	  .driver_data = (kernel_ulong_t)&sfh1_1_ops },
+	{ PCI_DEVICE_DATA(AMD, MP2_1_1, MP2_VER_1_1) },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 2/5] HID: amd_sfh: Serialize access to the shared emp2 pointer
  2026-08-03 14:57 [PATCH v2 0/5] Add SW_TABLET_MODE support for AMD SFH convertibles Basavaraj Natikar
  2026-08-03 14:57 ` [PATCH v2 1/5] HID: amd_sfh: Track MP2 version explicitly Basavaraj Natikar
@ 2026-08-03 14:57 ` Basavaraj Natikar
  2026-08-03 14:57 ` [PATCH v2 3/5] HID: amd_sfh: Add accessor to read the operating-mode sensor Basavaraj Natikar
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Basavaraj Natikar @ 2026-08-03 14:57 UTC (permalink / raw)
  To: jikos, bentiss, dmitry.torokhov; +Cc: linux-input, Basavaraj Natikar

The SFH accessors reach the device through a file-global emp2 pointer
that is published at probe and cleared on remove. amd_get_sfh_info() is
exported and called from other modules on unrelated threads, so a reader
can observe a non-NULL emp2 and then race a concurrent unbind that clears
it and frees the device.

Serialize the emp2 publish/clear and all readers under a mutex, so a
reader either sees a live device for the whole access or sees NULL.

Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
---
 drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
index 837d59e7a661..dd2720bae65c 100644
--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
@@ -8,12 +8,14 @@
  * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
  */
 #include <linux/amd-pmf-io.h>
+#include <linux/cleanup.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/iopoll.h>
 
 #include "amd_sfh_interface.h"
 
 static struct amd_mp2_dev *emp2;
+static DEFINE_MUTEX(emp2_lock);
 
 static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)
 {
@@ -78,12 +80,14 @@ static struct amd_mp2_ops amd_sfh_ops = {
 
 void sfh_deinit_emp2(void)
 {
+	guard(mutex)(&emp2_lock);
 	emp2 = NULL;
 }
 
 void sfh_interface_init(struct amd_mp2_dev *mp2)
 {
 	mp2->mp2_ops = &amd_sfh_ops;
+	guard(mutex)(&emp2_lock);
 	emp2 = mp2;
 }
 
@@ -160,6 +164,8 @@ static int amd_sfh_als_info(u32 *ambient_light)
 
 int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op)
 {
+	guard(mutex)(&emp2_lock);
+
 	if (sfh_info) {
 		switch (op) {
 		case MT_HPD:
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 3/5] HID: amd_sfh: Add accessor to read the operating-mode sensor
  2026-08-03 14:57 [PATCH v2 0/5] Add SW_TABLET_MODE support for AMD SFH convertibles Basavaraj Natikar
  2026-08-03 14:57 ` [PATCH v2 1/5] HID: amd_sfh: Track MP2 version explicitly Basavaraj Natikar
  2026-08-03 14:57 ` [PATCH v2 2/5] HID: amd_sfh: Serialize access to the shared emp2 pointer Basavaraj Natikar
@ 2026-08-03 14:57 ` Basavaraj Natikar
  2026-08-03 14:58 ` [PATCH v2 4/5] HID: amd_sfh: Register tablet-mode auxiliary device Basavaraj Natikar
  2026-08-03 14:58 ` [PATCH v2 5/5] Input: misc: Add AMD SFH tablet-mode switch driver Basavaraj Natikar
  4 siblings, 0 replies; 9+ messages in thread
From: Basavaraj Natikar @ 2026-08-03 14:57 UTC (permalink / raw)
  To: jikos, bentiss, dmitry.torokhov; +Cc: linux-input, Basavaraj Natikar

Allow other drivers to query the operating mode (laptop or tablet)
reported by the Sensor Fusion Hub. This is the interface used by the
tablet-mode switch driver to report the device posture to userspace.

Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
---
 drivers/hid/amd-sfh-hid/amd_sfh_client.c      | 16 +++++++++
 drivers/hid/amd-sfh-hid/amd_sfh_common.h      |  5 +++
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c        |  4 +++
 .../amd-sfh-hid/sfh1_1/amd_sfh_interface.c    | 33 +++++++++++++++++++
 .../amd-sfh-hid/sfh1_1/amd_sfh_interface.h    |  1 -
 include/linux/amd-pmf-io.h                    | 14 ++++++++
 6 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
index 96ae792beeb6..ae6add0b9ce3 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
@@ -383,3 +383,19 @@ int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
 
 	return 0;
 }
+
+bool amd_sfh_op_idx_enabled(struct amd_mp2_dev *mp2)
+{
+	struct amdtp_cl_data *cl = mp2->cl_data;
+	int i;
+
+	if (!cl)
+		return false;
+
+	for (i = 0; i < cl->num_hid_devices; i++)
+		if (cl->sensor_idx[i] == op_idx &&
+		    READ_ONCE(cl->sensor_sts[i]) == SENSOR_ENABLED)
+			return true;
+
+	return false;
+}
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h
index 68586f08ab23..0ca3254151ac 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h
@@ -106,4 +106,9 @@ static inline u64 amd_get_p2c_val(struct amd_mp2_dev *mp2, u32 idx)
 {
 	return mp2->rver == 1 ? AMD_P2C_MSG_V1(idx) :  AMD_P2C_MSG(idx);
 }
+
+bool amd_sfh_op_idx_enabled(struct amd_mp2_dev *mp2);
+void sfh_set_emp2(struct amd_mp2_dev *mp2);
+void sfh_deinit_emp2(void);
+
 #endif
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
index 92801ca38957..4b1cd260410d 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
@@ -251,6 +251,8 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
 static void amd_mp2_pci_remove(void *privdata)
 {
 	struct amd_mp2_dev *mp2 = privdata;
+
+	sfh_deinit_emp2();
 	amd_sfh_hid_client_deinit(privdata);
 	mp2->mp2_ops->stop_all(mp2);
 	pcim_intx(mp2->pdev, false);
@@ -419,6 +421,7 @@ static void sfh_init_work(struct work_struct *work)
 		return;
 	}
 
+	sfh_set_emp2(mp2);
 	amd_sfh_clear_intr(mp2);
 	mp2->init_done = 1;
 }
@@ -448,6 +451,7 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
 
 	privdata->pdev = pdev;
 	dev_set_drvdata(&pdev->dev, privdata);
+
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
index dd2720bae65c..097c5513ccd8 100644
--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
@@ -84,6 +84,12 @@ void sfh_deinit_emp2(void)
 	emp2 = NULL;
 }
 
+void sfh_set_emp2(struct amd_mp2_dev *mp2)
+{
+	guard(mutex)(&emp2_lock);
+	emp2 = mp2;
+}
+
 void sfh_interface_init(struct amd_mp2_dev *mp2)
 {
 	mp2->mp2_ops = &amd_sfh_ops;
@@ -91,6 +97,31 @@ void sfh_interface_init(struct amd_mp2_dev *mp2)
 	emp2 = mp2;
 }
 
+static int amd_sfh_op_mode_info(u32 *op_mode)
+{
+	struct sfh_op_mode mode;
+	bool present;
+
+	if (!op_mode)
+		return -EINVAL;
+	if (!emp2)
+		return -ENODEV;
+
+	present = emp2->sfh1_1_ops ? emp2->dev_en.is_sra_present
+				   : (emp2->mp2_ver == MP2_VER_V2 &&
+				      amd_sfh_op_idx_enabled(emp2));
+	if (!present)
+		return -ENODEV;
+
+	mode.val = readl(emp2->mmio + amd_get_c2p_val(emp2, 3));
+	dev_dbg(&emp2->pdev->dev, "op-mode: %s (mode=%u)\n",
+		mode.op_mode.mode == SFH_MODE_TABLET ? "tablet" : "laptop",
+		mode.op_mode.mode);
+	*op_mode = mode.op_mode.mode;
+
+	return 0;
+}
+
 static int amd_sfh_mode_info(u32 *platform_type, u32 *laptop_placement)
 {
 	struct sfh_op_mode mode;
@@ -175,6 +206,8 @@ int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op)
 		case MT_SRA:
 			return amd_sfh_mode_info(&sfh_info->platform_type,
 						 &sfh_info->laptop_placement);
+		case MT_OP_MODE:
+			return amd_sfh_op_mode_info(&sfh_info->op_mode);
 		}
 	}
 	return -EINVAL;
diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
index 665c99ad779f..56258c4d1b3a 100644
--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
@@ -185,7 +185,6 @@ struct sfh_op_mode {
 };
 
 void sfh_interface_init(struct amd_mp2_dev *mp2);
-void sfh_deinit_emp2(void);
 void amd_sfh1_1_set_desc_ops(struct amd_mp2_ops *mp2_ops);
 int amd_sfh_float_to_int(u32 flt32_val);
 #endif
diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
index 55198d2875cc..dc59c43bd8f2 100644
--- a/include/linux/amd-pmf-io.h
+++ b/include/linux/amd-pmf-io.h
@@ -19,11 +19,13 @@
  * @MT_HPD: Message ID to know the Human presence info from MP2 FW
  * @MT_ALS: Message ID to know the Ambient light info from MP2 FW
  * @MT_SRA: Message ID to know the SRA data from MP2 FW
+ * @MT_OP_MODE: Message ID to know the operating-mode (tablet/laptop) info
  */
 enum sfh_message_type {
 	MT_HPD,
 	MT_ALS,
 	MT_SRA,
+	MT_OP_MODE,
 };
 
 /**
@@ -44,12 +46,24 @@ enum sfh_hpd_info {
  * @user_present: Populates the user presence information
  * @platform_type: Operating modes (clamshell, flat, tent, etc.)
  * @laptop_placement: Device states (ontable, onlap, outbag)
+ * @op_mode: Operating-mode field (see enum sfh_dev_mode); used for tablet detection
  */
 struct amd_sfh_info {
 	u32 ambient_light;
 	u8 user_present;
 	u32 platform_type;
 	u32 laptop_placement;
+	u32 op_mode;
+};
+
+/**
+ * enum sfh_dev_mode - SFH operating-mode field (sfh_op_mode.mode, bits 0-2)
+ * @SFH_MODE_LAPTOP: Device is in laptop/clamshell posture
+ * @SFH_MODE_TABLET: Device is in tablet posture
+ */
+enum sfh_dev_mode {
+	SFH_MODE_LAPTOP	= 1,
+	SFH_MODE_TABLET	= 3,
 };
 
 enum laptop_placement {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 4/5] HID: amd_sfh: Register tablet-mode auxiliary device
  2026-08-03 14:57 [PATCH v2 0/5] Add SW_TABLET_MODE support for AMD SFH convertibles Basavaraj Natikar
                   ` (2 preceding siblings ...)
  2026-08-03 14:57 ` [PATCH v2 3/5] HID: amd_sfh: Add accessor to read the operating-mode sensor Basavaraj Natikar
@ 2026-08-03 14:58 ` Basavaraj Natikar
  2026-08-03 15:16   ` sashiko-bot
  2026-08-03 14:58 ` [PATCH v2 5/5] Input: misc: Add AMD SFH tablet-mode switch driver Basavaraj Natikar
  4 siblings, 1 reply; 9+ messages in thread
From: Basavaraj Natikar @ 2026-08-03 14:58 UTC (permalink / raw)
  To: jikos, bentiss, dmitry.torokhov; +Cc: linux-input, Basavaraj Natikar

Register an auxiliary device when the operating-mode sensor is present,
so a dedicated input driver can bind to it and report the device
posture. This keeps the input handling out of the sensor transport
driver.

Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
---
 drivers/hid/amd-sfh-hid/Kconfig          |  1 +
 drivers/hid/amd-sfh-hid/amd_sfh_common.h |  2 +
 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c   | 48 ++++++++++++++++++++++++
 3 files changed, 51 insertions(+)

diff --git a/drivers/hid/amd-sfh-hid/Kconfig b/drivers/hid/amd-sfh-hid/Kconfig
index 3291786a5ee6..d86d83ffebd7 100644
--- a/drivers/hid/amd-sfh-hid/Kconfig
+++ b/drivers/hid/amd-sfh-hid/Kconfig
@@ -6,6 +6,7 @@ menu "AMD SFH HID Support"
 config AMD_SFH_HID
 	tristate "AMD Sensor Fusion Hub"
 	depends on X86
+	select AUXILIARY_BUS
 	help
 	  If you say yes to this option, support will be included for the
 	  AMD Sensor Fusion Hub.
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h
index 0ca3254151ac..f8c6b7fc34fb 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h
@@ -10,6 +10,7 @@
 #ifndef AMD_SFH_COMMON_H
 #define AMD_SFH_COMMON_H
 
+#include <linux/auxiliary_bus.h>
 #include <linux/mutex.h>
 #include <linux/pci.h>
 #include "amd_sfh_hid.h"
@@ -70,6 +71,7 @@ struct amd_mp2_dev {
 	u8 init_done;
 	u8 rver;
 	u8 mp2_ver;
+	struct auxiliary_device *tm_auxdev;
 };
 
 struct amd_mp2_ops {
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
index 4b1cd260410d..f6f016c8c678 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
@@ -8,11 +8,13 @@
  *	    Basavaraj Natikar <Basavaraj.Natikar@amd.com>
  */
 
+#include <linux/auxiliary_bus.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/devm-helpers.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmi.h>
+#include <linux/idr.h>
 #include <linux/interrupt.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/iopoll.h>
@@ -389,6 +391,50 @@ static const struct attribute_group *amd_sfh_groups[] = {
 	NULL,
 };
 
+static DEFINE_IDA(sfh_tm_ida);
+
+static void amd_sfh_tm_cleanup(void *data)
+{
+	struct amd_mp2_dev *mp2 = data;
+	int id = mp2->tm_auxdev->id;
+
+	auxiliary_device_destroy(mp2->tm_auxdev);
+	ida_free(&sfh_tm_ida, id);
+	mp2->tm_auxdev = NULL;
+}
+
+static void amd_sfh_maybe_register_tm(struct amd_mp2_dev *mp2)
+{
+	struct auxiliary_device *adev;
+	bool present;
+	int id;
+
+	if (mp2->tm_auxdev)
+		return;
+
+	present = mp2->sfh1_1_ops ? mp2->dev_en.is_sra_present
+				  : (mp2->mp2_ver == MP2_VER_V2 &&
+				     amd_sfh_op_idx_enabled(mp2));
+	if (!present)
+		return;
+
+	id = ida_alloc(&sfh_tm_ida, GFP_KERNEL);
+	if (id < 0)
+		return;
+
+	adev = auxiliary_device_create(&mp2->pdev->dev, KBUILD_MODNAME,
+				       "tabletmode", NULL, id);
+	if (!adev) {
+		ida_free(&sfh_tm_ida, id);
+		dev_warn(&mp2->pdev->dev, "tabletmode auxdev create failed\n");
+		return;
+	}
+
+	mp2->tm_auxdev = adev;
+	if (devm_add_action_or_reset(&mp2->pdev->dev, amd_sfh_tm_cleanup, mp2))
+		dev_warn(&mp2->pdev->dev, "tabletmode cleanup registration failed\n");
+}
+
 static void sfh1_1_init_work(struct work_struct *work)
 {
 	struct amd_mp2_dev *mp2 = container_of(work, struct amd_mp2_dev, work);
@@ -405,6 +451,7 @@ static void sfh1_1_init_work(struct work_struct *work)
 	if (rc)
 		dev_warn(&mp2->pdev->dev, "failed to update sysfs group\n");
 
+	amd_sfh_maybe_register_tm(mp2);
 }
 
 static void sfh_init_work(struct work_struct *work)
@@ -424,6 +471,7 @@ static void sfh_init_work(struct work_struct *work)
 	sfh_set_emp2(mp2);
 	amd_sfh_clear_intr(mp2);
 	mp2->init_done = 1;
+	amd_sfh_maybe_register_tm(mp2);
 }
 
 static void amd_sfh_remove(struct pci_dev *pdev)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 5/5] Input: misc: Add AMD SFH tablet-mode switch driver
  2026-08-03 14:57 [PATCH v2 0/5] Add SW_TABLET_MODE support for AMD SFH convertibles Basavaraj Natikar
                   ` (3 preceding siblings ...)
  2026-08-03 14:58 ` [PATCH v2 4/5] HID: amd_sfh: Register tablet-mode auxiliary device Basavaraj Natikar
@ 2026-08-03 14:58 ` Basavaraj Natikar
  2026-08-03 16:18   ` Dmitry Torokhov
  4 siblings, 1 reply; 9+ messages in thread
From: Basavaraj Natikar @ 2026-08-03 14:58 UTC (permalink / raw)
  To: jikos, bentiss, dmitry.torokhov
  Cc: linux-input, Basavaraj Natikar, Helge Bahmann

Report whether an AMD convertible is in laptop or tablet mode using the
operating-mode sensor provided by the Sensor Fusion Hub, and expose it
to userspace as SW_TABLET_MODE, so userspace can react to the device
being folded into tablet posture.

Cc: Helge Bahmann <hcb@chaoticmind.net>
Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
---
 MAINTAINERS                             |  1 +
 drivers/input/misc/Kconfig              | 15 +++++
 drivers/input/misc/Makefile             |  1 +
 drivers/input/misc/amd_sfh_tabletmode.c | 81 +++++++++++++++++++++++++
 4 files changed, 98 insertions(+)
 create mode 100644 drivers/input/misc/amd_sfh_tabletmode.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 5114e6db7307..30b429eb9286 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1301,6 +1301,7 @@ L:	linux-input@vger.kernel.org
 S:	Maintained
 F:	Documentation/hid/amd-sfh*
 F:	drivers/hid/amd-sfh-hid/
+F:	drivers/input/misc/amd_sfh_tabletmode.c
 
 AMD SPI DRIVER
 M:	Raju Rangoju <Raju.Rangoju@amd.com>
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 1f6c57dba030..5b76be31f687 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -899,6 +899,21 @@ config INPUT_SOC_BUTTON_ARRAY
 	  To compile this driver as a module, choose M here: the
 	  module will be called soc_button_array.
 
+config INPUT_AMD_SFH_TABLETMODE
+	tristate "AMD SFH tablet-mode switch"
+	depends on AMD_SFH_HID
+	select AUXILIARY_BUS
+	help
+	  Expose SW_TABLET_MODE for AMD convertible laptops whose
+	  operation-mode sensor is provided by the AMD Sensor Fusion Hub.
+
+	  Userspace components such as systemd-logind and modern desktop
+	  environments react to SW_TABLET_MODE when the device is folded
+	  into tablet posture.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called amd_sfh_tabletmode.
+
 config INPUT_DRV260X_HAPTICS
 	tristate "TI DRV260X haptics support"
 	depends on INPUT && I2C
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 2281d6803fce..72aa0658ebb3 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_INPUT_RK805_PWRKEY)	+= rk805-pwrkey.o
 obj-$(CONFIG_INPUT_SC27XX_VIBRA)	+= sc27xx-vibra.o
 obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
 obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY)	+= soc_button_array.o
+obj-$(CONFIG_INPUT_AMD_SFH_TABLETMODE)	+= amd_sfh_tabletmode.o
 obj-$(CONFIG_INPUT_SPARCSPKR)		+= sparcspkr.o
 obj-$(CONFIG_INPUT_STPMIC1_ONKEY)  	+= stpmic1_onkey.o
 obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON)	+= tps65218-pwrbutton.o
diff --git a/drivers/input/misc/amd_sfh_tabletmode.c b/drivers/input/misc/amd_sfh_tabletmode.c
new file mode 100644
index 000000000000..3931a1c6eb74
--- /dev/null
+++ b/drivers/input/misc/amd_sfh_tabletmode.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD SFH tablet-mode switch driver
+ *
+ * Copyright (c) 2026, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
+ */
+
+#include <linux/amd-pmf-io.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/pci_ids.h>
+
+#define POLL_INTERVAL_MS	200
+
+static void sfh_tm_poll(struct input_dev *input)
+{
+	struct amd_sfh_info info = {};
+
+	if (amd_get_sfh_info(&info, MT_OP_MODE))
+		return;
+
+	input_report_switch(input, SW_TABLET_MODE,
+			    info.op_mode == SFH_MODE_TABLET);
+	input_sync(input);
+}
+
+static int sfh_tm_probe(struct auxiliary_device *auxdev,
+			const struct auxiliary_device_id *id)
+{
+	struct device *dev = &auxdev->dev;
+	struct amd_sfh_info info = {};
+	struct input_dev *input;
+	int error;
+
+	error = amd_get_sfh_info(&info, MT_OP_MODE);
+	if (error)
+		return error == -EINVAL ? -ENODEV : error;
+
+	input = devm_input_allocate_device(dev);
+	if (!input)
+		return -ENOMEM;
+
+	input->name		= "AMD SFH tablet mode switch";
+	input->phys		= "amd-sfh/tabletmode";
+	input->id.bustype	= BUS_HOST;
+	input->id.vendor	= PCI_VENDOR_ID_AMD;
+	input_set_capability(input, EV_SW, SW_TABLET_MODE);
+
+	error = input_setup_polling(input, sfh_tm_poll);
+	if (error)
+		return error;
+	input_set_poll_interval(input, POLL_INTERVAL_MS);
+
+	sfh_tm_poll(input);
+
+	error = input_register_device(input);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static const struct auxiliary_device_id sfh_tm_id_table[] = {
+	{ .name = "amd_sfh.tabletmode" },
+	{}
+};
+MODULE_DEVICE_TABLE(auxiliary, sfh_tm_id_table);
+
+static struct auxiliary_driver sfh_tm_driver = {
+	.name		= "tabletmode",
+	.id_table	= sfh_tm_id_table,
+	.probe		= sfh_tm_probe,
+};
+module_auxiliary_driver(sfh_tm_driver);
+
+MODULE_DESCRIPTION("AMD SFH tablet mode switch");
+MODULE_LICENSE("GPL");
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 4/5] HID: amd_sfh: Register tablet-mode auxiliary device
  2026-08-03 14:58 ` [PATCH v2 4/5] HID: amd_sfh: Register tablet-mode auxiliary device Basavaraj Natikar
@ 2026-08-03 15:16   ` sashiko-bot
  0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-08-03 15:16 UTC (permalink / raw)
  To: Basavaraj Natikar; +Cc: dmitry.torokhov, linux-input

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The tablet-mode auxiliary device is unregistered in the devres cleanup phase, which occurs after the parent driver has manually shut down the hardware in its `.remove` callback, creating a Use-After-Teardown window.
--

--- Patch [4]: [PATCH v2 4/5] HID: amd_sfh: Register tablet-mode auxiliary device ---
commit cb1f4966427e04f4389572394e9a4fb57915128b
Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com>

HID: amd_sfh: Register tablet-mode auxiliary device
    
Register an auxiliary device when the operating-mode sensor is present,
so a dedicated input driver can bind to it and report the device posture.
This keeps the input handling out of the sensor transport driver.

> diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
> index 4b1cd260410d1..f6f016c8c6787 100644
> --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
> +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
[ ... ]
> @@ -389,6 +391,50 @@ static const struct attribute_group *amd_sfh_groups[] = {
[ ... ]
> +static void amd_sfh_maybe_register_tm(struct amd_mp2_dev *mp2)
> +{
[ ... ]
> +	mp2->tm_auxdev = adev;
> +	if (devm_add_action_or_reset(&mp2->pdev->dev, amd_sfh_tm_cleanup, mp2))
> +		dev_warn(&mp2->pdev->dev, "tabletmode cleanup registration failed\n");
> +}
[ ... ]
> @@ -424,6 +471,7 @@ static void sfh_init_work(struct work_struct *work)
[ ... ]
>  static void amd_sfh_remove(struct pci_dev *pdev)
>  {
>  	struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev);
>  
>  	flush_work(&mp2->work);
>  	if (mp2->init_done)
>  		mp2->mp2_ops->remove(mp2);

[Severity: High]
Does this create a use-after-teardown window on device unbind?

Because the tablet-mode auxiliary device cleanup is registered via
devm_add_action_or_reset() in amd_sfh_maybe_register_tm(), the auxiliary
device is only destroyed during the devres release phase.

Since devres cleanup runs after amd_sfh_remove() completes,
mp2->mp2_ops->remove(mp2) manually tears down the underlying hardware before
the auxiliary device is destroyed.

If the auxiliary driver's remove callback or userspace attempts to
interact with the device during this window between amd_sfh_remove() and the
devres cleanup phase, could they end up accessing disabled hardware?

>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803145801.3801862-1-Basavaraj.Natikar@amd.com?part=4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 5/5] Input: misc: Add AMD SFH tablet-mode switch driver
  2026-08-03 14:58 ` [PATCH v2 5/5] Input: misc: Add AMD SFH tablet-mode switch driver Basavaraj Natikar
@ 2026-08-03 16:18   ` Dmitry Torokhov
  2026-08-03 17:42     ` Basavaraj Natikar
  0 siblings, 1 reply; 9+ messages in thread
From: Dmitry Torokhov @ 2026-08-03 16:18 UTC (permalink / raw)
  To: Basavaraj Natikar; +Cc: jikos, bentiss, linux-input, Helge Bahmann

On Mon, Aug 03, 2026 at 08:28:01PM +0530, Basavaraj Natikar wrote:
> Report whether an AMD convertible is in laptop or tablet mode using the
> operating-mode sensor provided by the Sensor Fusion Hub, and expose it
> to userspace as SW_TABLET_MODE, so userspace can react to the device
> being folded into tablet posture.
> 
> Cc: Helge Bahmann <hcb@chaoticmind.net>
> Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>

Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

> @@ -81,6 +81,7 @@ obj-$(CONFIG_INPUT_RK805_PWRKEY)	+= rk805-pwrkey.o
>  obj-$(CONFIG_INPUT_SC27XX_VIBRA)	+= sc27xx-vibra.o
>  obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
>  obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY)	+= soc_button_array.o
> +obj-$(CONFIG_INPUT_AMD_SFH_TABLETMODE)	+= amd_sfh_tabletmode.o

Could you please move this higher. It is trying to be sorted alphabetically.


Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2 5/5] Input: misc: Add AMD SFH tablet-mode switch driver
  2026-08-03 16:18   ` Dmitry Torokhov
@ 2026-08-03 17:42     ` Basavaraj Natikar
  0 siblings, 0 replies; 9+ messages in thread
From: Basavaraj Natikar @ 2026-08-03 17:42 UTC (permalink / raw)
  To: Dmitry Torokhov, Basavaraj Natikar
  Cc: jikos, bentiss, linux-input, Helge Bahmann


On 8/3/2026 9:48 PM, Dmitry Torokhov wrote:
> [You don't often get email from dmitry.torokhov@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> On Mon, Aug 03, 2026 at 08:28:01PM +0530, Basavaraj Natikar wrote:
>> Report whether an AMD convertible is in laptop or tablet mode using the
>> operating-mode sensor provided by the Sensor Fusion Hub, and expose it
>> to userspace as SW_TABLET_MODE, so userspace can react to the device
>> being folded into tablet posture.
>>
>> Cc: Helge Bahmann <hcb@chaoticmind.net>
>> Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
> Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>
>> @@ -81,6 +81,7 @@ obj-$(CONFIG_INPUT_RK805_PWRKEY)    += rk805-pwrkey.o
>>   obj-$(CONFIG_INPUT_SC27XX_VIBRA)     += sc27xx-vibra.o
>>   obj-$(CONFIG_INPUT_SGI_BTNS)         += sgi_btns.o
>>   obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
>> +obj-$(CONFIG_INPUT_AMD_SFH_TABLETMODE)       += amd_sfh_tabletmode.o
> Could you please move this higher. It is trying to be sorted alphabetically.

Sure, I'll move it to the correct alphabetical spot in v3.
Thanks for the review and the ack.

Thanks,
Basavaraj


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-08-03 17:42 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-03 14:57 [PATCH v2 0/5] Add SW_TABLET_MODE support for AMD SFH convertibles Basavaraj Natikar
2026-08-03 14:57 ` [PATCH v2 1/5] HID: amd_sfh: Track MP2 version explicitly Basavaraj Natikar
2026-08-03 14:57 ` [PATCH v2 2/5] HID: amd_sfh: Serialize access to the shared emp2 pointer Basavaraj Natikar
2026-08-03 14:57 ` [PATCH v2 3/5] HID: amd_sfh: Add accessor to read the operating-mode sensor Basavaraj Natikar
2026-08-03 14:58 ` [PATCH v2 4/5] HID: amd_sfh: Register tablet-mode auxiliary device Basavaraj Natikar
2026-08-03 15:16   ` sashiko-bot
2026-08-03 14:58 ` [PATCH v2 5/5] Input: misc: Add AMD SFH tablet-mode switch driver Basavaraj Natikar
2026-08-03 16:18   ` Dmitry Torokhov
2026-08-03 17:42     ` Basavaraj Natikar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox