hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/hwmon/mlxreg-fan.c
....@@ -27,7 +27,9 @@
2727 #define MLXREG_FAN_SPEED_MAX (MLXREG_FAN_MAX_STATE * 2)
2828 #define MLXREG_FAN_SPEED_MIN_LEVEL 2 /* 20 percent */
2929 #define MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF 44
30
-#define MLXREG_FAN_TACHO_DIVIDER_DEF 1132
30
+#define MLXREG_FAN_TACHO_DIV_MIN 283
31
+#define MLXREG_FAN_TACHO_DIV_DEF (MLXREG_FAN_TACHO_DIV_MIN * 4)
32
+#define MLXREG_FAN_TACHO_DIV_SCALE_MAX 64
3133 /*
3234 * FAN datasheet defines the formula for RPM calculations as RPM = 15/t-high.
3335 * The logic in a programmable device measures the time t-high by sampling the
....@@ -51,7 +53,7 @@
5153 */
5254 #define MLXREG_FAN_GET_RPM(rval, d, s) (DIV_ROUND_CLOSEST(15000000 * 100, \
5355 ((rval) + (s)) * (d)))
54
-#define MLXREG_FAN_GET_FAULT(val, mask) (!((val) ^ (mask)))
56
+#define MLXREG_FAN_GET_FAULT(val, mask) ((val) == (mask))
5557 #define MLXREG_FAN_PWM_DUTY2STATE(duty) (DIV_ROUND_CLOSEST((duty) * \
5658 MLXREG_FAN_MAX_STATE, \
5759 MLXREG_FAN_MAX_DUTY))
....@@ -124,6 +126,12 @@
124126 err = regmap_read(fan->regmap, tacho->reg, &regval);
125127 if (err)
126128 return err;
129
+
130
+ if (MLXREG_FAN_GET_FAULT(regval, tacho->mask)) {
131
+ /* FAN is broken - return zero for FAN speed. */
132
+ *val = 0;
133
+ return 0;
134
+ }
127135
128136 *val = MLXREG_FAN_GET_RPM(regval, fan->divider,
129137 fan->samples);
....@@ -227,40 +235,22 @@
227235 return 0;
228236 }
229237
230
-static const u32 mlxreg_fan_hwmon_fan_config[] = {
231
- HWMON_F_INPUT | HWMON_F_FAULT,
232
- HWMON_F_INPUT | HWMON_F_FAULT,
233
- HWMON_F_INPUT | HWMON_F_FAULT,
234
- HWMON_F_INPUT | HWMON_F_FAULT,
235
- HWMON_F_INPUT | HWMON_F_FAULT,
236
- HWMON_F_INPUT | HWMON_F_FAULT,
237
- HWMON_F_INPUT | HWMON_F_FAULT,
238
- HWMON_F_INPUT | HWMON_F_FAULT,
239
- HWMON_F_INPUT | HWMON_F_FAULT,
240
- HWMON_F_INPUT | HWMON_F_FAULT,
241
- HWMON_F_INPUT | HWMON_F_FAULT,
242
- HWMON_F_INPUT | HWMON_F_FAULT,
243
- 0
244
-};
245
-
246
-static const struct hwmon_channel_info mlxreg_fan_hwmon_fan = {
247
- .type = hwmon_fan,
248
- .config = mlxreg_fan_hwmon_fan_config,
249
-};
250
-
251
-static const u32 mlxreg_fan_hwmon_pwm_config[] = {
252
- HWMON_PWM_INPUT,
253
- 0
254
-};
255
-
256
-static const struct hwmon_channel_info mlxreg_fan_hwmon_pwm = {
257
- .type = hwmon_pwm,
258
- .config = mlxreg_fan_hwmon_pwm_config,
259
-};
260
-
261238 static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = {
262
- &mlxreg_fan_hwmon_fan,
263
- &mlxreg_fan_hwmon_pwm,
239
+ HWMON_CHANNEL_INFO(fan,
240
+ HWMON_F_INPUT | HWMON_F_FAULT,
241
+ HWMON_F_INPUT | HWMON_F_FAULT,
242
+ HWMON_F_INPUT | HWMON_F_FAULT,
243
+ HWMON_F_INPUT | HWMON_F_FAULT,
244
+ HWMON_F_INPUT | HWMON_F_FAULT,
245
+ HWMON_F_INPUT | HWMON_F_FAULT,
246
+ HWMON_F_INPUT | HWMON_F_FAULT,
247
+ HWMON_F_INPUT | HWMON_F_FAULT,
248
+ HWMON_F_INPUT | HWMON_F_FAULT,
249
+ HWMON_F_INPUT | HWMON_F_FAULT,
250
+ HWMON_F_INPUT | HWMON_F_FAULT,
251
+ HWMON_F_INPUT | HWMON_F_FAULT),
252
+ HWMON_CHANNEL_INFO(pwm,
253
+ HWMON_PWM_INPUT),
264254 NULL
265255 };
266256
....@@ -366,15 +356,57 @@
366356 .set_cur_state = mlxreg_fan_set_cur_state,
367357 };
368358
359
+static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan,
360
+ struct mlxreg_core_data *data)
361
+{
362
+ u32 regval;
363
+ int err;
364
+
365
+ err = regmap_read(fan->regmap, data->capability, &regval);
366
+ if (err) {
367
+ dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
368
+ data->capability);
369
+ return err;
370
+ }
371
+
372
+ return !!(regval & data->bit);
373
+}
374
+
375
+static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan,
376
+ struct mlxreg_core_data *data)
377
+{
378
+ u32 regval;
379
+ int err;
380
+
381
+ err = regmap_read(fan->regmap, data->capability, &regval);
382
+ if (err) {
383
+ dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
384
+ data->capability);
385
+ return err;
386
+ }
387
+
388
+ /*
389
+ * Set divider value according to the capability register, in case it
390
+ * contains valid value. Otherwise use default value. The purpose of
391
+ * this validation is to protect against the old hardware, in which
392
+ * this register can return zero.
393
+ */
394
+ if (regval > 0 && regval <= MLXREG_FAN_TACHO_DIV_SCALE_MAX)
395
+ fan->divider = regval * MLXREG_FAN_TACHO_DIV_MIN;
396
+
397
+ return 0;
398
+}
399
+
369400 static int mlxreg_fan_config(struct mlxreg_fan *fan,
370401 struct mlxreg_core_platform_data *pdata)
371402 {
372403 struct mlxreg_core_data *data = pdata->data;
373404 bool configured = false;
374405 int tacho_num = 0, i;
406
+ int err;
375407
376408 fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF;
377
- fan->divider = MLXREG_FAN_TACHO_DIVIDER_DEF;
409
+ fan->divider = MLXREG_FAN_TACHO_DIV_DEF;
378410 for (i = 0; i < pdata->counter; i++, data++) {
379411 if (strnstr(data->label, "tacho", sizeof(data->label))) {
380412 if (tacho_num == MLXREG_FAN_MAX_TACHO) {
....@@ -382,6 +414,17 @@
382414 data->label);
383415 return -EINVAL;
384416 }
417
+
418
+ if (data->capability) {
419
+ err = mlxreg_fan_connect_verify(fan, data);
420
+ if (err < 0)
421
+ return err;
422
+ else if (!err) {
423
+ tacho_num++;
424
+ continue;
425
+ }
426
+ }
427
+
385428 fan->tacho[tacho_num].reg = data->reg;
386429 fan->tacho[tacho_num].mask = data->mask;
387430 fan->tacho[tacho_num++].connected = true;
....@@ -400,13 +443,21 @@
400443 return -EINVAL;
401444 }
402445 /* Validate that conf parameters are not zeros. */
403
- if (!data->mask || !data->bit) {
446
+ if (!data->mask && !data->bit && !data->capability) {
404447 dev_err(fan->dev, "invalid conf entry params: %s\n",
405448 data->label);
406449 return -EINVAL;
407450 }
408
- fan->samples = data->mask;
409
- fan->divider = data->bit;
451
+ if (data->capability) {
452
+ err = mlxreg_fan_speed_divider_get(fan, data);
453
+ if (err)
454
+ return err;
455
+ } else {
456
+ if (data->mask)
457
+ fan->samples = data->mask;
458
+ if (data->bit)
459
+ fan->divider = data->bit;
460
+ }
410461 configured = true;
411462 } else {
412463 dev_err(fan->dev, "invalid label: %s\n", data->label);
....@@ -426,55 +477,45 @@
426477 static int mlxreg_fan_probe(struct platform_device *pdev)
427478 {
428479 struct mlxreg_core_platform_data *pdata;
480
+ struct device *dev = &pdev->dev;
429481 struct mlxreg_fan *fan;
430482 struct device *hwm;
431483 int err;
432484
433
- pdata = dev_get_platdata(&pdev->dev);
485
+ pdata = dev_get_platdata(dev);
434486 if (!pdata) {
435
- dev_err(&pdev->dev, "Failed to get platform data.\n");
487
+ dev_err(dev, "Failed to get platform data.\n");
436488 return -EINVAL;
437489 }
438490
439
- fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
491
+ fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL);
440492 if (!fan)
441493 return -ENOMEM;
442494
443
- fan->dev = &pdev->dev;
495
+ fan->dev = dev;
444496 fan->regmap = pdata->regmap;
445
- platform_set_drvdata(pdev, fan);
446497
447498 err = mlxreg_fan_config(fan, pdata);
448499 if (err)
449500 return err;
450501
451
- hwm = devm_hwmon_device_register_with_info(&pdev->dev, "mlxreg_fan",
502
+ hwm = devm_hwmon_device_register_with_info(dev, "mlxreg_fan",
452503 fan,
453504 &mlxreg_fan_hwmon_chip_info,
454505 NULL);
455506 if (IS_ERR(hwm)) {
456
- dev_err(&pdev->dev, "Failed to register hwmon device\n");
507
+ dev_err(dev, "Failed to register hwmon device\n");
457508 return PTR_ERR(hwm);
458509 }
459510
460511 if (IS_REACHABLE(CONFIG_THERMAL)) {
461
- fan->cdev = thermal_cooling_device_register("mlxreg_fan", fan,
462
- &mlxreg_fan_cooling_ops);
512
+ fan->cdev = devm_thermal_of_cooling_device_register(dev,
513
+ NULL, "mlxreg_fan", fan, &mlxreg_fan_cooling_ops);
463514 if (IS_ERR(fan->cdev)) {
464
- dev_err(&pdev->dev, "Failed to register cooling device\n");
515
+ dev_err(dev, "Failed to register cooling device\n");
465516 return PTR_ERR(fan->cdev);
466517 }
467518 }
468
-
469
- return 0;
470
-}
471
-
472
-static int mlxreg_fan_remove(struct platform_device *pdev)
473
-{
474
- struct mlxreg_fan *fan = platform_get_drvdata(pdev);
475
-
476
- if (IS_REACHABLE(CONFIG_THERMAL))
477
- thermal_cooling_device_unregister(fan->cdev);
478519
479520 return 0;
480521 }
....@@ -484,7 +525,6 @@
484525 .name = "mlxreg-fan",
485526 },
486527 .probe = mlxreg_fan_probe,
487
- .remove = mlxreg_fan_remove,
488528 };
489529
490530 module_platform_driver(mlxreg_fan_driver);