[PATCH v1 1/2] drm/xe/i2c: Handler for SMBus Alerts

From: Heikki Krogerus

Date: Mon Jun 22 2026 - 07:48:15 EST


Some devices that are attached to the I2C controller use the
SMBus Alert signal for example to inform the host about
thermal events, so registering the default SMBus Alert
device device for them. The alert device makes sure that
the alert is processed and passed to the correct I2C client
driver.

Signed-off-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx>
---
drivers/gpu/drm/xe/Makefile | 1 +
drivers/gpu/drm/xe/xe_i2c.c | 21 +++++++----
drivers/gpu/drm/xe/xe_i2c.h | 15 ++++++++
drivers/gpu/drm/xe/xe_i2c_smbus.c | 59 +++++++++++++++++++++++++++++++
4 files changed, 90 insertions(+), 6 deletions(-)
create mode 100644 drivers/gpu/drm/xe/xe_i2c_smbus.c

diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 8e7b146880f46..9c8af00cf37fd 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -153,6 +153,7 @@ xe-y += xe_bb.o \
xe_wopcm.o

xe-$(CONFIG_I2C) += xe_i2c.o
+xe-$(CONFIG_I2C_SMBUS) += xe_i2c_smbus.o
xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o
xe-$(CONFIG_DRM_GPUSVM) += xe_userptr.o

diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c
index 706783863d07d..732ad6ee05e9c 100644
--- a/drivers/gpu/drm/xe/xe_i2c.c
+++ b/drivers/gpu/drm/xe/xe_i2c.c
@@ -30,6 +30,7 @@
#include "xe_device.h"
#include "xe_i2c.h"
#include "xe_mmio.h"
+#include "xe_platform_types.h"
#include "xe_sriov.h"
#include "xe_survivability_mode.h"

@@ -163,7 +164,7 @@ bool xe_i2c_present(struct xe_device *xe)

static bool xe_i2c_irq_present(struct xe_device *xe)
{
- return xe->i2c && xe->i2c->adapter_irq;
+ return xe->i2c && (xe->i2c->adapter_irq || xe->i2c->smbus_alert);
}

/**
@@ -182,7 +183,10 @@ void xe_i2c_irq_handler(struct xe_device *xe, u32 master_ctl)
return;

/* Forward interrupt to I2C adapter */
- generic_handle_irq_safe(xe->i2c->adapter_irq);
+ if (xe->i2c->smbus_alert)
+ xe_i2c_handle_smbus_alert(xe->i2c);
+ else
+ generic_handle_irq_safe(xe->i2c->adapter_irq);

/* Deassert after I2C adapter clears the interrupt */
xe_mmio_rmw32(mmio, I2C_CONFIG_CMD, 0, PCI_COMMAND_INTX_DISABLE);
@@ -232,6 +236,9 @@ static int xe_i2c_create_irq(struct xe_device *xe)
xe_survivability_mode_is_boot_enabled(xe))
return 0;

+ if (xe->info.platform == XE_CRESCENTISLAND)
+ return xe_i2c_register_smbus_alert(i2c);
+
domain = irq_domain_create_linear(dev_fwnode(i2c->drm_dev), 1, &xe_i2c_irq_ops, NULL);
if (!domain)
return -ENOMEM;
@@ -244,6 +251,9 @@ static int xe_i2c_create_irq(struct xe_device *xe)

