1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Atlantic Network Driver 3 * 4 * Copyright (C) 2014-2019 aQuantia Corporation 5 * Copyright (C) 2019-2020 Marvell International Ltd. 6 */ 7 8 /* File aq_drvinfo.c: Definition of common code for firmware info in sys.*/ 9 10 #include <linux/init.h> 11 #include <linux/kobject.h> 12 #include <linux/module.h> 13 #include <linux/stat.h> 14 #include <linux/string.h> 15 #include <linux/hwmon.h> 16 #include <linux/uaccess.h> 17 18 #include "aq_drvinfo.h" 19 #include "aq_nic.h" 20 21 #if IS_REACHABLE(CONFIG_HWMON) 22 static const char * const atl_temp_label[] = { 23 "PHY Temperature", 24 "MAC Temperature", 25 }; 26 27 static int aq_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 28 u32 attr, int channel, long *value) 29 { 30 struct aq_nic_s *aq_nic = dev_get_drvdata(dev); 31 int err = 0; 32 int temp; 33 34 if (!aq_nic) 35 return -EIO; 36 37 if (type != hwmon_temp || attr != hwmon_temp_input) 38 return -EOPNOTSUPP; 39 40 switch (channel) { 41 case 0: 42 if (!aq_nic->aq_fw_ops->get_phy_temp) 43 return -EOPNOTSUPP; 44 45 err = aq_nic->aq_fw_ops->get_phy_temp(aq_nic->aq_hw, &temp); 46 *value = temp; 47 break; 48 case 1: 49 if (!aq_nic->aq_fw_ops->get_mac_temp && 50 !aq_nic->aq_hw_ops->hw_get_mac_temp) 51 return -EOPNOTSUPP; 52 53 if (aq_nic->aq_fw_ops->get_mac_temp) 54 err = aq_nic->aq_fw_ops->get_mac_temp(aq_nic->aq_hw, &temp); 55 else 56 err = aq_nic->aq_hw_ops->hw_get_mac_temp(aq_nic->aq_hw, &temp); 57 *value = temp; 58 break; 59 default: 60 return -EOPNOTSUPP; 61 } 62 63 return err; 64 } 65 66 static int aq_hwmon_read_string(struct device *dev, 67 enum hwmon_sensor_types type, 68 u32 attr, int channel, const char **str) 69 { 70 struct aq_nic_s *aq_nic = dev_get_drvdata(dev); 71 72 if (!aq_nic) 73 return -EIO; 74 75 if (type != hwmon_temp || attr != hwmon_temp_label) 76 return -EOPNOTSUPP; 77 78 if (channel < ARRAY_SIZE(atl_temp_label)) 79 *str = atl_temp_label[channel]; 80 else 81 return -EOPNOTSUPP; 82 83 return 0; 84 } 85 86 static umode_t aq_hwmon_is_visible(const void *data, 87 enum hwmon_sensor_types type, 88 u32 attr, int channel) 89 { 90 const struct aq_nic_s *nic = data; 91 92 if (type != hwmon_temp) 93 return 0; 94 95 if (channel == 0 && !nic->aq_fw_ops->get_phy_temp) 96 return 0; 97 else if (channel == 1 && !nic->aq_fw_ops->get_mac_temp && 98 !nic->aq_hw_ops->hw_get_mac_temp) 99 return 0; 100 101 switch (attr) { 102 case hwmon_temp_input: 103 case hwmon_temp_label: 104 return 0444; 105 default: 106 return 0; 107 } 108 } 109 110 static const struct hwmon_ops aq_hwmon_ops = { 111 .is_visible = aq_hwmon_is_visible, 112 .read = aq_hwmon_read, 113 .read_string = aq_hwmon_read_string, 114 }; 115 116 static u32 aq_hwmon_temp_config[] = { 117 HWMON_T_INPUT | HWMON_T_LABEL, 118 HWMON_T_INPUT | HWMON_T_LABEL, 119 0, 120 }; 121 122 static const struct hwmon_channel_info aq_hwmon_temp = { 123 .type = hwmon_temp, 124 .config = aq_hwmon_temp_config, 125 }; 126 127 static const struct hwmon_channel_info *aq_hwmon_info[] = { 128 &aq_hwmon_temp, 129 NULL, 130 }; 131 132 static const struct hwmon_chip_info aq_hwmon_chip_info = { 133 .ops = &aq_hwmon_ops, 134 .info = aq_hwmon_info, 135 }; 136 137 int aq_drvinfo_init(struct net_device *ndev) 138 { 139 struct aq_nic_s *aq_nic = netdev_priv(ndev); 140 struct device *dev = &aq_nic->pdev->dev; 141 struct device *hwmon_dev; 142 int err = 0; 143 144 hwmon_dev = devm_hwmon_device_register_with_info(dev, 145 ndev->name, 146 aq_nic, 147 &aq_hwmon_chip_info, 148 NULL); 149 150 if (IS_ERR(hwmon_dev)) 151 err = PTR_ERR(hwmon_dev); 152 153 return err; 154 } 155 156 #else 157 int aq_drvinfo_init(struct net_device *ndev) { return 0; } 158 #endif 159