Lines Matching +full:fan +full:- +full:0
1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
17 #define MLXREG_FAN_PWM_NOT_CONNECTED 0xff
27 * FAN datasheet defines the formula for RPM calculations as RPM = 15/t-high.
28 * The logic in a programmable device measures the time t-high by sampling the
29 * tachometer every t-sample (with the default value 11.32 uS) and increment
31 * RPM = 15 / (t-sample * (K + Regval)), where:
33 * - 0xff - represents tachometer fault;
34 * - 0xfe - represents tachometer minimum value , which is 4444 RPM;
35 * - 0x00 - represents tachometer maximum value , which is 300000 RPM;
39 * used: RPM = 15 / ((Regval + K) * 11.32) * 10^(-6)), which in the
42 * - for Regval 0x00, RPM will be 15000000 * 100 / (44 * 1132) = 30115;
43 * - for Regval 0xfe, RPM will be 15000000 * 100 / ((254 + 44) * 1132) = 4446;
60 * struct mlxreg_fan_tacho - tachometer data (internal use):
75 * struct mlxreg_fan_pwm - PWM data (internal use):
77 * @fan: private data;
86 struct mlxreg_fan *fan; member
95 * struct mlxreg_fan - private data (internal use):
101 * @tachos_per_drwr - number of tachometers per drawer;
123 struct mlxreg_fan *fan = dev_get_drvdata(dev); in mlxreg_fan_read() local
131 tacho = &fan->tacho[channel]; in mlxreg_fan_read()
135 * Check FAN presence: FAN related bit in presence register is one, in mlxreg_fan_read()
136 * if FAN is physically connected, zero - otherwise. in mlxreg_fan_read()
138 if (tacho->prsnt && fan->tachos_per_drwr) { in mlxreg_fan_read()
139 err = regmap_read(fan->regmap, tacho->prsnt, ®val); in mlxreg_fan_read()
144 * Map channel to presence bit - drawer can be equipped with in mlxreg_fan_read()
147 if (BIT(channel / fan->tachos_per_drwr) & regval) { in mlxreg_fan_read()
148 /* FAN is not connected - return zero for FAN speed. */ in mlxreg_fan_read()
149 *val = 0; in mlxreg_fan_read()
150 return 0; in mlxreg_fan_read()
154 err = regmap_read(fan->regmap, tacho->reg, ®val); in mlxreg_fan_read()
158 if (MLXREG_FAN_GET_FAULT(regval, tacho->mask)) { in mlxreg_fan_read()
159 /* FAN is broken - return zero for FAN speed. */ in mlxreg_fan_read()
160 *val = 0; in mlxreg_fan_read()
161 return 0; in mlxreg_fan_read()
164 *val = MLXREG_FAN_GET_RPM(regval, fan->divider, in mlxreg_fan_read()
165 fan->samples); in mlxreg_fan_read()
169 err = regmap_read(fan->regmap, tacho->reg, ®val); in mlxreg_fan_read()
173 *val = MLXREG_FAN_GET_FAULT(regval, tacho->mask); in mlxreg_fan_read()
177 return -EOPNOTSUPP; in mlxreg_fan_read()
182 pwm = &fan->pwm[channel]; in mlxreg_fan_read()
185 err = regmap_read(fan->regmap, pwm->reg, ®val); in mlxreg_fan_read()
193 return -EOPNOTSUPP; in mlxreg_fan_read()
198 return -EOPNOTSUPP; in mlxreg_fan_read()
201 return 0; in mlxreg_fan_read()
208 struct mlxreg_fan *fan = dev_get_drvdata(dev); in mlxreg_fan_write() local
217 return -EINVAL; in mlxreg_fan_write()
218 pwm = &fan->pwm[channel]; in mlxreg_fan_write()
219 /* If thermal is configured - handle PWM limit setting. */ in mlxreg_fan_write()
221 pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(val); in mlxreg_fan_write()
226 if (pwm->last_hwmon_state >= pwm->last_thermal_state) in mlxreg_fan_write()
227 return mlxreg_fan_set_cur_state(pwm->cdev, in mlxreg_fan_write()
228 pwm->last_hwmon_state); in mlxreg_fan_write()
229 return 0; in mlxreg_fan_write()
231 return regmap_write(fan->regmap, pwm->reg, val); in mlxreg_fan_write()
233 return -EOPNOTSUPP; in mlxreg_fan_write()
238 return -EOPNOTSUPP; in mlxreg_fan_write()
241 return -EOPNOTSUPP; in mlxreg_fan_write()
250 if (!(((struct mlxreg_fan *)data)->tacho[channel].connected)) in mlxreg_fan_is_visible()
251 return 0; in mlxreg_fan_is_visible()
263 if (!(((struct mlxreg_fan *)data)->pwm[channel].connected)) in mlxreg_fan_is_visible()
264 return 0; in mlxreg_fan_is_visible()
278 return 0; in mlxreg_fan_is_visible()
289 HWMON_CHANNEL_INFO(fan,
337 return 0; in mlxreg_fan_get_max_state()
344 struct mlxreg_fan_pwm *pwm = cdev->devdata; in mlxreg_fan_get_cur_state()
345 struct mlxreg_fan *fan = pwm->fan; in mlxreg_fan_get_cur_state() local
349 err = regmap_read(fan->regmap, pwm->reg, ®val); in mlxreg_fan_get_cur_state()
351 dev_err(fan->dev, "Failed to query PWM duty\n"); in mlxreg_fan_get_cur_state()
357 return 0; in mlxreg_fan_get_cur_state()
364 struct mlxreg_fan_pwm *pwm = cdev->devdata; in mlxreg_fan_set_cur_state()
365 struct mlxreg_fan *fan = pwm->fan; in mlxreg_fan_set_cur_state() local
369 return -EINVAL; in mlxreg_fan_set_cur_state()
372 pwm->last_thermal_state = state; in mlxreg_fan_set_cur_state()
374 state = max_t(unsigned long, state, pwm->last_hwmon_state); in mlxreg_fan_set_cur_state()
375 err = regmap_write(fan->regmap, pwm->reg, in mlxreg_fan_set_cur_state()
378 dev_err(fan->dev, "Failed to write PWM duty\n"); in mlxreg_fan_set_cur_state()
381 return 0; in mlxreg_fan_set_cur_state()
390 static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan, in mlxreg_fan_connect_verify() argument
396 err = regmap_read(fan->regmap, data->capability, ®val); in mlxreg_fan_connect_verify()
398 dev_err(fan->dev, "Failed to query capability register 0x%08x\n", in mlxreg_fan_connect_verify()
399 data->capability); in mlxreg_fan_connect_verify()
403 return !!(regval & data->bit); in mlxreg_fan_connect_verify()
406 static int mlxreg_pwm_connect_verify(struct mlxreg_fan *fan, in mlxreg_pwm_connect_verify() argument
412 err = regmap_read(fan->regmap, data->reg, ®val); in mlxreg_pwm_connect_verify()
414 dev_err(fan->dev, "Failed to query pwm register 0x%08x\n", in mlxreg_pwm_connect_verify()
415 data->reg); in mlxreg_pwm_connect_verify()
422 static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan, in mlxreg_fan_speed_divider_get() argument
428 err = regmap_read(fan->regmap, data->capability, ®val); in mlxreg_fan_speed_divider_get()
430 dev_err(fan->dev, "Failed to query capability register 0x%08x\n", in mlxreg_fan_speed_divider_get()
431 data->capability); in mlxreg_fan_speed_divider_get()
441 if (regval > 0 && regval <= MLXREG_FAN_TACHO_DIV_SCALE_MAX) in mlxreg_fan_speed_divider_get()
442 fan->divider = regval * MLXREG_FAN_TACHO_DIV_MIN; in mlxreg_fan_speed_divider_get()
444 return 0; in mlxreg_fan_speed_divider_get()
447 static int mlxreg_fan_config(struct mlxreg_fan *fan, in mlxreg_fan_config() argument
450 int tacho_num = 0, tacho_avail = 0, pwm_num = 0, i; in mlxreg_fan_config()
451 struct mlxreg_core_data *data = pdata->data; in mlxreg_fan_config()
455 fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF; in mlxreg_fan_config()
456 fan->divider = MLXREG_FAN_TACHO_DIV_DEF; in mlxreg_fan_config()
457 for (i = 0; i < pdata->counter; i++, data++) { in mlxreg_fan_config()
458 if (strnstr(data->label, "tacho", sizeof(data->label))) { in mlxreg_fan_config()
460 dev_err(fan->dev, "too many tacho entries: %s\n", in mlxreg_fan_config()
461 data->label); in mlxreg_fan_config()
462 return -EINVAL; in mlxreg_fan_config()
465 if (data->capability) { in mlxreg_fan_config()
466 err = mlxreg_fan_connect_verify(fan, data); in mlxreg_fan_config()
467 if (err < 0) in mlxreg_fan_config()
475 fan->tacho[tacho_num].reg = data->reg; in mlxreg_fan_config()
476 fan->tacho[tacho_num].mask = data->mask; in mlxreg_fan_config()
477 fan->tacho[tacho_num].prsnt = data->reg_prsnt; in mlxreg_fan_config()
478 fan->tacho[tacho_num++].connected = true; in mlxreg_fan_config()
480 } else if (strnstr(data->label, "pwm", sizeof(data->label))) { in mlxreg_fan_config()
482 dev_err(fan->dev, "too many pwm entries: %s\n", in mlxreg_fan_config()
483 data->label); in mlxreg_fan_config()
484 return -EINVAL; in mlxreg_fan_config()
489 err = mlxreg_pwm_connect_verify(fan, data); in mlxreg_fan_config()
490 if (err < 0) in mlxreg_fan_config()
496 fan->pwm[pwm_num].reg = data->reg; in mlxreg_fan_config()
497 fan->pwm[pwm_num].connected = true; in mlxreg_fan_config()
499 } else if (strnstr(data->label, "conf", sizeof(data->label))) { in mlxreg_fan_config()
501 dev_err(fan->dev, "duplicate conf entry: %s\n", in mlxreg_fan_config()
502 data->label); in mlxreg_fan_config()
503 return -EINVAL; in mlxreg_fan_config()
506 if (!data->mask && !data->bit && !data->capability) { in mlxreg_fan_config()
507 dev_err(fan->dev, "invalid conf entry params: %s\n", in mlxreg_fan_config()
508 data->label); in mlxreg_fan_config()
509 return -EINVAL; in mlxreg_fan_config()
511 if (data->capability) { in mlxreg_fan_config()
512 err = mlxreg_fan_speed_divider_get(fan, data); in mlxreg_fan_config()
516 if (data->mask) in mlxreg_fan_config()
517 fan->samples = data->mask; in mlxreg_fan_config()
518 if (data->bit) in mlxreg_fan_config()
519 fan->divider = data->bit; in mlxreg_fan_config()
523 dev_err(fan->dev, "invalid label: %s\n", data->label); in mlxreg_fan_config()
524 return -EINVAL; in mlxreg_fan_config()
528 if (pdata->capability) { in mlxreg_fan_config()
532 /* Obtain the number of FAN drawers, supported by system. */ in mlxreg_fan_config()
533 err = regmap_read(fan->regmap, pdata->capability, ®val); in mlxreg_fan_config()
535 dev_err(fan->dev, "Failed to query capability register 0x%08x\n", in mlxreg_fan_config()
536 pdata->capability); in mlxreg_fan_config()
542 dev_err(fan->dev, "Configuration is invalid: drawers num %d tachos num %d\n", in mlxreg_fan_config()
544 return -EINVAL; in mlxreg_fan_config()
548 fan->tachos_per_drwr = tacho_avail / drwr_avail; in mlxreg_fan_config()
551 return 0; in mlxreg_fan_config()
554 static int mlxreg_fan_cooling_config(struct device *dev, struct mlxreg_fan *fan) in mlxreg_fan_cooling_config() argument
558 for (i = 0; i < MLXREG_FAN_MAX_PWM; i++) { in mlxreg_fan_cooling_config()
559 struct mlxreg_fan_pwm *pwm = &fan->pwm[i]; in mlxreg_fan_cooling_config()
561 if (!pwm->connected) in mlxreg_fan_cooling_config()
563 pwm->fan = fan; in mlxreg_fan_cooling_config()
564 pwm->cdev = devm_thermal_of_cooling_device_register(dev, NULL, mlxreg_fan_name[i], in mlxreg_fan_cooling_config()
566 if (IS_ERR(pwm->cdev)) { in mlxreg_fan_cooling_config()
568 return PTR_ERR(pwm->cdev); in mlxreg_fan_cooling_config()
572 pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(MLXREG_FAN_MIN_DUTY); in mlxreg_fan_cooling_config()
575 return 0; in mlxreg_fan_cooling_config()
581 struct device *dev = &pdev->dev; in mlxreg_fan_probe()
582 struct mlxreg_fan *fan; in mlxreg_fan_probe() local
589 return -EINVAL; in mlxreg_fan_probe()
592 fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL); in mlxreg_fan_probe()
593 if (!fan) in mlxreg_fan_probe()
594 return -ENOMEM; in mlxreg_fan_probe()
596 fan->dev = dev; in mlxreg_fan_probe()
597 fan->regmap = pdata->regmap; in mlxreg_fan_probe()
599 err = mlxreg_fan_config(fan, pdata); in mlxreg_fan_probe()
604 fan, in mlxreg_fan_probe()
613 err = mlxreg_fan_cooling_config(dev, fan); in mlxreg_fan_probe()
620 .name = "mlxreg-fan",
628 MODULE_DESCRIPTION("Mellanox FAN driver");
630 MODULE_ALIAS("platform:mlxreg-fan");