staticlong axi_fan_control_get_pwm_duty(conststruct axi_fan_control_data *ctl)
{
u32 pwm_width = axi_ioread(ADI_REG_PWM_WIDTH, ctl);
u32 pwm_period = axi_ioread(ADI_REG_PWM_PERIOD, ctl); /* * PWM_PERIOD is a RO register set by the core. It should never be 0. * For now we are trusting the HW...
*/ return DIV_ROUND_CLOSEST(pwm_width * SYSFS_PWM_MAX, pwm_period);
}
if (tach == 0) /* should we return error, EAGAIN maybe? */ return 0; /* * The tacho period should be: * TACH = 60/(ppr * rpm), where rpm is revolutions per second * and ppr is pulses per revolution. * Given the tacho period, we can multiply it by the input clock * so that we know how many clocks we need to have this period. * From this, we can derive the RPM value.
*/ return DIV_ROUND_CLOSEST(60 * ctl->clk_rate, ctl->ppr * tach);
}
staticint axi_fan_control_read_temp(struct device *dev, u32 attr, long *val)
{ struct axi_fan_control_data *ctl = dev_get_drvdata(dev); long raw_temp;
switch (attr) { case hwmon_temp_input:
raw_temp = axi_ioread(ADI_REG_TEMPERATURE, ctl); /* * The formula for the temperature is: * T = (ADC * 501.3743 / 2^bits) - 273.6777 * It's multiplied by 1000 to have millidegrees as * specified by the hwmon sysfs interface.
*/
*val = ((raw_temp * 501374) >> 16) - 273677; return 0; default: return -ENOTSUPP;
}
}
static umode_t axi_fan_control_temp_is_visible(const u32 attr)
{ switch (attr) { case hwmon_temp_input: case hwmon_temp_label: return 0444; default: return 0;
}
}
static umode_t axi_fan_control_is_visible(constvoid *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{ switch (type) { case hwmon_fan: return axi_fan_control_fan_is_visible(attr); case hwmon_pwm: return axi_fan_control_pwm_is_visible(attr); case hwmon_temp: return axi_fan_control_temp_is_visible(attr); default: return 0;
}
}
/* * This core has two main ways of changing the PWM duty cycle. It is done, * either by a request from userspace (writing on pwm1_input) or by the * core itself. When the change is done by the core, it will use predefined * parameters to evaluate the tach signal and, on that case we cannot set them. * On the other hand, when the request is done by the user, with some arbitrary * value that the core does not now about, we have to provide the tach * parameters so that, the core can evaluate the signal. On the IRQ handler we * distinguish this by using the ADI_IRQ_SRC_TEMP_INCREASE interrupt. This tell * us that the CORE requested a new duty cycle. After this, there is 5s delay * on which the core waits for the fan rotation speed to stabilize. After this * we get ADI_IRQ_SRC_PWM_CHANGED irq where we will decide if we need to set * the tach parameters or not on the next tach measurement cycle (corresponding * already to the ney duty cycle) based on the %ctl->hw_pwm_req flag.
*/ static irqreturn_t axi_fan_control_irq_handler(int irq, void *data)
{ struct axi_fan_control_data *ctl = (struct axi_fan_control_data *)data;
u32 irq_pending = axi_ioread(ADI_REG_IRQ_PENDING, ctl);
u32 clear_mask;
if (irq_pending & ADI_IRQ_SRC_TEMP_INCREASE) /* hardware requested a new pwm */
ctl->hw_pwm_req = true;
if (irq_pending & ADI_IRQ_SRC_PWM_CHANGED) { /* * if the pwm changes on behalf of software, * we need to provide new tacho parameters to the core. * Wait for the next measurement for that...
*/ if (!ctl->hw_pwm_req) {
ctl->update_tacho_params = true;
} else {
ctl->hw_pwm_req = false;
hwmon_notify_event(ctl->hdev, hwmon_pwm,
hwmon_pwm_input, 0);
}
}
if (irq_pending & ADI_IRQ_SRC_NEW_MEASUR) { if (ctl->update_tacho_params) {
u32 new_tach = axi_ioread(ADI_REG_TACH_MEASUR, ctl); /* get 25% tolerance */
u32 tach_tol = DIV_ROUND_CLOSEST(new_tach * 25, 100);
/* set new tacho parameters */
axi_iowrite(new_tach, ADI_REG_TACH_PERIOD, ctl);
axi_iowrite(tach_tol, ADI_REG_TACH_TOLERANCE, ctl);
ctl->update_tacho_params = false;
}
}
if (irq_pending & ADI_IRQ_SRC_TACH_ERR)
ctl->fan_fault = 1;
/* temperature threshold below which PWM should be 0% */ static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp_hyst, axi_fan_control, ADI_REG_TEMP_00_H); /* temperature threshold above which PWM should be 25% */ static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp, axi_fan_control, ADI_REG_TEMP_25_L); /* temperature threshold below which PWM should be 25% */ static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_temp_hyst, axi_fan_control, ADI_REG_TEMP_25_H); /* temperature threshold above which PWM should be 50% */ static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_temp, axi_fan_control, ADI_REG_TEMP_50_L); /* temperature threshold below which PWM should be 50% */ static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_temp_hyst, axi_fan_control, ADI_REG_TEMP_50_H); /* temperature threshold above which PWM should be 75% */ static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_temp, axi_fan_control, ADI_REG_TEMP_75_L); /* temperature threshold below which PWM should be 75% */ static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_temp_hyst, axi_fan_control, ADI_REG_TEMP_75_H); /* temperature threshold above which PWM should be 100% */ static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_temp, axi_fan_control, ADI_REG_TEMP_100_L);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.