Lines Matching +full:use +full:- +full:internal +full:- +full:divider
1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
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;
45 * RPM = 15000000 * 100 / ((Regval + samples) * divider).
60 * struct mlxreg_fan_tacho - tachometer data (internal use):
75 * struct mlxreg_fan_pwm - PWM data (internal use):
95 * struct mlxreg_fan - private data (internal use):
101 * @tachos_per_drwr - number of tachometers per drawer;
103 * @divider: divider value for tachometer RPM calculation;
113 int divider; member
131 tacho = &fan->tacho[channel]; 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()
154 err = regmap_read(fan->regmap, tacho->reg, ®val); in mlxreg_fan_read()
158 *val = MLXREG_FAN_GET_RPM(regval, fan->divider, in mlxreg_fan_read()
159 fan->samples); in mlxreg_fan_read()
163 err = regmap_read(fan->regmap, tacho->reg, ®val); in mlxreg_fan_read()
167 *val = MLXREG_FAN_GET_FAULT(regval, tacho->mask); in mlxreg_fan_read()
171 return -EOPNOTSUPP; in mlxreg_fan_read()
176 pwm = &fan->pwm[channel]; in mlxreg_fan_read()
179 err = regmap_read(fan->regmap, pwm->reg, ®val); in mlxreg_fan_read()
187 return -EOPNOTSUPP; in mlxreg_fan_read()
192 return -EOPNOTSUPP; in mlxreg_fan_read()
211 return -EINVAL; in mlxreg_fan_write()
212 pwm = &fan->pwm[channel]; in mlxreg_fan_write()
213 /* If thermal is configured - handle PWM limit setting. */ in mlxreg_fan_write()
215 pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(val); in mlxreg_fan_write()
220 if (pwm->last_hwmon_state >= pwm->last_thermal_state) in mlxreg_fan_write()
221 return mlxreg_fan_set_cur_state(pwm->cdev, in mlxreg_fan_write()
222 pwm->last_hwmon_state); in mlxreg_fan_write()
225 return regmap_write(fan->regmap, pwm->reg, val); in mlxreg_fan_write()
227 return -EOPNOTSUPP; in mlxreg_fan_write()
232 return -EOPNOTSUPP; in mlxreg_fan_write()
235 return -EOPNOTSUPP; in mlxreg_fan_write()
244 if (!(((struct mlxreg_fan *)data)->tacho[channel].connected)) in mlxreg_fan_is_visible()
257 if (!(((struct mlxreg_fan *)data)->pwm[channel].connected)) in mlxreg_fan_is_visible()
328 struct mlxreg_fan_pwm *pwm = cdev->devdata; in mlxreg_fan_get_cur_state()
329 struct mlxreg_fan *fan = pwm->fan; in mlxreg_fan_get_cur_state()
333 err = regmap_read(fan->regmap, pwm->reg, ®val); in mlxreg_fan_get_cur_state()
335 dev_err(fan->dev, "Failed to query PWM duty\n"); in mlxreg_fan_get_cur_state()
348 struct mlxreg_fan_pwm *pwm = cdev->devdata; in mlxreg_fan_set_cur_state()
349 struct mlxreg_fan *fan = pwm->fan; in mlxreg_fan_set_cur_state()
353 return -EINVAL; in mlxreg_fan_set_cur_state()
356 pwm->last_thermal_state = state; in mlxreg_fan_set_cur_state()
358 state = max_t(unsigned long, state, pwm->last_hwmon_state); in mlxreg_fan_set_cur_state()
359 err = regmap_write(fan->regmap, pwm->reg, in mlxreg_fan_set_cur_state()
362 dev_err(fan->dev, "Failed to write PWM duty\n"); in mlxreg_fan_set_cur_state()
380 err = regmap_read(fan->regmap, data->capability, ®val); in mlxreg_fan_connect_verify()
382 dev_err(fan->dev, "Failed to query capability register 0x%08x\n", in mlxreg_fan_connect_verify()
383 data->capability); in mlxreg_fan_connect_verify()
387 return !!(regval & data->bit); in mlxreg_fan_connect_verify()
396 err = regmap_read(fan->regmap, data->reg, ®val); in mlxreg_pwm_connect_verify()
398 dev_err(fan->dev, "Failed to query pwm register 0x%08x\n", in mlxreg_pwm_connect_verify()
399 data->reg); in mlxreg_pwm_connect_verify()
412 err = regmap_read(fan->regmap, data->capability, ®val); in mlxreg_fan_speed_divider_get()
414 dev_err(fan->dev, "Failed to query capability register 0x%08x\n", in mlxreg_fan_speed_divider_get()
415 data->capability); in mlxreg_fan_speed_divider_get()
420 * Set divider value according to the capability register, in case it in mlxreg_fan_speed_divider_get()
421 * contains valid value. Otherwise use default value. The purpose of in mlxreg_fan_speed_divider_get()
426 fan->divider = regval * MLXREG_FAN_TACHO_DIV_MIN; in mlxreg_fan_speed_divider_get()
435 struct mlxreg_core_data *data = pdata->data; in mlxreg_fan_config()
439 fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF; in mlxreg_fan_config()
440 fan->divider = MLXREG_FAN_TACHO_DIV_DEF; in mlxreg_fan_config()
441 for (i = 0; i < pdata->counter; i++, data++) { in mlxreg_fan_config()
442 if (strnstr(data->label, "tacho", sizeof(data->label))) { in mlxreg_fan_config()
444 dev_err(fan->dev, "too many tacho entries: %s\n", in mlxreg_fan_config()
445 data->label); in mlxreg_fan_config()
446 return -EINVAL; in mlxreg_fan_config()
449 if (data->capability) { in mlxreg_fan_config()
459 fan->tacho[tacho_num].reg = data->reg; in mlxreg_fan_config()
460 fan->tacho[tacho_num].mask = data->mask; in mlxreg_fan_config()
461 fan->tacho[tacho_num].prsnt = data->reg_prsnt; in mlxreg_fan_config()
462 fan->tacho[tacho_num++].connected = true; in mlxreg_fan_config()
464 } else if (strnstr(data->label, "pwm", sizeof(data->label))) { in mlxreg_fan_config()
466 dev_err(fan->dev, "too many pwm entries: %s\n", in mlxreg_fan_config()
467 data->label); in mlxreg_fan_config()
468 return -EINVAL; in mlxreg_fan_config()
480 fan->pwm[pwm_num].reg = data->reg; in mlxreg_fan_config()
481 fan->pwm[pwm_num].connected = true; in mlxreg_fan_config()
483 } else if (strnstr(data->label, "conf", sizeof(data->label))) { in mlxreg_fan_config()
485 dev_err(fan->dev, "duplicate conf entry: %s\n", in mlxreg_fan_config()
486 data->label); in mlxreg_fan_config()
487 return -EINVAL; in mlxreg_fan_config()
490 if (!data->mask && !data->bit && !data->capability) { in mlxreg_fan_config()
491 dev_err(fan->dev, "invalid conf entry params: %s\n", in mlxreg_fan_config()
492 data->label); in mlxreg_fan_config()
493 return -EINVAL; in mlxreg_fan_config()
495 if (data->capability) { in mlxreg_fan_config()
500 if (data->mask) in mlxreg_fan_config()
501 fan->samples = data->mask; in mlxreg_fan_config()
502 if (data->bit) in mlxreg_fan_config()
503 fan->divider = data->bit; in mlxreg_fan_config()
507 dev_err(fan->dev, "invalid label: %s\n", data->label); in mlxreg_fan_config()
508 return -EINVAL; in mlxreg_fan_config()
512 if (pdata->capability) { in mlxreg_fan_config()
517 err = regmap_read(fan->regmap, pdata->capability, ®val); in mlxreg_fan_config()
519 dev_err(fan->dev, "Failed to query capability register 0x%08x\n", in mlxreg_fan_config()
520 pdata->capability); in mlxreg_fan_config()
526 dev_err(fan->dev, "Configuration is invalid: drawers num %d tachos num %d\n", in mlxreg_fan_config()
528 return -EINVAL; in mlxreg_fan_config()
532 fan->tachos_per_drwr = tacho_avail / drwr_avail; in mlxreg_fan_config()
543 struct mlxreg_fan_pwm *pwm = &fan->pwm[i]; in mlxreg_fan_cooling_config()
545 if (!pwm->connected) in mlxreg_fan_cooling_config()
547 pwm->fan = fan; in mlxreg_fan_cooling_config()
548 pwm->cdev = devm_thermal_of_cooling_device_register(dev, NULL, mlxreg_fan_name[i], in mlxreg_fan_cooling_config()
550 if (IS_ERR(pwm->cdev)) { in mlxreg_fan_cooling_config()
552 return PTR_ERR(pwm->cdev); in mlxreg_fan_cooling_config()
556 pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(MLXREG_FAN_MIN_DUTY); in mlxreg_fan_cooling_config()
565 struct device *dev = &pdev->dev; in mlxreg_fan_probe()
573 return -EINVAL; in mlxreg_fan_probe()
578 return -ENOMEM; in mlxreg_fan_probe()
580 fan->dev = dev; in mlxreg_fan_probe()
581 fan->regmap = pdata->regmap; in mlxreg_fan_probe()
604 .name = "mlxreg-fan",
614 MODULE_ALIAS("platform:mlxreg-fan");