117f54a3bSIgor Russkikh // SPDX-License-Identifier: GPL-2.0-only
28dcf2ad3SMark Starovoytov /* Atlantic Network Driver
38dcf2ad3SMark Starovoytov *
48dcf2ad3SMark Starovoytov * Copyright (C) 2014-2019 aQuantia Corporation
58dcf2ad3SMark Starovoytov * Copyright (C) 2019-2020 Marvell International Ltd.
68dcf2ad3SMark Starovoytov */
74c013153SYana Esina
84c013153SYana Esina /* File aq_drvinfo.c: Definition of common code for firmware info in sys.*/
94c013153SYana Esina
104c013153SYana Esina #include <linux/init.h>
114c013153SYana Esina #include <linux/kobject.h>
124c013153SYana Esina #include <linux/module.h>
134c013153SYana Esina #include <linux/stat.h>
144c013153SYana Esina #include <linux/string.h>
154c013153SYana Esina #include <linux/hwmon.h>
164c013153SYana Esina #include <linux/uaccess.h>
174c013153SYana Esina
184c013153SYana Esina #include "aq_drvinfo.h"
198dcf2ad3SMark Starovoytov #include "aq_nic.h"
204c013153SYana Esina
2170610c92SKefeng Wang #if IS_REACHABLE(CONFIG_HWMON)
228dcf2ad3SMark Starovoytov static const char * const atl_temp_label[] = {
238dcf2ad3SMark Starovoytov "PHY Temperature",
248dcf2ad3SMark Starovoytov "MAC Temperature",
258dcf2ad3SMark Starovoytov };
268dcf2ad3SMark Starovoytov
aq_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * value)274c013153SYana Esina static int aq_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
284c013153SYana Esina u32 attr, int channel, long *value)
294c013153SYana Esina {
304c013153SYana Esina struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
318dcf2ad3SMark Starovoytov int err = 0;
324c013153SYana Esina int temp;
334c013153SYana Esina
344c013153SYana Esina if (!aq_nic)
354c013153SYana Esina return -EIO;
364c013153SYana Esina
378dcf2ad3SMark Starovoytov if (type != hwmon_temp || attr != hwmon_temp_input)
384c013153SYana Esina return -EOPNOTSUPP;
394c013153SYana Esina
408dcf2ad3SMark Starovoytov switch (channel) {
418dcf2ad3SMark Starovoytov case 0:
424c013153SYana Esina if (!aq_nic->aq_fw_ops->get_phy_temp)
434c013153SYana Esina return -EOPNOTSUPP;
444c013153SYana Esina
454c013153SYana Esina err = aq_nic->aq_fw_ops->get_phy_temp(aq_nic->aq_hw, &temp);
464c013153SYana Esina *value = temp;
478dcf2ad3SMark Starovoytov break;
488dcf2ad3SMark Starovoytov case 1:
498dcf2ad3SMark Starovoytov if (!aq_nic->aq_fw_ops->get_mac_temp &&
508dcf2ad3SMark Starovoytov !aq_nic->aq_hw_ops->hw_get_mac_temp)
518dcf2ad3SMark Starovoytov return -EOPNOTSUPP;
528dcf2ad3SMark Starovoytov
538dcf2ad3SMark Starovoytov if (aq_nic->aq_fw_ops->get_mac_temp)
548dcf2ad3SMark Starovoytov err = aq_nic->aq_fw_ops->get_mac_temp(aq_nic->aq_hw, &temp);
558dcf2ad3SMark Starovoytov else
568dcf2ad3SMark Starovoytov err = aq_nic->aq_hw_ops->hw_get_mac_temp(aq_nic->aq_hw, &temp);
578dcf2ad3SMark Starovoytov *value = temp;
588dcf2ad3SMark Starovoytov break;
594c013153SYana Esina default:
604c013153SYana Esina return -EOPNOTSUPP;
614c013153SYana Esina }
628dcf2ad3SMark Starovoytov
638dcf2ad3SMark Starovoytov return err;
644c013153SYana Esina }
654c013153SYana Esina
aq_hwmon_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)664c013153SYana Esina static int aq_hwmon_read_string(struct device *dev,
674c013153SYana Esina enum hwmon_sensor_types type,
684c013153SYana Esina u32 attr, int channel, const char **str)
694c013153SYana Esina {
704c013153SYana Esina struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
714c013153SYana Esina
724c013153SYana Esina if (!aq_nic)
734c013153SYana Esina return -EIO;
744c013153SYana Esina
758dcf2ad3SMark Starovoytov if (type != hwmon_temp || attr != hwmon_temp_label)
764c013153SYana Esina return -EOPNOTSUPP;
774c013153SYana Esina
788dcf2ad3SMark Starovoytov if (channel < ARRAY_SIZE(atl_temp_label))
798dcf2ad3SMark Starovoytov *str = atl_temp_label[channel];
808dcf2ad3SMark Starovoytov else
814c013153SYana Esina return -EOPNOTSUPP;
824c013153SYana Esina
834c013153SYana Esina return 0;
844c013153SYana Esina }
854c013153SYana Esina
aq_hwmon_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)864c013153SYana Esina static umode_t aq_hwmon_is_visible(const void *data,
874c013153SYana Esina enum hwmon_sensor_types type,
884c013153SYana Esina u32 attr, int channel)
894c013153SYana Esina {
908dcf2ad3SMark Starovoytov const struct aq_nic_s *nic = data;
918dcf2ad3SMark Starovoytov
924c013153SYana Esina if (type != hwmon_temp)
934c013153SYana Esina return 0;
944c013153SYana Esina
958dcf2ad3SMark Starovoytov if (channel == 0 && !nic->aq_fw_ops->get_phy_temp)
968dcf2ad3SMark Starovoytov return 0;
978dcf2ad3SMark Starovoytov else if (channel == 1 && !nic->aq_fw_ops->get_mac_temp &&
988dcf2ad3SMark Starovoytov !nic->aq_hw_ops->hw_get_mac_temp)
998dcf2ad3SMark Starovoytov return 0;
1008dcf2ad3SMark Starovoytov
1014c013153SYana Esina switch (attr) {
1024c013153SYana Esina case hwmon_temp_input:
1034c013153SYana Esina case hwmon_temp_label:
1044c013153SYana Esina return 0444;
1054c013153SYana Esina default:
1064c013153SYana Esina return 0;
1074c013153SYana Esina }
1084c013153SYana Esina }
1094c013153SYana Esina
1104c013153SYana Esina static const struct hwmon_ops aq_hwmon_ops = {
1114c013153SYana Esina .is_visible = aq_hwmon_is_visible,
1124c013153SYana Esina .read = aq_hwmon_read,
1134c013153SYana Esina .read_string = aq_hwmon_read_string,
1144c013153SYana Esina };
1154c013153SYana Esina
1164c013153SYana Esina static u32 aq_hwmon_temp_config[] = {
1174c013153SYana Esina HWMON_T_INPUT | HWMON_T_LABEL,
1188dcf2ad3SMark Starovoytov HWMON_T_INPUT | HWMON_T_LABEL,
1194c013153SYana Esina 0,
1204c013153SYana Esina };
1214c013153SYana Esina
1224c013153SYana Esina static const struct hwmon_channel_info aq_hwmon_temp = {
1234c013153SYana Esina .type = hwmon_temp,
1244c013153SYana Esina .config = aq_hwmon_temp_config,
1254c013153SYana Esina };
1264c013153SYana Esina
127*bc1585f6SKrzysztof Kozlowski static const struct hwmon_channel_info * const aq_hwmon_info[] = {
1284c013153SYana Esina &aq_hwmon_temp,
1294c013153SYana Esina NULL,
1304c013153SYana Esina };
1314c013153SYana Esina
1324c013153SYana Esina static const struct hwmon_chip_info aq_hwmon_chip_info = {
1334c013153SYana Esina .ops = &aq_hwmon_ops,
1344c013153SYana Esina .info = aq_hwmon_info,
1354c013153SYana Esina };
1364c013153SYana Esina
aq_drvinfo_init(struct net_device * ndev)1374c013153SYana Esina int aq_drvinfo_init(struct net_device *ndev)
1384c013153SYana Esina {
1394c013153SYana Esina struct aq_nic_s *aq_nic = netdev_priv(ndev);
1404c013153SYana Esina struct device *dev = &aq_nic->pdev->dev;
1414c013153SYana Esina struct device *hwmon_dev;
1424c013153SYana Esina int err = 0;
1434c013153SYana Esina
1444c013153SYana Esina hwmon_dev = devm_hwmon_device_register_with_info(dev,
1454c013153SYana Esina ndev->name,
1464c013153SYana Esina aq_nic,
1474c013153SYana Esina &aq_hwmon_chip_info,
1484c013153SYana Esina NULL);
1494c013153SYana Esina
1504c013153SYana Esina if (IS_ERR(hwmon_dev))
1514c013153SYana Esina err = PTR_ERR(hwmon_dev);
1524c013153SYana Esina
1534c013153SYana Esina return err;
1544c013153SYana Esina }
15570610c92SKefeng Wang
15670610c92SKefeng Wang #else
aq_drvinfo_init(struct net_device * ndev)15770610c92SKefeng Wang int aq_drvinfo_init(struct net_device *ndev) { return 0; }
15870610c92SKefeng Wang #endif
159