3a9cdf0b22b8d363cf443c3c6d8c47f7b521f5c3
[platform/kernel/linux-starfive.git] / net / dsa / hwmon.c
1 /*
2  * net/dsa/hwmon.c - HWMON subsystem support
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  */
9
10 #include <linux/ctype.h>
11 #include <linux/hwmon.h>
12 #include <net/dsa.h>
13
14 #include "dsa_priv.h"
15
16 static ssize_t temp1_input_show(struct device *dev,
17                                 struct device_attribute *attr, char *buf)
18 {
19         struct dsa_switch *ds = dev_get_drvdata(dev);
20         int temp, ret;
21
22         ret = ds->ops->get_temp(ds, &temp);
23         if (ret < 0)
24                 return ret;
25
26         return sprintf(buf, "%d\n", temp * 1000);
27 }
28 static DEVICE_ATTR_RO(temp1_input);
29
30 static ssize_t temp1_max_show(struct device *dev,
31                               struct device_attribute *attr, char *buf)
32 {
33         struct dsa_switch *ds = dev_get_drvdata(dev);
34         int temp, ret;
35
36         ret = ds->ops->get_temp_limit(ds, &temp);
37         if (ret < 0)
38                 return ret;
39
40         return sprintf(buf, "%d\n", temp * 1000);
41 }
42
43 static ssize_t temp1_max_store(struct device *dev,
44                                struct device_attribute *attr, const char *buf,
45                                size_t count)
46 {
47         struct dsa_switch *ds = dev_get_drvdata(dev);
48         int temp, ret;
49
50         ret = kstrtoint(buf, 0, &temp);
51         if (ret < 0)
52                 return ret;
53
54         ret = ds->ops->set_temp_limit(ds, DIV_ROUND_CLOSEST(temp, 1000));
55         if (ret < 0)
56                 return ret;
57
58         return count;
59 }
60 static DEVICE_ATTR_RW(temp1_max);
61
62 static ssize_t temp1_max_alarm_show(struct device *dev,
63                                     struct device_attribute *attr, char *buf)
64 {
65         struct dsa_switch *ds = dev_get_drvdata(dev);
66         bool alarm;
67         int ret;
68
69         ret = ds->ops->get_temp_alarm(ds, &alarm);
70         if (ret < 0)
71                 return ret;
72
73         return sprintf(buf, "%d\n", alarm);
74 }
75 static DEVICE_ATTR_RO(temp1_max_alarm);
76
77 static struct attribute *dsa_hwmon_attrs[] = {
78         &dev_attr_temp1_input.attr,     /* 0 */
79         &dev_attr_temp1_max.attr,       /* 1 */
80         &dev_attr_temp1_max_alarm.attr, /* 2 */
81         NULL
82 };
83
84 static umode_t dsa_hwmon_attrs_visible(struct kobject *kobj,
85                                        struct attribute *attr, int index)
86 {
87         struct device *dev = container_of(kobj, struct device, kobj);
88         struct dsa_switch *ds = dev_get_drvdata(dev);
89         struct dsa_switch_ops *ops = ds->ops;
90         umode_t mode = attr->mode;
91
92         if (index == 1) {
93                 if (!ops->get_temp_limit)
94                         mode = 0;
95                 else if (!ops->set_temp_limit)
96                         mode &= ~S_IWUSR;
97         } else if (index == 2 && !ops->get_temp_alarm) {
98                 mode = 0;
99         }
100         return mode;
101 }
102
103 static const struct attribute_group dsa_hwmon_group = {
104         .attrs = dsa_hwmon_attrs,
105         .is_visible = dsa_hwmon_attrs_visible,
106 };
107 __ATTRIBUTE_GROUPS(dsa_hwmon);
108
109 void dsa_hwmon_register(struct dsa_switch *ds)
110 {
111         const char *netname = netdev_name(ds->dst->master_netdev);
112         char hname[IFNAMSIZ + 1];
113         int i, j;
114
115         /* If the switch provides temperature accessors, register with hardware
116          * monitoring subsystem. Treat registration error as non-fatal.
117          */
118         if (!ds->ops->get_temp)
119                 return;
120
121         /* Create valid hwmon 'name' attribute */
122         for (i = j = 0; i < IFNAMSIZ && netname[i]; i++) {
123                 if (isalnum(netname[i]))
124                         hname[j++] = netname[i];
125         }
126         hname[j] = '\0';
127         scnprintf(ds->hwmon_name, sizeof(ds->hwmon_name), "%s_dsa%d", hname,
128                   ds->index);
129         ds->hwmon_dev = hwmon_device_register_with_groups(NULL, ds->hwmon_name,
130                                                           ds, dsa_hwmon_groups);
131         if (IS_ERR(ds->hwmon_dev)) {
132                 pr_warn("DSA: failed to register HWMON subsystem for switch %d\n",
133                         ds->index);
134                 ds->hwmon_dev = NULL;
135         } else {
136                 pr_info("DSA: registered HWMON subsystem for switch %d\n",
137                         ds->index);
138         }
139 }
140
141 void dsa_hwmon_unregister(struct dsa_switch *ds)
142 {
143         if (ds->hwmon_dev) {
144                 hwmon_device_unregister(ds->hwmon_dev);
145                 ds->hwmon_dev = NULL;
146         }
147 }