| 1 | // SPDX-License-Identifier: GPL-2.0-only OR MIT |
| 2 | /* |
| 3 | * Apple SMC hwmon driver for Apple Silicon platforms |
| 4 | * |
| 5 | * The System Management Controller on Apple Silicon devices is responsible for |
| 6 | * measuring data from sensors across the SoC and machine. These include power, |
| 7 | * temperature, voltage and current sensors. Some "sensors" actually expose |
| 8 | * derived values. An example of this is the key PHPC, which is an estimate |
| 9 | * of the heat energy being dissipated by the SoC. |
| 10 | * |
| 11 | * While each SoC only has one SMC variant, each platform exposes a different |
| 12 | * set of sensors. For example, M1 MacBooks expose battery telemetry sensors |
| 13 | * which are not present on the M1 Mac mini. For this reason, the available |
| 14 | * sensors for a given platform are described in the device tree in a child |
| 15 | * node of the SMC device. We must walk this list of available sensors and |
| 16 | * populate the required hwmon data structures at runtime. |
| 17 | * |
| 18 | * Originally based on a concept by Jean-Francois Bortolotti <jeff@borto.fr> |
| 19 | * |
| 20 | * Copyright The Asahi Linux Contributors |
| 21 | */ |
| 22 | |
| 23 | #include <linux/bitfield.h> |
| 24 | #include <linux/hwmon.h> |
| 25 | #include <linux/mfd/macsmc.h> |
| 26 | #include <linux/module.h> |
| 27 | #include <linux/of.h> |
| 28 | #include <linux/platform_device.h> |
| 29 | |
| 30 | #define MAX_LABEL_LENGTH 32 |
| 31 | |
| 32 | /* Temperature, voltage, current, power, fan(s) */ |
| 33 | #define NUM_SENSOR_TYPES 5 |
| 34 | |
| 35 | #define FLT_EXP_BIAS 127 |
| 36 | #define FLT_EXP_MASK GENMASK(30, 23) |
| 37 | #define FLT_MANT_BIAS 23 |
| 38 | #define FLT_MANT_MASK GENMASK(22, 0) |
| 39 | #define FLT_SIGN_MASK BIT(31) |
| 40 | |
| 41 | static bool fan_control; |
| 42 | module_param_unsafe(fan_control, bool, 0644); |
| 43 | MODULE_PARM_DESC(fan_control, |
| 44 | "Override the SMC to set your own fan speeds on supported machines" ); |
| 45 | |
| 46 | struct macsmc_hwmon_sensor { |
| 47 | struct apple_smc_key_info info; |
| 48 | smc_key macsmc_key; |
| 49 | char label[MAX_LABEL_LENGTH]; |
| 50 | u32 attrs; |
| 51 | }; |
| 52 | |
| 53 | struct macsmc_hwmon_fan { |
| 54 | struct macsmc_hwmon_sensor now; |
| 55 | struct macsmc_hwmon_sensor min; |
| 56 | struct macsmc_hwmon_sensor max; |
| 57 | struct macsmc_hwmon_sensor set; |
| 58 | struct macsmc_hwmon_sensor mode; |
| 59 | char label[MAX_LABEL_LENGTH]; |
| 60 | u32 attrs; |
| 61 | bool manual; |
| 62 | }; |
| 63 | |
| 64 | struct macsmc_hwmon_sensors { |
| 65 | struct hwmon_channel_info channel_info; |
| 66 | struct macsmc_hwmon_sensor *sensors; |
| 67 | u32 count; |
| 68 | }; |
| 69 | |
| 70 | struct macsmc_hwmon_fans { |
| 71 | struct hwmon_channel_info channel_info; |
| 72 | struct macsmc_hwmon_fan *fans; |
| 73 | u32 count; |
| 74 | }; |
| 75 | |
| 76 | struct macsmc_hwmon { |
| 77 | struct device *dev; |
| 78 | struct apple_smc *smc; |
| 79 | struct device *hwmon_dev; |
| 80 | struct hwmon_chip_info chip_info; |
| 81 | /* Chip + sensor types + NULL */ |
| 82 | const struct hwmon_channel_info *channel_infos[1 + NUM_SENSOR_TYPES + 1]; |
| 83 | struct macsmc_hwmon_sensors temp; |
| 84 | struct macsmc_hwmon_sensors volt; |
| 85 | struct macsmc_hwmon_sensors curr; |
| 86 | struct macsmc_hwmon_sensors power; |
| 87 | struct macsmc_hwmon_fans fan; |
| 88 | }; |
| 89 | |
| 90 | static int macsmc_hwmon_read_label(struct device *dev, |
| 91 | enum hwmon_sensor_types type, u32 attr, |
| 92 | int channel, const char **str) |
| 93 | { |
| 94 | struct macsmc_hwmon *hwmon = dev_get_drvdata(dev); |
| 95 | |
| 96 | switch (type) { |
| 97 | case hwmon_temp: |
| 98 | *str = hwmon->temp.sensors[channel].label; |
| 99 | break; |
| 100 | case hwmon_in: |
| 101 | *str = hwmon->volt.sensors[channel].label; |
| 102 | break; |
| 103 | case hwmon_curr: |
| 104 | *str = hwmon->curr.sensors[channel].label; |
| 105 | break; |
| 106 | case hwmon_power: |
| 107 | *str = hwmon->power.sensors[channel].label; |
| 108 | break; |
| 109 | case hwmon_fan: |
| 110 | *str = hwmon->fan.fans[channel].label; |
| 111 | break; |
| 112 | default: |
| 113 | return -EOPNOTSUPP; |
| 114 | } |
| 115 | |
| 116 | return 0; |
| 117 | } |
| 118 | |
| 119 | /* |
| 120 | * A number of sensors report data in a 48.16 fixed-point decimal format that is |
| 121 | * not used by any other function of the SMC. |
| 122 | */ |
| 123 | static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key, |
| 124 | u64 *p, int scale) |
| 125 | { |
| 126 | u64 val; |
| 127 | int ret; |
| 128 | |
| 129 | ret = apple_smc_read_u64(smc, key, p: &val); |
| 130 | if (ret < 0) |
| 131 | return ret; |
| 132 | |
| 133 | *p = mult_frac(val, scale, 65536); |
| 134 | |
| 135 | return 0; |
| 136 | } |
| 137 | |
| 138 | /* |
| 139 | * Many sensors report their data as IEEE-754 floats. No other SMC function uses |
| 140 | * them. |
| 141 | */ |
| 142 | static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key, |
| 143 | int *p, int scale) |
| 144 | { |
| 145 | u32 fval; |
| 146 | u64 val; |
| 147 | int ret, exp; |
| 148 | |
| 149 | ret = apple_smc_read_u32(smc, key, p: &fval); |
| 150 | if (ret < 0) |
| 151 | return ret; |
| 152 | |
| 153 | val = ((u64)((fval & FLT_MANT_MASK) | BIT(23))); |
| 154 | exp = ((fval >> 23) & 0xff) - FLT_EXP_BIAS - FLT_MANT_BIAS; |
| 155 | |
| 156 | /* We never have negatively scaled SMC floats */ |
| 157 | val *= scale; |
| 158 | |
| 159 | if (exp > 63) |
| 160 | val = U64_MAX; |
| 161 | else if (exp < -63) |
| 162 | val = 0; |
| 163 | else if (exp < 0) |
| 164 | val >>= -exp; |
| 165 | else if (exp != 0 && (val & ~((1UL << (64 - exp)) - 1))) /* overflow */ |
| 166 | val = U64_MAX; |
| 167 | else |
| 168 | val <<= exp; |
| 169 | |
| 170 | if (fval & FLT_SIGN_MASK) { |
| 171 | if (val > (-(s64)INT_MIN)) |
| 172 | *p = INT_MIN; |
| 173 | else |
| 174 | *p = -val; |
| 175 | } else { |
| 176 | if (val > INT_MAX) |
| 177 | *p = INT_MAX; |
| 178 | else |
| 179 | *p = val; |
| 180 | } |
| 181 | |
| 182 | return 0; |
| 183 | } |
| 184 | |
| 185 | /* |
| 186 | * The SMC has keys of multiple types, denoted by a FourCC of the same format |
| 187 | * as the key ID. We don't know what data type a key encodes until we poke at it. |
| 188 | */ |
| 189 | static int macsmc_hwmon_read_key(struct apple_smc *smc, |
| 190 | struct macsmc_hwmon_sensor *sensor, int scale, |
| 191 | long *val) |
| 192 | { |
| 193 | int ret; |
| 194 | |
| 195 | switch (sensor->info.type_code) { |
| 196 | /* 32-bit IEEE 754 float */ |
| 197 | case __SMC_KEY('f', 'l', 't', ' '): { |
| 198 | u32 flt_ = 0; |
| 199 | |
| 200 | ret = macsmc_hwmon_read_f32_scaled(smc, key: sensor->macsmc_key, |
| 201 | p: &flt_, scale); |
| 202 | if (ret) |
| 203 | return ret; |
| 204 | |
| 205 | *val = flt_; |
| 206 | break; |
| 207 | } |
| 208 | /* 48.16 fixed point decimal */ |
| 209 | case __SMC_KEY('i', 'o', 'f', 't'): { |
| 210 | u64 ioft = 0; |
| 211 | |
| 212 | ret = macsmc_hwmon_read_ioft_scaled(smc, key: sensor->macsmc_key, |
| 213 | p: &ioft, scale); |
| 214 | if (ret) |
| 215 | return ret; |
| 216 | |
| 217 | *val = (long)ioft; |
| 218 | break; |
| 219 | } |
| 220 | default: |
| 221 | return -EOPNOTSUPP; |
| 222 | } |
| 223 | |
| 224 | return 0; |
| 225 | } |
| 226 | |
| 227 | static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, int value) |
| 228 | { |
| 229 | u64 val; |
| 230 | u32 fval = 0; |
| 231 | int exp = 0, neg; |
| 232 | |
| 233 | val = abs(value); |
| 234 | neg = val != value; |
| 235 | |
| 236 | if (val) { |
| 237 | int msb = __fls(word: val) - exp; |
| 238 | |
| 239 | if (msb > 23) { |
| 240 | val >>= msb - FLT_MANT_BIAS; |
| 241 | exp -= msb - FLT_MANT_BIAS; |
| 242 | } else if (msb < 23) { |
| 243 | val <<= FLT_MANT_BIAS - msb; |
| 244 | exp += msb; |
| 245 | } |
| 246 | |
| 247 | fval = FIELD_PREP(FLT_SIGN_MASK, neg) | |
| 248 | FIELD_PREP(FLT_EXP_MASK, exp + FLT_EXP_BIAS) | |
| 249 | FIELD_PREP(FLT_MANT_MASK, val); |
| 250 | } |
| 251 | |
| 252 | return apple_smc_write_u32(smc, key, p: fval); |
| 253 | } |
| 254 | |
| 255 | static int macsmc_hwmon_write_key(struct apple_smc *smc, |
| 256 | struct macsmc_hwmon_sensor *sensor, long val) |
| 257 | { |
| 258 | switch (sensor->info.type_code) { |
| 259 | /* 32-bit IEEE 754 float */ |
| 260 | case __SMC_KEY('f', 'l', 't', ' '): |
| 261 | return macsmc_hwmon_write_f32(smc, key: sensor->macsmc_key, value: val); |
| 262 | /* unsigned 8-bit integer */ |
| 263 | case __SMC_KEY('u', 'i', '8', ' '): |
| 264 | return apple_smc_write_u8(smc, key: sensor->macsmc_key, p: val); |
| 265 | default: |
| 266 | return -EOPNOTSUPP; |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | static int macsmc_hwmon_read_fan(struct macsmc_hwmon *hwmon, u32 attr, int chan, |
| 271 | long *val) |
| 272 | { |
| 273 | switch (attr) { |
| 274 | case hwmon_fan_input: |
| 275 | return macsmc_hwmon_read_key(smc: hwmon->smc, |
| 276 | sensor: &hwmon->fan.fans[chan].now, scale: 1, val); |
| 277 | case hwmon_fan_min: |
| 278 | return macsmc_hwmon_read_key(smc: hwmon->smc, |
| 279 | sensor: &hwmon->fan.fans[chan].min, scale: 1, val); |
| 280 | case hwmon_fan_max: |
| 281 | return macsmc_hwmon_read_key(smc: hwmon->smc, |
| 282 | sensor: &hwmon->fan.fans[chan].max, scale: 1, val); |
| 283 | case hwmon_fan_target: |
| 284 | return macsmc_hwmon_read_key(smc: hwmon->smc, |
| 285 | sensor: &hwmon->fan.fans[chan].set, scale: 1, val); |
| 286 | default: |
| 287 | return -EOPNOTSUPP; |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | static int macsmc_hwmon_write_fan(struct device *dev, u32 attr, int channel, |
| 292 | long val) |
| 293 | { |
| 294 | struct macsmc_hwmon *hwmon = dev_get_drvdata(dev); |
| 295 | long min, max; |
| 296 | int ret; |
| 297 | |
| 298 | if (!fan_control || hwmon->fan.fans[channel].mode.macsmc_key == 0) |
| 299 | return -EOPNOTSUPP; |
| 300 | |
| 301 | /* |
| 302 | * The SMC does no sanity checks on requested fan speeds, so we need to. |
| 303 | */ |
| 304 | ret = macsmc_hwmon_read_key(smc: hwmon->smc, sensor: &hwmon->fan.fans[channel].min, |
| 305 | scale: 1, val: &min); |
| 306 | if (ret) |
| 307 | return ret; |
| 308 | |
| 309 | ret = macsmc_hwmon_read_key(smc: hwmon->smc, sensor: &hwmon->fan.fans[channel].max, |
| 310 | scale: 1, val: &max); |
| 311 | if (ret) |
| 312 | return ret; |
| 313 | |
| 314 | if (val >= min && val <= max) { |
| 315 | if (!hwmon->fan.fans[channel].manual) { |
| 316 | /* Write 1 to mode key for manual control */ |
| 317 | ret = macsmc_hwmon_write_key(smc: hwmon->smc, |
| 318 | sensor: &hwmon->fan.fans[channel].mode, val: 1); |
| 319 | if (ret < 0) |
| 320 | return ret; |
| 321 | |
| 322 | hwmon->fan.fans[channel].manual = true; |
| 323 | } |
| 324 | return macsmc_hwmon_write_key(smc: hwmon->smc, |
| 325 | sensor: &hwmon->fan.fans[channel].set, val); |
| 326 | } else if (!val) { |
| 327 | if (hwmon->fan.fans[channel].manual) { |
| 328 | ret = macsmc_hwmon_write_key(smc: hwmon->smc, |
| 329 | sensor: &hwmon->fan.fans[channel].mode, val: 0); |
| 330 | if (ret < 0) |
| 331 | return ret; |
| 332 | |
| 333 | hwmon->fan.fans[channel].manual = false; |
| 334 | } |
| 335 | } else { |
| 336 | return -EINVAL; |
| 337 | } |
| 338 | |
| 339 | return 0; |
| 340 | } |
| 341 | |
| 342 | static int macsmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, |
| 343 | u32 attr, int channel, long *val) |
| 344 | { |
| 345 | struct macsmc_hwmon *hwmon = dev_get_drvdata(dev); |
| 346 | int ret = 0; |
| 347 | |
| 348 | switch (type) { |
| 349 | case hwmon_temp: |
| 350 | ret = macsmc_hwmon_read_key(smc: hwmon->smc, |
| 351 | sensor: &hwmon->temp.sensors[channel], scale: 1000, val); |
| 352 | break; |
| 353 | case hwmon_in: |
| 354 | ret = macsmc_hwmon_read_key(smc: hwmon->smc, |
| 355 | sensor: &hwmon->volt.sensors[channel], scale: 1000, val); |
| 356 | break; |
| 357 | case hwmon_curr: |
| 358 | ret = macsmc_hwmon_read_key(smc: hwmon->smc, |
| 359 | sensor: &hwmon->curr.sensors[channel], scale: 1000, val); |
| 360 | break; |
| 361 | case hwmon_power: |
| 362 | /* SMC returns power in Watts with acceptable precision to scale to uW */ |
| 363 | ret = macsmc_hwmon_read_key(smc: hwmon->smc, |
| 364 | sensor: &hwmon->power.sensors[channel], |
| 365 | scale: 1000000, val); |
| 366 | break; |
| 367 | case hwmon_fan: |
| 368 | ret = macsmc_hwmon_read_fan(hwmon, attr, chan: channel, val); |
| 369 | break; |
| 370 | default: |
| 371 | return -EOPNOTSUPP; |
| 372 | } |
| 373 | |
| 374 | return ret; |
| 375 | } |
| 376 | |
| 377 | static int macsmc_hwmon_write(struct device *dev, enum hwmon_sensor_types type, |
| 378 | u32 attr, int channel, long val) |
| 379 | { |
| 380 | switch (type) { |
| 381 | case hwmon_fan: |
| 382 | return macsmc_hwmon_write_fan(dev, attr, channel, val); |
| 383 | default: |
| 384 | return -EOPNOTSUPP; |
| 385 | } |
| 386 | } |
| 387 | |
| 388 | static umode_t macsmc_hwmon_fan_is_visible(const struct macsmc_hwmon_fan *fan, |
| 389 | u32 attr) |
| 390 | { |
| 391 | if (fan->attrs & BIT(attr)) { |
| 392 | if (attr == hwmon_fan_target && fan_control && fan->mode.macsmc_key) |
| 393 | return 0644; |
| 394 | |
| 395 | return 0444; |
| 396 | } |
| 397 | |
| 398 | return 0; |
| 399 | } |
| 400 | |
| 401 | static umode_t macsmc_hwmon_is_visible(const void *data, |
| 402 | enum hwmon_sensor_types type, u32 attr, |
| 403 | int channel) |
| 404 | { |
| 405 | const struct macsmc_hwmon *hwmon = data; |
| 406 | struct macsmc_hwmon_sensor *sensor; |
| 407 | |
| 408 | switch (type) { |
| 409 | case hwmon_in: |
| 410 | sensor = &hwmon->volt.sensors[channel]; |
| 411 | break; |
| 412 | case hwmon_curr: |
| 413 | sensor = &hwmon->curr.sensors[channel]; |
| 414 | break; |
| 415 | case hwmon_power: |
| 416 | sensor = &hwmon->power.sensors[channel]; |
| 417 | break; |
| 418 | case hwmon_temp: |
| 419 | sensor = &hwmon->temp.sensors[channel]; |
| 420 | break; |
| 421 | case hwmon_fan: |
| 422 | return macsmc_hwmon_fan_is_visible(fan: &hwmon->fan.fans[channel], attr); |
| 423 | default: |
| 424 | return 0; |
| 425 | } |
| 426 | |
| 427 | /* Sensors only register ro attributes */ |
| 428 | if (sensor->attrs & BIT(attr)) |
| 429 | return 0444; |
| 430 | |
| 431 | return 0; |
| 432 | } |
| 433 | |
| 434 | static const struct hwmon_ops macsmc_hwmon_ops = { |
| 435 | .is_visible = macsmc_hwmon_is_visible, |
| 436 | .read = macsmc_hwmon_read, |
| 437 | .read_string = macsmc_hwmon_read_label, |
| 438 | .write = macsmc_hwmon_write, |
| 439 | }; |
| 440 | |
| 441 | /* |
| 442 | * Get the key metadata, including key data type, from the SMC. |
| 443 | */ |
| 444 | static int macsmc_hwmon_parse_key(struct device *dev, struct apple_smc *smc, |
| 445 | struct macsmc_hwmon_sensor *sensor, |
| 446 | const char *key) |
| 447 | { |
| 448 | int ret; |
| 449 | |
| 450 | ret = apple_smc_get_key_info(smc, _SMC_KEY(key), info: &sensor->info); |
| 451 | if (ret) { |
| 452 | dev_dbg(dev, "Failed to retrieve key info for %s\n" , key); |
| 453 | return ret; |
| 454 | } |
| 455 | |
| 456 | sensor->macsmc_key = _SMC_KEY(key); |
| 457 | |
| 458 | return 0; |
| 459 | } |
| 460 | |
| 461 | /* |
| 462 | * A sensor is a single key-value pair as made available by the SMC. |
| 463 | * The devicetree gives us the SMC key ID and a friendly name where the |
| 464 | * purpose of the sensor is known. |
| 465 | */ |
| 466 | static int macsmc_hwmon_create_sensor(struct device *dev, struct apple_smc *smc, |
| 467 | struct device_node *sensor_node, |
| 468 | struct macsmc_hwmon_sensor *sensor) |
| 469 | { |
| 470 | const char *key, *label; |
| 471 | int ret; |
| 472 | |
| 473 | ret = of_property_read_string(np: sensor_node, propname: "apple,key-id" , out_string: &key); |
| 474 | if (ret) { |
| 475 | dev_dbg(dev, "Could not find apple,key-id in sensor node\n" ); |
| 476 | return ret; |
| 477 | } |
| 478 | |
| 479 | ret = macsmc_hwmon_parse_key(dev, smc, sensor, key); |
| 480 | if (ret) |
| 481 | return ret; |
| 482 | |
| 483 | ret = of_property_read_string(np: sensor_node, propname: "label" , out_string: &label); |
| 484 | if (ret) |
| 485 | dev_dbg(dev, "No label found for sensor %s\n" , key); |
| 486 | else |
| 487 | strscpy_pad(sensor->label, label, sizeof(sensor->label)); |
| 488 | |
| 489 | return 0; |
| 490 | } |
| 491 | |
| 492 | /* |
| 493 | * Fan data is exposed by the SMC as multiple sensors. |
| 494 | * |
| 495 | * The devicetree schema reuses apple,key-id for the actual fan speed sensor. |
| 496 | * Min, max and target keys do not need labels, so we can reuse label |
| 497 | * for naming the entire fan. |
| 498 | */ |
| 499 | static int macsmc_hwmon_create_fan(struct device *dev, struct apple_smc *smc, |
| 500 | struct device_node *fan_node, |
| 501 | struct macsmc_hwmon_fan *fan) |
| 502 | { |
| 503 | const char *label, *now, *min, *max, *set, *mode; |
| 504 | int ret; |
| 505 | |
| 506 | ret = of_property_read_string(np: fan_node, propname: "apple,key-id" , out_string: &now); |
| 507 | if (ret) { |
| 508 | dev_err(dev, "apple,key-id not found in fan node!\n" ); |
| 509 | return ret; |
| 510 | } |
| 511 | |
| 512 | ret = macsmc_hwmon_parse_key(dev, smc, sensor: &fan->now, key: now); |
| 513 | if (ret) |
| 514 | return ret; |
| 515 | |
| 516 | fan->attrs = HWMON_F_INPUT; |
| 517 | |
| 518 | ret = of_property_read_string(np: fan_node, propname: "label" , out_string: &label); |
| 519 | if (ret) { |
| 520 | dev_dbg(dev, "No label found for fan %s\n" , now); |
| 521 | } else { |
| 522 | strscpy_pad(fan->label, label, sizeof(fan->label)); |
| 523 | fan->attrs |= HWMON_F_LABEL; |
| 524 | } |
| 525 | |
| 526 | /* The following keys are not required to simply monitor fan speed */ |
| 527 | if (!of_property_read_string(np: fan_node, propname: "apple,fan-minimum" , out_string: &min)) { |
| 528 | ret = macsmc_hwmon_parse_key(dev, smc, sensor: &fan->min, key: min); |
| 529 | if (ret) |
| 530 | return ret; |
| 531 | |
| 532 | fan->attrs |= HWMON_F_MIN; |
| 533 | } |
| 534 | |
| 535 | if (!of_property_read_string(np: fan_node, propname: "apple,fan-maximum" , out_string: &max)) { |
| 536 | ret = macsmc_hwmon_parse_key(dev, smc, sensor: &fan->max, key: max); |
| 537 | if (ret) |
| 538 | return ret; |
| 539 | |
| 540 | fan->attrs |= HWMON_F_MAX; |
| 541 | } |
| 542 | |
| 543 | if (!of_property_read_string(np: fan_node, propname: "apple,fan-target" , out_string: &set)) { |
| 544 | ret = macsmc_hwmon_parse_key(dev, smc, sensor: &fan->set, key: set); |
| 545 | if (ret) |
| 546 | return ret; |
| 547 | |
| 548 | fan->attrs |= HWMON_F_TARGET; |
| 549 | } |
| 550 | |
| 551 | if (!of_property_read_string(np: fan_node, propname: "apple,fan-mode" , out_string: &mode)) { |
| 552 | ret = macsmc_hwmon_parse_key(dev, smc, sensor: &fan->mode, key: mode); |
| 553 | if (ret) |
| 554 | return ret; |
| 555 | } |
| 556 | |
| 557 | /* Initialise fan control mode to automatic */ |
| 558 | fan->manual = false; |
| 559 | |
| 560 | return 0; |
| 561 | } |
| 562 | |
| 563 | static int macsmc_hwmon_populate_sensors(struct macsmc_hwmon *hwmon, |
| 564 | struct device_node *hwmon_node) |
| 565 | { |
| 566 | struct device_node *key_node __maybe_unused; |
| 567 | struct macsmc_hwmon_sensor *sensor; |
| 568 | u32 n_current = 0, n_fan = 0, n_power = 0, n_temperature = 0, n_voltage = 0; |
| 569 | |
| 570 | for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-" ) { |
| 571 | n_current++; |
| 572 | } |
| 573 | |
| 574 | if (n_current) { |
| 575 | hwmon->curr.sensors = devm_kcalloc(dev: hwmon->dev, n: n_current, |
| 576 | size: sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL); |
| 577 | if (!hwmon->curr.sensors) |
| 578 | return -ENOMEM; |
| 579 | |
| 580 | for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-" ) { |
| 581 | sensor = &hwmon->curr.sensors[hwmon->curr.count]; |
| 582 | if (!macsmc_hwmon_create_sensor(dev: hwmon->dev, smc: hwmon->smc, sensor_node: key_node, sensor)) { |
| 583 | sensor->attrs = HWMON_C_INPUT; |
| 584 | |
| 585 | if (*sensor->label) |
| 586 | sensor->attrs |= HWMON_C_LABEL; |
| 587 | |
| 588 | hwmon->curr.count++; |
| 589 | } |
| 590 | } |
| 591 | } |
| 592 | |
| 593 | for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-" ) { |
| 594 | n_fan++; |
| 595 | } |
| 596 | |
| 597 | if (n_fan) { |
| 598 | hwmon->fan.fans = devm_kcalloc(dev: hwmon->dev, n: n_fan, |
| 599 | size: sizeof(struct macsmc_hwmon_fan), GFP_KERNEL); |
| 600 | if (!hwmon->fan.fans) |
| 601 | return -ENOMEM; |
| 602 | |
| 603 | for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-" ) { |
| 604 | if (!macsmc_hwmon_create_fan(dev: hwmon->dev, smc: hwmon->smc, fan_node: key_node, |
| 605 | fan: &hwmon->fan.fans[hwmon->fan.count])) |
| 606 | hwmon->fan.count++; |
| 607 | } |
| 608 | } |
| 609 | |
| 610 | for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-" ) { |
| 611 | n_power++; |
| 612 | } |
| 613 | |
| 614 | if (n_power) { |
| 615 | hwmon->power.sensors = devm_kcalloc(dev: hwmon->dev, n: n_power, |
| 616 | size: sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL); |
| 617 | if (!hwmon->power.sensors) |
| 618 | return -ENOMEM; |
| 619 | |
| 620 | for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-" ) { |
| 621 | sensor = &hwmon->power.sensors[hwmon->power.count]; |
| 622 | if (!macsmc_hwmon_create_sensor(dev: hwmon->dev, smc: hwmon->smc, sensor_node: key_node, sensor)) { |
| 623 | sensor->attrs = HWMON_P_INPUT; |
| 624 | |
| 625 | if (*sensor->label) |
| 626 | sensor->attrs |= HWMON_P_LABEL; |
| 627 | |
| 628 | hwmon->power.count++; |
| 629 | } |
| 630 | } |
| 631 | } |
| 632 | |
| 633 | for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-" ) { |
| 634 | n_temperature++; |
| 635 | } |
| 636 | |
| 637 | if (n_temperature) { |
| 638 | hwmon->temp.sensors = devm_kcalloc(dev: hwmon->dev, n: n_temperature, |
| 639 | size: sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL); |
| 640 | if (!hwmon->temp.sensors) |
| 641 | return -ENOMEM; |
| 642 | |
| 643 | for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-" ) { |
| 644 | sensor = &hwmon->temp.sensors[hwmon->temp.count]; |
| 645 | if (!macsmc_hwmon_create_sensor(dev: hwmon->dev, smc: hwmon->smc, sensor_node: key_node, sensor)) { |
| 646 | sensor->attrs = HWMON_T_INPUT; |
| 647 | |
| 648 | if (*sensor->label) |
| 649 | sensor->attrs |= HWMON_T_LABEL; |
| 650 | |
| 651 | hwmon->temp.count++; |
| 652 | } |
| 653 | } |
| 654 | } |
| 655 | |
| 656 | for_each_child_of_node_with_prefix(hwmon_node, key_node, "voltage-" ) { |
| 657 | n_voltage++; |
| 658 | } |
| 659 | |
| 660 | if (n_voltage) { |
| 661 | hwmon->volt.sensors = devm_kcalloc(dev: hwmon->dev, n: n_voltage, |
| 662 | size: sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL); |
| 663 | if (!hwmon->volt.sensors) |
| 664 | return -ENOMEM; |
| 665 | |
| 666 | for_each_child_of_node_with_prefix(hwmon_node, key_node, "volt-" ) { |
| 667 | sensor = &hwmon->temp.sensors[hwmon->temp.count]; |
| 668 | if (!macsmc_hwmon_create_sensor(dev: hwmon->dev, smc: hwmon->smc, sensor_node: key_node, sensor)) { |
| 669 | sensor->attrs = HWMON_I_INPUT; |
| 670 | |
| 671 | if (*sensor->label) |
| 672 | sensor->attrs |= HWMON_I_LABEL; |
| 673 | |
| 674 | hwmon->volt.count++; |
| 675 | } |
| 676 | } |
| 677 | } |
| 678 | |
| 679 | return 0; |
| 680 | } |
| 681 | |
| 682 | /* Create NULL-terminated config arrays */ |
| 683 | static void macsmc_hwmon_populate_configs(u32 *configs, const struct macsmc_hwmon_sensors *sensors) |
| 684 | { |
| 685 | int idx; |
| 686 | |
| 687 | for (idx = 0; idx < sensors->count; idx++) |
| 688 | configs[idx] = sensors->sensors[idx].attrs; |
| 689 | } |
| 690 | |
| 691 | static void macsmc_hwmon_populate_fan_configs(u32 *configs, const struct macsmc_hwmon_fans *fans) |
| 692 | { |
| 693 | int idx; |
| 694 | |
| 695 | for (idx = 0; idx < fans->count; idx++) |
| 696 | configs[idx] = fans->fans[idx].attrs; |
| 697 | } |
| 698 | |
| 699 | static const struct hwmon_channel_info *const macsmc_chip_channel_info = |
| 700 | HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ); |
| 701 | |
| 702 | static int macsmc_hwmon_create_infos(struct macsmc_hwmon *hwmon) |
| 703 | { |
| 704 | struct hwmon_channel_info *channel_info; |
| 705 | int i = 0; |
| 706 | |
| 707 | /* chip */ |
| 708 | hwmon->channel_infos[i++] = macsmc_chip_channel_info; |
| 709 | |
| 710 | if (hwmon->curr.count) { |
| 711 | channel_info = &hwmon->curr.channel_info; |
| 712 | channel_info->type = hwmon_curr; |
| 713 | channel_info->config = devm_kcalloc(dev: hwmon->dev, n: hwmon->curr.count + 1, |
| 714 | size: sizeof(u32), GFP_KERNEL); |
| 715 | if (!channel_info->config) |
| 716 | return -ENOMEM; |
| 717 | |
| 718 | macsmc_hwmon_populate_configs(configs: (u32 *)channel_info->config, sensors: &hwmon->curr); |
| 719 | hwmon->channel_infos[i++] = channel_info; |
| 720 | } |
| 721 | |
| 722 | if (hwmon->fan.count) { |
| 723 | channel_info = &hwmon->fan.channel_info; |
| 724 | channel_info->type = hwmon_fan; |
| 725 | channel_info->config = devm_kcalloc(dev: hwmon->dev, n: hwmon->fan.count + 1, |
| 726 | size: sizeof(u32), GFP_KERNEL); |
| 727 | if (!channel_info->config) |
| 728 | return -ENOMEM; |
| 729 | |
| 730 | macsmc_hwmon_populate_fan_configs(configs: (u32 *)channel_info->config, fans: &hwmon->fan); |
| 731 | hwmon->channel_infos[i++] = channel_info; |
| 732 | } |
| 733 | |
| 734 | if (hwmon->power.count) { |
| 735 | channel_info = &hwmon->power.channel_info; |
| 736 | channel_info->type = hwmon_power; |
| 737 | channel_info->config = devm_kcalloc(dev: hwmon->dev, n: hwmon->power.count + 1, |
| 738 | size: sizeof(u32), GFP_KERNEL); |
| 739 | if (!channel_info->config) |
| 740 | return -ENOMEM; |
| 741 | |
| 742 | macsmc_hwmon_populate_configs(configs: (u32 *)channel_info->config, sensors: &hwmon->power); |
| 743 | hwmon->channel_infos[i++] = channel_info; |
| 744 | } |
| 745 | |
| 746 | if (hwmon->temp.count) { |
| 747 | channel_info = &hwmon->temp.channel_info; |
| 748 | channel_info->type = hwmon_temp; |
| 749 | channel_info->config = devm_kcalloc(dev: hwmon->dev, n: hwmon->temp.count + 1, |
| 750 | size: sizeof(u32), GFP_KERNEL); |
| 751 | if (!channel_info->config) |
| 752 | return -ENOMEM; |
| 753 | |
| 754 | macsmc_hwmon_populate_configs(configs: (u32 *)channel_info->config, sensors: &hwmon->temp); |
| 755 | hwmon->channel_infos[i++] = channel_info; |
| 756 | } |
| 757 | |
| 758 | if (hwmon->volt.count) { |
| 759 | channel_info = &hwmon->volt.channel_info; |
| 760 | channel_info->type = hwmon_in; |
| 761 | channel_info->config = devm_kcalloc(dev: hwmon->dev, n: hwmon->volt.count + 1, |
| 762 | size: sizeof(u32), GFP_KERNEL); |
| 763 | if (!channel_info->config) |
| 764 | return -ENOMEM; |
| 765 | |
| 766 | macsmc_hwmon_populate_configs(configs: (u32 *)channel_info->config, sensors: &hwmon->volt); |
| 767 | hwmon->channel_infos[i++] = channel_info; |
| 768 | } |
| 769 | |
| 770 | return 0; |
| 771 | } |
| 772 | |
| 773 | static int macsmc_hwmon_probe(struct platform_device *pdev) |
| 774 | { |
| 775 | struct apple_smc *smc = dev_get_drvdata(dev: pdev->dev.parent); |
| 776 | struct macsmc_hwmon *hwmon; |
| 777 | int ret; |
| 778 | |
| 779 | /* |
| 780 | * The MFD driver will try to probe us unconditionally. Some devices |
| 781 | * with the SMC do not have hwmon capabilities. Only probe if we have |
| 782 | * a hwmon node. |
| 783 | */ |
| 784 | if (!pdev->dev.of_node) |
| 785 | return -ENODEV; |
| 786 | |
| 787 | hwmon = devm_kzalloc(dev: &pdev->dev, size: sizeof(*hwmon), |
| 788 | GFP_KERNEL); |
| 789 | if (!hwmon) |
| 790 | return -ENOMEM; |
| 791 | |
| 792 | hwmon->dev = &pdev->dev; |
| 793 | hwmon->smc = smc; |
| 794 | |
| 795 | ret = macsmc_hwmon_populate_sensors(hwmon, hwmon_node: hwmon->dev->of_node); |
| 796 | if (ret) { |
| 797 | dev_err(hwmon->dev, "Could not parse sensors\n" ); |
| 798 | return ret; |
| 799 | } |
| 800 | |
| 801 | if (!hwmon->curr.count && !hwmon->fan.count && |
| 802 | !hwmon->power.count && !hwmon->temp.count && |
| 803 | !hwmon->volt.count) { |
| 804 | dev_err(hwmon->dev, |
| 805 | "No valid sensors found of any supported type\n" ); |
| 806 | return -ENODEV; |
| 807 | } |
| 808 | |
| 809 | ret = macsmc_hwmon_create_infos(hwmon); |
| 810 | if (ret) |
| 811 | return ret; |
| 812 | |
| 813 | hwmon->chip_info.ops = &macsmc_hwmon_ops; |
| 814 | hwmon->chip_info.info = |
| 815 | (const struct hwmon_channel_info *const *)&hwmon->channel_infos; |
| 816 | |
| 817 | hwmon->hwmon_dev = devm_hwmon_device_register_with_info(dev: &pdev->dev, |
| 818 | name: "macsmc_hwmon" , drvdata: hwmon, |
| 819 | info: &hwmon->chip_info, NULL); |
| 820 | if (IS_ERR(ptr: hwmon->hwmon_dev)) |
| 821 | return dev_err_probe(dev: hwmon->dev, err: PTR_ERR(ptr: hwmon->hwmon_dev), |
| 822 | fmt: "Probing SMC hwmon device failed\n" ); |
| 823 | |
| 824 | dev_dbg(hwmon->dev, "Registered SMC hwmon device. Sensors:\n" ); |
| 825 | dev_dbg(hwmon->dev, |
| 826 | "Current: %d, Fans: %d, Power: %d, Temperature: %d, Voltage: %d" , |
| 827 | hwmon->curr.count, hwmon->fan.count, |
| 828 | hwmon->power.count, hwmon->temp.count, |
| 829 | hwmon->volt.count); |
| 830 | |
| 831 | return 0; |
| 832 | } |
| 833 | |
| 834 | static const struct of_device_id macsmc_hwmon_of_table[] = { |
| 835 | { .compatible = "apple,smc-hwmon" }, |
| 836 | {} |
| 837 | }; |
| 838 | MODULE_DEVICE_TABLE(of, macsmc_hwmon_of_table); |
| 839 | |
| 840 | static struct platform_driver macsmc_hwmon_driver = { |
| 841 | .probe = macsmc_hwmon_probe, |
| 842 | .driver = { |
| 843 | .name = "macsmc-hwmon" , |
| 844 | .of_match_table = macsmc_hwmon_of_table, |
| 845 | }, |
| 846 | }; |
| 847 | module_platform_driver(macsmc_hwmon_driver); |
| 848 | |
| 849 | MODULE_DESCRIPTION("Apple Silicon SMC hwmon driver" ); |
| 850 | MODULE_AUTHOR("James Calligeros <jcalligeros99@gmail.com>" ); |
| 851 | MODULE_LICENSE("Dual MIT/GPL" ); |
| 852 | |