Files
build/patch/kernel/archive/meson64-6.16/hwmon-emc2305-fixups-for-driver.patch
2025-08-31 12:42:15 +02:00

253 lines
7.3 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Patrick Yavitz <pyavitz@gmail.com>
Date: Wed, 9 Apr 2025 04:34:27 -0400
Subject: hwmon: emc2305: fixups for driver
The driver had a number of issues, checkpatch warnings/errors,
and other limitations, so fix these up to make it usable.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
hwmon: emc2305: Add calls to initialise of cooling maps
Commit 46ef9d4 ("hwmon: emc2305: fixups for driver submitted to
mailing lists") missed adding the call to thermal_of_cooling_device_register
required to configure any cooling maps for the device, hence stopping it
from actually ever changing speed.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
hwmon: emc2305: Change OF properties pwm-min & pwm-max to u8
There is no DT binding for emc2305 as mainline are still
discussing how to do a generic fan binding.
The 5.15 driver was reading the "emc2305," properties
"cooling-levels", "pwm-max", "pwm-min", and "pwm-channel" as u8.
The overlay was writing them as u16 (;) so it was working.
The 6.1 driver was reading as u32, which failed as there is
insufficient data.
As this is all downstream only, revert to u8 to match 5.15.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/hwmon/emc2305.c | 110 +++++++++-
1 file changed, 104 insertions(+), 6 deletions(-)
diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c
index 111111111111..222222222222 100644
--- a/drivers/hwmon/emc2305.c
+++ b/drivers/hwmon/emc2305.c
@@ -12,12 +12,13 @@
#include <linux/platform_data/emc2305.h>
#include <linux/thermal.h>
+#define EMC2305_REG_FAN_STATUS 0x24
+#define EMC2305_REG_FAN_STALL_STATUS 0x25
#define EMC2305_REG_DRIVE_FAIL_STATUS 0x27
#define EMC2305_REG_VENDOR 0xfe
#define EMC2305_FAN_MAX 0xff
#define EMC2305_FAN_MIN 0x00
#define EMC2305_FAN_MAX_STATE 10
-#define EMC2305_DEVICE 0x34
#define EMC2305_VENDOR 0x5d
#define EMC2305_REG_PRODUCT_ID 0xfd
#define EMC2305_TACH_REGS_UNUSE_BITS 3
@@ -36,6 +37,7 @@
#define EMC2305_RPM_FACTOR 3932160
#define EMC2305_REG_FAN_DRIVE(n) (0x30 + 0x10 * (n))
+#define EMC2305_REG_FAN_CFG(n) (0x32 + 0x10 * (n))
#define EMC2305_REG_FAN_MIN_DRIVE(n) (0x38 + 0x10 * (n))
#define EMC2305_REG_FAN_TACH(n) (0x3e + 0x10 * (n))
@@ -100,6 +102,7 @@ struct emc2305_data {
u8 pwm_num;
bool pwm_separate;
u8 pwm_min[EMC2305_PWM_MAX];
+ u8 pwm_max;
struct emc2305_cdev_data cdev_data[EMC2305_PWM_MAX];
};
@@ -112,6 +115,8 @@ static char *emc2305_fan_name[] = {
"emc2305_fan5",
};
+static void emc2305_unset_tz(struct device *dev);
+
static int emc2305_get_max_channel(const struct emc2305_data *data)
{
return data->pwm_num;
@@ -270,7 +275,7 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel)
struct i2c_client *client = data->client;
int ret;
- if (val < data->pwm_min[channel] || val > EMC2305_FAN_MAX)
+ if (val < data->pwm_min[channel] || val > data->pwm_max)
return -EINVAL;
ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(channel), val);
@@ -281,6 +286,49 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel)
return 0;
}
+static int emc2305_get_tz_of(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct emc2305_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+ u8 val;
+ int i;
+
+ /* OF parameters are optional - overwrite default setting
+ * if some of them are provided.
+ */
+
+ ret = of_property_read_u8(np, "emc2305,cooling-levels", &val);
+ if (!ret)
+ data->max_state = val;
+ else if (ret != -EINVAL)
+ return ret;
+
+ ret = of_property_read_u8(np, "emc2305,pwm-max", &val);
+ if (!ret)
+ data->pwm_max = val;
+ else if (ret != -EINVAL)
+ return ret;
+
+ ret = of_property_read_u8(np, "emc2305,pwm-min", &val);
+ if (!ret)
+ for (i = 0; i < EMC2305_PWM_MAX; i++)
+ data->pwm_min[i] = val;
+ else if (ret != -EINVAL)
+ return ret;
+
+ /* Not defined or 0 means one thermal zone over all cooling devices.
+ * Otherwise - separated thermal zones for each PWM channel.
+ */
+ ret = of_property_read_u8(np, "emc2305,pwm-channel", &val);
+ if (!ret)
+ data->pwm_separate = (val != 0);
+ else if (ret != -EINVAL)
+ return ret;
+
+ return 0;
+}
+
static int emc2305_set_single_tz(struct device *dev, int idx)
{
struct emc2305_data *data = dev_get_drvdata(dev);
@@ -290,9 +338,16 @@ static int emc2305_set_single_tz(struct device *dev, int idx)
cdev_idx = (idx) ? idx - 1 : 0;
pwm = data->pwm_min[cdev_idx];
- data->cdev_data[cdev_idx].cdev =
- devm_thermal_of_cooling_device_register(dev, dev->of_node,
- emc2305_fan_name[idx], data,
+ if (dev->of_node)
+ data->cdev_data[cdev_idx].cdev =
+ devm_thermal_of_cooling_device_register(dev, dev->of_node,
+ emc2305_fan_name[idx],
+ data,
+ &emc2305_cooling_ops);
+ else
+ data->cdev_data[cdev_idx].cdev =
+ thermal_cooling_device_register(emc2305_fan_name[idx],
+ data,
&emc2305_cooling_ops);
if (IS_ERR(data->cdev_data[cdev_idx].cdev)) {
@@ -331,9 +386,26 @@ static int emc2305_set_tz(struct device *dev)
for (i = 0; i < data->pwm_num; i++) {
ret = emc2305_set_single_tz(dev, i + 1);
if (ret)
- return ret;
+ goto thermal_cooling_device_register_fail;
}
return 0;
+
+thermal_cooling_device_register_fail:
+ emc2305_unset_tz(dev);
+ return ret;
+}
+
+static void emc2305_unset_tz(struct device *dev)
+{
+ struct emc2305_data *data = dev_get_drvdata(dev);
+ int i;
+
+ /* Unregister cooling device. */
+ if (!dev->of_node) {
+ for (i = 0; i < EMC2305_PWM_MAX; i++)
+ if (data->cdev_data[i].cdev)
+ thermal_cooling_device_unregister(data->cdev_data[i].cdev);
+ }
}
static umode_t
@@ -555,11 +627,18 @@ static int emc2305_probe(struct i2c_client *client)
data->pwm_separate = pdata->pwm_separate;
for (i = 0; i < EMC2305_PWM_MAX; i++)
data->pwm_min[i] = pdata->pwm_min[i];
+ data->pwm_max = EMC2305_FAN_MAX;
} else {
data->max_state = EMC2305_FAN_MAX_STATE;
data->pwm_separate = false;
for (i = 0; i < EMC2305_PWM_MAX; i++)
data->pwm_min[i] = EMC2305_FAN_MIN;
+ data->pwm_max = EMC2305_FAN_MAX;
+ if (dev->of_node) {
+ ret = emc2305_get_tz_of(dev);
+ if (ret < 0)
+ return ret;
+ }
}
data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "emc2305", data,
@@ -580,21 +659,40 @@ static int emc2305_probe(struct i2c_client *client)
return ret;
}
+ /* Acknowledge any existing faults. Stops the device responding on the
+ * SMBus alert address.
+ */
+ i2c_smbus_read_byte_data(client, EMC2305_REG_FAN_STALL_STATUS);
+ i2c_smbus_read_byte_data(client, EMC2305_REG_FAN_STATUS);
+
return 0;
}
static const struct of_device_id of_emc2305_match_table[] = {
+ { .compatible = "smsc,emc2305" },
{ .compatible = "microchip,emc2305", },
+ { .compatible = "microchip,emc2303", },
+ { .compatible = "microchip,emc2302", },
+ { .compatible = "microchip,emc2301", },
{},
};
MODULE_DEVICE_TABLE(of, of_emc2305_match_table);
+static void emc2305_remove(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+
+ if (IS_REACHABLE(CONFIG_THERMAL))
+ emc2305_unset_tz(dev);
+}
+
static struct i2c_driver emc2305_driver = {
.driver = {
.name = "emc2305",
.of_match_table = of_emc2305_match_table,
},
.probe = emc2305_probe,
+ .remove = emc2305_remove,
.id_table = emc2305_ids,
};
--
Armbian