static void xe_i2c_remove_irq(struct xe_i2c *i2c)
{
+ if (i2c->smbus_alert)
+ i2c_unregister_device(i2c->smbus_alert);
+
if (!i2c->irqdomain)
return;

@@ -327,7 +337,6 @@ int xe_i2c_probe(struct xe_device *xe)
{
struct device *drm_dev = xe->drm.dev;
struct xe_i2c_endpoint ep;
- struct regmap *regmap;
struct xe_i2c *i2c;
int ret;

@@ -354,9 +363,9 @@ int xe_i2c_probe(struct xe_device *xe)
/* PCI PM isn't aware of this device, bring it up and match it with SGUnit state. */
xe_i2c_pm_resume(xe, true);

- regmap = devm_regmap_init(drm_dev, NULL, i2c, &i2c_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
+ i2c->regmap = devm_regmap_init(drm_dev, NULL, i2c, &i2c_regmap_config);
+ if (IS_ERR(i2c->regmap))
+ return PTR_ERR(i2c->regmap);

i2c->bus_notifier.notifier_call = xe_i2c_notifier;
ret = bus_register_notifier(&i2c_bus_type, &i2c->bus_notifier);
diff --git a/drivers/gpu/drm/xe/xe_i2c.h b/drivers/gpu/drm/xe/xe_i2c.h
index 425d8160835f4..fdbad51950423 100644
--- a/drivers/gpu/drm/xe/xe_i2c.h
+++ b/drivers/gpu/drm/xe/xe_i2c.h
@@ -3,6 +3,7 @@
#define _XE_I2C_H_

#include <linux/bits.h>
+#include <linux/errno.h>
#include <linux/notifier.h>
#include <linux/types.h>
#include <linux/workqueue.h>
@@ -12,6 +13,7 @@ struct fwnode_handle;
struct i2c_adapter;
struct i2c_client;
struct irq_domain;
+struct regmap;
struct platform_device;
struct xe_device;
struct xe_mmio;
@@ -40,6 +42,8 @@ struct xe_i2c {

struct irq_domain *irqdomain;
int adapter_irq;
+ struct i2c_client *smbus_alert;
+ struct regmap *regmap;

struct xe_i2c_endpoint ep;
struct device *drm_dev;
@@ -65,4 +69,15 @@ static inline void xe_i2c_pm_suspend(struct xe_device *xe) { }
static inline void xe_i2c_pm_resume(struct xe_device *xe, bool d3cold) { }
#endif

+#if IS_ENABLED(CONFIG_I2C_SMBUS)
+void xe_i2c_handle_smbus_alert(struct xe_i2c *i2c);
+int xe_i2c_register_smbus_alert(struct xe_i2c *i2c);
+#else
+static inline void xe_i2c_handle_smbus_alert(struct xe_i2c *i2c) { }
+static inline int xe_i2c_register_smbus_alert(struct xe_i2c *i2c)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
#endif
diff --git a/drivers/gpu/drm/xe/xe_i2c_smbus.c b/drivers/gpu/drm/xe/xe_i2c_smbus.c
new file mode 100644
index 0000000000000..185a6d2f0a508
--- /dev/null
+++ b/drivers/gpu/drm/xe/xe_i2c_smbus.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Intel Xe SMBus handling
+ *
+ * Copyright (C) 2026 Intel Corporation.
+ */
+
+#include <linux/i2c-smbus.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include "xe_i2c.h"
+
+/**
+ * DOC: Handler for SMBus Alerts
+ *
+ * If the I2C controller on the platform supports the SMBus extensions, a
+ * dedicated SMBus alert device needs to be registered for it. The alert device
+ * handles the standard SMBus alert processing and forwarding of the alert to
+ * the correct I2C client driver. On most platforms the i2c client device that
+ * generates the alerts will be the AMC.
+ */
+
+#define DW_IC_SMBUS_INTR_STAT 0xc8
+#define DW_IC_CLR_SMBUS_INTR 0xd4
+
+#define DW_IC_SMBUS_INTR_ALERT BIT(10)
+
+void xe_i2c_handle_smbus_alert(struct xe_i2c *i2c)
+{
+ u32 stat;
+
+ if (!i2c->smbus_alert)
+ return;
+
+ regmap_read(i2c->regmap, DW_IC_SMBUS_INTR_STAT, &stat);
+ if (!stat)
+ return;
+
+ regmap_write(i2c->regmap, DW_IC_CLR_SMBUS_INTR, stat);
+
+ if (stat & DW_IC_SMBUS_INTR_ALERT)
+ i2c_handle_smbus_alert(i2c->smbus_alert);
+}
+
+static struct i2c_smbus_alert_setup xe_i2c_smbus_setup;
+
+int xe_i2c_register_smbus_alert(struct xe_i2c *i2c)
+{
+ struct i2c_client *alert;
+
+ alert = i2c_new_smbus_alert_device(i2c->adapter, &xe_i2c_smbus_setup);
+ if (IS_ERR(alert))
+ return PTR_ERR(alert);
+
+ i2c->smbus_alert = alert;
+
+ return 0;
+}
--
2.50.1