-
Notifications
You must be signed in to change notification settings - Fork 31
/
3006-applesmc-fan-support-on-T2-Macs.patch
227 lines (203 loc) · 6.33 KB
/
3006-applesmc-fan-support-on-T2-Macs.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
From 4b80a87b8273833a093cdac96dabdb865e0d6e86 Mon Sep 17 00:00:00 2001
From: Paul Pawlowski <[email protected]>
Date: Sun, 17 Nov 2019 23:12:18 +0100
Subject: [PATCH 6/6] applesmc: 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 <[email protected]>
---
drivers/hwmon/applesmc.c | 119 +++++++++++++++++++++++++++++++++------
1 file changed, 102 insertions(+), 17 deletions(-)
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index ae0aa5dbc842..867cf857448c 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -87,6 +87,7 @@
#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[] = {
@@ -96,6 +97,7 @@ static const char *const fan_speed_fmt[] = {
"F%dSf", /* safe speed - not all models */
"F%dTg", /* target speed (manual: rw) */
};
+#define FAN_MANUAL_FMT "F%dMd"
#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
@@ -734,6 +736,42 @@ static int applesmc_read_s16(struct applesmc_device *smc,
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
+ * part can be easily extracted.
+ */
+static inline u32 applesmc_float_to_u32(u32 d)
+{
+ u8 sign = (u8) ((d >> 31) & 1);
+ s32 exp = (s32) ((d >> 23) & 0xff) - 0x7f;
+ u32 fr = d & ((1u << 23) - 1);
+
+ if (sign || exp < 0)
+ return 0;
+
+ return (u32) ((1u << exp) + (fr >> (23 - exp)));
+}
+
+/**
+ * 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 d)
+{
+ u32 dc = d, bc = 0, exp;
+
+ if (!d)
+ return 0;
+
+ while (dc >>= 1)
+ ++bc;
+ exp = 0x7f + bc;
+
+ return (u32) ((exp << 23) |
+ ((d << (23 - (exp - 0x7f))) & ((1u << 23) - 1)));
+}
/*
* applesmc_device_init - initialize the accelerometer. Can sleep.
*/
@@ -1242,6 +1280,7 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
struct applesmc_device *smc = dev_get_drvdata(dev);
+ const struct applesmc_entry *entry;
int ret;
unsigned int speed = 0;
char newkey[5];
@@ -1250,11 +1289,21 @@ 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(smc, newkey, buffer, 2);
+ entry = applesmc_get_entry_by_key(smc, newkey);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+ if (!strcmp(entry->type, FLOAT_TYPE)) {
+ ret = applesmc_read_entry(smc, entry, (u8 *) &speed, 4);
+ speed = applesmc_float_to_u32(speed);
+ } else {
+ ret = applesmc_read_entry(smc, entry, buffer, 2);
+ speed = ((buffer[0] << 8 | buffer[1]) >> 2);
+ }
+
if (ret)
return ret;
- speed = ((buffer[0] << 8 | buffer[1]) >> 2);
return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
}
@@ -1263,6 +1312,7 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
const char *sysfsbuf, size_t count)
{
struct applesmc_device *smc = dev_get_drvdata(dev);
+ const struct applesmc_entry *entry;
int ret;
unsigned long speed;
char newkey[5];
@@ -1274,9 +1324,18 @@ 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(smc, newkey, buffer, 2);
+ entry = applesmc_get_entry_by_key(smc, newkey);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+ if (!strcmp(entry->type, FLOAT_TYPE)) {
+ speed = applesmc_u32_to_float(speed);
+ ret = applesmc_write_entry(smc, entry, (u8 *) &speed, 4);
+ } else {
+ buffer[0] = (speed >> 6) & 0xff;
+ buffer[1] = (speed << 2) & 0xff;
+ ret = applesmc_write_key(smc, newkey, buffer, 2);
+ }
if (ret)
return ret;
@@ -1291,12 +1350,26 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
int ret;
u16 manual = 0;
u8 buffer[2];
+ char newkey[5];
+ bool has_newkey = false;
+
+ scnprintf(newkey, sizeof(newkey), FAN_MANUAL_FMT, to_index(attr));
+
+ ret = applesmc_has_key(smc, newkey, &has_newkey);
+ if (ret)
+ return ret;
+
+ if (has_newkey) {
+ ret = applesmc_read_key(smc, newkey, buffer, 1);
+ manual = buffer[0];
+ } else {
+ ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
+ manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
+ }
- ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
if (ret)
return ret;
- manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
}
@@ -1307,27 +1380,39 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
struct applesmc_device *smc = dev_get_drvdata(dev);
int ret;
u8 buffer[2];
+ char newkey[5];
+ bool has_newkey = false;
unsigned long input;
u16 val;
if (kstrtoul(sysfsbuf, 10, &input) < 0)
return -EINVAL;
- ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
+ scnprintf(newkey, sizeof(newkey), FAN_MANUAL_FMT, to_index(attr));
+
+ ret = applesmc_has_key(smc, newkey, &has_newkey);
if (ret)
- goto out;
+ return ret;
- val = (buffer[0] << 8 | buffer[1]);
+ if (has_newkey) {
+ buffer[0] = input & 1;
+ ret = applesmc_write_key(smc, newkey, buffer, 1);
+ } else {
+ ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
+ val = (buffer[0] << 8 | buffer[1]);
+ if (ret)
+ goto out;
- if (input)
- val = val | (0x01 << to_index(attr));
- else
- val = val & ~(0x01 << to_index(attr));
+ if (input)
+ val = val | (0x01 << to_index(attr));
+ else
+ val = val & ~(0x01 << to_index(attr));
- buffer[0] = (val >> 8) & 0xFF;
- buffer[1] = val & 0xFF;
+ buffer[0] = (val >> 8) & 0xFF;
+ buffer[1] = val & 0xFF;
- ret = applesmc_write_key(smc, FANS_MANUAL, buffer, 2);
+ ret = applesmc_write_key(smc, FANS_MANUAL, buffer, 2);
+ }
out:
if (ret)
--
2.31.1