[PATCH 2/3] thermal: samsung: acpm-tmu: refactor SoC-specific operations into driver data
From: Alexey Klimov
Date: Wed Jul 08 2026 - 21:11:58 EST
The current ACPM TMU driver assumes that all TMU operations (init,
threshold updates, and interrupt clearing) are handled exclusively
via ACPM IPC commands, which is true for the GS101.
However, other Exynos platforms (like Exynos850) lack complete firmware
support for these operations and require direct MMIO register access
instead for missing ACPM TMU IPC calls.
Prepare the driver for multi-SoC support by moving the hardcoded GS101
IPC calls into SoC-specific callbacks: "tz_control", "tmu_init",
"tmu_update_thresholds" and "tmu_check_and_clear_irqs" within the
acpm_tmu_driver_data struct. Additionally, save the regmap pointer in
the private structure so that these callbacks can utilize it for other
SoCs.
Signed-off-by: Alexey Klimov <alexey.klimov@xxxxxxxxxx>
---
drivers/thermal/samsung/acpm-tmu.c | 112 +++++++++++++++++++++++++------------
1 file changed, 76 insertions(+), 36 deletions(-)
diff --git a/drivers/thermal/samsung/acpm-tmu.c b/drivers/thermal/samsung/acpm-tmu.c
index f9802080acd7..b3cea9890b4b 100644
--- a/drivers/thermal/samsung/acpm-tmu.c
+++ b/drivers/thermal/samsung/acpm-tmu.c
@@ -72,6 +72,8 @@ struct acpm_tmu_sensor {
};
struct acpm_tmu_priv {
+ const struct acpm_tmu_driver_data *data;
+ struct regmap *regmap;
struct regmap_field *regmap_fields[REG_INTPEND_COUNT];
struct acpm_handle *handle;
struct device *dev;
@@ -84,9 +86,18 @@ struct acpm_tmu_priv {
struct acpm_tmu_driver_data {
const struct reg_field *reg_fields;
+ const struct regmap_config *regmap_config;
const struct acpm_tmu_sensor_group *sensor_groups;
unsigned int num_sensor_groups;
unsigned int mbox_chan_id;
+
+ /* SoC-specific TMU routines and values */
+ int (*tz_control)(struct acpm_tmu_sensor *sensor, bool on);
+ int (*tmu_check_and_clear_irqs)(struct acpm_tmu_sensor *sensor,
+ bool *pending_irq);
+ int (*tmu_init)(struct acpm_tmu_priv *priv);
+ int (*tmu_update_thresholds)(struct acpm_tmu_sensor *sensor,
+ u8 thresholds[2], u8 inten);
};
#define ACPM_TMU_SENSOR_GROUP(_mask, _id) \
@@ -128,24 +139,32 @@ static const struct regmap_config gs101_regmap_config = {
.max_register = GS101_REG_INTPEND(15),
};
-static const struct acpm_tmu_driver_data acpm_tmu_gs101 = {
- .reg_fields = gs101_reg_fields,
- .sensor_groups = gs101_sensor_groups,
- .num_sensor_groups = ARRAY_SIZE(gs101_sensor_groups),
- .mbox_chan_id = 9,
-};
+static int gs101_tz_control(struct acpm_tmu_sensor *sensor, bool on)
+{
+ struct acpm_tmu_priv *priv = sensor->priv;
+ struct acpm_handle *handle = priv->handle;
+
+ return handle->ops->tmu.tz_control(handle, priv->mbox_chan_id,
+ sensor->group->id, on);
+}
+
+static int gs101_tmu_init(struct acpm_tmu_priv *priv)
+{
+ struct acpm_handle *handle = priv->handle;
+
+ return handle->ops->tmu.init(handle, priv->mbox_chan_id);
+}
static int acpm_tmu_op_tz_control(struct acpm_tmu_sensor *sensor, bool on)
{
struct acpm_tmu_priv *priv = sensor->priv;
- struct acpm_handle *handle = priv->handle;
- const struct acpm_tmu_ops *ops = &handle->ops->tmu;
int ret;
- ret = ops->tz_control(handle, priv->mbox_chan_id, sensor->group->id,
- on);
- if (ret)
- return ret;
+ if (priv->data->tz_control) {
+ ret = priv->data->tz_control(sensor, on);
+ if (ret)
+ return ret;
+ }
sensor->enabled = on;
@@ -249,8 +268,8 @@ static int acpm_tmu_get_temp(struct thermal_zone_device *tz, int *temp)
return 0;
}
-static int acpm_tmu_update_thresholds(struct acpm_tmu_sensor *sensor,
- u8 thresholds[2], u8 inten)
+static int gs101_tmu_update_thresholds(struct acpm_tmu_sensor *sensor,
+ u8 thresholds[2], u8 inten)
{
struct acpm_tmu_priv *priv = sensor->priv;
struct acpm_handle *handle = priv->handle;
@@ -314,7 +333,8 @@ static int acpm_tmu_set_trips(struct thermal_zone_device *tz, int low, int high)
if (ret)
return ret;
- ret = acpm_tmu_update_thresholds(sensor, thresholds, inten);
+ if (priv->data->tmu_update_thresholds)
+ ret = priv->data->tmu_update_thresholds(sensor, thresholds, inten);
pm_runtime_put_autosuspend(dev);
@@ -326,10 +346,11 @@ static const struct thermal_zone_device_ops acpm_tmu_sensor_ops = {
.set_trips = acpm_tmu_set_trips,
};
-static int acpm_tmu_has_pending_irq(struct acpm_tmu_sensor *sensor,
- bool *pending_irq)
+static int gs101_handle_irqs(struct acpm_tmu_sensor *sensor, bool *pending_irq)
{
struct acpm_tmu_priv *priv = sensor->priv;
+ struct acpm_handle *handle = priv->handle;
+ const struct acpm_tmu_ops *ops = &handle->ops->tmu;
unsigned long mask = sensor->group->mask;
int i, ret;
u32 val;
@@ -347,14 +368,17 @@ static int acpm_tmu_has_pending_irq(struct acpm_tmu_sensor *sensor,
}
}
- return 0;
+ ret = ops->clear_tz_irq(handle, priv->mbox_chan_id, sensor->group->id);
+ if (ret)
+ dev_err(priv->dev, "Sensor %d: failed to clear IRQ (%d)\n",
+ i, ret);
+
+ return ret;
}
static irqreturn_t acpm_tmu_thread_fn(int irq, void *id)
{
struct acpm_tmu_priv *priv = id;
- struct acpm_handle *handle = priv->handle;
- const struct acpm_tmu_ops *ops = &handle->ops->tmu;
struct device *dev = priv->dev;
bool handled = false;
int i, ret;
@@ -372,20 +396,12 @@ static irqreturn_t acpm_tmu_thread_fn(int irq, void *id)
if (!sensor->tzd)
continue;
- ret = acpm_tmu_has_pending_irq(sensor, &pending_irq);
+ ret = priv->data->tmu_check_and_clear_irqs(sensor, &pending_irq);
if (ret || !pending_irq)
continue;
handled = true;
- scoped_guard(mutex, &sensor->lock) {
- ret = ops->clear_tz_irq(handle, priv->mbox_chan_id,
- sensor->group->id);
- if (ret)
- dev_err(priv->dev, "Sensor %d: failed to clear IRQ (%d)\n",
- i, ret);
- }
-
thermal_zone_device_update(sensor->tzd,
THERMAL_EVENT_UNSPECIFIED);
}
@@ -395,15 +411,30 @@ static irqreturn_t acpm_tmu_thread_fn(int irq, void *id)
return handled ? IRQ_HANDLED : IRQ_NONE;
}
+static const struct acpm_tmu_driver_data acpm_tmu_gs101 = {
+ .reg_fields = gs101_reg_fields,
+ .regmap_config = &gs101_regmap_config,
+ .sensor_groups = gs101_sensor_groups,
+ .num_sensor_groups = ARRAY_SIZE(gs101_sensor_groups),
+ .mbox_chan_id = 9,
+ .tz_control = gs101_tz_control,
+ .tmu_check_and_clear_irqs = gs101_handle_irqs,
+ .tmu_init = gs101_tmu_init,
+ .tmu_update_thresholds = gs101_tmu_update_thresholds,
+};
+
static const struct of_device_id acpm_tmu_match[] = {
- { .compatible = "google,gs101-tmu-top" },
+ {
+ .compatible = "google,gs101-tmu-top",
+ .data = &acpm_tmu_gs101
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, acpm_tmu_match);
static int acpm_tmu_probe(struct platform_device *pdev)
{
- const struct acpm_tmu_driver_data *data = &acpm_tmu_gs101;
+ const struct acpm_tmu_driver_data *data;
struct acpm_handle *acpm_handle;
struct device *dev = &pdev->dev;
struct acpm_tmu_priv *priv;
@@ -411,6 +442,10 @@ static int acpm_tmu_probe(struct platform_device *pdev)
void __iomem *base;
int i, ret;
+ data = of_device_get_match_data(dev);
+ if (!data)
+ return dev_err_probe(dev, -ENODEV, "No matching driver data found\n");
+
acpm_handle = devm_acpm_get_by_phandle(dev);
if (IS_ERR(acpm_handle))
return dev_err_probe(dev, PTR_ERR(acpm_handle),
@@ -422,6 +457,7 @@ static int acpm_tmu_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
+ priv->data = data;
priv->dev = dev;
priv->handle = acpm_handle;
priv->mbox_chan_id = data->mbox_chan_id;
@@ -433,10 +469,12 @@ static int acpm_tmu_probe(struct platform_device *pdev)
if (IS_ERR(base))
return dev_err_probe(dev, PTR_ERR(base), "Failed to ioremap resource\n");
- regmap = devm_regmap_init_mmio(dev, base, &gs101_regmap_config);
+ regmap = devm_regmap_init_mmio(dev, base, data->regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap), "Failed to init regmap\n");
+ priv->regmap = regmap;
+
ret = devm_regmap_field_bulk_alloc(dev, regmap, priv->regmap_fields,
data->reg_fields, REG_INTPEND_COUNT);
if (ret)
@@ -463,10 +501,12 @@ static int acpm_tmu_probe(struct platform_device *pdev)
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to resume device\n");
- ret = acpm_handle->ops->tmu.init(acpm_handle, priv->mbox_chan_id);
- if (ret) {
- ret = dev_err_probe(dev, ret, "Failed to init TMU\n");
- goto err_pm_put;
+ if (priv->data->tmu_init) {
+ ret = priv->data->tmu_init(priv);
+ if (ret) {
+ ret = dev_err_probe(dev, ret, "Failed to init TMU\n");
+ goto err_pm_put;
+ }
}
for (i = 0; i < priv->num_sensors; i++) {
--
2.51.0