| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852 |
- // SPDX-License-Identifier: GPL-2.0-only OR MIT
- /*
- * Apple SMC hwmon driver for Apple Silicon platforms
- *
- * The System Management Controller on Apple Silicon devices is responsible for
- * measuring data from sensors across the SoC and machine. These include power,
- * temperature, voltage and current sensors. Some "sensors" actually expose
- * derived values. An example of this is the key PHPC, which is an estimate
- * of the heat energy being dissipated by the SoC.
- *
- * While each SoC only has one SMC variant, each platform exposes a different
- * set of sensors. For example, M1 MacBooks expose battery telemetry sensors
- * which are not present on the M1 Mac mini. For this reason, the available
- * sensors for a given platform are described in the device tree in a child
- * node of the SMC device. We must walk this list of available sensors and
- * populate the required hwmon data structures at runtime.
- *
- * Originally based on a concept by Jean-Francois Bortolotti <jeff@borto.fr>
- *
- * Copyright The Asahi Linux Contributors
- */
- #include <linux/bitfield.h>
- #include <linux/hwmon.h>
- #include <linux/math64.h>
- #include <linux/mfd/macsmc.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/platform_device.h>
- #define MAX_LABEL_LENGTH 32
- /* Temperature, voltage, current, power, fan(s) */
- #define NUM_SENSOR_TYPES 5
- #define FLT_EXP_BIAS 127
- #define FLT_EXP_MASK GENMASK(30, 23)
- #define FLT_MANT_BIAS 23
- #define FLT_MANT_MASK GENMASK(22, 0)
- #define FLT_SIGN_MASK BIT(31)
- static bool fan_control;
- module_param_unsafe(fan_control, bool, 0644);
- MODULE_PARM_DESC(fan_control,
- "Override the SMC to set your own fan speeds on supported machines");
- struct macsmc_hwmon_sensor {
- struct apple_smc_key_info info;
- smc_key macsmc_key;
- char label[MAX_LABEL_LENGTH];
- u32 attrs;
- };
- struct macsmc_hwmon_fan {
- struct macsmc_hwmon_sensor now;
- struct macsmc_hwmon_sensor min;
- struct macsmc_hwmon_sensor max;
- struct macsmc_hwmon_sensor set;
- struct macsmc_hwmon_sensor mode;
- char label[MAX_LABEL_LENGTH];
- u32 attrs;
- bool manual;
- };
- struct macsmc_hwmon_sensors {
- struct hwmon_channel_info channel_info;
- struct macsmc_hwmon_sensor *sensors;
- u32 count;
- };
- struct macsmc_hwmon_fans {
- struct hwmon_channel_info channel_info;
- struct macsmc_hwmon_fan *fans;
- u32 count;
- };
- struct macsmc_hwmon {
- struct device *dev;
- struct apple_smc *smc;
- struct device *hwmon_dev;
- struct hwmon_chip_info chip_info;
- /* Chip + sensor types + NULL */
- const struct hwmon_channel_info *channel_infos[1 + NUM_SENSOR_TYPES + 1];
- struct macsmc_hwmon_sensors temp;
- struct macsmc_hwmon_sensors volt;
- struct macsmc_hwmon_sensors curr;
- struct macsmc_hwmon_sensors power;
- struct macsmc_hwmon_fans fan;
- };
- static int macsmc_hwmon_read_label(struct device *dev,
- enum hwmon_sensor_types type, u32 attr,
- int channel, const char **str)
- {
- struct macsmc_hwmon *hwmon = dev_get_drvdata(dev);
- switch (type) {
- case hwmon_temp:
- *str = hwmon->temp.sensors[channel].label;
- break;
- case hwmon_in:
- *str = hwmon->volt.sensors[channel].label;
- break;
- case hwmon_curr:
- *str = hwmon->curr.sensors[channel].label;
- break;
- case hwmon_power:
- *str = hwmon->power.sensors[channel].label;
- break;
- case hwmon_fan:
- *str = hwmon->fan.fans[channel].label;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
- }
- /*
- * A number of sensors report data in a 48.16 fixed-point decimal format that is
- * not used by any other function of the SMC.
- */
- static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
- u64 *p, int scale)
- {
- u64 val;
- int ret;
- ret = apple_smc_read_u64(smc, key, &val);
- if (ret < 0)
- return ret;
- *p = mul_u64_u32_div(val, scale, 65536);
- return 0;
- }
- /*
- * Many sensors report their data as IEEE-754 floats. No other SMC function uses
- * them.
- */
- static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
- long *p, int scale)
- {
- u32 fval;
- u64 val;
- int ret, exp;
- ret = apple_smc_read_u32(smc, key, &fval);
- if (ret < 0)
- return ret;
- val = ((u64)((fval & FLT_MANT_MASK) | BIT(23)));
- exp = ((fval >> 23) & 0xff) - FLT_EXP_BIAS - FLT_MANT_BIAS;
- /* We never have negatively scaled SMC floats */
- val *= scale;
- if (exp > 63)
- val = U64_MAX;
- else if (exp < -63)
- val = 0;
- else if (exp < 0)
- val >>= -exp;
- else if (exp != 0 && (val & ~((1ULL << (64 - exp)) - 1))) /* overflow */
- val = U64_MAX;
- else
- val <<= exp;
- if (fval & FLT_SIGN_MASK) {
- if (val > (u64)LONG_MAX + 1)
- *p = LONG_MIN;
- else
- *p = -(long)val;
- } else {
- if (val > (u64)LONG_MAX)
- *p = LONG_MAX;
- else
- *p = (long)val;
- }
- return 0;
- }
- /*
- * The SMC has keys of multiple types, denoted by a FourCC of the same format
- * as the key ID. We don't know what data type a key encodes until we poke at it.
- */
- static int macsmc_hwmon_read_key(struct apple_smc *smc,
- struct macsmc_hwmon_sensor *sensor, int scale,
- long *val)
- {
- int ret;
- switch (sensor->info.type_code) {
- /* 32-bit IEEE 754 float */
- case __SMC_KEY('f', 'l', 't', ' '): {
- long flt_ = 0;
- ret = macsmc_hwmon_read_f32_scaled(smc, sensor->macsmc_key,
- &flt_, scale);
- if (ret)
- return ret;
- *val = flt_;
- break;
- }
- /* 48.16 fixed point decimal */
- case __SMC_KEY('i', 'o', 'f', 't'): {
- u64 ioft = 0;
- ret = macsmc_hwmon_read_ioft_scaled(smc, sensor->macsmc_key,
- &ioft, scale);
- if (ret)
- return ret;
- if (ioft > LONG_MAX)
- *val = LONG_MAX;
- else
- *val = (long)ioft;
- break;
- }
- default:
- return -EOPNOTSUPP;
- }
- return 0;
- }
- static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, long value)
- {
- u64 val;
- u32 fval = 0;
- int exp, neg;
- neg = value < 0;
- val = abs(value);
- if (val) {
- exp = __fls(val);
- if (exp > 23)
- val >>= exp - 23;
- else
- val <<= 23 - exp;
- fval = FIELD_PREP(FLT_SIGN_MASK, neg) |
- FIELD_PREP(FLT_EXP_MASK, exp + FLT_EXP_BIAS) |
- FIELD_PREP(FLT_MANT_MASK, val & FLT_MANT_MASK);
- }
- return apple_smc_write_u32(smc, key, fval);
- }
- static int macsmc_hwmon_write_key(struct apple_smc *smc,
- struct macsmc_hwmon_sensor *sensor, long val)
- {
- switch (sensor->info.type_code) {
- /* 32-bit IEEE 754 float */
- case __SMC_KEY('f', 'l', 't', ' '):
- return macsmc_hwmon_write_f32(smc, sensor->macsmc_key, val);
- /* unsigned 8-bit integer */
- case __SMC_KEY('u', 'i', '8', ' '):
- return apple_smc_write_u8(smc, sensor->macsmc_key, val);
- default:
- return -EOPNOTSUPP;
- }
- }
- static int macsmc_hwmon_read_fan(struct macsmc_hwmon *hwmon, u32 attr, int chan,
- long *val)
- {
- switch (attr) {
- case hwmon_fan_input:
- return macsmc_hwmon_read_key(hwmon->smc,
- &hwmon->fan.fans[chan].now, 1, val);
- case hwmon_fan_min:
- return macsmc_hwmon_read_key(hwmon->smc,
- &hwmon->fan.fans[chan].min, 1, val);
- case hwmon_fan_max:
- return macsmc_hwmon_read_key(hwmon->smc,
- &hwmon->fan.fans[chan].max, 1, val);
- case hwmon_fan_target:
- return macsmc_hwmon_read_key(hwmon->smc,
- &hwmon->fan.fans[chan].set, 1, val);
- default:
- return -EOPNOTSUPP;
- }
- }
- static int macsmc_hwmon_write_fan(struct device *dev, u32 attr, int channel,
- long val)
- {
- struct macsmc_hwmon *hwmon = dev_get_drvdata(dev);
- long min, max;
- int ret;
- if (!fan_control || hwmon->fan.fans[channel].mode.macsmc_key == 0)
- return -EOPNOTSUPP;
- /*
- * The SMC does no sanity checks on requested fan speeds, so we need to.
- */
- ret = macsmc_hwmon_read_key(hwmon->smc, &hwmon->fan.fans[channel].min,
- 1, &min);
- if (ret)
- return ret;
- ret = macsmc_hwmon_read_key(hwmon->smc, &hwmon->fan.fans[channel].max,
- 1, &max);
- if (ret)
- return ret;
- if (val >= min && val <= max) {
- if (!hwmon->fan.fans[channel].manual) {
- /* Write 1 to mode key for manual control */
- ret = macsmc_hwmon_write_key(hwmon->smc,
- &hwmon->fan.fans[channel].mode, 1);
- if (ret < 0)
- return ret;
- hwmon->fan.fans[channel].manual = true;
- }
- return macsmc_hwmon_write_key(hwmon->smc,
- &hwmon->fan.fans[channel].set, val);
- } else if (!val) {
- if (hwmon->fan.fans[channel].manual) {
- ret = macsmc_hwmon_write_key(hwmon->smc,
- &hwmon->fan.fans[channel].mode, 0);
- if (ret < 0)
- return ret;
- hwmon->fan.fans[channel].manual = false;
- }
- } else {
- return -EINVAL;
- }
- return 0;
- }
- static int macsmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
- u32 attr, int channel, long *val)
- {
- struct macsmc_hwmon *hwmon = dev_get_drvdata(dev);
- int ret = 0;
- switch (type) {
- case hwmon_temp:
- ret = macsmc_hwmon_read_key(hwmon->smc,
- &hwmon->temp.sensors[channel], 1000, val);
- break;
- case hwmon_in:
- ret = macsmc_hwmon_read_key(hwmon->smc,
- &hwmon->volt.sensors[channel], 1000, val);
- break;
- case hwmon_curr:
- ret = macsmc_hwmon_read_key(hwmon->smc,
- &hwmon->curr.sensors[channel], 1000, val);
- break;
- case hwmon_power:
- /* SMC returns power in Watts with acceptable precision to scale to uW */
- ret = macsmc_hwmon_read_key(hwmon->smc,
- &hwmon->power.sensors[channel],
- 1000000, val);
- break;
- case hwmon_fan:
- ret = macsmc_hwmon_read_fan(hwmon, attr, channel, val);
- break;
- default:
- return -EOPNOTSUPP;
- }
- return ret;
- }
- static int macsmc_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
- u32 attr, int channel, long val)
- {
- switch (type) {
- case hwmon_fan:
- return macsmc_hwmon_write_fan(dev, attr, channel, val);
- default:
- return -EOPNOTSUPP;
- }
- }
- static umode_t macsmc_hwmon_fan_is_visible(const struct macsmc_hwmon_fan *fan,
- u32 attr)
- {
- if (fan->attrs & BIT(attr)) {
- if (attr == hwmon_fan_target && fan_control && fan->mode.macsmc_key)
- return 0644;
- return 0444;
- }
- return 0;
- }
- static umode_t macsmc_hwmon_is_visible(const void *data,
- enum hwmon_sensor_types type, u32 attr,
- int channel)
- {
- const struct macsmc_hwmon *hwmon = data;
- struct macsmc_hwmon_sensor *sensor;
- switch (type) {
- case hwmon_in:
- sensor = &hwmon->volt.sensors[channel];
- break;
- case hwmon_curr:
- sensor = &hwmon->curr.sensors[channel];
- break;
- case hwmon_power:
- sensor = &hwmon->power.sensors[channel];
- break;
- case hwmon_temp:
- sensor = &hwmon->temp.sensors[channel];
- break;
- case hwmon_fan:
- return macsmc_hwmon_fan_is_visible(&hwmon->fan.fans[channel], attr);
- default:
- return 0;
- }
- /* Sensors only register ro attributes */
- if (sensor->attrs & BIT(attr))
- return 0444;
- return 0;
- }
- static const struct hwmon_ops macsmc_hwmon_ops = {
- .is_visible = macsmc_hwmon_is_visible,
- .read = macsmc_hwmon_read,
- .read_string = macsmc_hwmon_read_label,
- .write = macsmc_hwmon_write,
- };
- /*
- * Get the key metadata, including key data type, from the SMC.
- */
- static int macsmc_hwmon_parse_key(struct device *dev, struct apple_smc *smc,
- struct macsmc_hwmon_sensor *sensor,
- const char *key)
- {
- int ret;
- ret = apple_smc_get_key_info(smc, _SMC_KEY(key), &sensor->info);
- if (ret) {
- dev_dbg(dev, "Failed to retrieve key info for %s\n", key);
- return ret;
- }
- sensor->macsmc_key = _SMC_KEY(key);
- return 0;
- }
- /*
- * A sensor is a single key-value pair as made available by the SMC.
- * The devicetree gives us the SMC key ID and a friendly name where the
- * purpose of the sensor is known.
- */
- static int macsmc_hwmon_create_sensor(struct device *dev, struct apple_smc *smc,
- struct device_node *sensor_node,
- struct macsmc_hwmon_sensor *sensor)
- {
- const char *key, *label;
- int ret;
- ret = of_property_read_string(sensor_node, "apple,key-id", &key);
- if (ret) {
- dev_dbg(dev, "Could not find apple,key-id in sensor node\n");
- return ret;
- }
- ret = macsmc_hwmon_parse_key(dev, smc, sensor, key);
- if (ret)
- return ret;
- ret = of_property_read_string(sensor_node, "label", &label);
- if (ret)
- dev_dbg(dev, "No label found for sensor %s\n", key);
- else
- strscpy_pad(sensor->label, label, sizeof(sensor->label));
- return 0;
- }
- /*
- * Fan data is exposed by the SMC as multiple sensors.
- *
- * The devicetree schema reuses apple,key-id for the actual fan speed sensor.
- * Min, max and target keys do not need labels, so we can reuse label
- * for naming the entire fan.
- */
- static int macsmc_hwmon_create_fan(struct device *dev, struct apple_smc *smc,
- struct device_node *fan_node,
- struct macsmc_hwmon_fan *fan)
- {
- const char *label, *now, *min, *max, *set, *mode;
- int ret;
- ret = of_property_read_string(fan_node, "apple,key-id", &now);
- if (ret) {
- dev_err(dev, "apple,key-id not found in fan node!\n");
- return ret;
- }
- ret = macsmc_hwmon_parse_key(dev, smc, &fan->now, now);
- if (ret)
- return ret;
- fan->attrs = HWMON_F_INPUT;
- ret = of_property_read_string(fan_node, "label", &label);
- if (ret) {
- dev_dbg(dev, "No label found for fan %s\n", now);
- } else {
- strscpy_pad(fan->label, label, sizeof(fan->label));
- fan->attrs |= HWMON_F_LABEL;
- }
- /* The following keys are not required to simply monitor fan speed */
- if (!of_property_read_string(fan_node, "apple,fan-minimum", &min)) {
- ret = macsmc_hwmon_parse_key(dev, smc, &fan->min, min);
- if (ret)
- return ret;
- fan->attrs |= HWMON_F_MIN;
- }
- if (!of_property_read_string(fan_node, "apple,fan-maximum", &max)) {
- ret = macsmc_hwmon_parse_key(dev, smc, &fan->max, max);
- if (ret)
- return ret;
- fan->attrs |= HWMON_F_MAX;
- }
- if (!of_property_read_string(fan_node, "apple,fan-target", &set)) {
- ret = macsmc_hwmon_parse_key(dev, smc, &fan->set, set);
- if (ret)
- return ret;
- fan->attrs |= HWMON_F_TARGET;
- }
- if (!of_property_read_string(fan_node, "apple,fan-mode", &mode)) {
- ret = macsmc_hwmon_parse_key(dev, smc, &fan->mode, mode);
- if (ret)
- return ret;
- }
- /* Initialise fan control mode to automatic */
- fan->manual = false;
- return 0;
- }
- static int macsmc_hwmon_populate_sensors(struct macsmc_hwmon *hwmon,
- struct device_node *hwmon_node)
- {
- struct device_node *key_node __maybe_unused;
- struct macsmc_hwmon_sensor *sensor;
- u32 n_current = 0, n_fan = 0, n_power = 0, n_temperature = 0, n_voltage = 0;
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-") {
- n_current++;
- }
- if (n_current) {
- hwmon->curr.sensors = devm_kcalloc(hwmon->dev, n_current,
- sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
- if (!hwmon->curr.sensors)
- return -ENOMEM;
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-") {
- sensor = &hwmon->curr.sensors[hwmon->curr.count];
- if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
- sensor->attrs = HWMON_C_INPUT;
- if (*sensor->label)
- sensor->attrs |= HWMON_C_LABEL;
- hwmon->curr.count++;
- }
- }
- }
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-") {
- n_fan++;
- }
- if (n_fan) {
- hwmon->fan.fans = devm_kcalloc(hwmon->dev, n_fan,
- sizeof(struct macsmc_hwmon_fan), GFP_KERNEL);
- if (!hwmon->fan.fans)
- return -ENOMEM;
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-") {
- if (!macsmc_hwmon_create_fan(hwmon->dev, hwmon->smc, key_node,
- &hwmon->fan.fans[hwmon->fan.count]))
- hwmon->fan.count++;
- }
- }
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-") {
- n_power++;
- }
- if (n_power) {
- hwmon->power.sensors = devm_kcalloc(hwmon->dev, n_power,
- sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
- if (!hwmon->power.sensors)
- return -ENOMEM;
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-") {
- sensor = &hwmon->power.sensors[hwmon->power.count];
- if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
- sensor->attrs = HWMON_P_INPUT;
- if (*sensor->label)
- sensor->attrs |= HWMON_P_LABEL;
- hwmon->power.count++;
- }
- }
- }
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-") {
- n_temperature++;
- }
- if (n_temperature) {
- hwmon->temp.sensors = devm_kcalloc(hwmon->dev, n_temperature,
- sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
- if (!hwmon->temp.sensors)
- return -ENOMEM;
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-") {
- sensor = &hwmon->temp.sensors[hwmon->temp.count];
- if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
- sensor->attrs = HWMON_T_INPUT;
- if (*sensor->label)
- sensor->attrs |= HWMON_T_LABEL;
- hwmon->temp.count++;
- }
- }
- }
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "voltage-") {
- n_voltage++;
- }
- if (n_voltage) {
- hwmon->volt.sensors = devm_kcalloc(hwmon->dev, n_voltage,
- sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
- if (!hwmon->volt.sensors)
- return -ENOMEM;
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "voltage-") {
- sensor = &hwmon->volt.sensors[hwmon->volt.count];
- if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
- sensor->attrs = HWMON_I_INPUT;
- if (*sensor->label)
- sensor->attrs |= HWMON_I_LABEL;
- hwmon->volt.count++;
- }
- }
- }
- return 0;
- }
- /* Create NULL-terminated config arrays */
- static void macsmc_hwmon_populate_configs(u32 *configs, const struct macsmc_hwmon_sensors *sensors)
- {
- int idx;
- for (idx = 0; idx < sensors->count; idx++)
- configs[idx] = sensors->sensors[idx].attrs;
- }
- static void macsmc_hwmon_populate_fan_configs(u32 *configs, const struct macsmc_hwmon_fans *fans)
- {
- int idx;
- for (idx = 0; idx < fans->count; idx++)
- configs[idx] = fans->fans[idx].attrs;
- }
- static const struct hwmon_channel_info *const macsmc_chip_channel_info =
- HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ);
- static int macsmc_hwmon_create_infos(struct macsmc_hwmon *hwmon)
- {
- struct hwmon_channel_info *channel_info;
- int i = 0;
- /* chip */
- hwmon->channel_infos[i++] = macsmc_chip_channel_info;
- if (hwmon->curr.count) {
- channel_info = &hwmon->curr.channel_info;
- channel_info->type = hwmon_curr;
- channel_info->config = devm_kcalloc(hwmon->dev, hwmon->curr.count + 1,
- sizeof(u32), GFP_KERNEL);
- if (!channel_info->config)
- return -ENOMEM;
- macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->curr);
- hwmon->channel_infos[i++] = channel_info;
- }
- if (hwmon->fan.count) {
- channel_info = &hwmon->fan.channel_info;
- channel_info->type = hwmon_fan;
- channel_info->config = devm_kcalloc(hwmon->dev, hwmon->fan.count + 1,
- sizeof(u32), GFP_KERNEL);
- if (!channel_info->config)
- return -ENOMEM;
- macsmc_hwmon_populate_fan_configs((u32 *)channel_info->config, &hwmon->fan);
- hwmon->channel_infos[i++] = channel_info;
- }
- if (hwmon->power.count) {
- channel_info = &hwmon->power.channel_info;
- channel_info->type = hwmon_power;
- channel_info->config = devm_kcalloc(hwmon->dev, hwmon->power.count + 1,
- sizeof(u32), GFP_KERNEL);
- if (!channel_info->config)
- return -ENOMEM;
- macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->power);
- hwmon->channel_infos[i++] = channel_info;
- }
- if (hwmon->temp.count) {
- channel_info = &hwmon->temp.channel_info;
- channel_info->type = hwmon_temp;
- channel_info->config = devm_kcalloc(hwmon->dev, hwmon->temp.count + 1,
- sizeof(u32), GFP_KERNEL);
- if (!channel_info->config)
- return -ENOMEM;
- macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->temp);
- hwmon->channel_infos[i++] = channel_info;
- }
- if (hwmon->volt.count) {
- channel_info = &hwmon->volt.channel_info;
- channel_info->type = hwmon_in;
- channel_info->config = devm_kcalloc(hwmon->dev, hwmon->volt.count + 1,
- sizeof(u32), GFP_KERNEL);
- if (!channel_info->config)
- return -ENOMEM;
- macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->volt);
- hwmon->channel_infos[i++] = channel_info;
- }
- return 0;
- }
- static int macsmc_hwmon_probe(struct platform_device *pdev)
- {
- struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
- struct macsmc_hwmon *hwmon;
- int ret;
- /*
- * The MFD driver will try to probe us unconditionally. Some devices
- * with the SMC do not have hwmon capabilities. Only probe if we have
- * a hwmon node.
- */
- if (!pdev->dev.of_node)
- return -ENODEV;
- hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon),
- GFP_KERNEL);
- if (!hwmon)
- return -ENOMEM;
- hwmon->dev = &pdev->dev;
- hwmon->smc = smc;
- ret = macsmc_hwmon_populate_sensors(hwmon, hwmon->dev->of_node);
- if (ret) {
- dev_err(hwmon->dev, "Could not parse sensors\n");
- return ret;
- }
- if (!hwmon->curr.count && !hwmon->fan.count &&
- !hwmon->power.count && !hwmon->temp.count &&
- !hwmon->volt.count) {
- dev_err(hwmon->dev,
- "No valid sensors found of any supported type\n");
- return -ENODEV;
- }
- ret = macsmc_hwmon_create_infos(hwmon);
- if (ret)
- return ret;
- hwmon->chip_info.ops = &macsmc_hwmon_ops;
- hwmon->chip_info.info =
- (const struct hwmon_channel_info *const *)&hwmon->channel_infos;
- hwmon->hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
- "macsmc_hwmon", hwmon,
- &hwmon->chip_info, NULL);
- if (IS_ERR(hwmon->hwmon_dev))
- return dev_err_probe(hwmon->dev, PTR_ERR(hwmon->hwmon_dev),
- "Probing SMC hwmon device failed\n");
- dev_dbg(hwmon->dev, "Registered SMC hwmon device. Sensors:\n");
- dev_dbg(hwmon->dev,
- "Current: %d, Fans: %d, Power: %d, Temperature: %d, Voltage: %d",
- hwmon->curr.count, hwmon->fan.count,
- hwmon->power.count, hwmon->temp.count,
- hwmon->volt.count);
- return 0;
- }
- static const struct of_device_id macsmc_hwmon_of_table[] = {
- { .compatible = "apple,smc-hwmon" },
- {}
- };
- MODULE_DEVICE_TABLE(of, macsmc_hwmon_of_table);
- static struct platform_driver macsmc_hwmon_driver = {
- .probe = macsmc_hwmon_probe,
- .driver = {
- .name = "macsmc-hwmon",
- .of_match_table = macsmc_hwmon_of_table,
- },
- };
- module_platform_driver(macsmc_hwmon_driver);
- MODULE_DESCRIPTION("Apple Silicon SMC hwmon driver");
- MODULE_AUTHOR("James Calligeros <jcalligeros99@gmail.com>");
- MODULE_LICENSE("Dual MIT/GPL");
|