1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
4 #include <linux/kernel.h>
5 #include <linux/types.h>
6 #include <linux/device.h>
7 #include <linux/sysfs.h>
8 #include <linux/hwmon.h>
10 #include <linux/sfp.h>
15 #define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127
16 #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \
17 MLXSW_MFCR_TACHOS_MAX + MLXSW_MFCR_PWMS_MAX)
19 struct mlxsw_hwmon_attr {
20 struct device_attribute dev_attr;
21 struct mlxsw_hwmon *hwmon;
22 unsigned int type_index;
27 struct mlxsw_core *core;
28 const struct mlxsw_bus_info *bus_info;
29 struct device *hwmon_dev;
30 struct attribute_group group;
31 const struct attribute_group *groups[2];
32 struct attribute *attrs[MLXSW_HWMON_ATTR_COUNT + 1];
33 struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT];
34 unsigned int attrs_count;
38 static ssize_t mlxsw_hwmon_temp_show(struct device *dev,
39 struct device_attribute *attr,
42 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
43 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
44 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
45 char mtmp_pl[MLXSW_REG_MTMP_LEN];
49 mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index,
51 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
53 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n");
56 mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL);
57 return sprintf(buf, "%u\n", temp);
60 static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev,
61 struct device_attribute *attr,
64 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
65 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
66 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
67 char mtmp_pl[MLXSW_REG_MTMP_LEN];
68 unsigned int temp_max;
71 mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index,
73 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
75 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n");
78 mlxsw_reg_mtmp_unpack(mtmp_pl, NULL, &temp_max, NULL);
79 return sprintf(buf, "%u\n", temp_max);
82 static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev,
83 struct device_attribute *attr,
84 const char *buf, size_t len)
86 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
87 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
88 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
89 char mtmp_pl[MLXSW_REG_MTMP_LEN];
93 err = kstrtoul(buf, 10, &val);
99 mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, true, true);
100 err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl);
102 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to reset temp sensor history\n");
108 static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev,
109 struct device_attribute *attr,
112 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
113 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
114 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
115 char mfsm_pl[MLXSW_REG_MFSM_LEN];
118 mlxsw_reg_mfsm_pack(mfsm_pl, mlwsw_hwmon_attr->type_index);
119 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsm), mfsm_pl);
121 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n");
124 return sprintf(buf, "%u\n", mlxsw_reg_mfsm_rpm_get(mfsm_pl));
127 static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev,
128 struct device_attribute *attr,
131 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
132 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
133 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
134 char fore_pl[MLXSW_REG_FORE_LEN];
138 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(fore), fore_pl);
140 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n");
143 mlxsw_reg_fore_unpack(fore_pl, mlwsw_hwmon_attr->type_index, &fault);
145 return sprintf(buf, "%u\n", fault);
148 static ssize_t mlxsw_hwmon_pwm_show(struct device *dev,
149 struct device_attribute *attr,
152 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
153 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
154 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
155 char mfsc_pl[MLXSW_REG_MFSC_LEN];
158 mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, 0);
159 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl);
161 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query PWM\n");
164 return sprintf(buf, "%u\n",
165 mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl));
168 static ssize_t mlxsw_hwmon_pwm_store(struct device *dev,
169 struct device_attribute *attr,
170 const char *buf, size_t len)
172 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
173 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
174 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
175 char mfsc_pl[MLXSW_REG_MFSC_LEN];
179 err = kstrtoul(buf, 10, &val);
185 mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, val);
186 err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl);
188 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to write PWM\n");
194 static ssize_t mlxsw_hwmon_module_temp_show(struct device *dev,
195 struct device_attribute *attr,
198 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
199 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
200 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
201 char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
206 module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
207 mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
209 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl);
211 dev_err(dev, "Failed to query module temperature sensor\n");
215 mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
216 /* Update status and temperature cache. */
218 case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
219 case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
220 case MLXSW_REG_MTBR_INDEX_NA:
223 case MLXSW_REG_MTBR_BAD_SENS_INFO:
224 /* Untrusted cable is connected. Reading temperature from its
230 temp = MLXSW_REG_MTMP_TEMP_TO_MC(temp);
234 return sprintf(buf, "%u\n", temp);
237 static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev,
238 struct device_attribute *attr,
241 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
242 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
243 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
244 char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0};
249 module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
250 mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module,
252 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl);
254 dev_err(dev, "Failed to query module temperature sensor\n");
258 mlxsw_reg_mtbr_temp_unpack(mtbr_pl, 0, &temp, NULL);
260 /* Update status and temperature cache. */
262 case MLXSW_REG_MTBR_BAD_SENS_INFO:
263 /* Untrusted cable is connected. Reading temperature from its
268 case MLXSW_REG_MTBR_NO_CONN: /* fall-through */
269 case MLXSW_REG_MTBR_NO_TEMP_SENS: /* fall-through */
270 case MLXSW_REG_MTBR_INDEX_NA:
276 return sprintf(buf, "%u\n", fault);
280 mlxsw_hwmon_module_temp_critical_show(struct device *dev,
281 struct device_attribute *attr, char *buf)
283 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
284 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
285 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
290 module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
291 err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module,
292 SFP_TEMP_HIGH_WARN, &temp);
294 dev_err(dev, "Failed to query module temperature thresholds\n");
298 return sprintf(buf, "%u\n", temp);
302 mlxsw_hwmon_module_temp_emergency_show(struct device *dev,
303 struct device_attribute *attr,
306 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
307 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
308 struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon;
313 module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count;
314 err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module,
315 SFP_TEMP_HIGH_ALARM, &temp);
317 dev_err(dev, "Failed to query module temperature thresholds\n");
321 return sprintf(buf, "%u\n", temp);
325 mlxsw_hwmon_module_temp_label_show(struct device *dev,
326 struct device_attribute *attr,
329 struct mlxsw_hwmon_attr *mlwsw_hwmon_attr =
330 container_of(attr, struct mlxsw_hwmon_attr, dev_attr);
332 return sprintf(buf, "front panel %03u\n",
333 mlwsw_hwmon_attr->type_index);
336 enum mlxsw_hwmon_attr_type {
337 MLXSW_HWMON_ATTR_TYPE_TEMP,
338 MLXSW_HWMON_ATTR_TYPE_TEMP_MAX,
339 MLXSW_HWMON_ATTR_TYPE_TEMP_RST,
340 MLXSW_HWMON_ATTR_TYPE_FAN_RPM,
341 MLXSW_HWMON_ATTR_TYPE_FAN_FAULT,
342 MLXSW_HWMON_ATTR_TYPE_PWM,
343 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE,
344 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
345 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT,
346 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
347 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL,
350 static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon,
351 enum mlxsw_hwmon_attr_type attr_type,
352 unsigned int type_index, unsigned int num) {
353 struct mlxsw_hwmon_attr *mlxsw_hwmon_attr;
354 unsigned int attr_index;
356 attr_index = mlxsw_hwmon->attrs_count;
357 mlxsw_hwmon_attr = &mlxsw_hwmon->hwmon_attrs[attr_index];
360 case MLXSW_HWMON_ATTR_TYPE_TEMP:
361 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_show;
362 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
363 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
364 "temp%u_input", num + 1);
366 case MLXSW_HWMON_ATTR_TYPE_TEMP_MAX:
367 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_max_show;
368 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
369 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
370 "temp%u_highest", num + 1);
372 case MLXSW_HWMON_ATTR_TYPE_TEMP_RST:
373 mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_temp_rst_store;
374 mlxsw_hwmon_attr->dev_attr.attr.mode = 0200;
375 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
376 "temp%u_reset_history", num + 1);
378 case MLXSW_HWMON_ATTR_TYPE_FAN_RPM:
379 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_rpm_show;
380 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
381 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
382 "fan%u_input", num + 1);
384 case MLXSW_HWMON_ATTR_TYPE_FAN_FAULT:
385 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_fault_show;
386 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
387 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
388 "fan%u_fault", num + 1);
390 case MLXSW_HWMON_ATTR_TYPE_PWM:
391 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_pwm_show;
392 mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_pwm_store;
393 mlxsw_hwmon_attr->dev_attr.attr.mode = 0644;
394 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
397 case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE:
398 mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_module_temp_show;
399 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
400 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
401 "temp%u_input", num + 1);
403 case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT:
404 mlxsw_hwmon_attr->dev_attr.show =
405 mlxsw_hwmon_module_temp_fault_show;
406 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
407 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
408 "temp%u_fault", num + 1);
410 case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT:
411 mlxsw_hwmon_attr->dev_attr.show =
412 mlxsw_hwmon_module_temp_critical_show;
413 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
414 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
415 "temp%u_crit", num + 1);
417 case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG:
418 mlxsw_hwmon_attr->dev_attr.show =
419 mlxsw_hwmon_module_temp_emergency_show;
420 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
421 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
422 "temp%u_emergency", num + 1);
424 case MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL:
425 mlxsw_hwmon_attr->dev_attr.show =
426 mlxsw_hwmon_module_temp_label_show;
427 mlxsw_hwmon_attr->dev_attr.attr.mode = 0444;
428 snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name),
429 "temp%u_label", num + 1);
435 mlxsw_hwmon_attr->type_index = type_index;
436 mlxsw_hwmon_attr->hwmon = mlxsw_hwmon;
437 mlxsw_hwmon_attr->dev_attr.attr.name = mlxsw_hwmon_attr->name;
438 sysfs_attr_init(&mlxsw_hwmon_attr->dev_attr.attr);
440 mlxsw_hwmon->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr;
441 mlxsw_hwmon->attrs_count++;
444 static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon)
446 char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0};
447 char mtmp_pl[MLXSW_REG_MTMP_LEN];
451 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtcap), mtcap_pl);
453 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get number of temp sensors\n");
456 mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl);
457 for (i = 0; i < mlxsw_hwmon->sensor_count; i++) {
458 mlxsw_reg_mtmp_pack(mtmp_pl, i, true, true);
459 err = mlxsw_reg_write(mlxsw_hwmon->core,
460 MLXSW_REG(mtmp), mtmp_pl);
462 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n",
466 mlxsw_hwmon_attr_add(mlxsw_hwmon,
467 MLXSW_HWMON_ATTR_TYPE_TEMP, i, i);
468 mlxsw_hwmon_attr_add(mlxsw_hwmon,
469 MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, i, i);
470 mlxsw_hwmon_attr_add(mlxsw_hwmon,
471 MLXSW_HWMON_ATTR_TYPE_TEMP_RST, i, i);
476 static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon)
478 char mfcr_pl[MLXSW_REG_MFCR_LEN] = {0};
479 enum mlxsw_reg_mfcr_pwm_frequency freq;
480 unsigned int type_index;
486 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfcr), mfcr_pl);
488 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get to probe PWMs and Tachometers\n");
491 mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active);
493 for (type_index = 0; type_index < MLXSW_MFCR_TACHOS_MAX; type_index++) {
494 if (tacho_active & BIT(type_index)) {
495 mlxsw_hwmon_attr_add(mlxsw_hwmon,
496 MLXSW_HWMON_ATTR_TYPE_FAN_RPM,
498 mlxsw_hwmon_attr_add(mlxsw_hwmon,
499 MLXSW_HWMON_ATTR_TYPE_FAN_FAULT,
504 for (type_index = 0; type_index < MLXSW_MFCR_PWMS_MAX; type_index++) {
505 if (pwm_active & BIT(type_index))
506 mlxsw_hwmon_attr_add(mlxsw_hwmon,
507 MLXSW_HWMON_ATTR_TYPE_PWM,
513 static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon)
515 unsigned int module_count = mlxsw_core_max_ports(mlxsw_hwmon->core);
516 char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0};
521 /* Add extra attributes for module temperature. Sensor index is
522 * assigned to sensor_count value, while all indexed before
523 * sensor_count are already utilized by the sensors connected through
524 * mtmp register by mlxsw_hwmon_temp_init().
526 index = mlxsw_hwmon->sensor_count;
527 for (i = 1; i < module_count; i++) {
528 mlxsw_reg_pmlp_pack(pmlp_pl, i);
529 err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(pmlp),
532 dev_err(mlxsw_hwmon->bus_info->dev, "Failed to read module index %d\n",
536 width = mlxsw_reg_pmlp_width_get(pmlp_pl);
539 mlxsw_hwmon_attr_add(mlxsw_hwmon,
540 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, index,
542 mlxsw_hwmon_attr_add(mlxsw_hwmon,
543 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT,
545 mlxsw_hwmon_attr_add(mlxsw_hwmon,
546 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT,
548 mlxsw_hwmon_attr_add(mlxsw_hwmon,
549 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG,
551 mlxsw_hwmon_attr_add(mlxsw_hwmon,
552 MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL,
560 int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core,
561 const struct mlxsw_bus_info *mlxsw_bus_info,
562 struct mlxsw_hwmon **p_hwmon)
564 struct mlxsw_hwmon *mlxsw_hwmon;
565 struct device *hwmon_dev;
568 mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL);
571 mlxsw_hwmon->core = mlxsw_core;
572 mlxsw_hwmon->bus_info = mlxsw_bus_info;
574 err = mlxsw_hwmon_temp_init(mlxsw_hwmon);
578 err = mlxsw_hwmon_fans_init(mlxsw_hwmon);
582 err = mlxsw_hwmon_module_init(mlxsw_hwmon);
584 goto err_temp_module_init;
586 mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group;
587 mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs;
589 hwmon_dev = hwmon_device_register_with_groups(mlxsw_bus_info->dev,
590 "mlxsw", mlxsw_hwmon,
591 mlxsw_hwmon->groups);
592 if (IS_ERR(hwmon_dev)) {
593 err = PTR_ERR(hwmon_dev);
594 goto err_hwmon_register;
597 mlxsw_hwmon->hwmon_dev = hwmon_dev;
598 *p_hwmon = mlxsw_hwmon;
602 err_temp_module_init:
609 void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon)
611 hwmon_device_unregister(mlxsw_hwmon->hwmon_dev);