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