Skip to content

Commit 9366495

Browse files
Paul Pawlowski1Naim
authored andcommitted
applesmc-t2: fan support on T2 Macs
T2 Macs changed the fan values from shorts to floats, and changed the fan manual override setting from a bitmask to a per-fan boolean named F0Md (thanks to @kleuter for mentioning it). A minimal soft-float implementation has been written for convert floats to integers (and vice versa). Signed-off-by: Aun-Ali Zaidi <admin@kodeit.net>
1 parent f802a93 commit 9366495

1 file changed

Lines changed: 102 additions & 17 deletions

File tree

drivers/hwmon/applesmc-t2.c

Lines changed: 102 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
#define FAN_ID_FMT "F%dID" /* r-o char[16] */
8888

8989
#define TEMP_SENSOR_TYPE "sp78"
90+
#define FLOAT_TYPE "flt "
9091

9192
/* List of keys used to read/write fan speeds */
9293
static const char *const fan_speed_fmt[] = {
@@ -96,6 +97,7 @@ static const char *const fan_speed_fmt[] = {
9697
"F%dSf", /* safe speed - not all models */
9798
"F%dTg", /* target speed (manual: rw) */
9899
};
100+
#define FAN_MANUAL_FMT "F%dMd"
99101

100102
#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
101103
#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
@@ -734,6 +736,42 @@ static int applesmc_read_s16(struct applesmc_device *smc,
734736
return 0;
735737
}
736738

739+
/**
740+
* applesmc_float_to_u32 - Retrieve the integral part of a float.
741+
* This is needed because Apple made fans use float values in the T2.
742+
* The fractional point is not significantly useful though, and the integral
743+
* part can be easily extracted.
744+
*/
745+
static inline u32 applesmc_float_to_u32(u32 d)
746+
{
747+
u8 sign = (u8) ((d >> 31) & 1);
748+
s32 exp = (s32) ((d >> 23) & 0xff) - 0x7f;
749+
u32 fr = d & ((1u << 23) - 1);
750+
751+
if (sign || exp < 0)
752+
return 0;
753+
754+
return (u32) ((1u << exp) + (fr >> (23 - exp)));
755+
}
756+
757+
/**
758+
* applesmc_u32_to_float - Convert an u32 into a float.
759+
* See applesmc_float_to_u32 for a rationale.
760+
*/
761+
static inline u32 applesmc_u32_to_float(u32 d)
762+
{
763+
u32 dc = d, bc = 0, exp;
764+
765+
if (!d)
766+
return 0;
767+
768+
while (dc >>= 1)
769+
++bc;
770+
exp = 0x7f + bc;
771+
772+
return (u32) ((exp << 23) |
773+
((d << (23 - (exp - 0x7f))) & ((1u << 23) - 1)));
774+
}
737775
/*
738776
* applesmc_device_init - initialize the accelerometer. Can sleep.
739777
*/
@@ -1241,6 +1279,7 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
12411279
struct device_attribute *attr, char *sysfsbuf)
12421280
{
12431281
struct applesmc_device *smc = dev_get_drvdata(dev);
1282+
const struct applesmc_entry *entry;
12441283
int ret;
12451284
unsigned int speed = 0;
12461285
char newkey[5];
@@ -1249,11 +1288,21 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
12491288
scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
12501289
to_index(attr));
12511290

1252-
ret = applesmc_read_key(smc, newkey, buffer, 2);
1291+
entry = applesmc_get_entry_by_key(smc, newkey);
1292+
if (IS_ERR(entry))
1293+
return PTR_ERR(entry);
1294+
1295+
if (!strcmp(entry->type, FLOAT_TYPE)) {
1296+
ret = applesmc_read_entry(smc, entry, (u8 *) &speed, 4);
1297+
speed = applesmc_float_to_u32(speed);
1298+
} else {
1299+
ret = applesmc_read_entry(smc, entry, buffer, 2);
1300+
speed = ((buffer[0] << 8 | buffer[1]) >> 2);
1301+
}
1302+
12531303
if (ret)
12541304
return ret;
12551305

1256-
speed = ((buffer[0] << 8 | buffer[1]) >> 2);
12571306
return sysfs_emit(sysfsbuf, "%u\n", speed);
12581307
}
12591308

