189309da3SJiri Pirko /* 289309da3SJiri Pirko * drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c 389309da3SJiri Pirko * Copyright (c) 2015 Mellanox Technologies. All rights reserved. 489309da3SJiri Pirko * Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com> 589309da3SJiri Pirko * 689309da3SJiri Pirko * Redistribution and use in source and binary forms, with or without 789309da3SJiri Pirko * modification, are permitted provided that the following conditions are met: 889309da3SJiri Pirko * 989309da3SJiri Pirko * 1. Redistributions of source code must retain the above copyright 1089309da3SJiri Pirko * notice, this list of conditions and the following disclaimer. 1189309da3SJiri Pirko * 2. Redistributions in binary form must reproduce the above copyright 1289309da3SJiri Pirko * notice, this list of conditions and the following disclaimer in the 1389309da3SJiri Pirko * documentation and/or other materials provided with the distribution. 1489309da3SJiri Pirko * 3. Neither the names of the copyright holders nor the names of its 1589309da3SJiri Pirko * contributors may be used to endorse or promote products derived from 1689309da3SJiri Pirko * this software without specific prior written permission. 1789309da3SJiri Pirko * 1889309da3SJiri Pirko * Alternatively, this software may be distributed under the terms of the 1989309da3SJiri Pirko * GNU General Public License ("GPL") version 2 as published by the Free 2089309da3SJiri Pirko * Software Foundation. 2189309da3SJiri Pirko * 2289309da3SJiri Pirko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2389309da3SJiri Pirko * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2489309da3SJiri Pirko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2589309da3SJiri Pirko * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2689309da3SJiri Pirko * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2789309da3SJiri Pirko * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2889309da3SJiri Pirko * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2989309da3SJiri Pirko * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3089309da3SJiri Pirko * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3189309da3SJiri Pirko * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3289309da3SJiri Pirko * POSSIBILITY OF SUCH DAMAGE. 3389309da3SJiri Pirko */ 3489309da3SJiri Pirko 3589309da3SJiri Pirko #include <linux/kernel.h> 3689309da3SJiri Pirko #include <linux/types.h> 3789309da3SJiri Pirko #include <linux/device.h> 3889309da3SJiri Pirko #include <linux/sysfs.h> 3989309da3SJiri Pirko #include <linux/hwmon.h> 4089309da3SJiri Pirko #include <linux/err.h> 4189309da3SJiri Pirko 4289309da3SJiri Pirko #include "core.h" 4389309da3SJiri Pirko 4489309da3SJiri Pirko #define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127 4552581961SJiri Pirko #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \ 4652581961SJiri Pirko MLXSW_MFCR_TACHOS_MAX + MLXSW_MFCR_PWMS_MAX) 4789309da3SJiri Pirko 4889309da3SJiri Pirko struct mlxsw_hwmon_attr { 4989309da3SJiri Pirko struct device_attribute dev_attr; 5089309da3SJiri Pirko struct mlxsw_hwmon *hwmon; 5189309da3SJiri Pirko unsigned int type_index; 52e7bc73cbSJiri Pirko char name[32]; 5389309da3SJiri Pirko }; 5489309da3SJiri Pirko 5589309da3SJiri Pirko struct mlxsw_hwmon { 5689309da3SJiri Pirko struct mlxsw_core *core; 5789309da3SJiri Pirko const struct mlxsw_bus_info *bus_info; 5889309da3SJiri Pirko struct device *hwmon_dev; 5989309da3SJiri Pirko struct attribute_group group; 6089309da3SJiri Pirko const struct attribute_group *groups[2]; 6189309da3SJiri Pirko struct attribute *attrs[MLXSW_HWMON_ATTR_COUNT + 1]; 6289309da3SJiri Pirko struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT]; 6389309da3SJiri Pirko unsigned int attrs_count; 6489309da3SJiri Pirko }; 6589309da3SJiri Pirko 6689309da3SJiri Pirko static ssize_t mlxsw_hwmon_temp_show(struct device *dev, 6789309da3SJiri Pirko struct device_attribute *attr, 6889309da3SJiri Pirko char *buf) 6989309da3SJiri Pirko { 7089309da3SJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 7189309da3SJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 7289309da3SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 7389309da3SJiri Pirko char mtmp_pl[MLXSW_REG_MTMP_LEN]; 7489309da3SJiri Pirko unsigned int temp; 7589309da3SJiri Pirko int err; 7689309da3SJiri Pirko 7789309da3SJiri Pirko mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, 7889309da3SJiri Pirko false, false); 7989309da3SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); 8089309da3SJiri Pirko if (err) { 8189309da3SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); 8289309da3SJiri Pirko return err; 8389309da3SJiri Pirko } 8489309da3SJiri Pirko mlxsw_reg_mtmp_unpack(mtmp_pl, &temp, NULL, NULL); 8589309da3SJiri Pirko return sprintf(buf, "%u\n", temp); 8689309da3SJiri Pirko } 8789309da3SJiri Pirko 8889309da3SJiri Pirko static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, 8989309da3SJiri Pirko struct device_attribute *attr, 9089309da3SJiri Pirko char *buf) 9189309da3SJiri Pirko { 9289309da3SJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 9389309da3SJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 9489309da3SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 9589309da3SJiri Pirko char mtmp_pl[MLXSW_REG_MTMP_LEN]; 9689309da3SJiri Pirko unsigned int temp_max; 9789309da3SJiri Pirko int err; 9889309da3SJiri Pirko 9989309da3SJiri Pirko mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, 10089309da3SJiri Pirko false, false); 10189309da3SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); 10289309da3SJiri Pirko if (err) { 10389309da3SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); 10489309da3SJiri Pirko return err; 10589309da3SJiri Pirko } 10689309da3SJiri Pirko mlxsw_reg_mtmp_unpack(mtmp_pl, NULL, &temp_max, NULL); 10789309da3SJiri Pirko return sprintf(buf, "%u\n", temp_max); 10889309da3SJiri Pirko } 10989309da3SJiri Pirko 110e7bc73cbSJiri Pirko static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, 111e7bc73cbSJiri Pirko struct device_attribute *attr, 112e7bc73cbSJiri Pirko const char *buf, size_t len) 113e7bc73cbSJiri Pirko { 114e7bc73cbSJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 115e7bc73cbSJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 116e7bc73cbSJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 117e7bc73cbSJiri Pirko char mtmp_pl[MLXSW_REG_MTMP_LEN]; 118e7bc73cbSJiri Pirko unsigned long val; 119e7bc73cbSJiri Pirko int err; 120e7bc73cbSJiri Pirko 121e7bc73cbSJiri Pirko err = kstrtoul(buf, 10, &val); 122e7bc73cbSJiri Pirko if (err) 123e7bc73cbSJiri Pirko return err; 124e7bc73cbSJiri Pirko if (val != 1) 125e7bc73cbSJiri Pirko return -EINVAL; 126e7bc73cbSJiri Pirko 127e7bc73cbSJiri Pirko mlxsw_reg_mtmp_pack(mtmp_pl, mlwsw_hwmon_attr->type_index, true, true); 128e7bc73cbSJiri Pirko err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); 129e7bc73cbSJiri Pirko if (err) { 130e7bc73cbSJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to reset temp sensor history\n"); 131e7bc73cbSJiri Pirko return err; 132e7bc73cbSJiri Pirko } 133719255d0SDan Carpenter return len; 134e7bc73cbSJiri Pirko } 135e7bc73cbSJiri Pirko 13652581961SJiri Pirko static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev, 13752581961SJiri Pirko struct device_attribute *attr, 13852581961SJiri Pirko char *buf) 13952581961SJiri Pirko { 14052581961SJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 14152581961SJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 14252581961SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 14352581961SJiri Pirko char mfsm_pl[MLXSW_REG_MFSM_LEN]; 14452581961SJiri Pirko int err; 14552581961SJiri Pirko 14652581961SJiri Pirko mlxsw_reg_mfsm_pack(mfsm_pl, mlwsw_hwmon_attr->type_index); 14752581961SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsm), mfsm_pl); 14852581961SJiri Pirko if (err) { 14952581961SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n"); 15052581961SJiri Pirko return err; 15152581961SJiri Pirko } 15252581961SJiri Pirko return sprintf(buf, "%u\n", mlxsw_reg_mfsm_rpm_get(mfsm_pl)); 15352581961SJiri Pirko } 15452581961SJiri Pirko 15552581961SJiri Pirko static ssize_t mlxsw_hwmon_pwm_show(struct device *dev, 15652581961SJiri Pirko struct device_attribute *attr, 15752581961SJiri Pirko char *buf) 15852581961SJiri Pirko { 15952581961SJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 16052581961SJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 16152581961SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 16252581961SJiri Pirko char mfsc_pl[MLXSW_REG_MFSC_LEN]; 16352581961SJiri Pirko int err; 16452581961SJiri Pirko 16552581961SJiri Pirko mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, 0); 16652581961SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl); 16752581961SJiri Pirko if (err) { 16852581961SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query PWM\n"); 16952581961SJiri Pirko return err; 17052581961SJiri Pirko } 17152581961SJiri Pirko return sprintf(buf, "%u\n", 17252581961SJiri Pirko mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl)); 17352581961SJiri Pirko } 17452581961SJiri Pirko 17552581961SJiri Pirko static ssize_t mlxsw_hwmon_pwm_store(struct device *dev, 17652581961SJiri Pirko struct device_attribute *attr, 17752581961SJiri Pirko const char *buf, size_t len) 17852581961SJiri Pirko { 17952581961SJiri Pirko struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = 18052581961SJiri Pirko container_of(attr, struct mlxsw_hwmon_attr, dev_attr); 18152581961SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; 18252581961SJiri Pirko char mfsc_pl[MLXSW_REG_MFSC_LEN]; 18352581961SJiri Pirko unsigned long val; 18452581961SJiri Pirko int err; 18552581961SJiri Pirko 18652581961SJiri Pirko err = kstrtoul(buf, 10, &val); 18752581961SJiri Pirko if (err) 18852581961SJiri Pirko return err; 18952581961SJiri Pirko if (val > 255) 19052581961SJiri Pirko return -EINVAL; 19152581961SJiri Pirko 19252581961SJiri Pirko mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, val); 19352581961SJiri Pirko err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl); 19452581961SJiri Pirko if (err) { 19552581961SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to write PWM\n"); 19652581961SJiri Pirko return err; 19752581961SJiri Pirko } 198515123e2SDan Carpenter return len; 19952581961SJiri Pirko } 20052581961SJiri Pirko 20189309da3SJiri Pirko enum mlxsw_hwmon_attr_type { 20289309da3SJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP, 20389309da3SJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, 204e7bc73cbSJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP_RST, 20552581961SJiri Pirko MLXSW_HWMON_ATTR_TYPE_FAN_RPM, 20652581961SJiri Pirko MLXSW_HWMON_ATTR_TYPE_PWM, 20789309da3SJiri Pirko }; 20889309da3SJiri Pirko 20989309da3SJiri Pirko static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, 21089309da3SJiri Pirko enum mlxsw_hwmon_attr_type attr_type, 21189309da3SJiri Pirko unsigned int type_index, unsigned int num) { 21289309da3SJiri Pirko struct mlxsw_hwmon_attr *mlxsw_hwmon_attr; 21389309da3SJiri Pirko unsigned int attr_index; 21489309da3SJiri Pirko 21589309da3SJiri Pirko attr_index = mlxsw_hwmon->attrs_count; 21689309da3SJiri Pirko mlxsw_hwmon_attr = &mlxsw_hwmon->hwmon_attrs[attr_index]; 21789309da3SJiri Pirko 21889309da3SJiri Pirko switch (attr_type) { 21989309da3SJiri Pirko case MLXSW_HWMON_ATTR_TYPE_TEMP: 22089309da3SJiri Pirko mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_show; 221d3757ba4SJoe Perches mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 22289309da3SJiri Pirko snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 22389309da3SJiri Pirko "temp%u_input", num + 1); 22489309da3SJiri Pirko break; 22589309da3SJiri Pirko case MLXSW_HWMON_ATTR_TYPE_TEMP_MAX: 22689309da3SJiri Pirko mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_temp_max_show; 227d3757ba4SJoe Perches mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 22889309da3SJiri Pirko snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 22989309da3SJiri Pirko "temp%u_highest", num + 1); 23089309da3SJiri Pirko break; 231e7bc73cbSJiri Pirko case MLXSW_HWMON_ATTR_TYPE_TEMP_RST: 232e7bc73cbSJiri Pirko mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_temp_rst_store; 233d3757ba4SJoe Perches mlxsw_hwmon_attr->dev_attr.attr.mode = 0200; 234e7bc73cbSJiri Pirko snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 235e7bc73cbSJiri Pirko "temp%u_reset_history", num + 1); 236e7bc73cbSJiri Pirko break; 23752581961SJiri Pirko case MLXSW_HWMON_ATTR_TYPE_FAN_RPM: 23852581961SJiri Pirko mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_fan_rpm_show; 239d3757ba4SJoe Perches mlxsw_hwmon_attr->dev_attr.attr.mode = 0444; 24052581961SJiri Pirko snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 24152581961SJiri Pirko "fan%u_input", num + 1); 24252581961SJiri Pirko break; 24352581961SJiri Pirko case MLXSW_HWMON_ATTR_TYPE_PWM: 24452581961SJiri Pirko mlxsw_hwmon_attr->dev_attr.show = mlxsw_hwmon_pwm_show; 24552581961SJiri Pirko mlxsw_hwmon_attr->dev_attr.store = mlxsw_hwmon_pwm_store; 246d3757ba4SJoe Perches mlxsw_hwmon_attr->dev_attr.attr.mode = 0644; 24752581961SJiri Pirko snprintf(mlxsw_hwmon_attr->name, sizeof(mlxsw_hwmon_attr->name), 24852581961SJiri Pirko "pwm%u", num + 1); 24952581961SJiri Pirko break; 25089309da3SJiri Pirko default: 2516b20da4dSJiri Pirko WARN_ON(1); 25289309da3SJiri Pirko } 25389309da3SJiri Pirko 25489309da3SJiri Pirko mlxsw_hwmon_attr->type_index = type_index; 25589309da3SJiri Pirko mlxsw_hwmon_attr->hwmon = mlxsw_hwmon; 25689309da3SJiri Pirko mlxsw_hwmon_attr->dev_attr.attr.name = mlxsw_hwmon_attr->name; 25789309da3SJiri Pirko sysfs_attr_init(&mlxsw_hwmon_attr->dev_attr.attr); 25889309da3SJiri Pirko 25989309da3SJiri Pirko mlxsw_hwmon->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr; 26089309da3SJiri Pirko mlxsw_hwmon->attrs_count++; 26189309da3SJiri Pirko } 26289309da3SJiri Pirko 26389309da3SJiri Pirko static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) 26489309da3SJiri Pirko { 2655b090740SElad Raz char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0}; 26689309da3SJiri Pirko char mtmp_pl[MLXSW_REG_MTMP_LEN]; 26789309da3SJiri Pirko u8 sensor_count; 26889309da3SJiri Pirko int i; 26989309da3SJiri Pirko int err; 27089309da3SJiri Pirko 27189309da3SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtcap), mtcap_pl); 27289309da3SJiri Pirko if (err) { 27389309da3SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get number of temp sensors\n"); 27489309da3SJiri Pirko return err; 27589309da3SJiri Pirko } 27689309da3SJiri Pirko sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl); 27789309da3SJiri Pirko for (i = 0; i < sensor_count; i++) { 278b626f2cbSJiri Pirko mlxsw_reg_mtmp_pack(mtmp_pl, i, true, true); 27989309da3SJiri Pirko err = mlxsw_reg_write(mlxsw_hwmon->core, 28089309da3SJiri Pirko MLXSW_REG(mtmp), mtmp_pl); 28189309da3SJiri Pirko if (err) { 28289309da3SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to setup temp sensor number %d\n", 28389309da3SJiri Pirko i); 28489309da3SJiri Pirko return err; 28589309da3SJiri Pirko } 28689309da3SJiri Pirko mlxsw_hwmon_attr_add(mlxsw_hwmon, 28789309da3SJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP, i, i); 28889309da3SJiri Pirko mlxsw_hwmon_attr_add(mlxsw_hwmon, 28989309da3SJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, i, i); 290e7bc73cbSJiri Pirko mlxsw_hwmon_attr_add(mlxsw_hwmon, 291e7bc73cbSJiri Pirko MLXSW_HWMON_ATTR_TYPE_TEMP_RST, i, i); 29289309da3SJiri Pirko } 29389309da3SJiri Pirko return 0; 29489309da3SJiri Pirko } 29589309da3SJiri Pirko 29652581961SJiri Pirko static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) 29752581961SJiri Pirko { 2985b090740SElad Raz char mfcr_pl[MLXSW_REG_MFCR_LEN] = {0}; 29952581961SJiri Pirko enum mlxsw_reg_mfcr_pwm_frequency freq; 30052581961SJiri Pirko unsigned int type_index; 30152581961SJiri Pirko unsigned int num; 30252581961SJiri Pirko u16 tacho_active; 30352581961SJiri Pirko u8 pwm_active; 30452581961SJiri Pirko int err; 30552581961SJiri Pirko 30652581961SJiri Pirko err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfcr), mfcr_pl); 30752581961SJiri Pirko if (err) { 30852581961SJiri Pirko dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get to probe PWMs and Tachometers\n"); 30952581961SJiri Pirko return err; 31052581961SJiri Pirko } 31152581961SJiri Pirko mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active); 31252581961SJiri Pirko num = 0; 31352581961SJiri Pirko for (type_index = 0; type_index < MLXSW_MFCR_TACHOS_MAX; type_index++) { 31452581961SJiri Pirko if (tacho_active & BIT(type_index)) 31552581961SJiri Pirko mlxsw_hwmon_attr_add(mlxsw_hwmon, 31652581961SJiri Pirko MLXSW_HWMON_ATTR_TYPE_FAN_RPM, 31752581961SJiri Pirko type_index, num++); 31852581961SJiri Pirko } 31952581961SJiri Pirko num = 0; 32052581961SJiri Pirko for (type_index = 0; type_index < MLXSW_MFCR_PWMS_MAX; type_index++) { 32152581961SJiri Pirko if (pwm_active & BIT(type_index)) 32252581961SJiri Pirko mlxsw_hwmon_attr_add(mlxsw_hwmon, 32352581961SJiri Pirko MLXSW_HWMON_ATTR_TYPE_PWM, 32452581961SJiri Pirko type_index, num++); 32552581961SJiri Pirko } 32652581961SJiri Pirko return 0; 32752581961SJiri Pirko } 32852581961SJiri Pirko 32989309da3SJiri Pirko int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, 33089309da3SJiri Pirko const struct mlxsw_bus_info *mlxsw_bus_info, 33189309da3SJiri Pirko struct mlxsw_hwmon **p_hwmon) 33289309da3SJiri Pirko { 33389309da3SJiri Pirko struct mlxsw_hwmon *mlxsw_hwmon; 33489309da3SJiri Pirko struct device *hwmon_dev; 33589309da3SJiri Pirko int err; 33689309da3SJiri Pirko 337f4cee3afSJiri Pirko mlxsw_hwmon = devm_kzalloc(mlxsw_bus_info->dev, sizeof(*mlxsw_hwmon), 338f4cee3afSJiri Pirko GFP_KERNEL); 33989309da3SJiri Pirko if (!mlxsw_hwmon) 34089309da3SJiri Pirko return -ENOMEM; 34189309da3SJiri Pirko mlxsw_hwmon->core = mlxsw_core; 34289309da3SJiri Pirko mlxsw_hwmon->bus_info = mlxsw_bus_info; 34389309da3SJiri Pirko 34489309da3SJiri Pirko err = mlxsw_hwmon_temp_init(mlxsw_hwmon); 34589309da3SJiri Pirko if (err) 34689309da3SJiri Pirko goto err_temp_init; 34789309da3SJiri Pirko 34852581961SJiri Pirko err = mlxsw_hwmon_fans_init(mlxsw_hwmon); 34952581961SJiri Pirko if (err) 35052581961SJiri Pirko goto err_fans_init; 35152581961SJiri Pirko 35289309da3SJiri Pirko mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; 35389309da3SJiri Pirko mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; 35489309da3SJiri Pirko 35589309da3SJiri Pirko hwmon_dev = devm_hwmon_device_register_with_groups(mlxsw_bus_info->dev, 35689309da3SJiri Pirko "mlxsw", 35789309da3SJiri Pirko mlxsw_hwmon, 35889309da3SJiri Pirko mlxsw_hwmon->groups); 35989309da3SJiri Pirko if (IS_ERR(hwmon_dev)) { 36089309da3SJiri Pirko err = PTR_ERR(hwmon_dev); 36189309da3SJiri Pirko goto err_hwmon_register; 36289309da3SJiri Pirko } 36389309da3SJiri Pirko 36489309da3SJiri Pirko mlxsw_hwmon->hwmon_dev = hwmon_dev; 36589309da3SJiri Pirko *p_hwmon = mlxsw_hwmon; 36689309da3SJiri Pirko return 0; 36789309da3SJiri Pirko 36889309da3SJiri Pirko err_hwmon_register: 36952581961SJiri Pirko err_fans_init: 37089309da3SJiri Pirko err_temp_init: 37189309da3SJiri Pirko return err; 37289309da3SJiri Pirko } 373