[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250312123055.1735-3-messigoatcr7nop@gmail.com>
Date: Wed, 12 Mar 2025 18:00:23 +0530
From: Subu Dwevedi <messigoatcr7nop@...il.com>
To:
Cc: Subu Dwevedi <messigoatcr7nop@...il.com>,
Henrik Rydberg <rydberg@...math.org>,
Jean Delvare <jdelvare@...e.com>,
Guenter Roeck <linux@...ck-us.net>,
linux-hwmon@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH 2/2] hwmon/applesmc: add fan support for newer macs
Newer Mac models have transitioned
the fan speed values from short to float.
Additionally, the fan manual
control mechanism (fan_manual) have changed from u16 to u8
Signed-off-by: Subu Dwevedi <messigoatcr7nop@...il.com>
---
drivers/hwmon/applesmc.c | 124 +++++++++++++++++++++++++++++++--------
1 file changed, 101 insertions(+), 23 deletions(-)
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 1be4a4026a6e..9157f5978ee7 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -71,10 +71,12 @@
#define MOTION_SENSOR_KEY "MOCN" /* r/w ui16 */
#define FANS_COUNT "FNum" /* r-o ui8 */
+#define FANS_MANUAL_FMT "F%dMd" /* r-w ui8*/
#define FANS_MANUAL "FS! " /* r-w ui16 */
#define FAN_ID_FMT "F%dID" /* r-o char[16] */
#define TEMP_SENSOR_TYPE "sp78"
+#define FLOAT_TYPE "flt "
/* List of keys used to read/write fan speeds */
static const char *const fan_speed_fmt[] = {
@@ -145,6 +147,8 @@ static s16 rest_y;
static u8 backlight_state[2];
static u8 *__iomem mmio_base;
static bool is_mmio;
+static bool is_fan_manual_fmt;
+static bool is_fan_speed_float;
static u32 mmio_base_addr, mmio_base_size;
static struct device *hwmon_dev;
static struct input_dev *applesmc_idev;
@@ -652,6 +656,50 @@ static int applesmc_read_s16(const char *key, s16 *value)
return 0;
}
+/*
+ * applesmc_float_to_u32 - Retrieve the integral part of a float.
+ * This is needed because Apple made fans use float values in the T2.
+ * The fractional point is not significantly useful though, and the integral
+ */
+static inline u32 applesmc_float_to_u32(u32 from)
+{
+ u8 sign = from >> 31;
+ s32 exp = ((from >> 23) & 0xFF) - 0x7F;
+ u32 fr = from & GENMASK(22, 0);
+ u32 round_up = 0;
+
+ if (sign || exp < 0)
+ return 0;
+
+ u32 int_part = BIT(exp);
+ u32 frac_part = fr >> (23 - exp);
+
+ if (fr & BIT(22 - exp))
+ round_up = 1;
+
+ return int_part + frac_part + round_up;
+}
+
+/*
+ * applesmc_u32_to_float - Convert an u32 into a float.
+ * See applesmc_float_to_u32 for a rationale.
+ */
+static inline u32 applesmc_u32_to_float(u32 from)
+{
+ if (!from)
+ return 0;
+
+ u32 bc = fls(from) - 1;
+ u32 exp = 0x7F + bc;
+ u32 frac_part = (from << (23 - bc)) & GENMASK(22, 0);
+ u32 round_up = 0;
+
+ if (from & BIT(bc - 1))
+ round_up = 1;
+
+ return (exp << 23) | (frac_part + round_up);
+}
+
/*
* applesmc_device_init - initialize the accelerometer. Can sleep.
*/
@@ -763,6 +811,8 @@ static int applesmc_init_mmio_try(void)
static int applesmc_init_smcreg_try(void)
{
struct applesmc_registers *s = &smcreg;
+ const struct applesmc_entry *e;
+ char newkey[5];
bool left_light_sensor = false, right_light_sensor = false;
unsigned int count;
u8 tmp[1];
@@ -788,6 +838,15 @@ static int applesmc_init_smcreg_try(void)
if (!s->cache)
return -ENOMEM;
+ scnprintf(newkey, sizeof(newkey), fan_speed_fmt[1], 1); //example value
+
+ e = applesmc_get_entry_by_key(newkey);
+ if (IS_ERR(e))
+ return PTR_ERR(e);
+
+ if (!strcmp(e->type, FLOAT_TYPE))
+ is_fan_speed_float = true;
+
ret = applesmc_read_key(FANS_COUNT, tmp, 1);
if (ret)
return ret;
@@ -820,6 +879,10 @@ static int applesmc_init_smcreg_try(void)
if (ret)
return ret;
+ ret = applesmc_has_key(FANS_MANUAL_FMT, &is_fan_manual_fmt);
+ if (ret)
+ return ret;
+
s->num_light_sensors = left_light_sensor + right_light_sensor;
s->init_complete = true;
@@ -1044,11 +1107,16 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
to_index(attr));
- ret = applesmc_read_key(newkey, buffer, 2);
+ if (is_fan_speed_float) {
+ ret = applesmc_read_key(newkey, (u8 *) &speed, 4);
+ speed = applesmc_float_to_u32(speed);
+ } else {
+ ret = applesmc_read_key(newkey, buffer, 2);
+ speed = ((buffer[0] << 8 | buffer[1]) >> 2);
+ }
if (ret)
return ret;
- speed = ((buffer[0] << 8 | buffer[1]) >> 2);
return sysfs_emit(sysfsbuf, "%u\n", speed);
}
@@ -1067,10 +1135,14 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
to_index(attr));
- buffer[0] = (speed >> 6) & 0xff;
- buffer[1] = (speed << 2) & 0xff;
- ret = applesmc_write_key(newkey, buffer, 2);
-
+ if (is_fan_speed_float) {
+ speed = applesmc_u32_to_float(speed);
+ ret = applesmc_write_key(newkey, (u8 *) &speed, 4);
+ } else {
+ buffer[0] = (speed >> 6) & 0xff;
+ buffer[1] = (speed << 2) & 0xff;
+ ret = applesmc_write_key(newkey, buffer, 2);
+ }
if (ret)
return ret;
else
@@ -1084,11 +1156,13 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
u16 manual = 0;
u8 buffer[2];
- ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
- if (ret)
- return ret;
-
- manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
+ if (is_fan_manual_fmt) {
+ ret = applesmc_read_key(FANS_MANUAL_FMT, buffer, 1);
+ manual = buffer[0];
+ } else {
+ ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
+ manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
+ }
return sysfs_emit(sysfsbuf, "%d\n", manual);
}
@@ -1104,22 +1178,26 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
if (kstrtoul(sysfsbuf, 10, &input) < 0)
return -EINVAL;
- ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
- if (ret)
- goto out;
-
- val = (buffer[0] << 8 | buffer[1]);
+ if (is_fan_manual_fmt) {
+ buffer[0] = input & 0x01;
+ ret = applesmc_write_key(FANS_MANUAL_FMT, buffer, 1);
+ } else {
+ ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
+ if (ret)
+ goto out;
- if (input)
- val = val | (0x01 << to_index(attr));
- else
- val = val & ~(0x01 << to_index(attr));
+ val = (buffer[0] << 8 | buffer[1]);
- buffer[0] = (val >> 8) & 0xFF;
- buffer[1] = val & 0xFF;
+ if (input)
+ val = val | (0x01 << to_index(attr));
+ else
+ val = val & ~(0x01 << to_index(attr));
- ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
+ buffer[0] = (val >> 8) & 0xFF;
+ buffer[1] = val & 0xFF;
+ ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
+ }
out:
if (ret)
return ret;
--
2.43.0
Powered by blists - more mailing lists