@@ -1262,6 +1311,7 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
12621311
const char *sysfsbuf, size_t count)
12631312
{
12641313
struct applesmc_device *smc = dev_get_drvdata(dev);
1314+
const struct applesmc_entry *entry;
12651315
int ret;
12661316
unsigned long speed;
12671317
char newkey[5];
@@ -1273,9 +1323,18 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
12731323
scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
12741324
to_index(attr));
12751325

1276-
buffer[0] = (speed >> 6) & 0xff;
1277-
buffer[1] = (speed << 2) & 0xff;
1278-
ret = applesmc_write_key(smc, newkey, buffer, 2);
1326+
entry = applesmc_get_entry_by_key(smc, newkey);
1327+
if (IS_ERR(entry))
1328+
return PTR_ERR(entry);
1329+
1330+
if (!strcmp(entry->type, FLOAT_TYPE)) {
1331+
speed = applesmc_u32_to_float(speed);
1332+
ret = applesmc_write_entry(smc, entry, (u8 *) &speed, 4);
1333+
} else {
1334+
buffer[0] = (speed >> 6) & 0xff;
1335+
buffer[1] = (speed << 2) & 0xff;
1336+
ret = applesmc_write_key(smc, newkey, buffer, 2);
1337+
}
12791338

12801339
if (ret)
12811340
return ret;
@@ -1290,12 +1349,26 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
12901349
int ret;
12911350
u16 manual = 0;
12921351
u8 buffer[2];
1352+
char newkey[5];
1353+
bool has_newkey = false;
1354+
1355+
scnprintf(newkey, sizeof(newkey), FAN_MANUAL_FMT, to_index(attr));
1356+
1357+
ret = applesmc_has_key(smc, newkey, &has_newkey);
1358+
if (ret)
1359+
return ret;
1360+
1361+
if (has_newkey) {
1362+
ret = applesmc_read_key(smc, newkey, buffer, 1);
1363+
manual = buffer[0];
1364+
} else {
1365+
ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
1366+
manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
1367+
}
12931368

1294-
ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
12951369
if (ret)
12961370
return ret;
12971371

1298-
manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
12991372
return sysfs_emit(sysfsbuf, "%d\n", manual);
13001373
}
13011374

@@ -1306,27 +1379,39 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
13061379
struct applesmc_device *smc = dev_get_drvdata(dev);
13071380
int ret;
13081381
u8 buffer[2];
1382+
char newkey[5];
1383+
bool has_newkey = false;
13091384
unsigned long input;
13101385
u16 val;
13111386

13121387
if (kstrtoul(sysfsbuf, 10, &input) < 0)
13131388
return -EINVAL;
13141389

1315-
ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
1390+
scnprintf(newkey, sizeof(newkey), FAN_MANUAL_FMT, to_index(attr));
1391+
1392+
ret = applesmc_has_key(smc, newkey, &has_newkey);
13161393
if (ret)
1317-
goto out;
1394+
return ret;
13181395

1319-
val = (buffer[0] << 8 | buffer[1]);
1396+
if (has_newkey) {
1397+
buffer[0] = input & 1;
1398+
ret = applesmc_write_key(smc, newkey, buffer, 1);
1399+
} else {
1400+
ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
1401+
val = (buffer[0] << 8 | buffer[1]);
1402+
if (ret)
1403+
goto out;
13201404

1321-
if (input)
1322-
val = val | (0x01 << to_index(attr));
1323-
else
1324-
val = val & ~(0x01 << to_index(attr));
1405+
if (input)
1406+
val = val | (0x01 << to_index(attr));
1407+
else
1408+
val = val & ~(0x01 << to_index(attr));
13251409

1326-
buffer[0] = (val >> 8) & 0xFF;
1327-
buffer[1] = val & 0xFF;
1410+
buffer[0] = (val >> 8) & 0xFF;
1411+
buffer[1] = val & 0xFF;
13281412

1329-
ret = applesmc_write_key(smc, FANS_MANUAL, buffer, 2);
1413+
ret = applesmc_write_key(smc, FANS_MANUAL, buffer, 2);
1414+
}
13301415

13311416
out:
13321417
if (ret)

0 commit comments

Comments
 (0)