162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Atlantic Network Driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2014-2019 aQuantia Corporation
562306a36Sopenharmony_ci * Copyright (C) 2019-2020 Marvell International Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/* File aq_drvinfo.c: Definition of common code for firmware info in sys.*/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/kobject.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/stat.h>
1462306a36Sopenharmony_ci#include <linux/string.h>
1562306a36Sopenharmony_ci#include <linux/hwmon.h>
1662306a36Sopenharmony_ci#include <linux/uaccess.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "aq_drvinfo.h"
1962306a36Sopenharmony_ci#include "aq_nic.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#if IS_REACHABLE(CONFIG_HWMON)
2262306a36Sopenharmony_cistatic const char * const atl_temp_label[] = {
2362306a36Sopenharmony_ci	"PHY Temperature",
2462306a36Sopenharmony_ci	"MAC Temperature",
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int aq_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
2862306a36Sopenharmony_ci			 u32 attr, int channel, long *value)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
3162306a36Sopenharmony_ci	int err = 0;
3262306a36Sopenharmony_ci	int temp;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (!aq_nic)
3562306a36Sopenharmony_ci		return -EIO;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (type != hwmon_temp || attr != hwmon_temp_input)
3862306a36Sopenharmony_ci		return -EOPNOTSUPP;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	switch (channel) {
4162306a36Sopenharmony_ci	case 0:
4262306a36Sopenharmony_ci		if (!aq_nic->aq_fw_ops->get_phy_temp)
4362306a36Sopenharmony_ci			return -EOPNOTSUPP;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci		err = aq_nic->aq_fw_ops->get_phy_temp(aq_nic->aq_hw, &temp);
4662306a36Sopenharmony_ci		*value = temp;
4762306a36Sopenharmony_ci		break;
4862306a36Sopenharmony_ci	case 1:
4962306a36Sopenharmony_ci		if (!aq_nic->aq_fw_ops->get_mac_temp &&
5062306a36Sopenharmony_ci		    !aq_nic->aq_hw_ops->hw_get_mac_temp)
5162306a36Sopenharmony_ci			return -EOPNOTSUPP;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci		if (aq_nic->aq_fw_ops->get_mac_temp)
5462306a36Sopenharmony_ci			err = aq_nic->aq_fw_ops->get_mac_temp(aq_nic->aq_hw, &temp);
5562306a36Sopenharmony_ci		else
5662306a36Sopenharmony_ci			err = aq_nic->aq_hw_ops->hw_get_mac_temp(aq_nic->aq_hw, &temp);
5762306a36Sopenharmony_ci		*value = temp;
5862306a36Sopenharmony_ci		break;
5962306a36Sopenharmony_ci	default:
6062306a36Sopenharmony_ci		return -EOPNOTSUPP;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return err;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic int aq_hwmon_read_string(struct device *dev,
6762306a36Sopenharmony_ci				enum hwmon_sensor_types type,
6862306a36Sopenharmony_ci				u32 attr, int channel, const char **str)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (!aq_nic)
7362306a36Sopenharmony_ci		return -EIO;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (type != hwmon_temp || attr != hwmon_temp_label)
7662306a36Sopenharmony_ci		return -EOPNOTSUPP;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (channel < ARRAY_SIZE(atl_temp_label))
7962306a36Sopenharmony_ci		*str = atl_temp_label[channel];
8062306a36Sopenharmony_ci	else
8162306a36Sopenharmony_ci		return -EOPNOTSUPP;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return 0;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic umode_t aq_hwmon_is_visible(const void *data,
8762306a36Sopenharmony_ci				   enum hwmon_sensor_types type,
8862306a36Sopenharmony_ci				   u32 attr, int channel)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	const struct aq_nic_s *nic = data;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (type != hwmon_temp)
9362306a36Sopenharmony_ci		return 0;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (channel == 0 && !nic->aq_fw_ops->get_phy_temp)
9662306a36Sopenharmony_ci		return 0;
9762306a36Sopenharmony_ci	else if (channel == 1 && !nic->aq_fw_ops->get_mac_temp &&
9862306a36Sopenharmony_ci		 !nic->aq_hw_ops->hw_get_mac_temp)
9962306a36Sopenharmony_ci		return 0;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	switch (attr) {
10262306a36Sopenharmony_ci	case hwmon_temp_input:
10362306a36Sopenharmony_ci	case hwmon_temp_label:
10462306a36Sopenharmony_ci		return 0444;
10562306a36Sopenharmony_ci	default:
10662306a36Sopenharmony_ci		return 0;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic const struct hwmon_ops aq_hwmon_ops = {
11162306a36Sopenharmony_ci	.is_visible = aq_hwmon_is_visible,
11262306a36Sopenharmony_ci	.read = aq_hwmon_read,
11362306a36Sopenharmony_ci	.read_string = aq_hwmon_read_string,
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic u32 aq_hwmon_temp_config[] = {
11762306a36Sopenharmony_ci	HWMON_T_INPUT | HWMON_T_LABEL,
11862306a36Sopenharmony_ci	HWMON_T_INPUT | HWMON_T_LABEL,
11962306a36Sopenharmony_ci	0,
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic const struct hwmon_channel_info aq_hwmon_temp = {
12362306a36Sopenharmony_ci	.type = hwmon_temp,
12462306a36Sopenharmony_ci	.config = aq_hwmon_temp_config,
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const struct hwmon_channel_info * const aq_hwmon_info[] = {
12862306a36Sopenharmony_ci	&aq_hwmon_temp,
12962306a36Sopenharmony_ci	NULL,
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic const struct hwmon_chip_info aq_hwmon_chip_info = {
13362306a36Sopenharmony_ci	.ops = &aq_hwmon_ops,
13462306a36Sopenharmony_ci	.info = aq_hwmon_info,
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ciint aq_drvinfo_init(struct net_device *ndev)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct aq_nic_s *aq_nic = netdev_priv(ndev);
14062306a36Sopenharmony_ci	struct device *dev = &aq_nic->pdev->dev;
14162306a36Sopenharmony_ci	struct device *hwmon_dev;
14262306a36Sopenharmony_ci	int err = 0;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_info(dev,
14562306a36Sopenharmony_ci							 ndev->name,
14662306a36Sopenharmony_ci							 aq_nic,
14762306a36Sopenharmony_ci							 &aq_hwmon_chip_info,
14862306a36Sopenharmony_ci							 NULL);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (IS_ERR(hwmon_dev))
15162306a36Sopenharmony_ci		err = PTR_ERR(hwmon_dev);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return err;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#else
15762306a36Sopenharmony_ciint aq_drvinfo_init(struct net_device *ndev) { return 0; }
15862306a36Sopenharmony_ci#endif
159