aq_drvinfo.c 3.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
2 3 4 5 6
/* Atlantic Network Driver
 *
 * Copyright (C) 2014-2019 aQuantia Corporation
 * Copyright (C) 2019-2020 Marvell International Ltd.
 */
7 8 9 10 11 12 13 14 15 16 17 18

/* File aq_drvinfo.c: Definition of common code for firmware info in sys.*/

#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/hwmon.h>
#include <linux/uaccess.h>

#include "aq_drvinfo.h"
19
#include "aq_nic.h"
20

21
#if IS_REACHABLE(CONFIG_HWMON)
22 23 24 25 26
static const char * const atl_temp_label[] = {
	"PHY Temperature",
	"MAC Temperature",
};

27 28 29 30
static int aq_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
			 u32 attr, int channel, long *value)
{
	struct aq_nic_s *aq_nic = dev_get_drvdata(dev);
31
	int err = 0;
32 33 34 35 36
	int temp;

	if (!aq_nic)
		return -EIO;

37
	if (type != hwmon_temp || attr != hwmon_temp_input)
38 39
		return -EOPNOTSUPP;

40 41 42 43
	switch (channel) {
	case 0:
		if (!aq_nic->aq_fw_ops->get_phy_temp)
			return -EOPNOTSUPP;
44 45 46

		err = aq_nic->aq_fw_ops->get_phy_temp(aq_nic->aq_hw, &temp);
		*value = temp;
47 48 49 50 51 52 53 54 55 56 57 58
		break;
	case 1:
		if (!aq_nic->aq_fw_ops->get_mac_temp &&
		    !aq_nic->aq_hw_ops->hw_get_mac_temp)
			return -EOPNOTSUPP;

		if (aq_nic->aq_fw_ops->get_mac_temp)
			err = aq_nic->aq_fw_ops->get_mac_temp(aq_nic->aq_hw, &temp);
		else
			err = aq_nic->aq_hw_ops->hw_get_mac_temp(aq_nic->aq_hw, &temp);
		*value = temp;
		break;
59 60 61
	default:
		return -EOPNOTSUPP;
	}
62 63

	return err;
64 65 66 67 68 69 70 71 72 73 74
}

static int aq_hwmon_read_string(struct device *dev,
				enum hwmon_sensor_types type,
				u32 attr, int channel, const char **str)
{
	struct aq_nic_s *aq_nic = dev_get_drvdata(dev);

	if (!aq_nic)
		return -EIO;

75
	if (type != hwmon_temp || attr != hwmon_temp_label)
76 77
		return -EOPNOTSUPP;

78 79 80
	if (channel < ARRAY_SIZE(atl_temp_label))
		*str = atl_temp_label[channel];
	else
81 82
		return -EOPNOTSUPP;

83
	return 0;
84 85 86 87 88 89
}

static umode_t aq_hwmon_is_visible(const void *data,
				   enum hwmon_sensor_types type,
				   u32 attr, int channel)
{
90 91
	const struct aq_nic_s *nic = data;

92 93 94
	if (type != hwmon_temp)
		return 0;

95 96 97 98 99 100
	if (channel == 0 && !nic->aq_fw_ops->get_phy_temp)
		return 0;
	else if (channel == 1 && !nic->aq_fw_ops->get_mac_temp &&
		 !nic->aq_hw_ops->hw_get_mac_temp)
		return 0;

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
	switch (attr) {
	case hwmon_temp_input:
	case hwmon_temp_label:
		return 0444;
	default:
		return 0;
	}
}

static const struct hwmon_ops aq_hwmon_ops = {
	.is_visible = aq_hwmon_is_visible,
	.read = aq_hwmon_read,
	.read_string = aq_hwmon_read_string,
};

static u32 aq_hwmon_temp_config[] = {
117
	HWMON_T_INPUT | HWMON_T_LABEL,
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
	HWMON_T_INPUT | HWMON_T_LABEL,
	0,
};

static const struct hwmon_channel_info aq_hwmon_temp = {
	.type = hwmon_temp,
	.config = aq_hwmon_temp_config,
};

static const struct hwmon_channel_info *aq_hwmon_info[] = {
	&aq_hwmon_temp,
	NULL,
};

static const struct hwmon_chip_info aq_hwmon_chip_info = {
	.ops = &aq_hwmon_ops,
	.info = aq_hwmon_info,
};

int aq_drvinfo_init(struct net_device *ndev)
{
	struct aq_nic_s *aq_nic = netdev_priv(ndev);
	struct device *dev = &aq_nic->pdev->dev;
	struct device *hwmon_dev;
	int err = 0;

	hwmon_dev = devm_hwmon_device_register_with_info(dev,
							 ndev->name,
							 aq_nic,
							 &aq_hwmon_chip_info,
							 NULL);

	if (IS_ERR(hwmon_dev))
		err = PTR_ERR(hwmon_dev);

	return err;
}
155 156 157 158

#else
int aq_drvinfo_init(struct net_device *ndev) { return 0; }
#endif