Skip to content

Commit f7bf7eb

Browse files
vadimp-nvidiagroeck
authored andcommitted
hwmon: (mlxreg-fan) Add support for fan drawers capability and present registers
Add support for fan drawer's capability and present registers in order to set mapping between the fan drawers and tachometers. Some systems are equipped with fan drawers with one tachometer inside. Others with fan drawers with several tachometers inside. Using present register along with tachometer-to-drawer mapping allows to skip reading missed tachometers and expose input for them as zero, instead of exposing fault code returned by hardware. Signed-off-by: Vadim Pasternak <vadimp@nvidia.com> Link: https://lore.kernel.org/r/20210322172237.2213584-1-vadimp@nvidia.com Signed-off-by: Guenter Roeck <linux@roeck-us.net>
1 parent cb3d37b commit f7bf7eb

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

drivers/hwmon/mlxreg-fan.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,13 @@
6767
* @connected: indicates if tachometer is connected;
6868
* @reg: register offset;
6969
* @mask: fault mask;
70+
* @prsnt: present register offset;
7071
*/
7172
struct mlxreg_fan_tacho {
7273
bool connected;
7374
u32 reg;
7475
u32 mask;
76+
u32 prsnt;
7577
};
7678

7779
/*
@@ -92,6 +94,7 @@ struct mlxreg_fan_pwm {
9294
* @regmap: register map of parent device;
9395
* @tacho: tachometer data;
9496
* @pwm: PWM data;
97+
* @tachos_per_drwr - number of tachometers per drawer;
9598
* @samples: minimum allowed samples per pulse;
9699
* @divider: divider value for tachometer RPM calculation;
97100
* @cooling: cooling device levels;
@@ -103,6 +106,7 @@ struct mlxreg_fan {
103106
struct mlxreg_core_platform_data *pdata;
104107
struct mlxreg_fan_tacho tacho[MLXREG_FAN_MAX_TACHO];
105108
struct mlxreg_fan_pwm pwm;
109+
int tachos_per_drwr;
106110
int samples;
107111
int divider;
108112
u8 cooling_levels[MLXREG_FAN_MAX_STATE + 1];
@@ -123,6 +127,26 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
123127
tacho = &fan->tacho[channel];
124128
switch (attr) {
125129
case hwmon_fan_input:
130+
/*
131+
* Check FAN presence: FAN related bit in presence register is one,
132+
* if FAN is physically connected, zero - otherwise.
133+
*/
134+
if (tacho->prsnt && fan->tachos_per_drwr) {
135+
err = regmap_read(fan->regmap, tacho->prsnt, &regval);
136+
if (err)
137+
return err;
138+
139+
/*
140+
* Map channel to presence bit - drawer can be equipped with
141+
* one or few FANs, while presence is indicated per drawer.
142+
*/
143+
if (BIT(channel / fan->tachos_per_drwr) & regval) {
144+
/* FAN is not connected - return zero for FAN speed. */
145+
*val = 0;
146+
return 0;
147+
}
148+
}
149+
126150
err = regmap_read(fan->regmap, tacho->reg, &regval);
127151
if (err)
128152
return err;
@@ -389,8 +413,8 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
389413
struct mlxreg_core_platform_data *pdata)
390414
{
391415
struct mlxreg_core_data *data = pdata->data;
416+
int tacho_num = 0, tacho_avail = 0, i;
392417
bool configured = false;
393-
int tacho_num = 0, i;
394418
int err;
395419

396420
fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF;
@@ -415,7 +439,9 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
415439

416440
fan->tacho[tacho_num].reg = data->reg;
417441
fan->tacho[tacho_num].mask = data->mask;
442+
fan->tacho[tacho_num].prsnt = data->reg_prsnt;
418443
fan->tacho[tacho_num++].connected = true;
444+
tacho_avail++;
419445
} else if (strnstr(data->label, "pwm", sizeof(data->label))) {
420446
if (fan->pwm.connected) {
421447
dev_err(fan->dev, "duplicate pwm entry: %s\n",
@@ -453,6 +479,29 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
453479
}
454480
}
455481

482+
if (pdata->capability) {
483+
int drwr_avail;
484+
u32 regval;
485+
486+
/* Obtain the number of FAN drawers, supported by system. */
487+
err = regmap_read(fan->regmap, pdata->capability, &regval);
488+
if (err) {
489+
dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
490+
pdata->capability);
491+
return err;
492+
}
493+
494+
drwr_avail = hweight32(regval);
495+
if (!tacho_avail || !drwr_avail || tacho_avail < drwr_avail) {
496+
dev_err(fan->dev, "Configuration is invalid: drawers num %d tachos num %d\n",
497+
drwr_avail, tacho_avail);
498+
return -EINVAL;
499+
}
500+
501+
/* Set the number of tachometers per one drawer. */
502+
fan->tachos_per_drwr = tacho_avail / drwr_avail;
503+
}
504+
456505
/* Init cooling levels per PWM state. */
457506
for (i = 0; i < MLXREG_FAN_SPEED_MIN_LEVEL; i++)
458507
fan->cooling_levels[i] = MLXREG_FAN_SPEED_MIN_LEVEL;

0 commit comments

Comments
 (0)