// SPDX-License-Identifier: GPL-2.0-or-later /* * max6639.c - Support for Maxim MAX6639 * * 2-Channel Temperature Monitor with Dual PWM Fan-Speed Controller * * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de> * * based on the initial MAX6639 support from semptian.net * by He Changqing <hechangqing@semptian.com>
*/
/* * Client data (each client gets its own)
*/ struct max6639_data { struct regmap *regmap; struct mutex update_lock;
/* Register values initialized only once */
u8 ppr[MAX6639_NUM_CHANNELS]; /* Pulses per rotation 0..3 for 1..4 ppr */
u8 rpm_range[MAX6639_NUM_CHANNELS]; /* Index in above rpm_ranges table */
u32 target_rpm[MAX6639_NUM_CHANNELS];
/* Optional regulator for FAN supply */ struct regulator *reg;
};
staticint max6639_temp_read_input(struct device *dev, int channel, long *temp)
{
u32 regs[2] = { MAX6639_REG_TEMP_EXT(channel), MAX6639_REG_TEMP(channel) }; struct max6639_data *data = dev_get_drvdata(dev);
u8 regvals[2]; int res;
res = regmap_multi_reg_read(data->regmap, regs, regvals, 2); if (res < 0) return res;
res = regmap_read(data->regmap, MAX6639_REG_STATUS, &val); if (res < 0) return res;
*status = val;
return 0;
}
staticint max6639_temp_set_max(struct max6639_data *data, int channel, long val)
{ int res;
res = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(channel),
TEMP_LIMIT_TO_REG(val)); return res;
}
staticint max6639_temp_set_crit(struct max6639_data *data, int channel, long val)
{ int res;
res = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(channel), TEMP_LIMIT_TO_REG(val));
return res;
}
staticint max6639_temp_set_emergency(struct max6639_data *data, int channel, long val)
{ int res;
res = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(channel), TEMP_LIMIT_TO_REG(val));
return res;
}
staticint max6639_read_fan(struct device *dev, u32 attr, int channel, long *fan_val)
{ struct max6639_data *data = dev_get_drvdata(dev); unsignedint val; int res;
switch (attr) { case hwmon_fan_input:
res = regmap_read(data->regmap, MAX6639_REG_FAN_CNT(channel), &val); if (res < 0) return res;
*fan_val = FAN_FROM_REG(val, data->rpm_range[channel]); return 0; case hwmon_fan_fault:
res = max6639_get_status(dev, &val); if (res < 0) return res;
*fan_val = !!(val & BIT(1 - channel)); return 0; case hwmon_fan_pulses:
*fan_val = data->ppr[channel]; return 0; default: return -EOPNOTSUPP;
}
}
staticint max6639_set_ppr(struct max6639_data *data, int channel, u8 ppr)
{ /* Decrement the PPR value and shift left by 6 to match the register format */ return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), ppr-- << 6);
}
staticint max6639_write_fan(struct device *dev, u32 attr, int channel, long val)
{ struct max6639_data *data = dev_get_drvdata(dev); int err;
switch (attr) { case hwmon_fan_pulses: if (val <= 0 || val > 4) return -EINVAL;
mutex_lock(&data->update_lock); /* Set Fan pulse per revolution */
err = max6639_set_ppr(data, channel, val); if (err < 0) {
mutex_unlock(&data->update_lock); return err;
}
data->ppr[channel] = val;
static umode_t max6639_pwm_is_visible(constvoid *_data, u32 attr, int channel)
{ switch (attr) { case hwmon_pwm_input: case hwmon_pwm_freq: return 0644; default: return 0;
}
}
staticint max6639_read_temp(struct device *dev, u32 attr, int channel, long *val)
{ unsignedint status; int res;
switch (attr) { case hwmon_temp_input:
res = max6639_temp_read_input(dev, channel, val); return res; case hwmon_temp_fault:
res = max6639_temp_read_fault(dev, channel, val); return res; case hwmon_temp_max:
res = max6639_temp_read_max(dev, channel, val); return res; case hwmon_temp_crit:
res = max6639_temp_read_crit(dev, channel, val); return res; case hwmon_temp_emergency:
res = max6639_temp_read_emergency(dev, channel, val); return res; case hwmon_temp_max_alarm:
res = max6639_get_status(dev, &status); if (res < 0) return res;
*val = !!(status & BIT(3 - channel)); return 0; case hwmon_temp_crit_alarm:
res = max6639_get_status(dev, &status); if (res < 0) return res;
*val = !!(status & BIT(7 - channel)); return 0; case hwmon_temp_emergency_alarm:
res = max6639_get_status(dev, &status); if (res < 0) return res;
*val = !!(status & BIT(5 - channel)); return 0; default: return -EOPNOTSUPP;
}
}
staticint max6639_write_temp(struct device *dev, u32 attr, int channel, long val)
{ struct max6639_data *data = dev_get_drvdata(dev);
switch (attr) { case hwmon_temp_max: return max6639_temp_set_max(data, channel, val); case hwmon_temp_crit: return max6639_temp_set_crit(data, channel, val); case hwmon_temp_emergency: return max6639_temp_set_emergency(data, channel, val); default: return -EOPNOTSUPP;
}
}
static umode_t max6639_temp_is_visible(constvoid *_data, u32 attr, int channel)
{ switch (attr) { case hwmon_temp_input: case hwmon_temp_fault: case hwmon_temp_max_alarm: case hwmon_temp_crit_alarm: case hwmon_temp_emergency_alarm: return 0444; case hwmon_temp_max: case hwmon_temp_crit: case hwmon_temp_emergency: return 0644; default: return 0;
}
}
staticint max6639_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{ switch (type) { case hwmon_fan: return max6639_read_fan(dev, attr, channel, val); case hwmon_pwm: return max6639_read_pwm(dev, attr, channel, val); case hwmon_temp: return max6639_read_temp(dev, attr, channel, val); default: return -EOPNOTSUPP;
}
}
staticint max6639_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{ switch (type) { case hwmon_fan: return max6639_write_fan(dev, attr, channel, val); case hwmon_pwm: return max6639_write_pwm(dev, attr, channel, val); case hwmon_temp: return max6639_write_temp(dev, attr, channel, val); default: return -EOPNOTSUPP;
}
}
static umode_t max6639_is_visible(constvoid *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{ switch (type) { case hwmon_fan: return max6639_fan_is_visible(data, attr, channel); case hwmon_pwm: return max6639_pwm_is_visible(data, attr, channel); case hwmon_temp: return max6639_temp_is_visible(data, attr, channel); default: return 0;
}
}
/* Set PWM based on target RPM if specified */ if (data->target_rpm[i] > rpm_ranges[data->rpm_range[i]])
data->target_rpm[i] = rpm_ranges[data->rpm_range[i]];
staticbool max6639_regmap_is_volatile(struct device *dev, unsignedint reg)
{ switch (reg) { case MAX6639_REG_TEMP(0): case MAX6639_REG_TEMP_EXT(0): case MAX6639_REG_TEMP(1): case MAX6639_REG_TEMP_EXT(1): case MAX6639_REG_STATUS: case MAX6639_REG_FAN_CNT(0): case MAX6639_REG_FAN_CNT(1): case MAX6639_REG_TARGTDUTY(0): case MAX6639_REG_TARGTDUTY(1): returntrue; default: returnfalse;
}
}
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.