2 * drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c
3 * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <linux/kernel.h>
36 #include <linux/types.h>
37 #include <linux/device.h>
38 #include <linux/sysfs.h>
39 #include <linux/hwmon.h>
40 #include <linux/err.h>
44 #define MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT 127
45 #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_TEMP_SENSOR_MAX_COUNT * 4 + \
46 MLXSW_MFCR_TACHOS_MAX + MLXSW_MFCR_PWMS_MAX)
48 struct mlxsw_hwmon_attr
{
49 struct device_attribute dev_attr
;
50 struct mlxsw_hwmon
*hwmon
;
51 unsigned int type_index
;
56 struct mlxsw_core
*core
;
57 const struct mlxsw_bus_info
*bus_info
;
58 struct device
*hwmon_dev
;
59 struct attribute_group group
;
60 const struct attribute_group
*groups
[2];
61 struct attribute
*attrs
[MLXSW_HWMON_ATTR_COUNT
+ 1];
62 struct mlxsw_hwmon_attr hwmon_attrs
[MLXSW_HWMON_ATTR_COUNT
];
63 unsigned int attrs_count
;
66 static ssize_t
mlxsw_hwmon_temp_show(struct device
*dev
,
67 struct device_attribute
*attr
,
70 struct mlxsw_hwmon_attr
*mlwsw_hwmon_attr
=
71 container_of(attr
, struct mlxsw_hwmon_attr
, dev_attr
);
72 struct mlxsw_hwmon
*mlxsw_hwmon
= mlwsw_hwmon_attr
->hwmon
;
73 char mtmp_pl
[MLXSW_REG_MTMP_LEN
];
77 mlxsw_reg_mtmp_pack(mtmp_pl
, mlwsw_hwmon_attr
->type_index
,
79 err
= mlxsw_reg_query(mlxsw_hwmon
->core
, MLXSW_REG(mtmp
), mtmp_pl
);
81 dev_err(mlxsw_hwmon
->bus_info
->dev
, "Failed to query temp sensor\n");
84 mlxsw_reg_mtmp_unpack(mtmp_pl
, &temp
, NULL
, NULL
);
85 return sprintf(buf
, "%u\n", temp
);
88 static ssize_t
mlxsw_hwmon_temp_max_show(struct device
*dev
,
89 struct device_attribute
*attr
,
92 struct mlxsw_hwmon_attr
*mlwsw_hwmon_attr
=
93 container_of(attr
, struct mlxsw_hwmon_attr
, dev_attr
);
94 struct mlxsw_hwmon
*mlxsw_hwmon
= mlwsw_hwmon_attr
->hwmon
;
95 char mtmp_pl
[MLXSW_REG_MTMP_LEN
];
96 unsigned int temp_max
;
99 mlxsw_reg_mtmp_pack(mtmp_pl
, mlwsw_hwmon_attr
->type_index
,
101 err
= mlxsw_reg_query(mlxsw_hwmon
->core
, MLXSW_REG(mtmp
), mtmp_pl
);
103 dev_err(mlxsw_hwmon
->bus_info
->dev
, "Failed to query temp sensor\n");
106 mlxsw_reg_mtmp_unpack(mtmp_pl
, NULL
, &temp_max
, NULL
);
107 return sprintf(buf
, "%u\n", temp_max
);
110 static ssize_t
mlxsw_hwmon_temp_rst_store(struct device
*dev
,
111 struct device_attribute
*attr
,
112 const char *buf
, size_t len
)
114 struct mlxsw_hwmon_attr
*mlwsw_hwmon_attr
=
115 container_of(attr
, struct mlxsw_hwmon_attr
, dev_attr
);
116 struct mlxsw_hwmon
*mlxsw_hwmon
= mlwsw_hwmon_attr
->hwmon
;
117 char mtmp_pl
[MLXSW_REG_MTMP_LEN
];
121 err
= kstrtoul(buf
, 10, &val
);
127 mlxsw_reg_mtmp_pack(mtmp_pl
, mlwsw_hwmon_attr
->type_index
, true, true);
128 err
= mlxsw_reg_write(mlxsw_hwmon
->core
, MLXSW_REG(mtmp
), mtmp_pl
);
130 dev_err(mlxsw_hwmon
->bus_info
->dev
, "Failed to reset temp sensor history\n");
136 static ssize_t
mlxsw_hwmon_fan_rpm_show(struct device
*dev
,
137 struct device_attribute
*attr
,
140 struct mlxsw_hwmon_attr
*mlwsw_hwmon_attr
=
141 container_of(attr
, struct mlxsw_hwmon_attr
, dev_attr
);
142 struct mlxsw_hwmon
*mlxsw_hwmon
= mlwsw_hwmon_attr
->hwmon
;
143 char mfsm_pl
[MLXSW_REG_MFSM_LEN
];
146 mlxsw_reg_mfsm_pack(mfsm_pl
, mlwsw_hwmon_attr
->type_index
);
147 err
= mlxsw_reg_query(mlxsw_hwmon
->core
, MLXSW_REG(mfsm
), mfsm_pl
);
149 dev_err(mlxsw_hwmon
->bus_info
->dev
, "Failed to query fan\n");
152 return sprintf(buf
, "%u\n", mlxsw_reg_mfsm_rpm_get(mfsm_pl
));
155 static ssize_t
mlxsw_hwmon_pwm_show(struct device
*dev
,
156 struct device_attribute
*attr
,
159 struct mlxsw_hwmon_attr
*mlwsw_hwmon_attr
=
160 container_of(attr
, struct mlxsw_hwmon_attr
, dev_attr
);
161 struct mlxsw_hwmon
*mlxsw_hwmon
= mlwsw_hwmon_attr
->hwmon
;
162 char mfsc_pl
[MLXSW_REG_MFSC_LEN
];
165 mlxsw_reg_mfsc_pack(mfsc_pl
, mlwsw_hwmon_attr
->type_index
, 0);
166 err
= mlxsw_reg_query(mlxsw_hwmon
->core
, MLXSW_REG(mfsc
), mfsc_pl
);
168 dev_err(mlxsw_hwmon
->bus_info
->dev
, "Failed to query PWM\n");
171 return sprintf(buf
, "%u\n",
172 mlxsw_reg_mfsc_pwm_duty_cycle_get(mfsc_pl
));
175 static ssize_t
mlxsw_hwmon_pwm_store(struct device
*dev
,
176 struct device_attribute
*attr
,
177 const char *buf
, size_t len
)
179 struct mlxsw_hwmon_attr
*mlwsw_hwmon_attr
=
180 container_of(attr
, struct mlxsw_hwmon_attr
, dev_attr
);
181 struct mlxsw_hwmon
*mlxsw_hwmon
= mlwsw_hwmon_attr
->hwmon
;
182 char mfsc_pl
[MLXSW_REG_MFSC_LEN
];
186 err
= kstrtoul(buf
, 10, &val
);
192 mlxsw_reg_mfsc_pack(mfsc_pl
, mlwsw_hwmon_attr
->type_index
, val
);
193 err
= mlxsw_reg_write(mlxsw_hwmon
->core
, MLXSW_REG(mfsc
), mfsc_pl
);
195 dev_err(mlxsw_hwmon
->bus_info
->dev
, "Failed to write PWM\n");
201 enum mlxsw_hwmon_attr_type
{
202 MLXSW_HWMON_ATTR_TYPE_TEMP
,
203 MLXSW_HWMON_ATTR_TYPE_TEMP_MAX
,
204 MLXSW_HWMON_ATTR_TYPE_TEMP_RST
,
205 MLXSW_HWMON_ATTR_TYPE_FAN_RPM
,
206 MLXSW_HWMON_ATTR_TYPE_PWM
,
209 static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon
*mlxsw_hwmon
,
210 enum mlxsw_hwmon_attr_type attr_type
,
211 unsigned int type_index
, unsigned int num
) {
212 struct mlxsw_hwmon_attr
*mlxsw_hwmon_attr
;
213 unsigned int attr_index
;
215 attr_index
= mlxsw_hwmon
->attrs_count
;
216 mlxsw_hwmon_attr
= &mlxsw_hwmon
->hwmon_attrs
[attr_index
];
219 case MLXSW_HWMON_ATTR_TYPE_TEMP
:
220 mlxsw_hwmon_attr
->dev_attr
.show
= mlxsw_hwmon_temp_show
;
221 mlxsw_hwmon_attr
->dev_attr
.attr
.mode
= S_IRUGO
;
222 snprintf(mlxsw_hwmon_attr
->name
, sizeof(mlxsw_hwmon_attr
->name
),
223 "temp%u_input", num
+ 1);
225 case MLXSW_HWMON_ATTR_TYPE_TEMP_MAX
:
226 mlxsw_hwmon_attr
->dev_attr
.show
= mlxsw_hwmon_temp_max_show
;
227 mlxsw_hwmon_attr
->dev_attr
.attr
.mode
= S_IRUGO
;
228 snprintf(mlxsw_hwmon_attr
->name
, sizeof(mlxsw_hwmon_attr
->name
),
229 "temp%u_highest", num
+ 1);
231 case MLXSW_HWMON_ATTR_TYPE_TEMP_RST
:
232 mlxsw_hwmon_attr
->dev_attr
.store
= mlxsw_hwmon_temp_rst_store
;
233 mlxsw_hwmon_attr
->dev_attr
.attr
.mode
= S_IWUSR
;
234 snprintf(mlxsw_hwmon_attr
->name
, sizeof(mlxsw_hwmon_attr
->name
),
235 "temp%u_reset_history", num
+ 1);
237 case MLXSW_HWMON_ATTR_TYPE_FAN_RPM
:
238 mlxsw_hwmon_attr
->dev_attr
.show
= mlxsw_hwmon_fan_rpm_show
;
239 mlxsw_hwmon_attr
->dev_attr
.attr
.mode
= S_IRUGO
;
240 snprintf(mlxsw_hwmon_attr
->name
, sizeof(mlxsw_hwmon_attr
->name
),
241 "fan%u_input", num
+ 1);
243 case MLXSW_HWMON_ATTR_TYPE_PWM
:
244 mlxsw_hwmon_attr
->dev_attr
.show
= mlxsw_hwmon_pwm_show
;
245 mlxsw_hwmon_attr
->dev_attr
.store
= mlxsw_hwmon_pwm_store
;
246 mlxsw_hwmon_attr
->dev_attr
.attr
.mode
= S_IWUSR
| S_IRUGO
;
247 snprintf(mlxsw_hwmon_attr
->name
, sizeof(mlxsw_hwmon_attr
->name
),
254 mlxsw_hwmon_attr
->type_index
= type_index
;
255 mlxsw_hwmon_attr
->hwmon
= mlxsw_hwmon
;
256 mlxsw_hwmon_attr
->dev_attr
.attr
.name
= mlxsw_hwmon_attr
->name
;
257 sysfs_attr_init(&mlxsw_hwmon_attr
->dev_attr
.attr
);
259 mlxsw_hwmon
->attrs
[attr_index
] = &mlxsw_hwmon_attr
->dev_attr
.attr
;
260 mlxsw_hwmon
->attrs_count
++;
263 static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon
*mlxsw_hwmon
)
265 char mtcap_pl
[MLXSW_REG_MTCAP_LEN
] = {0};
266 char mtmp_pl
[MLXSW_REG_MTMP_LEN
];
271 err
= mlxsw_reg_query(mlxsw_hwmon
->core
, MLXSW_REG(mtcap
), mtcap_pl
);
273 dev_err(mlxsw_hwmon
->bus_info
->dev
, "Failed to get number of temp sensors\n");
276 sensor_count
= mlxsw_reg_mtcap_sensor_count_get(mtcap_pl
);
277 for (i
= 0; i
< sensor_count
; i
++) {
278 mlxsw_reg_mtmp_pack(mtmp_pl
, i
, true, true);
279 err
= mlxsw_reg_write(mlxsw_hwmon
->core
,
280 MLXSW_REG(mtmp
), mtmp_pl
);
282 dev_err(mlxsw_hwmon
->bus_info
->dev
, "Failed to setup temp sensor number %d\n",
286 mlxsw_hwmon_attr_add(mlxsw_hwmon
,
287 MLXSW_HWMON_ATTR_TYPE_TEMP
, i
, i
);
288 mlxsw_hwmon_attr_add(mlxsw_hwmon
,
289 MLXSW_HWMON_ATTR_TYPE_TEMP_MAX
, i
, i
);
290 mlxsw_hwmon_attr_add(mlxsw_hwmon
,
291 MLXSW_HWMON_ATTR_TYPE_TEMP_RST
, i
, i
);
296 static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon
*mlxsw_hwmon
)
298 char mfcr_pl
[MLXSW_REG_MFCR_LEN
] = {0};
299 enum mlxsw_reg_mfcr_pwm_frequency freq
;
300 unsigned int type_index
;
306 err
= mlxsw_reg_query(mlxsw_hwmon
->core
, MLXSW_REG(mfcr
), mfcr_pl
);
308 dev_err(mlxsw_hwmon
->bus_info
->dev
, "Failed to get to probe PWMs and Tachometers\n");
311 mlxsw_reg_mfcr_unpack(mfcr_pl
, &freq
, &tacho_active
, &pwm_active
);
313 for (type_index
= 0; type_index
< MLXSW_MFCR_TACHOS_MAX
; type_index
++) {
314 if (tacho_active
& BIT(type_index
))
315 mlxsw_hwmon_attr_add(mlxsw_hwmon
,
316 MLXSW_HWMON_ATTR_TYPE_FAN_RPM
,
320 for (type_index
= 0; type_index
< MLXSW_MFCR_PWMS_MAX
; type_index
++) {
321 if (pwm_active
& BIT(type_index
))
322 mlxsw_hwmon_attr_add(mlxsw_hwmon
,
323 MLXSW_HWMON_ATTR_TYPE_PWM
,
329 int mlxsw_hwmon_init(struct mlxsw_core
*mlxsw_core
,
330 const struct mlxsw_bus_info
*mlxsw_bus_info
,
331 struct mlxsw_hwmon
**p_hwmon
)
333 struct mlxsw_hwmon
*mlxsw_hwmon
;
334 struct device
*hwmon_dev
;
337 mlxsw_hwmon
= devm_kzalloc(mlxsw_bus_info
->dev
, sizeof(*mlxsw_hwmon
),
341 mlxsw_hwmon
->core
= mlxsw_core
;
342 mlxsw_hwmon
->bus_info
= mlxsw_bus_info
;
344 err
= mlxsw_hwmon_temp_init(mlxsw_hwmon
);
348 err
= mlxsw_hwmon_fans_init(mlxsw_hwmon
);
352 mlxsw_hwmon
->groups
[0] = &mlxsw_hwmon
->group
;
353 mlxsw_hwmon
->group
.attrs
= mlxsw_hwmon
->attrs
;
355 hwmon_dev
= devm_hwmon_device_register_with_groups(mlxsw_bus_info
->dev
,
358 mlxsw_hwmon
->groups
);
359 if (IS_ERR(hwmon_dev
)) {
360 err
= PTR_ERR(hwmon_dev
);
361 goto err_hwmon_register
;
364 mlxsw_hwmon
->hwmon_dev
= hwmon_dev
;
365 *p_hwmon
= mlxsw_hwmon
;