138b04ad0SIbrahim Tilki // SPDX-License-Identifier: GPL-2.0-only 238b04ad0SIbrahim Tilki 338b04ad0SIbrahim Tilki #include <linux/bitfield.h> 438b04ad0SIbrahim Tilki #include <linux/bits.h> 538b04ad0SIbrahim Tilki #include <linux/err.h> 638b04ad0SIbrahim Tilki #include <linux/hwmon.h> 738b04ad0SIbrahim Tilki #include <linux/hwmon-sysfs.h> 838b04ad0SIbrahim Tilki #include <linux/i2c.h> 938b04ad0SIbrahim Tilki #include <linux/regmap.h> 1038b04ad0SIbrahim Tilki #include <linux/util_macros.h> 1138b04ad0SIbrahim Tilki 1238b04ad0SIbrahim Tilki #define REG_CR1 0x00 1338b04ad0SIbrahim Tilki #define CR1_HYST BIT(5) 1438b04ad0SIbrahim Tilki #define CR1_DRV GENMASK(4, 3) 1538b04ad0SIbrahim Tilki #define CR1_TEMP_SRC GENMASK(1, 0) 1638b04ad0SIbrahim Tilki #define REG_CR2 0x01 1738b04ad0SIbrahim Tilki #define CR2_STBY BIT(7) 1838b04ad0SIbrahim Tilki #define CR2_ALERTS BIT(6) 1938b04ad0SIbrahim Tilki #define CR2_DFC BIT(0) 2038b04ad0SIbrahim Tilki #define REG_CR3 0x02 2138b04ad0SIbrahim Tilki #define REG_PWMR 0x50 2238b04ad0SIbrahim Tilki #define REG_PWMV 0x51 2338b04ad0SIbrahim Tilki #define REG_STATUS 0x5A 2438b04ad0SIbrahim Tilki #define STATUS_ALARM_CRIT(ch) BIT(2 + 2 * (ch)) 2538b04ad0SIbrahim Tilki #define STATUS_ALARM_MAX(ch) BIT(3 + 2 * (ch)) 2638b04ad0SIbrahim Tilki #define STATUS_RDFA BIT(6) 2738b04ad0SIbrahim Tilki 2838b04ad0SIbrahim Tilki #define REG_TACH(ch) (0x52 + (ch) * 2) 2938b04ad0SIbrahim Tilki #define REG_TEMP_INPUT(ch) (0x56 + (ch) * 2) 3038b04ad0SIbrahim Tilki #define REG_TEMP_MAX(ch) (0x06 + (ch) * 2) 3138b04ad0SIbrahim Tilki #define REG_TEMP_CRIT(ch) (0x0A + (ch) * 2) 3238b04ad0SIbrahim Tilki 3338b04ad0SIbrahim Tilki #define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) 3438b04ad0SIbrahim Tilki #define TEMP11_TO_REG(val) (DIV_ROUND_CLOSEST(clamp_val((val), -128000, \ 3538b04ad0SIbrahim Tilki 127875), 125) * 32) 3638b04ad0SIbrahim Tilki 3738b04ad0SIbrahim Tilki #define LUT_SIZE 48 3838b04ad0SIbrahim Tilki 3938b04ad0SIbrahim Tilki #define REG_LUT(index) (0x20 + (index)) 4038b04ad0SIbrahim Tilki 4138b04ad0SIbrahim Tilki struct max31760_state { 4238b04ad0SIbrahim Tilki struct regmap *regmap; 4338b04ad0SIbrahim Tilki 4438b04ad0SIbrahim Tilki struct lut_attribute { 4538b04ad0SIbrahim Tilki char name[24]; 4638b04ad0SIbrahim Tilki struct sensor_device_attribute sda; 4738b04ad0SIbrahim Tilki } lut[LUT_SIZE]; 4838b04ad0SIbrahim Tilki 4938b04ad0SIbrahim Tilki struct attribute *attrs[LUT_SIZE + 2]; 5038b04ad0SIbrahim Tilki struct attribute_group group; 5138b04ad0SIbrahim Tilki const struct attribute_group *groups[2]; 5238b04ad0SIbrahim Tilki }; 5338b04ad0SIbrahim Tilki 5438b04ad0SIbrahim Tilki static bool max31760_volatile_reg(struct device *dev, unsigned int reg) 5538b04ad0SIbrahim Tilki { 5638b04ad0SIbrahim Tilki return reg > 0x50; 5738b04ad0SIbrahim Tilki } 5838b04ad0SIbrahim Tilki 5938b04ad0SIbrahim Tilki static const struct regmap_config regmap_config = { 6038b04ad0SIbrahim Tilki .reg_bits = 8, 6138b04ad0SIbrahim Tilki .val_bits = 8, 6238b04ad0SIbrahim Tilki .max_register = 0x5B, 6338b04ad0SIbrahim Tilki .cache_type = REGCACHE_RBTREE, 6438b04ad0SIbrahim Tilki .volatile_reg = max31760_volatile_reg, 6538b04ad0SIbrahim Tilki }; 6638b04ad0SIbrahim Tilki 6738b04ad0SIbrahim Tilki static const int max31760_pwm_freq[] = {33, 150, 1500, 25000}; 6838b04ad0SIbrahim Tilki 6938b04ad0SIbrahim Tilki static int tach_to_rpm(u16 tach) 7038b04ad0SIbrahim Tilki { 7138b04ad0SIbrahim Tilki if (tach == 0) 7238b04ad0SIbrahim Tilki tach = 1; 7338b04ad0SIbrahim Tilki 7438b04ad0SIbrahim Tilki return 60 * 100000 / tach / 2; 7538b04ad0SIbrahim Tilki } 7638b04ad0SIbrahim Tilki 7738b04ad0SIbrahim Tilki static int max31760_read(struct device *dev, enum hwmon_sensor_types type, 7838b04ad0SIbrahim Tilki u32 attr, int channel, long *val) 7938b04ad0SIbrahim Tilki { 8038b04ad0SIbrahim Tilki struct max31760_state *state = dev_get_drvdata(dev); 8138b04ad0SIbrahim Tilki unsigned int regval; 8238b04ad0SIbrahim Tilki unsigned int reg_temp; 8338b04ad0SIbrahim Tilki s16 temp; 8438b04ad0SIbrahim Tilki u8 reg[2]; 8538b04ad0SIbrahim Tilki int ret; 8638b04ad0SIbrahim Tilki 8738b04ad0SIbrahim Tilki switch (type) { 8838b04ad0SIbrahim Tilki case hwmon_temp: 8938b04ad0SIbrahim Tilki switch (attr) { 9038b04ad0SIbrahim Tilki case hwmon_temp_fault: 9138b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_STATUS, ®val); 9238b04ad0SIbrahim Tilki if (ret) 9338b04ad0SIbrahim Tilki return ret; 9438b04ad0SIbrahim Tilki 9538b04ad0SIbrahim Tilki *val = FIELD_GET(STATUS_RDFA, regval); 9638b04ad0SIbrahim Tilki 9738b04ad0SIbrahim Tilki return 0; 9838b04ad0SIbrahim Tilki case hwmon_temp_max_alarm: 9938b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_STATUS, ®val); 10038b04ad0SIbrahim Tilki if (ret) 10138b04ad0SIbrahim Tilki return ret; 10238b04ad0SIbrahim Tilki 10338b04ad0SIbrahim Tilki if (channel) 10438b04ad0SIbrahim Tilki *val = FIELD_GET(STATUS_ALARM_MAX(1), regval); 10538b04ad0SIbrahim Tilki else 10638b04ad0SIbrahim Tilki *val = FIELD_GET(STATUS_ALARM_MAX(0), regval); 10738b04ad0SIbrahim Tilki 10838b04ad0SIbrahim Tilki return 0; 10938b04ad0SIbrahim Tilki case hwmon_temp_crit_alarm: 11038b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_STATUS, ®val); 11138b04ad0SIbrahim Tilki if (ret) 11238b04ad0SIbrahim Tilki return ret; 11338b04ad0SIbrahim Tilki 11438b04ad0SIbrahim Tilki if (channel) 11538b04ad0SIbrahim Tilki *val = FIELD_GET(STATUS_ALARM_CRIT(1), regval); 11638b04ad0SIbrahim Tilki else 11738b04ad0SIbrahim Tilki *val = FIELD_GET(STATUS_ALARM_CRIT(0), regval); 11838b04ad0SIbrahim Tilki 11938b04ad0SIbrahim Tilki return 0; 12038b04ad0SIbrahim Tilki case hwmon_temp_input: 12138b04ad0SIbrahim Tilki reg_temp = REG_TEMP_INPUT(channel); 12238b04ad0SIbrahim Tilki break; 12338b04ad0SIbrahim Tilki case hwmon_temp_max: 12438b04ad0SIbrahim Tilki reg_temp = REG_TEMP_MAX(channel); 12538b04ad0SIbrahim Tilki break; 12638b04ad0SIbrahim Tilki case hwmon_temp_crit: 12738b04ad0SIbrahim Tilki reg_temp = REG_TEMP_CRIT(channel); 12838b04ad0SIbrahim Tilki break; 12938b04ad0SIbrahim Tilki default: 13038b04ad0SIbrahim Tilki return -EOPNOTSUPP; 13138b04ad0SIbrahim Tilki } 13238b04ad0SIbrahim Tilki 13338b04ad0SIbrahim Tilki ret = regmap_bulk_read(state->regmap, reg_temp, reg, 2); 13438b04ad0SIbrahim Tilki if (ret) 13538b04ad0SIbrahim Tilki return ret; 13638b04ad0SIbrahim Tilki 13738b04ad0SIbrahim Tilki temp = (reg[0] << 8) | reg[1]; 13838b04ad0SIbrahim Tilki 13938b04ad0SIbrahim Tilki *val = TEMP11_FROM_REG(temp); 14038b04ad0SIbrahim Tilki 14138b04ad0SIbrahim Tilki return 0; 14238b04ad0SIbrahim Tilki case hwmon_fan: 14338b04ad0SIbrahim Tilki switch (attr) { 14438b04ad0SIbrahim Tilki case hwmon_fan_input: 14538b04ad0SIbrahim Tilki ret = regmap_bulk_read(state->regmap, REG_TACH(channel), reg, 2); 14638b04ad0SIbrahim Tilki if (ret) 14738b04ad0SIbrahim Tilki return ret; 14838b04ad0SIbrahim Tilki 14938b04ad0SIbrahim Tilki *val = tach_to_rpm(reg[0] * 256 + reg[1]); 15038b04ad0SIbrahim Tilki 15138b04ad0SIbrahim Tilki return 0; 15238b04ad0SIbrahim Tilki case hwmon_fan_fault: 15338b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_STATUS, ®val); 15438b04ad0SIbrahim Tilki if (ret) 15538b04ad0SIbrahim Tilki return ret; 15638b04ad0SIbrahim Tilki 15738b04ad0SIbrahim Tilki if (channel) 15838b04ad0SIbrahim Tilki *val = FIELD_GET(BIT(1), regval); 15938b04ad0SIbrahim Tilki else 16038b04ad0SIbrahim Tilki *val = FIELD_GET(BIT(0), regval); 16138b04ad0SIbrahim Tilki 16238b04ad0SIbrahim Tilki return 0; 16338b04ad0SIbrahim Tilki case hwmon_fan_enable: 16438b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_CR3, ®val); 16538b04ad0SIbrahim Tilki if (ret) 16638b04ad0SIbrahim Tilki return ret; 16738b04ad0SIbrahim Tilki 16838b04ad0SIbrahim Tilki if (channel) 16938b04ad0SIbrahim Tilki *val = FIELD_GET(BIT(1), regval); 17038b04ad0SIbrahim Tilki else 17138b04ad0SIbrahim Tilki *val = FIELD_GET(BIT(0), regval); 17238b04ad0SIbrahim Tilki 17338b04ad0SIbrahim Tilki return 0; 17438b04ad0SIbrahim Tilki default: 17538b04ad0SIbrahim Tilki return -EOPNOTSUPP; 17638b04ad0SIbrahim Tilki } 17738b04ad0SIbrahim Tilki case hwmon_pwm: 17838b04ad0SIbrahim Tilki switch (attr) { 17938b04ad0SIbrahim Tilki case hwmon_pwm_input: 18038b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_PWMV, ®val); 18138b04ad0SIbrahim Tilki if (ret) 18238b04ad0SIbrahim Tilki return ret; 18338b04ad0SIbrahim Tilki 18438b04ad0SIbrahim Tilki *val = regval; 18538b04ad0SIbrahim Tilki 18638b04ad0SIbrahim Tilki return 0; 18738b04ad0SIbrahim Tilki case hwmon_pwm_freq: 18838b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_CR1, ®val); 18938b04ad0SIbrahim Tilki if (ret) 19038b04ad0SIbrahim Tilki return ret; 19138b04ad0SIbrahim Tilki 19238b04ad0SIbrahim Tilki regval = FIELD_GET(CR1_DRV, regval); 19338b04ad0SIbrahim Tilki if (regval >= ARRAY_SIZE(max31760_pwm_freq)) 19438b04ad0SIbrahim Tilki return -EINVAL; 19538b04ad0SIbrahim Tilki 19638b04ad0SIbrahim Tilki *val = max31760_pwm_freq[regval]; 19738b04ad0SIbrahim Tilki 19838b04ad0SIbrahim Tilki return 0; 19938b04ad0SIbrahim Tilki case hwmon_pwm_enable: 20038b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_CR2, ®val); 20138b04ad0SIbrahim Tilki if (ret) 20238b04ad0SIbrahim Tilki return ret; 20338b04ad0SIbrahim Tilki 20438b04ad0SIbrahim Tilki *val = 2 - FIELD_GET(CR2_DFC, regval); 20538b04ad0SIbrahim Tilki 20638b04ad0SIbrahim Tilki return 0; 20738b04ad0SIbrahim Tilki case hwmon_pwm_auto_channels_temp: 20838b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_CR1, ®val); 20938b04ad0SIbrahim Tilki if (ret) 21038b04ad0SIbrahim Tilki return ret; 21138b04ad0SIbrahim Tilki 21238b04ad0SIbrahim Tilki switch (FIELD_GET(CR1_TEMP_SRC, regval)) { 21338b04ad0SIbrahim Tilki case 0: 21438b04ad0SIbrahim Tilki *val = 2; 21538b04ad0SIbrahim Tilki break; 21638b04ad0SIbrahim Tilki case 1: 21738b04ad0SIbrahim Tilki *val = 1; 21838b04ad0SIbrahim Tilki break; 21938b04ad0SIbrahim Tilki case 2: 22038b04ad0SIbrahim Tilki case 3: 22138b04ad0SIbrahim Tilki *val = 3; 22238b04ad0SIbrahim Tilki break; 22338b04ad0SIbrahim Tilki default: 22438b04ad0SIbrahim Tilki return -EINVAL; 22538b04ad0SIbrahim Tilki } 22638b04ad0SIbrahim Tilki 22738b04ad0SIbrahim Tilki return 0; 22838b04ad0SIbrahim Tilki default: 22938b04ad0SIbrahim Tilki return -EOPNOTSUPP; 23038b04ad0SIbrahim Tilki } 23138b04ad0SIbrahim Tilki default: 23238b04ad0SIbrahim Tilki return -EOPNOTSUPP; 23338b04ad0SIbrahim Tilki } 23438b04ad0SIbrahim Tilki } 23538b04ad0SIbrahim Tilki 23638b04ad0SIbrahim Tilki static int max31760_write(struct device *dev, enum hwmon_sensor_types type, 23738b04ad0SIbrahim Tilki u32 attr, int channel, long val) 23838b04ad0SIbrahim Tilki { 23938b04ad0SIbrahim Tilki struct max31760_state *state = dev_get_drvdata(dev); 24038b04ad0SIbrahim Tilki unsigned int pwm_index; 24138b04ad0SIbrahim Tilki unsigned int reg_temp; 24238b04ad0SIbrahim Tilki int temp; 24338b04ad0SIbrahim Tilki u8 reg_val[2]; 24438b04ad0SIbrahim Tilki 24538b04ad0SIbrahim Tilki switch (type) { 24638b04ad0SIbrahim Tilki case hwmon_temp: 24738b04ad0SIbrahim Tilki switch (attr) { 24838b04ad0SIbrahim Tilki case hwmon_temp_max: 24938b04ad0SIbrahim Tilki reg_temp = REG_TEMP_MAX(channel); 25038b04ad0SIbrahim Tilki break; 25138b04ad0SIbrahim Tilki case hwmon_temp_crit: 25238b04ad0SIbrahim Tilki reg_temp = REG_TEMP_CRIT(channel); 25338b04ad0SIbrahim Tilki break; 25438b04ad0SIbrahim Tilki default: 25538b04ad0SIbrahim Tilki return -EOPNOTSUPP; 25638b04ad0SIbrahim Tilki } 25738b04ad0SIbrahim Tilki 25838b04ad0SIbrahim Tilki temp = TEMP11_TO_REG(val); 25938b04ad0SIbrahim Tilki reg_val[0] = temp >> 8; 26038b04ad0SIbrahim Tilki reg_val[1] = temp & 0xFF; 26138b04ad0SIbrahim Tilki 26238b04ad0SIbrahim Tilki return regmap_bulk_write(state->regmap, reg_temp, reg_val, 2); 26338b04ad0SIbrahim Tilki case hwmon_fan: 26438b04ad0SIbrahim Tilki switch (attr) { 26538b04ad0SIbrahim Tilki case hwmon_fan_enable: 26638b04ad0SIbrahim Tilki if (val == 0) 26738b04ad0SIbrahim Tilki return regmap_clear_bits(state->regmap, REG_CR3, BIT(channel)); 26838b04ad0SIbrahim Tilki 26938b04ad0SIbrahim Tilki if (val == 1) 27038b04ad0SIbrahim Tilki return regmap_set_bits(state->regmap, REG_CR3, BIT(channel)); 27138b04ad0SIbrahim Tilki 27238b04ad0SIbrahim Tilki return -EINVAL; 27338b04ad0SIbrahim Tilki default: 27438b04ad0SIbrahim Tilki return -EOPNOTSUPP; 27538b04ad0SIbrahim Tilki } 27638b04ad0SIbrahim Tilki case hwmon_pwm: 27738b04ad0SIbrahim Tilki switch (attr) { 27838b04ad0SIbrahim Tilki case hwmon_pwm_input: 27938b04ad0SIbrahim Tilki if (val < 0 || val > 255) 28038b04ad0SIbrahim Tilki return -EINVAL; 28138b04ad0SIbrahim Tilki 28238b04ad0SIbrahim Tilki return regmap_write(state->regmap, REG_PWMR, val); 28338b04ad0SIbrahim Tilki case hwmon_pwm_enable: 28438b04ad0SIbrahim Tilki if (val == 1) 28538b04ad0SIbrahim Tilki return regmap_set_bits(state->regmap, REG_CR2, CR2_DFC); 28638b04ad0SIbrahim Tilki 28738b04ad0SIbrahim Tilki if (val == 2) 28838b04ad0SIbrahim Tilki return regmap_clear_bits(state->regmap, REG_CR2, CR2_DFC); 28938b04ad0SIbrahim Tilki 29038b04ad0SIbrahim Tilki return -EINVAL; 29138b04ad0SIbrahim Tilki case hwmon_pwm_freq: 29238b04ad0SIbrahim Tilki pwm_index = find_closest(val, max31760_pwm_freq, 29338b04ad0SIbrahim Tilki ARRAY_SIZE(max31760_pwm_freq)); 29438b04ad0SIbrahim Tilki 29538b04ad0SIbrahim Tilki return regmap_update_bits(state->regmap, 29638b04ad0SIbrahim Tilki REG_CR1, CR1_DRV, 29738b04ad0SIbrahim Tilki FIELD_PREP(CR1_DRV, pwm_index)); 29838b04ad0SIbrahim Tilki case hwmon_pwm_auto_channels_temp: 29938b04ad0SIbrahim Tilki switch (val) { 30038b04ad0SIbrahim Tilki case 1: 30138b04ad0SIbrahim Tilki break; 30238b04ad0SIbrahim Tilki case 2: 30338b04ad0SIbrahim Tilki val = 0; 30438b04ad0SIbrahim Tilki break; 30538b04ad0SIbrahim Tilki case 3: 30638b04ad0SIbrahim Tilki val = 2; 30738b04ad0SIbrahim Tilki break; 30838b04ad0SIbrahim Tilki default: 30938b04ad0SIbrahim Tilki return -EINVAL; 31038b04ad0SIbrahim Tilki } 31138b04ad0SIbrahim Tilki 31238b04ad0SIbrahim Tilki return regmap_update_bits(state->regmap, REG_CR1, CR1_TEMP_SRC, val); 31338b04ad0SIbrahim Tilki default: 31438b04ad0SIbrahim Tilki return -EOPNOTSUPP; 31538b04ad0SIbrahim Tilki } 31638b04ad0SIbrahim Tilki default: 31738b04ad0SIbrahim Tilki return -EOPNOTSUPP; 31838b04ad0SIbrahim Tilki } 31938b04ad0SIbrahim Tilki } 32038b04ad0SIbrahim Tilki 32102681a9fSKrzysztof Kozlowski static const struct hwmon_channel_info * const max31760_info[] = { 32238b04ad0SIbrahim Tilki HWMON_CHANNEL_INFO(chip, 32338b04ad0SIbrahim Tilki HWMON_C_REGISTER_TZ), 32438b04ad0SIbrahim Tilki HWMON_CHANNEL_INFO(fan, 32538b04ad0SIbrahim Tilki HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_ENABLE, 32638b04ad0SIbrahim Tilki HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_ENABLE), 32738b04ad0SIbrahim Tilki HWMON_CHANNEL_INFO(temp, 32838b04ad0SIbrahim Tilki HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT | 32938b04ad0SIbrahim Tilki HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_LABEL, 33038b04ad0SIbrahim Tilki HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | 33138b04ad0SIbrahim Tilki HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_LABEL), 33238b04ad0SIbrahim Tilki HWMON_CHANNEL_INFO(pwm, 33338b04ad0SIbrahim Tilki HWMON_PWM_ENABLE | HWMON_PWM_FREQ | HWMON_PWM_INPUT | 33438b04ad0SIbrahim Tilki HWMON_PWM_AUTO_CHANNELS_TEMP), 33538b04ad0SIbrahim Tilki NULL 33638b04ad0SIbrahim Tilki }; 33738b04ad0SIbrahim Tilki 33838b04ad0SIbrahim Tilki static umode_t max31760_is_visible(const void *data, 33938b04ad0SIbrahim Tilki enum hwmon_sensor_types type, 34038b04ad0SIbrahim Tilki u32 attr, int channel) 34138b04ad0SIbrahim Tilki { 34238b04ad0SIbrahim Tilki switch (type) { 34338b04ad0SIbrahim Tilki case hwmon_temp: 34438b04ad0SIbrahim Tilki switch (attr) { 34538b04ad0SIbrahim Tilki case hwmon_temp_input: 34638b04ad0SIbrahim Tilki case hwmon_temp_max_alarm: 34738b04ad0SIbrahim Tilki case hwmon_temp_crit_alarm: 34838b04ad0SIbrahim Tilki case hwmon_temp_fault: 34938b04ad0SIbrahim Tilki case hwmon_temp_label: 35038b04ad0SIbrahim Tilki return 0444; 35138b04ad0SIbrahim Tilki case hwmon_temp_max: 35238b04ad0SIbrahim Tilki case hwmon_temp_crit: 35338b04ad0SIbrahim Tilki return 0644; 35438b04ad0SIbrahim Tilki default: 35538b04ad0SIbrahim Tilki return 0; 35638b04ad0SIbrahim Tilki } 35738b04ad0SIbrahim Tilki case hwmon_fan: 35838b04ad0SIbrahim Tilki switch (attr) { 35938b04ad0SIbrahim Tilki case hwmon_fan_input: 36038b04ad0SIbrahim Tilki case hwmon_fan_fault: 36138b04ad0SIbrahim Tilki return 0444; 36238b04ad0SIbrahim Tilki case hwmon_fan_enable: 36338b04ad0SIbrahim Tilki return 0644; 36438b04ad0SIbrahim Tilki default: 36538b04ad0SIbrahim Tilki return 0; 36638b04ad0SIbrahim Tilki } 36738b04ad0SIbrahim Tilki case hwmon_pwm: 36838b04ad0SIbrahim Tilki switch (attr) { 36938b04ad0SIbrahim Tilki case hwmon_pwm_enable: 37038b04ad0SIbrahim Tilki case hwmon_pwm_input: 37138b04ad0SIbrahim Tilki case hwmon_pwm_freq: 37238b04ad0SIbrahim Tilki case hwmon_pwm_auto_channels_temp: 37338b04ad0SIbrahim Tilki return 0644; 37438b04ad0SIbrahim Tilki default: 37538b04ad0SIbrahim Tilki return 0; 37638b04ad0SIbrahim Tilki } 37738b04ad0SIbrahim Tilki default: 37838b04ad0SIbrahim Tilki return 0; 37938b04ad0SIbrahim Tilki } 38038b04ad0SIbrahim Tilki } 38138b04ad0SIbrahim Tilki 38238b04ad0SIbrahim Tilki static int max31760_read_string(struct device *dev, 38338b04ad0SIbrahim Tilki enum hwmon_sensor_types type, 38438b04ad0SIbrahim Tilki u32 attr, int channel, const char **str) 38538b04ad0SIbrahim Tilki { 38638b04ad0SIbrahim Tilki switch (type) { 38738b04ad0SIbrahim Tilki case hwmon_temp: 38838b04ad0SIbrahim Tilki if (attr != hwmon_temp_label) 38938b04ad0SIbrahim Tilki return -EOPNOTSUPP; 39038b04ad0SIbrahim Tilki 39138b04ad0SIbrahim Tilki *str = channel ? "local" : "remote"; 39238b04ad0SIbrahim Tilki 39338b04ad0SIbrahim Tilki return 0; 39438b04ad0SIbrahim Tilki default: 39538b04ad0SIbrahim Tilki return -EOPNOTSUPP; 39638b04ad0SIbrahim Tilki } 39738b04ad0SIbrahim Tilki } 39838b04ad0SIbrahim Tilki 39938b04ad0SIbrahim Tilki static const struct hwmon_ops max31760_hwmon_ops = { 40038b04ad0SIbrahim Tilki .is_visible = max31760_is_visible, 40138b04ad0SIbrahim Tilki .read = max31760_read, 40238b04ad0SIbrahim Tilki .write = max31760_write, 40338b04ad0SIbrahim Tilki .read_string = max31760_read_string 40438b04ad0SIbrahim Tilki }; 40538b04ad0SIbrahim Tilki 40638b04ad0SIbrahim Tilki static const struct hwmon_chip_info max31760_chip_info = { 40738b04ad0SIbrahim Tilki .ops = &max31760_hwmon_ops, 40838b04ad0SIbrahim Tilki .info = max31760_info, 40938b04ad0SIbrahim Tilki }; 41038b04ad0SIbrahim Tilki 41138b04ad0SIbrahim Tilki static ssize_t lut_show(struct device *dev, 41238b04ad0SIbrahim Tilki struct device_attribute *devattr, char *buf) 41338b04ad0SIbrahim Tilki { 41438b04ad0SIbrahim Tilki struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); 41538b04ad0SIbrahim Tilki struct max31760_state *state = dev_get_drvdata(dev); 41638b04ad0SIbrahim Tilki int ret; 41738b04ad0SIbrahim Tilki unsigned int regval; 41838b04ad0SIbrahim Tilki 41938b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_LUT(sda->index), ®val); 42038b04ad0SIbrahim Tilki if (ret) 42138b04ad0SIbrahim Tilki return ret; 42238b04ad0SIbrahim Tilki 42338b04ad0SIbrahim Tilki return sysfs_emit(buf, "%d\n", regval); 42438b04ad0SIbrahim Tilki } 42538b04ad0SIbrahim Tilki 42638b04ad0SIbrahim Tilki static ssize_t lut_store(struct device *dev, 42738b04ad0SIbrahim Tilki struct device_attribute *devattr, 42838b04ad0SIbrahim Tilki const char *buf, size_t count) 42938b04ad0SIbrahim Tilki { 43038b04ad0SIbrahim Tilki struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); 43138b04ad0SIbrahim Tilki struct max31760_state *state = dev_get_drvdata(dev); 43238b04ad0SIbrahim Tilki int ret; 43338b04ad0SIbrahim Tilki u8 pwm; 43438b04ad0SIbrahim Tilki 43538b04ad0SIbrahim Tilki ret = kstrtou8(buf, 10, &pwm); 43638b04ad0SIbrahim Tilki if (ret) 43738b04ad0SIbrahim Tilki return ret; 43838b04ad0SIbrahim Tilki 43938b04ad0SIbrahim Tilki ret = regmap_write(state->regmap, REG_LUT(sda->index), pwm); 44038b04ad0SIbrahim Tilki if (ret) 44138b04ad0SIbrahim Tilki return ret; 44238b04ad0SIbrahim Tilki 44338b04ad0SIbrahim Tilki return count; 44438b04ad0SIbrahim Tilki } 44538b04ad0SIbrahim Tilki 44638b04ad0SIbrahim Tilki static ssize_t pwm1_auto_point_temp_hyst_show(struct device *dev, 44738b04ad0SIbrahim Tilki struct device_attribute *attr, 44838b04ad0SIbrahim Tilki char *buf) 44938b04ad0SIbrahim Tilki { 45038b04ad0SIbrahim Tilki struct max31760_state *state = dev_get_drvdata(dev); 45138b04ad0SIbrahim Tilki unsigned int regval; 45238b04ad0SIbrahim Tilki int ret; 45338b04ad0SIbrahim Tilki 45438b04ad0SIbrahim Tilki ret = regmap_read(state->regmap, REG_CR1, ®val); 45538b04ad0SIbrahim Tilki if (ret) 45638b04ad0SIbrahim Tilki return ret; 45738b04ad0SIbrahim Tilki 45838b04ad0SIbrahim Tilki return sysfs_emit(buf, "%d\n", (1 + (int)FIELD_GET(CR1_HYST, regval)) * 2000); 45938b04ad0SIbrahim Tilki } 46038b04ad0SIbrahim Tilki 46138b04ad0SIbrahim Tilki static ssize_t pwm1_auto_point_temp_hyst_store(struct device *dev, 46238b04ad0SIbrahim Tilki struct device_attribute *attr, 46338b04ad0SIbrahim Tilki const char *buf, 46438b04ad0SIbrahim Tilki size_t count) 46538b04ad0SIbrahim Tilki { 46638b04ad0SIbrahim Tilki struct max31760_state *state = dev_get_drvdata(dev); 46738b04ad0SIbrahim Tilki unsigned int hyst; 46838b04ad0SIbrahim Tilki int ret; 46938b04ad0SIbrahim Tilki 47038b04ad0SIbrahim Tilki ret = kstrtou32(buf, 10, &hyst); 47138b04ad0SIbrahim Tilki if (ret) 47238b04ad0SIbrahim Tilki return ret; 47338b04ad0SIbrahim Tilki 47438b04ad0SIbrahim Tilki if (hyst < 3000) 47538b04ad0SIbrahim Tilki ret = regmap_clear_bits(state->regmap, REG_CR1, CR1_HYST); 47638b04ad0SIbrahim Tilki else 47738b04ad0SIbrahim Tilki ret = regmap_set_bits(state->regmap, REG_CR1, CR1_HYST); 47838b04ad0SIbrahim Tilki 47938b04ad0SIbrahim Tilki if (ret) 48038b04ad0SIbrahim Tilki return ret; 48138b04ad0SIbrahim Tilki 48238b04ad0SIbrahim Tilki return count; 48338b04ad0SIbrahim Tilki } 48438b04ad0SIbrahim Tilki 48538b04ad0SIbrahim Tilki static DEVICE_ATTR_RW(pwm1_auto_point_temp_hyst); 48638b04ad0SIbrahim Tilki 48738b04ad0SIbrahim Tilki static void max31760_create_lut_nodes(struct max31760_state *state) 48838b04ad0SIbrahim Tilki { 48938b04ad0SIbrahim Tilki int i; 49038b04ad0SIbrahim Tilki struct sensor_device_attribute *sda; 49138b04ad0SIbrahim Tilki struct lut_attribute *lut; 49238b04ad0SIbrahim Tilki 49338b04ad0SIbrahim Tilki for (i = 0; i < LUT_SIZE; ++i) { 49438b04ad0SIbrahim Tilki lut = &state->lut[i]; 49538b04ad0SIbrahim Tilki sda = &lut->sda; 49638b04ad0SIbrahim Tilki 49738b04ad0SIbrahim Tilki snprintf(lut->name, sizeof(lut->name), 49838b04ad0SIbrahim Tilki "pwm1_auto_point%d_pwm", i + 1); 49938b04ad0SIbrahim Tilki 50038b04ad0SIbrahim Tilki sda->dev_attr.attr.mode = 0644; 50138b04ad0SIbrahim Tilki sda->index = i; 50238b04ad0SIbrahim Tilki sda->dev_attr.show = lut_show; 50338b04ad0SIbrahim Tilki sda->dev_attr.store = lut_store; 50438b04ad0SIbrahim Tilki sda->dev_attr.attr.name = lut->name; 50538b04ad0SIbrahim Tilki 50638b04ad0SIbrahim Tilki sysfs_attr_init(&sda->dev_attr.attr); 50738b04ad0SIbrahim Tilki 50838b04ad0SIbrahim Tilki state->attrs[i] = &sda->dev_attr.attr; 50938b04ad0SIbrahim Tilki } 51038b04ad0SIbrahim Tilki 51138b04ad0SIbrahim Tilki state->attrs[i] = &dev_attr_pwm1_auto_point_temp_hyst.attr; 51238b04ad0SIbrahim Tilki 51338b04ad0SIbrahim Tilki state->group.attrs = state->attrs; 51438b04ad0SIbrahim Tilki state->groups[0] = &state->group; 51538b04ad0SIbrahim Tilki } 51638b04ad0SIbrahim Tilki 51738b04ad0SIbrahim Tilki static int max31760_probe(struct i2c_client *client) 51838b04ad0SIbrahim Tilki { 51938b04ad0SIbrahim Tilki struct device *dev = &client->dev; 52038b04ad0SIbrahim Tilki struct max31760_state *state; 52138b04ad0SIbrahim Tilki struct device *hwmon_dev; 52238b04ad0SIbrahim Tilki int ret; 52338b04ad0SIbrahim Tilki 52438b04ad0SIbrahim Tilki state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); 52538b04ad0SIbrahim Tilki if (!state) 52638b04ad0SIbrahim Tilki return -ENOMEM; 52738b04ad0SIbrahim Tilki 52838b04ad0SIbrahim Tilki state->regmap = devm_regmap_init_i2c(client, ®map_config); 52938b04ad0SIbrahim Tilki if (IS_ERR(state->regmap)) 53038b04ad0SIbrahim Tilki return dev_err_probe(dev, 53138b04ad0SIbrahim Tilki PTR_ERR(state->regmap), 53238b04ad0SIbrahim Tilki "regmap initialization failed\n"); 53338b04ad0SIbrahim Tilki 53438b04ad0SIbrahim Tilki dev_set_drvdata(dev, state); 53538b04ad0SIbrahim Tilki 53638b04ad0SIbrahim Tilki /* Set alert output to comparator mode */ 53738b04ad0SIbrahim Tilki ret = regmap_set_bits(state->regmap, REG_CR2, CR2_ALERTS); 53838b04ad0SIbrahim Tilki if (ret) 53938b04ad0SIbrahim Tilki return dev_err_probe(dev, ret, "cannot write register\n"); 54038b04ad0SIbrahim Tilki 54138b04ad0SIbrahim Tilki max31760_create_lut_nodes(state); 54238b04ad0SIbrahim Tilki 54338b04ad0SIbrahim Tilki hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 54438b04ad0SIbrahim Tilki state, 54538b04ad0SIbrahim Tilki &max31760_chip_info, 54638b04ad0SIbrahim Tilki state->groups); 54738b04ad0SIbrahim Tilki 54838b04ad0SIbrahim Tilki return PTR_ERR_OR_ZERO(hwmon_dev); 54938b04ad0SIbrahim Tilki } 55038b04ad0SIbrahim Tilki 55138b04ad0SIbrahim Tilki static const struct of_device_id max31760_of_match[] = { 55238b04ad0SIbrahim Tilki {.compatible = "adi,max31760"}, 55338b04ad0SIbrahim Tilki { } 55438b04ad0SIbrahim Tilki }; 55538b04ad0SIbrahim Tilki MODULE_DEVICE_TABLE(of, max31760_of_match); 55638b04ad0SIbrahim Tilki 55738b04ad0SIbrahim Tilki static const struct i2c_device_id max31760_id[] = { 55838b04ad0SIbrahim Tilki {"max31760"}, 55938b04ad0SIbrahim Tilki { } 56038b04ad0SIbrahim Tilki }; 56138b04ad0SIbrahim Tilki MODULE_DEVICE_TABLE(i2c, max31760_id); 56238b04ad0SIbrahim Tilki 56338b04ad0SIbrahim Tilki static int max31760_suspend(struct device *dev) 56438b04ad0SIbrahim Tilki { 56538b04ad0SIbrahim Tilki struct max31760_state *state = dev_get_drvdata(dev); 56638b04ad0SIbrahim Tilki 56738b04ad0SIbrahim Tilki return regmap_set_bits(state->regmap, REG_CR2, CR2_STBY); 56838b04ad0SIbrahim Tilki } 56938b04ad0SIbrahim Tilki 57038b04ad0SIbrahim Tilki static int max31760_resume(struct device *dev) 57138b04ad0SIbrahim Tilki { 57238b04ad0SIbrahim Tilki struct max31760_state *state = dev_get_drvdata(dev); 57338b04ad0SIbrahim Tilki 57438b04ad0SIbrahim Tilki return regmap_clear_bits(state->regmap, REG_CR2, CR2_STBY); 57538b04ad0SIbrahim Tilki } 57638b04ad0SIbrahim Tilki 57738b04ad0SIbrahim Tilki static DEFINE_SIMPLE_DEV_PM_OPS(max31760_pm_ops, max31760_suspend, 57838b04ad0SIbrahim Tilki max31760_resume); 57938b04ad0SIbrahim Tilki 58038b04ad0SIbrahim Tilki static struct i2c_driver max31760_driver = { 58138b04ad0SIbrahim Tilki .class = I2C_CLASS_HWMON, 58238b04ad0SIbrahim Tilki .driver = { 58338b04ad0SIbrahim Tilki .name = "max31760", 58438b04ad0SIbrahim Tilki .of_match_table = max31760_of_match, 58538b04ad0SIbrahim Tilki .pm = pm_ptr(&max31760_pm_ops) 58638b04ad0SIbrahim Tilki }, 587*1975d167SUwe Kleine-König .probe = max31760_probe, 58838b04ad0SIbrahim Tilki .id_table = max31760_id 58938b04ad0SIbrahim Tilki }; 59038b04ad0SIbrahim Tilki module_i2c_driver(max31760_driver); 59138b04ad0SIbrahim Tilki 59238b04ad0SIbrahim Tilki MODULE_AUTHOR("Ibrahim Tilki <Ibrahim.Tilki@analog.com>"); 59338b04ad0SIbrahim Tilki MODULE_DESCRIPTION("Analog Devices MAX31760 Fan Speed Controller"); 59438b04ad0SIbrahim Tilki MODULE_SOFTDEP("pre: regmap_i2c"); 59538b04ad0SIbrahim Tilki MODULE_VERSION("1.0"); 59638b04ad0SIbrahim Tilki MODULE_LICENSE("GPL"); 597