162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/bitfield.h> 462306a36Sopenharmony_ci#include <linux/bits.h> 562306a36Sopenharmony_ci#include <linux/err.h> 662306a36Sopenharmony_ci#include <linux/hwmon.h> 762306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 862306a36Sopenharmony_ci#include <linux/i2c.h> 962306a36Sopenharmony_ci#include <linux/regmap.h> 1062306a36Sopenharmony_ci#include <linux/util_macros.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define REG_CR1 0x00 1362306a36Sopenharmony_ci#define CR1_HYST BIT(5) 1462306a36Sopenharmony_ci#define CR1_DRV GENMASK(4, 3) 1562306a36Sopenharmony_ci#define CR1_TEMP_SRC GENMASK(1, 0) 1662306a36Sopenharmony_ci#define REG_CR2 0x01 1762306a36Sopenharmony_ci#define CR2_STBY BIT(7) 1862306a36Sopenharmony_ci#define CR2_ALERTS BIT(6) 1962306a36Sopenharmony_ci#define CR2_DFC BIT(0) 2062306a36Sopenharmony_ci#define REG_CR3 0x02 2162306a36Sopenharmony_ci#define REG_PWMR 0x50 2262306a36Sopenharmony_ci#define REG_PWMV 0x51 2362306a36Sopenharmony_ci#define REG_STATUS 0x5A 2462306a36Sopenharmony_ci#define STATUS_ALARM_CRIT(ch) BIT(2 + 2 * (ch)) 2562306a36Sopenharmony_ci#define STATUS_ALARM_MAX(ch) BIT(3 + 2 * (ch)) 2662306a36Sopenharmony_ci#define STATUS_RDFA BIT(6) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define REG_TACH(ch) (0x52 + (ch) * 2) 2962306a36Sopenharmony_ci#define REG_TEMP_INPUT(ch) (0x56 + (ch) * 2) 3062306a36Sopenharmony_ci#define REG_TEMP_MAX(ch) (0x06 + (ch) * 2) 3162306a36Sopenharmony_ci#define REG_TEMP_CRIT(ch) (0x0A + (ch) * 2) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) 3462306a36Sopenharmony_ci#define TEMP11_TO_REG(val) (DIV_ROUND_CLOSEST(clamp_val((val), -128000, \ 3562306a36Sopenharmony_ci 127875), 125) * 32) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define LUT_SIZE 48 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define REG_LUT(index) (0x20 + (index)) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct max31760_state { 4262306a36Sopenharmony_ci struct regmap *regmap; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci struct lut_attribute { 4562306a36Sopenharmony_ci char name[24]; 4662306a36Sopenharmony_ci struct sensor_device_attribute sda; 4762306a36Sopenharmony_ci } lut[LUT_SIZE]; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci struct attribute *attrs[LUT_SIZE + 2]; 5062306a36Sopenharmony_ci struct attribute_group group; 5162306a36Sopenharmony_ci const struct attribute_group *groups[2]; 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic bool max31760_volatile_reg(struct device *dev, unsigned int reg) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci return reg > 0x50; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic const struct regmap_config regmap_config = { 6062306a36Sopenharmony_ci .reg_bits = 8, 6162306a36Sopenharmony_ci .val_bits = 8, 6262306a36Sopenharmony_ci .max_register = 0x5B, 6362306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 6462306a36Sopenharmony_ci .volatile_reg = max31760_volatile_reg, 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic const int max31760_pwm_freq[] = {33, 150, 1500, 25000}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int tach_to_rpm(u16 tach) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci if (tach == 0) 7262306a36Sopenharmony_ci tach = 1; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return 60 * 100000 / tach / 2; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int max31760_read(struct device *dev, enum hwmon_sensor_types type, 7862306a36Sopenharmony_ci u32 attr, int channel, long *val) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct max31760_state *state = dev_get_drvdata(dev); 8162306a36Sopenharmony_ci unsigned int regval; 8262306a36Sopenharmony_ci unsigned int reg_temp; 8362306a36Sopenharmony_ci s16 temp; 8462306a36Sopenharmony_ci u8 reg[2]; 8562306a36Sopenharmony_ci int ret; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci switch (type) { 8862306a36Sopenharmony_ci case hwmon_temp: 8962306a36Sopenharmony_ci switch (attr) { 9062306a36Sopenharmony_ci case hwmon_temp_fault: 9162306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_STATUS, ®val); 9262306a36Sopenharmony_ci if (ret) 9362306a36Sopenharmony_ci return ret; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci *val = FIELD_GET(STATUS_RDFA, regval); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci case hwmon_temp_max_alarm: 9962306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_STATUS, ®val); 10062306a36Sopenharmony_ci if (ret) 10162306a36Sopenharmony_ci return ret; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (channel) 10462306a36Sopenharmony_ci *val = FIELD_GET(STATUS_ALARM_MAX(1), regval); 10562306a36Sopenharmony_ci else 10662306a36Sopenharmony_ci *val = FIELD_GET(STATUS_ALARM_MAX(0), regval); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci case hwmon_temp_crit_alarm: 11062306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_STATUS, ®val); 11162306a36Sopenharmony_ci if (ret) 11262306a36Sopenharmony_ci return ret; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (channel) 11562306a36Sopenharmony_ci *val = FIELD_GET(STATUS_ALARM_CRIT(1), regval); 11662306a36Sopenharmony_ci else 11762306a36Sopenharmony_ci *val = FIELD_GET(STATUS_ALARM_CRIT(0), regval); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci case hwmon_temp_input: 12162306a36Sopenharmony_ci reg_temp = REG_TEMP_INPUT(channel); 12262306a36Sopenharmony_ci break; 12362306a36Sopenharmony_ci case hwmon_temp_max: 12462306a36Sopenharmony_ci reg_temp = REG_TEMP_MAX(channel); 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci case hwmon_temp_crit: 12762306a36Sopenharmony_ci reg_temp = REG_TEMP_CRIT(channel); 12862306a36Sopenharmony_ci break; 12962306a36Sopenharmony_ci default: 13062306a36Sopenharmony_ci return -EOPNOTSUPP; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ret = regmap_bulk_read(state->regmap, reg_temp, reg, 2); 13462306a36Sopenharmony_ci if (ret) 13562306a36Sopenharmony_ci return ret; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci temp = (reg[0] << 8) | reg[1]; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci *val = TEMP11_FROM_REG(temp); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci case hwmon_fan: 14362306a36Sopenharmony_ci switch (attr) { 14462306a36Sopenharmony_ci case hwmon_fan_input: 14562306a36Sopenharmony_ci ret = regmap_bulk_read(state->regmap, REG_TACH(channel), reg, 2); 14662306a36Sopenharmony_ci if (ret) 14762306a36Sopenharmony_ci return ret; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci *val = tach_to_rpm(reg[0] * 256 + reg[1]); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci case hwmon_fan_fault: 15362306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_STATUS, ®val); 15462306a36Sopenharmony_ci if (ret) 15562306a36Sopenharmony_ci return ret; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (channel) 15862306a36Sopenharmony_ci *val = FIELD_GET(BIT(1), regval); 15962306a36Sopenharmony_ci else 16062306a36Sopenharmony_ci *val = FIELD_GET(BIT(0), regval); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci case hwmon_fan_enable: 16462306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_CR3, ®val); 16562306a36Sopenharmony_ci if (ret) 16662306a36Sopenharmony_ci return ret; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (channel) 16962306a36Sopenharmony_ci *val = FIELD_GET(BIT(1), regval); 17062306a36Sopenharmony_ci else 17162306a36Sopenharmony_ci *val = FIELD_GET(BIT(0), regval); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci default: 17562306a36Sopenharmony_ci return -EOPNOTSUPP; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci case hwmon_pwm: 17862306a36Sopenharmony_ci switch (attr) { 17962306a36Sopenharmony_ci case hwmon_pwm_input: 18062306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_PWMV, ®val); 18162306a36Sopenharmony_ci if (ret) 18262306a36Sopenharmony_ci return ret; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci *val = regval; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return 0; 18762306a36Sopenharmony_ci case hwmon_pwm_freq: 18862306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_CR1, ®val); 18962306a36Sopenharmony_ci if (ret) 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci regval = FIELD_GET(CR1_DRV, regval); 19362306a36Sopenharmony_ci if (regval >= ARRAY_SIZE(max31760_pwm_freq)) 19462306a36Sopenharmony_ci return -EINVAL; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci *val = max31760_pwm_freq[regval]; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return 0; 19962306a36Sopenharmony_ci case hwmon_pwm_enable: 20062306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_CR2, ®val); 20162306a36Sopenharmony_ci if (ret) 20262306a36Sopenharmony_ci return ret; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci *val = 2 - FIELD_GET(CR2_DFC, regval); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci case hwmon_pwm_auto_channels_temp: 20862306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_CR1, ®val); 20962306a36Sopenharmony_ci if (ret) 21062306a36Sopenharmony_ci return ret; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci switch (FIELD_GET(CR1_TEMP_SRC, regval)) { 21362306a36Sopenharmony_ci case 0: 21462306a36Sopenharmony_ci *val = 2; 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci case 1: 21762306a36Sopenharmony_ci *val = 1; 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci case 2: 22062306a36Sopenharmony_ci case 3: 22162306a36Sopenharmony_ci *val = 3; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci default: 22462306a36Sopenharmony_ci return -EINVAL; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci default: 22962306a36Sopenharmony_ci return -EOPNOTSUPP; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci default: 23262306a36Sopenharmony_ci return -EOPNOTSUPP; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int max31760_write(struct device *dev, enum hwmon_sensor_types type, 23762306a36Sopenharmony_ci u32 attr, int channel, long val) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct max31760_state *state = dev_get_drvdata(dev); 24062306a36Sopenharmony_ci unsigned int pwm_index; 24162306a36Sopenharmony_ci unsigned int reg_temp; 24262306a36Sopenharmony_ci int temp; 24362306a36Sopenharmony_ci u8 reg_val[2]; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci switch (type) { 24662306a36Sopenharmony_ci case hwmon_temp: 24762306a36Sopenharmony_ci switch (attr) { 24862306a36Sopenharmony_ci case hwmon_temp_max: 24962306a36Sopenharmony_ci reg_temp = REG_TEMP_MAX(channel); 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci case hwmon_temp_crit: 25262306a36Sopenharmony_ci reg_temp = REG_TEMP_CRIT(channel); 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci default: 25562306a36Sopenharmony_ci return -EOPNOTSUPP; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci temp = TEMP11_TO_REG(val); 25962306a36Sopenharmony_ci reg_val[0] = temp >> 8; 26062306a36Sopenharmony_ci reg_val[1] = temp & 0xFF; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return regmap_bulk_write(state->regmap, reg_temp, reg_val, 2); 26362306a36Sopenharmony_ci case hwmon_fan: 26462306a36Sopenharmony_ci switch (attr) { 26562306a36Sopenharmony_ci case hwmon_fan_enable: 26662306a36Sopenharmony_ci if (val == 0) 26762306a36Sopenharmony_ci return regmap_clear_bits(state->regmap, REG_CR3, BIT(channel)); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (val == 1) 27062306a36Sopenharmony_ci return regmap_set_bits(state->regmap, REG_CR3, BIT(channel)); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return -EINVAL; 27362306a36Sopenharmony_ci default: 27462306a36Sopenharmony_ci return -EOPNOTSUPP; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci case hwmon_pwm: 27762306a36Sopenharmony_ci switch (attr) { 27862306a36Sopenharmony_ci case hwmon_pwm_input: 27962306a36Sopenharmony_ci if (val < 0 || val > 255) 28062306a36Sopenharmony_ci return -EINVAL; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return regmap_write(state->regmap, REG_PWMR, val); 28362306a36Sopenharmony_ci case hwmon_pwm_enable: 28462306a36Sopenharmony_ci if (val == 1) 28562306a36Sopenharmony_ci return regmap_set_bits(state->regmap, REG_CR2, CR2_DFC); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (val == 2) 28862306a36Sopenharmony_ci return regmap_clear_bits(state->regmap, REG_CR2, CR2_DFC); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return -EINVAL; 29162306a36Sopenharmony_ci case hwmon_pwm_freq: 29262306a36Sopenharmony_ci pwm_index = find_closest(val, max31760_pwm_freq, 29362306a36Sopenharmony_ci ARRAY_SIZE(max31760_pwm_freq)); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return regmap_update_bits(state->regmap, 29662306a36Sopenharmony_ci REG_CR1, CR1_DRV, 29762306a36Sopenharmony_ci FIELD_PREP(CR1_DRV, pwm_index)); 29862306a36Sopenharmony_ci case hwmon_pwm_auto_channels_temp: 29962306a36Sopenharmony_ci switch (val) { 30062306a36Sopenharmony_ci case 1: 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci case 2: 30362306a36Sopenharmony_ci val = 0; 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci case 3: 30662306a36Sopenharmony_ci val = 2; 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci default: 30962306a36Sopenharmony_ci return -EINVAL; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return regmap_update_bits(state->regmap, REG_CR1, CR1_TEMP_SRC, val); 31362306a36Sopenharmony_ci default: 31462306a36Sopenharmony_ci return -EOPNOTSUPP; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci default: 31762306a36Sopenharmony_ci return -EOPNOTSUPP; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic const struct hwmon_channel_info * const max31760_info[] = { 32262306a36Sopenharmony_ci HWMON_CHANNEL_INFO(chip, 32362306a36Sopenharmony_ci HWMON_C_REGISTER_TZ), 32462306a36Sopenharmony_ci HWMON_CHANNEL_INFO(fan, 32562306a36Sopenharmony_ci HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_ENABLE, 32662306a36Sopenharmony_ci HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_ENABLE), 32762306a36Sopenharmony_ci HWMON_CHANNEL_INFO(temp, 32862306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT | 32962306a36Sopenharmony_ci HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_LABEL, 33062306a36Sopenharmony_ci HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | 33162306a36Sopenharmony_ci HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_LABEL), 33262306a36Sopenharmony_ci HWMON_CHANNEL_INFO(pwm, 33362306a36Sopenharmony_ci HWMON_PWM_ENABLE | HWMON_PWM_FREQ | HWMON_PWM_INPUT | 33462306a36Sopenharmony_ci HWMON_PWM_AUTO_CHANNELS_TEMP), 33562306a36Sopenharmony_ci NULL 33662306a36Sopenharmony_ci}; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic umode_t max31760_is_visible(const void *data, 33962306a36Sopenharmony_ci enum hwmon_sensor_types type, 34062306a36Sopenharmony_ci u32 attr, int channel) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci switch (type) { 34362306a36Sopenharmony_ci case hwmon_temp: 34462306a36Sopenharmony_ci switch (attr) { 34562306a36Sopenharmony_ci case hwmon_temp_input: 34662306a36Sopenharmony_ci case hwmon_temp_max_alarm: 34762306a36Sopenharmony_ci case hwmon_temp_crit_alarm: 34862306a36Sopenharmony_ci case hwmon_temp_fault: 34962306a36Sopenharmony_ci case hwmon_temp_label: 35062306a36Sopenharmony_ci return 0444; 35162306a36Sopenharmony_ci case hwmon_temp_max: 35262306a36Sopenharmony_ci case hwmon_temp_crit: 35362306a36Sopenharmony_ci return 0644; 35462306a36Sopenharmony_ci default: 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci case hwmon_fan: 35862306a36Sopenharmony_ci switch (attr) { 35962306a36Sopenharmony_ci case hwmon_fan_input: 36062306a36Sopenharmony_ci case hwmon_fan_fault: 36162306a36Sopenharmony_ci return 0444; 36262306a36Sopenharmony_ci case hwmon_fan_enable: 36362306a36Sopenharmony_ci return 0644; 36462306a36Sopenharmony_ci default: 36562306a36Sopenharmony_ci return 0; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci case hwmon_pwm: 36862306a36Sopenharmony_ci switch (attr) { 36962306a36Sopenharmony_ci case hwmon_pwm_enable: 37062306a36Sopenharmony_ci case hwmon_pwm_input: 37162306a36Sopenharmony_ci case hwmon_pwm_freq: 37262306a36Sopenharmony_ci case hwmon_pwm_auto_channels_temp: 37362306a36Sopenharmony_ci return 0644; 37462306a36Sopenharmony_ci default: 37562306a36Sopenharmony_ci return 0; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci default: 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int max31760_read_string(struct device *dev, 38362306a36Sopenharmony_ci enum hwmon_sensor_types type, 38462306a36Sopenharmony_ci u32 attr, int channel, const char **str) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci switch (type) { 38762306a36Sopenharmony_ci case hwmon_temp: 38862306a36Sopenharmony_ci if (attr != hwmon_temp_label) 38962306a36Sopenharmony_ci return -EOPNOTSUPP; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci *str = channel ? "local" : "remote"; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci default: 39562306a36Sopenharmony_ci return -EOPNOTSUPP; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic const struct hwmon_ops max31760_hwmon_ops = { 40062306a36Sopenharmony_ci .is_visible = max31760_is_visible, 40162306a36Sopenharmony_ci .read = max31760_read, 40262306a36Sopenharmony_ci .write = max31760_write, 40362306a36Sopenharmony_ci .read_string = max31760_read_string 40462306a36Sopenharmony_ci}; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic const struct hwmon_chip_info max31760_chip_info = { 40762306a36Sopenharmony_ci .ops = &max31760_hwmon_ops, 40862306a36Sopenharmony_ci .info = max31760_info, 40962306a36Sopenharmony_ci}; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic ssize_t lut_show(struct device *dev, 41262306a36Sopenharmony_ci struct device_attribute *devattr, char *buf) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); 41562306a36Sopenharmony_ci struct max31760_state *state = dev_get_drvdata(dev); 41662306a36Sopenharmony_ci int ret; 41762306a36Sopenharmony_ci unsigned int regval; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_LUT(sda->index), ®val); 42062306a36Sopenharmony_ci if (ret) 42162306a36Sopenharmony_ci return ret; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", regval); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic ssize_t lut_store(struct device *dev, 42762306a36Sopenharmony_ci struct device_attribute *devattr, 42862306a36Sopenharmony_ci const char *buf, size_t count) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); 43162306a36Sopenharmony_ci struct max31760_state *state = dev_get_drvdata(dev); 43262306a36Sopenharmony_ci int ret; 43362306a36Sopenharmony_ci u8 pwm; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci ret = kstrtou8(buf, 10, &pwm); 43662306a36Sopenharmony_ci if (ret) 43762306a36Sopenharmony_ci return ret; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci ret = regmap_write(state->regmap, REG_LUT(sda->index), pwm); 44062306a36Sopenharmony_ci if (ret) 44162306a36Sopenharmony_ci return ret; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return count; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic ssize_t pwm1_auto_point_temp_hyst_show(struct device *dev, 44762306a36Sopenharmony_ci struct device_attribute *attr, 44862306a36Sopenharmony_ci char *buf) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct max31760_state *state = dev_get_drvdata(dev); 45162306a36Sopenharmony_ci unsigned int regval; 45262306a36Sopenharmony_ci int ret; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci ret = regmap_read(state->regmap, REG_CR1, ®val); 45562306a36Sopenharmony_ci if (ret) 45662306a36Sopenharmony_ci return ret; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", (1 + (int)FIELD_GET(CR1_HYST, regval)) * 2000); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic ssize_t pwm1_auto_point_temp_hyst_store(struct device *dev, 46262306a36Sopenharmony_ci struct device_attribute *attr, 46362306a36Sopenharmony_ci const char *buf, 46462306a36Sopenharmony_ci size_t count) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct max31760_state *state = dev_get_drvdata(dev); 46762306a36Sopenharmony_ci unsigned int hyst; 46862306a36Sopenharmony_ci int ret; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci ret = kstrtou32(buf, 10, &hyst); 47162306a36Sopenharmony_ci if (ret) 47262306a36Sopenharmony_ci return ret; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (hyst < 3000) 47562306a36Sopenharmony_ci ret = regmap_clear_bits(state->regmap, REG_CR1, CR1_HYST); 47662306a36Sopenharmony_ci else 47762306a36Sopenharmony_ci ret = regmap_set_bits(state->regmap, REG_CR1, CR1_HYST); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (ret) 48062306a36Sopenharmony_ci return ret; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return count; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(pwm1_auto_point_temp_hyst); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic void max31760_create_lut_nodes(struct max31760_state *state) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci int i; 49062306a36Sopenharmony_ci struct sensor_device_attribute *sda; 49162306a36Sopenharmony_ci struct lut_attribute *lut; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci for (i = 0; i < LUT_SIZE; ++i) { 49462306a36Sopenharmony_ci lut = &state->lut[i]; 49562306a36Sopenharmony_ci sda = &lut->sda; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci snprintf(lut->name, sizeof(lut->name), 49862306a36Sopenharmony_ci "pwm1_auto_point%d_pwm", i + 1); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci sda->dev_attr.attr.mode = 0644; 50162306a36Sopenharmony_ci sda->index = i; 50262306a36Sopenharmony_ci sda->dev_attr.show = lut_show; 50362306a36Sopenharmony_ci sda->dev_attr.store = lut_store; 50462306a36Sopenharmony_ci sda->dev_attr.attr.name = lut->name; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci sysfs_attr_init(&sda->dev_attr.attr); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci state->attrs[i] = &sda->dev_attr.attr; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci state->attrs[i] = &dev_attr_pwm1_auto_point_temp_hyst.attr; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci state->group.attrs = state->attrs; 51462306a36Sopenharmony_ci state->groups[0] = &state->group; 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic int max31760_probe(struct i2c_client *client) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci struct device *dev = &client->dev; 52062306a36Sopenharmony_ci struct max31760_state *state; 52162306a36Sopenharmony_ci struct device *hwmon_dev; 52262306a36Sopenharmony_ci int ret; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); 52562306a36Sopenharmony_ci if (!state) 52662306a36Sopenharmony_ci return -ENOMEM; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci state->regmap = devm_regmap_init_i2c(client, ®map_config); 52962306a36Sopenharmony_ci if (IS_ERR(state->regmap)) 53062306a36Sopenharmony_ci return dev_err_probe(dev, 53162306a36Sopenharmony_ci PTR_ERR(state->regmap), 53262306a36Sopenharmony_ci "regmap initialization failed\n"); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci dev_set_drvdata(dev, state); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* Set alert output to comparator mode */ 53762306a36Sopenharmony_ci ret = regmap_set_bits(state->regmap, REG_CR2, CR2_ALERTS); 53862306a36Sopenharmony_ci if (ret) 53962306a36Sopenharmony_ci return dev_err_probe(dev, ret, "cannot write register\n"); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci max31760_create_lut_nodes(state); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 54462306a36Sopenharmony_ci state, 54562306a36Sopenharmony_ci &max31760_chip_info, 54662306a36Sopenharmony_ci state->groups); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic const struct of_device_id max31760_of_match[] = { 55262306a36Sopenharmony_ci {.compatible = "adi,max31760"}, 55362306a36Sopenharmony_ci { } 55462306a36Sopenharmony_ci}; 55562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, max31760_of_match); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic const struct i2c_device_id max31760_id[] = { 55862306a36Sopenharmony_ci {"max31760"}, 55962306a36Sopenharmony_ci { } 56062306a36Sopenharmony_ci}; 56162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max31760_id); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic int max31760_suspend(struct device *dev) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct max31760_state *state = dev_get_drvdata(dev); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return regmap_set_bits(state->regmap, REG_CR2, CR2_STBY); 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int max31760_resume(struct device *dev) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct max31760_state *state = dev_get_drvdata(dev); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci return regmap_clear_bits(state->regmap, REG_CR2, CR2_STBY); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(max31760_pm_ops, max31760_suspend, 57862306a36Sopenharmony_ci max31760_resume); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic struct i2c_driver max31760_driver = { 58162306a36Sopenharmony_ci .class = I2C_CLASS_HWMON, 58262306a36Sopenharmony_ci .driver = { 58362306a36Sopenharmony_ci .name = "max31760", 58462306a36Sopenharmony_ci .of_match_table = max31760_of_match, 58562306a36Sopenharmony_ci .pm = pm_ptr(&max31760_pm_ops) 58662306a36Sopenharmony_ci }, 58762306a36Sopenharmony_ci .probe = max31760_probe, 58862306a36Sopenharmony_ci .id_table = max31760_id 58962306a36Sopenharmony_ci}; 59062306a36Sopenharmony_cimodule_i2c_driver(max31760_driver); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ciMODULE_AUTHOR("Ibrahim Tilki <Ibrahim.Tilki@analog.com>"); 59362306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices MAX31760 Fan Speed Controller"); 59462306a36Sopenharmony_ciMODULE_SOFTDEP("pre: regmap_i2c"); 59562306a36Sopenharmony_ciMODULE_VERSION("1.0"); 59662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 597