xref: /openbmc/linux/drivers/hwmon/mlxreg-fan.c (revision e8ffca61)
1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2 //
3 // Copyright (c) 2018 Mellanox Technologies. All rights reserved.
4 // Copyright (c) 2018 Vadim Pasternak <vadimp@mellanox.com>
5 
6 #include <linux/bitops.h>
7 #include <linux/device.h>
8 #include <linux/hwmon.h>
9 #include <linux/module.h>
10 #include <linux/platform_data/mlxreg.h>
11 #include <linux/platform_device.h>
12 #include <linux/regmap.h>
13 #include <linux/thermal.h>
14 
15 #define MLXREG_FAN_MAX_TACHO		14
16 #define MLXREG_FAN_MAX_PWM		4
17 #define MLXREG_FAN_PWM_NOT_CONNECTED	0xff
18 #define MLXREG_FAN_MAX_STATE		10
19 #define MLXREG_FAN_MIN_DUTY		51	/* 20% */
20 #define MLXREG_FAN_MAX_DUTY		255	/* 100% */
21 /*
22  * Minimum and maximum FAN allowed speed in percent: from 20% to 100%. Values
23  * MLXREG_FAN_MAX_STATE + x, where x is between 2 and 10 are used for
24  * setting FAN speed dynamic minimum. For example, if value is set to 14 (40%)
25  * cooling levels vector will be set to 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10 to
26  * introduce PWM speed in percent: 40, 40, 40, 40, 40, 50, 60. 70, 80, 90, 100.
27  */
28 #define MLXREG_FAN_SPEED_MIN			(MLXREG_FAN_MAX_STATE + 2)
29 #define MLXREG_FAN_SPEED_MAX			(MLXREG_FAN_MAX_STATE * 2)
30 #define MLXREG_FAN_SPEED_MIN_LEVEL		2	/* 20 percent */
31 #define MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF	44
32 #define MLXREG_FAN_TACHO_DIV_MIN		283
33 #define MLXREG_FAN_TACHO_DIV_DEF		(MLXREG_FAN_TACHO_DIV_MIN * 4)
34 #define MLXREG_FAN_TACHO_DIV_SCALE_MAX	64
35 /*
36  * FAN datasheet defines the formula for RPM calculations as RPM = 15/t-high.
37  * The logic in a programmable device measures the time t-high by sampling the
38  * tachometer every t-sample (with the default value 11.32 uS) and increment
39  * a counter (N) as long as the pulse has not change:
40  * RPM = 15 / (t-sample * (K + Regval)), where:
41  * Regval: is the value read from the programmable device register;
42  *  - 0xff - represents tachometer fault;
43  *  - 0xfe - represents tachometer minimum value , which is 4444 RPM;
44  *  - 0x00 - represents tachometer maximum value , which is 300000 RPM;
45  * K: is 44 and it represents the minimum allowed samples per pulse;
46  * N: is equal K + Regval;
47  * In order to calculate RPM from the register value the following formula is
48  * used: RPM = 15 / ((Regval + K) * 11.32) * 10^(-6)), which in  the
49  * default case is modified to:
50  * RPM = 15000000 * 100 / ((Regval + 44) * 1132);
51  * - for Regval 0x00, RPM will be 15000000 * 100 / (44 * 1132) = 30115;
52  * - for Regval 0xfe, RPM will be 15000000 * 100 / ((254 + 44) * 1132) = 4446;
53  * In common case the formula is modified to:
54  * RPM = 15000000 * 100 / ((Regval + samples) * divider).
55  */
56 #define MLXREG_FAN_GET_RPM(rval, d, s)	(DIV_ROUND_CLOSEST(15000000 * 100, \
57 					 ((rval) + (s)) * (d)))
58 #define MLXREG_FAN_GET_FAULT(val, mask) ((val) == (mask))
59 #define MLXREG_FAN_PWM_DUTY2STATE(duty)	(DIV_ROUND_CLOSEST((duty) *	\
60 					 MLXREG_FAN_MAX_STATE,		\
61 					 MLXREG_FAN_MAX_DUTY))
62 #define MLXREG_FAN_PWM_STATE2DUTY(stat)	(DIV_ROUND_CLOSEST((stat) *	\
63 					 MLXREG_FAN_MAX_DUTY,		\
64 					 MLXREG_FAN_MAX_STATE))
65 
66 struct mlxreg_fan;
67 
68 /*
69  * struct mlxreg_fan_tacho - tachometer data (internal use):
70  *
71  * @connected: indicates if tachometer is connected;
72  * @reg: register offset;
73  * @mask: fault mask;
74  * @prsnt: present register offset;
75  */
76 struct mlxreg_fan_tacho {
77 	bool connected;
78 	u32 reg;
79 	u32 mask;
80 	u32 prsnt;
81 };
82 
83 /*
84  * struct mlxreg_fan_pwm - PWM data (internal use):
85  *
86  * @fan: private data;
87  * @connected: indicates if PWM is connected;
88  * @reg: register offset;
89  * @cooling: cooling device levels;
90  * @cdev: cooling device;
91  */
92 struct mlxreg_fan_pwm {
93 	struct mlxreg_fan *fan;
94 	bool connected;
95 	u32 reg;
96 	u8 cooling_levels[MLXREG_FAN_MAX_STATE + 1];
97 	struct thermal_cooling_device *cdev;
98 };
99 
100 /*
101  * struct mlxreg_fan - private data (internal use):
102  *
103  * @dev: basic device;
104  * @regmap: register map of parent device;
105  * @tacho: tachometer data;
106  * @pwm: PWM data;
107  * @tachos_per_drwr - number of tachometers per drawer;
108  * @samples: minimum allowed samples per pulse;
109  * @divider: divider value for tachometer RPM calculation;
110  */
111 struct mlxreg_fan {
112 	struct device *dev;
113 	void *regmap;
114 	struct mlxreg_core_platform_data *pdata;
115 	struct mlxreg_fan_tacho tacho[MLXREG_FAN_MAX_TACHO];
116 	struct mlxreg_fan_pwm pwm[MLXREG_FAN_MAX_PWM];
117 	int tachos_per_drwr;
118 	int samples;
119 	int divider;
120 };
121 
122 static int
123 mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
124 		int channel, long *val)
125 {
126 	struct mlxreg_fan *fan = dev_get_drvdata(dev);
127 	struct mlxreg_fan_tacho *tacho;
128 	struct mlxreg_fan_pwm *pwm;
129 	u32 regval;
130 	int err;
131 
132 	switch (type) {
133 	case hwmon_fan:
134 		tacho = &fan->tacho[channel];
135 		switch (attr) {
136 		case hwmon_fan_input:
137 			/*
138 			 * Check FAN presence: FAN related bit in presence register is one,
139 			 * if FAN is physically connected, zero - otherwise.
140 			 */
141 			if (tacho->prsnt && fan->tachos_per_drwr) {
142 				err = regmap_read(fan->regmap, tacho->prsnt, &regval);
143 				if (err)
144 					return err;
145 
146 				/*
147 				 * Map channel to presence bit - drawer can be equipped with
148 				 * one or few FANs, while presence is indicated per drawer.
149 				 */
150 				if (BIT(channel / fan->tachos_per_drwr) & regval) {
151 					/* FAN is not connected - return zero for FAN speed. */
152 					*val = 0;
153 					return 0;
154 				}
155 			}
156 
157 			err = regmap_read(fan->regmap, tacho->reg, &regval);
158 			if (err)
159 				return err;
160 
161 			*val = MLXREG_FAN_GET_RPM(regval, fan->divider,
162 						  fan->samples);
163 			break;
164 
165 		case hwmon_fan_fault:
166 			err = regmap_read(fan->regmap, tacho->reg, &regval);
167 			if (err)
168 				return err;
169 
170 			*val = MLXREG_FAN_GET_FAULT(regval, tacho->mask);
171 			break;
172 
173 		default:
174 			return -EOPNOTSUPP;
175 		}
176 		break;
177 
178 	case hwmon_pwm:
179 		pwm = &fan->pwm[channel];
180 		switch (attr) {
181 		case hwmon_pwm_input:
182 			err = regmap_read(fan->regmap, pwm->reg, &regval);
183 			if (err)
184 				return err;
185 
186 			*val = regval;
187 			break;
188 
189 		default:
190 			return -EOPNOTSUPP;
191 		}
192 		break;
193 
194 	default:
195 		return -EOPNOTSUPP;
196 	}
197 
198 	return 0;
199 }
200 
201 static int
202 mlxreg_fan_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
203 		 int channel, long val)
204 {
205 	struct mlxreg_fan *fan = dev_get_drvdata(dev);
206 	struct mlxreg_fan_pwm *pwm;
207 
208 	switch (type) {
209 	case hwmon_pwm:
210 		switch (attr) {
211 		case hwmon_pwm_input:
212 			if (val < MLXREG_FAN_MIN_DUTY ||
213 			    val > MLXREG_FAN_MAX_DUTY)
214 				return -EINVAL;
215 			pwm = &fan->pwm[channel];
216 			return regmap_write(fan->regmap, pwm->reg, val);
217 		default:
218 			return -EOPNOTSUPP;
219 		}
220 		break;
221 
222 	default:
223 		return -EOPNOTSUPP;
224 	}
225 
226 	return -EOPNOTSUPP;
227 }
228 
229 static umode_t
230 mlxreg_fan_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
231 		      int channel)
232 {
233 	switch (type) {
234 	case hwmon_fan:
235 		if (!(((struct mlxreg_fan *)data)->tacho[channel].connected))
236 			return 0;
237 
238 		switch (attr) {
239 		case hwmon_fan_input:
240 		case hwmon_fan_fault:
241 			return 0444;
242 		default:
243 			break;
244 		}
245 		break;
246 
247 	case hwmon_pwm:
248 		if (!(((struct mlxreg_fan *)data)->pwm[channel].connected))
249 			return 0;
250 
251 		switch (attr) {
252 		case hwmon_pwm_input:
253 			return 0644;
254 		default:
255 			break;
256 		}
257 		break;
258 
259 	default:
260 		break;
261 	}
262 
263 	return 0;
264 }
265 
266 static char *mlxreg_fan_name[] = {
267 	"mlxreg_fan",
268 	"mlxreg_fan1",
269 	"mlxreg_fan2",
270 	"mlxreg_fan3",
271 };
272 
273 static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = {
274 	HWMON_CHANNEL_INFO(fan,
275 			   HWMON_F_INPUT | HWMON_F_FAULT,
276 			   HWMON_F_INPUT | HWMON_F_FAULT,
277 			   HWMON_F_INPUT | HWMON_F_FAULT,
278 			   HWMON_F_INPUT | HWMON_F_FAULT,
279 			   HWMON_F_INPUT | HWMON_F_FAULT,
280 			   HWMON_F_INPUT | HWMON_F_FAULT,
281 			   HWMON_F_INPUT | HWMON_F_FAULT,
282 			   HWMON_F_INPUT | HWMON_F_FAULT,
283 			   HWMON_F_INPUT | HWMON_F_FAULT,
284 			   HWMON_F_INPUT | HWMON_F_FAULT,
285 			   HWMON_F_INPUT | HWMON_F_FAULT,
286 			   HWMON_F_INPUT | HWMON_F_FAULT,
287 			   HWMON_F_INPUT | HWMON_F_FAULT,
288 			   HWMON_F_INPUT | HWMON_F_FAULT),
289 	HWMON_CHANNEL_INFO(pwm,
290 			   HWMON_PWM_INPUT,
291 			   HWMON_PWM_INPUT,
292 			   HWMON_PWM_INPUT,
293 			   HWMON_PWM_INPUT),
294 	NULL
295 };
296 
297 static const struct hwmon_ops mlxreg_fan_hwmon_hwmon_ops = {
298 	.is_visible = mlxreg_fan_is_visible,
299 	.read = mlxreg_fan_read,
300 	.write = mlxreg_fan_write,
301 };
302 
303 static const struct hwmon_chip_info mlxreg_fan_hwmon_chip_info = {
304 	.ops = &mlxreg_fan_hwmon_hwmon_ops,
305 	.info = mlxreg_fan_hwmon_info,
306 };
307 
308 static int mlxreg_fan_get_max_state(struct thermal_cooling_device *cdev,
309 				    unsigned long *state)
310 {
311 	*state = MLXREG_FAN_MAX_STATE;
312 	return 0;
313 }
314 
315 static int mlxreg_fan_get_cur_state(struct thermal_cooling_device *cdev,
316 				    unsigned long *state)
317 
318 {
319 	struct mlxreg_fan_pwm *pwm = cdev->devdata;
320 	struct mlxreg_fan *fan = pwm->fan;
321 	u32 regval;
322 	int err;
323 
324 	err = regmap_read(fan->regmap, pwm->reg, &regval);
325 	if (err) {
326 		dev_err(fan->dev, "Failed to query PWM duty\n");
327 		return err;
328 	}
329 
330 	*state = MLXREG_FAN_PWM_DUTY2STATE(regval);
331 
332 	return 0;
333 }
334 
335 static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev,
336 				    unsigned long state)
337 
338 {
339 	struct mlxreg_fan_pwm *pwm = cdev->devdata;
340 	struct mlxreg_fan *fan = pwm->fan;
341 	unsigned long cur_state;
342 	int i, config = 0;
343 	u32 regval;
344 	int err;
345 
346 	/*
347 	 * Verify if this request is for changing allowed FAN dynamical
348 	 * minimum. If it is - update cooling levels accordingly and update
349 	 * state, if current state is below the newly requested minimum state.
350 	 * For example, if current state is 5, and minimal state is to be
351 	 * changed from 4 to 6, fan->cooling_levels[0 to 5] will be changed all
352 	 * from 4 to 6. And state 5 (fan->cooling_levels[4]) should be
353 	 * overwritten.
354 	 */
355 	if (state >= MLXREG_FAN_SPEED_MIN && state <= MLXREG_FAN_SPEED_MAX) {
356 		/*
357 		 * This is configuration change, which is only supported through sysfs.
358 		 * For configuration non-zero value is to be returned to avoid thermal
359 		 * statistics update.
360 		 */
361 		config = 1;
362 		state -= MLXREG_FAN_MAX_STATE;
363 		for (i = 0; i < state; i++)
364 			pwm->cooling_levels[i] = state;
365 		for (i = state; i <= MLXREG_FAN_MAX_STATE; i++)
366 			pwm->cooling_levels[i] = i;
367 
368 		err = regmap_read(fan->regmap, pwm->reg, &regval);
369 		if (err) {
370 			dev_err(fan->dev, "Failed to query PWM duty\n");
371 			return err;
372 		}
373 
374 		cur_state = MLXREG_FAN_PWM_DUTY2STATE(regval);
375 		if (state < cur_state)
376 			return config;
377 
378 		state = cur_state;
379 	}
380 
381 	if (state > MLXREG_FAN_MAX_STATE)
382 		return -EINVAL;
383 
384 	/* Normalize the state to the valid speed range. */
385 	state = pwm->cooling_levels[state];
386 	err = regmap_write(fan->regmap, pwm->reg,
387 			   MLXREG_FAN_PWM_STATE2DUTY(state));
388 	if (err) {
389 		dev_err(fan->dev, "Failed to write PWM duty\n");
390 		return err;
391 	}
392 	return config;
393 }
394 
395 static const struct thermal_cooling_device_ops mlxreg_fan_cooling_ops = {
396 	.get_max_state	= mlxreg_fan_get_max_state,
397 	.get_cur_state	= mlxreg_fan_get_cur_state,
398 	.set_cur_state	= mlxreg_fan_set_cur_state,
399 };
400 
401 static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan,
402 				     struct mlxreg_core_data *data)
403 {
404 	u32 regval;
405 	int err;
406 
407 	err = regmap_read(fan->regmap, data->capability, &regval);
408 	if (err) {
409 		dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
410 			data->capability);
411 		return err;
412 	}
413 
414 	return !!(regval & data->bit);
415 }
416 
417 static int mlxreg_pwm_connect_verify(struct mlxreg_fan *fan,
418 				     struct mlxreg_core_data *data)
419 {
420 	u32 regval;
421 	int err;
422 
423 	err = regmap_read(fan->regmap, data->reg, &regval);
424 	if (err) {
425 		dev_err(fan->dev, "Failed to query pwm register 0x%08x\n",
426 			data->reg);
427 		return err;
428 	}
429 
430 	return regval != MLXREG_FAN_PWM_NOT_CONNECTED;
431 }
432 
433 static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan,
434 					struct mlxreg_core_data *data)
435 {
436 	u32 regval;
437 	int err;
438 
439 	err = regmap_read(fan->regmap, data->capability, &regval);
440 	if (err) {
441 		dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
442 			data->capability);
443 		return err;
444 	}
445 
446 	/*
447 	 * Set divider value according to the capability register, in case it
448 	 * contains valid value. Otherwise use default value. The purpose of
449 	 * this validation is to protect against the old hardware, in which
450 	 * this register can return zero.
451 	 */
452 	if (regval > 0 && regval <= MLXREG_FAN_TACHO_DIV_SCALE_MAX)
453 		fan->divider = regval * MLXREG_FAN_TACHO_DIV_MIN;
454 
455 	return 0;
456 }
457 
458 static int mlxreg_fan_config(struct mlxreg_fan *fan,
459 			     struct mlxreg_core_platform_data *pdata)
460 {
461 	int tacho_num = 0, tacho_avail = 0, pwm_num = 0, i;
462 	struct mlxreg_core_data *data = pdata->data;
463 	bool configured = false;
464 	int err;
465 
466 	fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF;
467 	fan->divider = MLXREG_FAN_TACHO_DIV_DEF;
468 	for (i = 0; i < pdata->counter; i++, data++) {
469 		if (strnstr(data->label, "tacho", sizeof(data->label))) {
470 			if (tacho_num == MLXREG_FAN_MAX_TACHO) {
471 				dev_err(fan->dev, "too many tacho entries: %s\n",
472 					data->label);
473 				return -EINVAL;
474 			}
475 
476 			if (data->capability) {
477 				err = mlxreg_fan_connect_verify(fan, data);
478 				if (err < 0)
479 					return err;
480 				else if (!err) {
481 					tacho_num++;
482 					continue;
483 				}
484 			}
485 
486 			fan->tacho[tacho_num].reg = data->reg;
487 			fan->tacho[tacho_num].mask = data->mask;
488 			fan->tacho[tacho_num].prsnt = data->reg_prsnt;
489 			fan->tacho[tacho_num++].connected = true;
490 			tacho_avail++;
491 		} else if (strnstr(data->label, "pwm", sizeof(data->label))) {
492 			if (pwm_num == MLXREG_FAN_MAX_TACHO) {
493 				dev_err(fan->dev, "too many pwm entries: %s\n",
494 					data->label);
495 				return -EINVAL;
496 			}
497 
498 			/* Validate if more then one PWM is connected. */
499 			if (pwm_num) {
500 				err = mlxreg_pwm_connect_verify(fan, data);
501 				if (err < 0)
502 					return err;
503 				else if (!err)
504 					continue;
505 			}
506 
507 			fan->pwm[pwm_num].reg = data->reg;
508 			fan->pwm[pwm_num].connected = true;
509 			pwm_num++;
510 		} else if (strnstr(data->label, "conf", sizeof(data->label))) {
511 			if (configured) {
512 				dev_err(fan->dev, "duplicate conf entry: %s\n",
513 					data->label);
514 				return -EINVAL;
515 			}
516 			/* Validate that conf parameters are not zeros. */
517 			if (!data->mask && !data->bit && !data->capability) {
518 				dev_err(fan->dev, "invalid conf entry params: %s\n",
519 					data->label);
520 				return -EINVAL;
521 			}
522 			if (data->capability) {
523 				err = mlxreg_fan_speed_divider_get(fan, data);
524 				if (err)
525 					return err;
526 			} else {
527 				if (data->mask)
528 					fan->samples = data->mask;
529 				if (data->bit)
530 					fan->divider = data->bit;
531 			}
532 			configured = true;
533 		} else {
534 			dev_err(fan->dev, "invalid label: %s\n", data->label);
535 			return -EINVAL;
536 		}
537 	}
538 
539 	if (pdata->capability) {
540 		int drwr_avail;
541 		u32 regval;
542 
543 		/* Obtain the number of FAN drawers, supported by system. */
544 		err = regmap_read(fan->regmap, pdata->capability, &regval);
545 		if (err) {
546 			dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
547 				pdata->capability);
548 			return err;
549 		}
550 
551 		drwr_avail = hweight32(regval);
552 		if (!tacho_avail || !drwr_avail || tacho_avail < drwr_avail) {
553 			dev_err(fan->dev, "Configuration is invalid: drawers num %d tachos num %d\n",
554 				drwr_avail, tacho_avail);
555 			return -EINVAL;
556 		}
557 
558 		/* Set the number of tachometers per one drawer. */
559 		fan->tachos_per_drwr = tacho_avail / drwr_avail;
560 	}
561 
562 	return 0;
563 }
564 
565 static int mlxreg_fan_cooling_config(struct device *dev, struct mlxreg_fan *fan)
566 {
567 	int i, j;
568 
569 	for (i = 0; i < MLXREG_FAN_MAX_PWM; i++) {
570 		struct mlxreg_fan_pwm *pwm = &fan->pwm[i];
571 
572 		if (!pwm->connected)
573 			continue;
574 		pwm->fan = fan;
575 		pwm->cdev = devm_thermal_of_cooling_device_register(dev, NULL, mlxreg_fan_name[i],
576 								    pwm, &mlxreg_fan_cooling_ops);
577 		if (IS_ERR(pwm->cdev)) {
578 			dev_err(dev, "Failed to register cooling device\n");
579 			return PTR_ERR(pwm->cdev);
580 		}
581 
582 		/* Init cooling levels per PWM state. */
583 		for (j = 0; j < MLXREG_FAN_SPEED_MIN_LEVEL; j++)
584 			pwm->cooling_levels[j] = MLXREG_FAN_SPEED_MIN_LEVEL;
585 		for (j = MLXREG_FAN_SPEED_MIN_LEVEL; j <= MLXREG_FAN_MAX_STATE; j++)
586 			pwm->cooling_levels[j] = j;
587 	}
588 
589 	return 0;
590 }
591 
592 static int mlxreg_fan_probe(struct platform_device *pdev)
593 {
594 	struct mlxreg_core_platform_data *pdata;
595 	struct device *dev = &pdev->dev;
596 	struct mlxreg_fan *fan;
597 	struct device *hwm;
598 	int err;
599 
600 	pdata = dev_get_platdata(dev);
601 	if (!pdata) {
602 		dev_err(dev, "Failed to get platform data.\n");
603 		return -EINVAL;
604 	}
605 
606 	fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL);
607 	if (!fan)
608 		return -ENOMEM;
609 
610 	fan->dev = dev;
611 	fan->regmap = pdata->regmap;
612 
613 	err = mlxreg_fan_config(fan, pdata);
614 	if (err)
615 		return err;
616 
617 	hwm = devm_hwmon_device_register_with_info(dev, "mlxreg_fan",
618 						   fan,
619 						   &mlxreg_fan_hwmon_chip_info,
620 						   NULL);
621 	if (IS_ERR(hwm)) {
622 		dev_err(dev, "Failed to register hwmon device\n");
623 		return PTR_ERR(hwm);
624 	}
625 
626 	if (IS_REACHABLE(CONFIG_THERMAL))
627 		err = mlxreg_fan_cooling_config(dev, fan);
628 
629 	return err;
630 }
631 
632 static struct platform_driver mlxreg_fan_driver = {
633 	.driver = {
634 	    .name = "mlxreg-fan",
635 	},
636 	.probe = mlxreg_fan_probe,
637 };
638 
639 module_platform_driver(mlxreg_fan_driver);
640 
641 MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
642 MODULE_DESCRIPTION("Mellanox FAN driver");
643 MODULE_LICENSE("GPL");
644 MODULE_ALIAS("platform:mlxreg-fan");
645