1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 292b64580SVadim Pasternak /* 392b64580SVadim Pasternak * Hardware monitoring driver for Maxim MAX6621 492b64580SVadim Pasternak * 592b64580SVadim Pasternak * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 692b64580SVadim Pasternak * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com> 792b64580SVadim Pasternak */ 892b64580SVadim Pasternak 992b64580SVadim Pasternak #include <linux/bitops.h> 1092b64580SVadim Pasternak #include <linux/hwmon.h> 1192b64580SVadim Pasternak #include <linux/hwmon-sysfs.h> 1292b64580SVadim Pasternak #include <linux/i2c.h> 1392b64580SVadim Pasternak #include <linux/init.h> 1492b64580SVadim Pasternak #include <linux/module.h> 1592b64580SVadim Pasternak #include <linux/of_device.h> 1692b64580SVadim Pasternak #include <linux/regmap.h> 1792b64580SVadim Pasternak 1892b64580SVadim Pasternak #define MAX6621_DRV_NAME "max6621" 1992b64580SVadim Pasternak #define MAX6621_TEMP_INPUT_REG_NUM 9 2092b64580SVadim Pasternak #define MAX6621_TEMP_INPUT_MIN -127000 2192b64580SVadim Pasternak #define MAX6621_TEMP_INPUT_MAX 128000 2292b64580SVadim Pasternak #define MAX6621_TEMP_ALERT_CHAN_SHIFT 1 2392b64580SVadim Pasternak 2492b64580SVadim Pasternak #define MAX6621_TEMP_S0D0_REG 0x00 2592b64580SVadim Pasternak #define MAX6621_TEMP_S0D1_REG 0x01 2692b64580SVadim Pasternak #define MAX6621_TEMP_S1D0_REG 0x02 2792b64580SVadim Pasternak #define MAX6621_TEMP_S1D1_REG 0x03 2892b64580SVadim Pasternak #define MAX6621_TEMP_S2D0_REG 0x04 2992b64580SVadim Pasternak #define MAX6621_TEMP_S2D1_REG 0x05 3092b64580SVadim Pasternak #define MAX6621_TEMP_S3D0_REG 0x06 3192b64580SVadim Pasternak #define MAX6621_TEMP_S3D1_REG 0x07 3292b64580SVadim Pasternak #define MAX6621_TEMP_MAX_REG 0x08 3392b64580SVadim Pasternak #define MAX6621_TEMP_MAX_ADDR_REG 0x0a 3492b64580SVadim Pasternak #define MAX6621_TEMP_ALERT_CAUSE_REG 0x0b 3592b64580SVadim Pasternak #define MAX6621_CONFIG0_REG 0x0c 3692b64580SVadim Pasternak #define MAX6621_CONFIG1_REG 0x0d 3792b64580SVadim Pasternak #define MAX6621_CONFIG2_REG 0x0e 3892b64580SVadim Pasternak #define MAX6621_CONFIG3_REG 0x0f 3992b64580SVadim Pasternak #define MAX6621_TEMP_S0_ALERT_REG 0x10 4092b64580SVadim Pasternak #define MAX6621_TEMP_S1_ALERT_REG 0x11 4192b64580SVadim Pasternak #define MAX6621_TEMP_S2_ALERT_REG 0x12 4292b64580SVadim Pasternak #define MAX6621_TEMP_S3_ALERT_REG 0x13 4392b64580SVadim Pasternak #define MAX6621_CLEAR_ALERT_REG 0x15 4492b64580SVadim Pasternak #define MAX6621_REG_MAX (MAX6621_CLEAR_ALERT_REG + 1) 4592b64580SVadim Pasternak #define MAX6621_REG_TEMP_SHIFT 0x06 4692b64580SVadim Pasternak 4792b64580SVadim Pasternak #define MAX6621_ENABLE_TEMP_ALERTS_BIT 4 4892b64580SVadim Pasternak #define MAX6621_ENABLE_I2C_CRC_BIT 5 4992b64580SVadim Pasternak #define MAX6621_ENABLE_ALTERNATE_DATA 6 5092b64580SVadim Pasternak #define MAX6621_ENABLE_LOCKUP_TO 7 5192b64580SVadim Pasternak #define MAX6621_ENABLE_S0D0_BIT 8 5292b64580SVadim Pasternak #define MAX6621_ENABLE_S3D1_BIT 15 5392b64580SVadim Pasternak #define MAX6621_ENABLE_TEMP_ALL GENMASK(MAX6621_ENABLE_S3D1_BIT, \ 5492b64580SVadim Pasternak MAX6621_ENABLE_S0D0_BIT) 5592b64580SVadim Pasternak #define MAX6621_POLL_DELAY_MASK 0x5 5692b64580SVadim Pasternak #define MAX6621_CONFIG0_INIT (MAX6621_ENABLE_TEMP_ALL | \ 5792b64580SVadim Pasternak BIT(MAX6621_ENABLE_LOCKUP_TO) | \ 5892b64580SVadim Pasternak BIT(MAX6621_ENABLE_I2C_CRC_BIT) | \ 5992b64580SVadim Pasternak MAX6621_POLL_DELAY_MASK) 6092b64580SVadim Pasternak #define MAX6621_PECI_BIT_TIME 0x2 6192b64580SVadim Pasternak #define MAX6621_PECI_RETRY_NUM 0x3 6292b64580SVadim Pasternak #define MAX6621_CONFIG1_INIT ((MAX6621_PECI_BIT_TIME << 8) | \ 6392b64580SVadim Pasternak MAX6621_PECI_RETRY_NUM) 6492b64580SVadim Pasternak 6592b64580SVadim Pasternak /* Error codes */ 6692b64580SVadim Pasternak #define MAX6621_TRAN_FAILED 0x8100 /* 6792b64580SVadim Pasternak * PECI transaction failed for more 6892b64580SVadim Pasternak * than the configured number of 6992b64580SVadim Pasternak * consecutive retries. 7092b64580SVadim Pasternak */ 7192b64580SVadim Pasternak #define MAX6621_POOL_DIS 0x8101 /* 7292b64580SVadim Pasternak * Polling disabled for requested 7392b64580SVadim Pasternak * socket/domain. 7492b64580SVadim Pasternak */ 7592b64580SVadim Pasternak #define MAX6621_POOL_UNCOMPLETE 0x8102 /* 7692b64580SVadim Pasternak * First poll not yet completed for 7792b64580SVadim Pasternak * requested socket/domain (on 7892b64580SVadim Pasternak * startup). 7992b64580SVadim Pasternak */ 8092b64580SVadim Pasternak #define MAX6621_SD_DIS 0x8103 /* 8192b64580SVadim Pasternak * Read maximum temperature requested, 8292b64580SVadim Pasternak * but no sockets/domains enabled or 8392b64580SVadim Pasternak * all enabled sockets/domains have 8492b64580SVadim Pasternak * errors; or read maximum temperature 8592b64580SVadim Pasternak * address requested, but read maximum 8692b64580SVadim Pasternak * temperature was not called. 8792b64580SVadim Pasternak */ 8892b64580SVadim Pasternak #define MAX6621_ALERT_DIS 0x8104 /* 8992b64580SVadim Pasternak * Get alert socket/domain requested, 9092b64580SVadim Pasternak * but no alert active. 9192b64580SVadim Pasternak */ 9292b64580SVadim Pasternak #define MAX6621_PECI_ERR_MIN 0x8000 /* Intel spec PECI error min value. */ 9392b64580SVadim Pasternak #define MAX6621_PECI_ERR_MAX 0x80ff /* Intel spec PECI error max value. */ 9492b64580SVadim Pasternak 9592b64580SVadim Pasternak static const u32 max6621_temp_regs[] = { 9692b64580SVadim Pasternak MAX6621_TEMP_MAX_REG, MAX6621_TEMP_S0D0_REG, MAX6621_TEMP_S1D0_REG, 9792b64580SVadim Pasternak MAX6621_TEMP_S2D0_REG, MAX6621_TEMP_S3D0_REG, MAX6621_TEMP_S0D1_REG, 9892b64580SVadim Pasternak MAX6621_TEMP_S1D1_REG, MAX6621_TEMP_S2D1_REG, MAX6621_TEMP_S3D1_REG, 9992b64580SVadim Pasternak }; 10092b64580SVadim Pasternak 10192b64580SVadim Pasternak static const char *const max6621_temp_labels[] = { 10292b64580SVadim Pasternak "maximum", 10392b64580SVadim Pasternak "socket0_0", 10492b64580SVadim Pasternak "socket1_0", 10592b64580SVadim Pasternak "socket2_0", 10692b64580SVadim Pasternak "socket3_0", 10792b64580SVadim Pasternak "socket0_1", 10892b64580SVadim Pasternak "socket1_1", 10992b64580SVadim Pasternak "socket2_1", 11092b64580SVadim Pasternak "socket3_1", 11192b64580SVadim Pasternak }; 11292b64580SVadim Pasternak 11392b64580SVadim Pasternak static const int max6621_temp_alert_chan2reg[] = { 11492b64580SVadim Pasternak MAX6621_TEMP_S0_ALERT_REG, 11592b64580SVadim Pasternak MAX6621_TEMP_S1_ALERT_REG, 11692b64580SVadim Pasternak MAX6621_TEMP_S2_ALERT_REG, 11792b64580SVadim Pasternak MAX6621_TEMP_S3_ALERT_REG, 11892b64580SVadim Pasternak }; 11992b64580SVadim Pasternak 12092b64580SVadim Pasternak /** 12192b64580SVadim Pasternak * struct max6621_data - private data: 12292b64580SVadim Pasternak * 12392b64580SVadim Pasternak * @client: I2C client; 12492b64580SVadim Pasternak * @regmap: register map handle; 12592b64580SVadim Pasternak * @input_chan2reg: mapping from channel to register; 12692b64580SVadim Pasternak */ 12792b64580SVadim Pasternak struct max6621_data { 12892b64580SVadim Pasternak struct i2c_client *client; 12992b64580SVadim Pasternak struct regmap *regmap; 13092b64580SVadim Pasternak int input_chan2reg[MAX6621_TEMP_INPUT_REG_NUM + 1]; 13192b64580SVadim Pasternak }; 13292b64580SVadim Pasternak 13392b64580SVadim Pasternak static long max6621_temp_mc2reg(long val) 13492b64580SVadim Pasternak { 13592b64580SVadim Pasternak return (val / 1000L) << MAX6621_REG_TEMP_SHIFT; 13692b64580SVadim Pasternak } 13792b64580SVadim Pasternak 13892b64580SVadim Pasternak static umode_t 13992b64580SVadim Pasternak max6621_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, 14092b64580SVadim Pasternak int channel) 14192b64580SVadim Pasternak { 14292b64580SVadim Pasternak /* Skip channels which are not physically conncted. */ 14392b64580SVadim Pasternak if (((struct max6621_data *)data)->input_chan2reg[channel] < 0) 14492b64580SVadim Pasternak return 0; 14592b64580SVadim Pasternak 14692b64580SVadim Pasternak switch (type) { 14792b64580SVadim Pasternak case hwmon_temp: 14892b64580SVadim Pasternak switch (attr) { 14992b64580SVadim Pasternak case hwmon_temp_input: 15092b64580SVadim Pasternak case hwmon_temp_label: 15192b64580SVadim Pasternak case hwmon_temp_crit_alarm: 15292b64580SVadim Pasternak return 0444; 15392b64580SVadim Pasternak case hwmon_temp_offset: 15492b64580SVadim Pasternak case hwmon_temp_crit: 15592b64580SVadim Pasternak return 0644; 15692b64580SVadim Pasternak default: 15792b64580SVadim Pasternak break; 15892b64580SVadim Pasternak } 15958e31cf0SGustavo A. R. Silva break; 16092b64580SVadim Pasternak default: 16192b64580SVadim Pasternak break; 16292b64580SVadim Pasternak } 16392b64580SVadim Pasternak 16492b64580SVadim Pasternak return 0; 16592b64580SVadim Pasternak } 16692b64580SVadim Pasternak 16792b64580SVadim Pasternak static int max6621_verify_reg_data(struct device *dev, int regval) 16892b64580SVadim Pasternak { 16992b64580SVadim Pasternak if (regval >= MAX6621_PECI_ERR_MIN && 17092b64580SVadim Pasternak regval <= MAX6621_PECI_ERR_MAX) { 17192b64580SVadim Pasternak dev_dbg(dev, "PECI error code - err 0x%04x.\n", 17292b64580SVadim Pasternak regval); 17392b64580SVadim Pasternak 17492b64580SVadim Pasternak return -EIO; 17592b64580SVadim Pasternak } 17692b64580SVadim Pasternak 17792b64580SVadim Pasternak switch (regval) { 17892b64580SVadim Pasternak case MAX6621_TRAN_FAILED: 17992b64580SVadim Pasternak dev_dbg(dev, "PECI transaction failed - err 0x%04x.\n", 18092b64580SVadim Pasternak regval); 18192b64580SVadim Pasternak return -EIO; 18292b64580SVadim Pasternak case MAX6621_POOL_DIS: 18392b64580SVadim Pasternak dev_dbg(dev, "Polling disabled - err 0x%04x.\n", regval); 18492b64580SVadim Pasternak return -EOPNOTSUPP; 18592b64580SVadim Pasternak case MAX6621_POOL_UNCOMPLETE: 18692b64580SVadim Pasternak dev_dbg(dev, "First poll not completed on startup - err 0x%04x.\n", 18792b64580SVadim Pasternak regval); 18892b64580SVadim Pasternak return -EIO; 18992b64580SVadim Pasternak case MAX6621_SD_DIS: 19092b64580SVadim Pasternak dev_dbg(dev, "Resource is disabled - err 0x%04x.\n", regval); 19192b64580SVadim Pasternak return -EOPNOTSUPP; 19292b64580SVadim Pasternak case MAX6621_ALERT_DIS: 19392b64580SVadim Pasternak dev_dbg(dev, "No alert active - err 0x%04x.\n", regval); 19492b64580SVadim Pasternak return -EOPNOTSUPP; 19592b64580SVadim Pasternak default: 19692b64580SVadim Pasternak return 0; 19792b64580SVadim Pasternak } 19892b64580SVadim Pasternak } 19992b64580SVadim Pasternak 20092b64580SVadim Pasternak static int 20192b64580SVadim Pasternak max6621_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, 20292b64580SVadim Pasternak int channel, long *val) 20392b64580SVadim Pasternak { 20492b64580SVadim Pasternak struct max6621_data *data = dev_get_drvdata(dev); 20592b64580SVadim Pasternak u32 regval; 20692b64580SVadim Pasternak int reg; 20792b64580SVadim Pasternak s8 temp; 20892b64580SVadim Pasternak int ret; 20992b64580SVadim Pasternak 21092b64580SVadim Pasternak switch (type) { 21192b64580SVadim Pasternak case hwmon_temp: 21292b64580SVadim Pasternak switch (attr) { 21392b64580SVadim Pasternak case hwmon_temp_input: 21492b64580SVadim Pasternak reg = data->input_chan2reg[channel]; 21592b64580SVadim Pasternak ret = regmap_read(data->regmap, reg, ®val); 21692b64580SVadim Pasternak if (ret) 21792b64580SVadim Pasternak return ret; 21892b64580SVadim Pasternak 21992b64580SVadim Pasternak ret = max6621_verify_reg_data(dev, regval); 22092b64580SVadim Pasternak if (ret) 22192b64580SVadim Pasternak return ret; 22292b64580SVadim Pasternak 22392b64580SVadim Pasternak /* 22492b64580SVadim Pasternak * Bit MAX6621_REG_TEMP_SHIFT represents 1 degree step. 22592b64580SVadim Pasternak * The temperature is given in two's complement and 8 22692b64580SVadim Pasternak * bits is used for the register conversion. 22792b64580SVadim Pasternak */ 22892b64580SVadim Pasternak temp = (regval >> MAX6621_REG_TEMP_SHIFT); 22992b64580SVadim Pasternak *val = temp * 1000L; 23092b64580SVadim Pasternak 23192b64580SVadim Pasternak break; 23292b64580SVadim Pasternak case hwmon_temp_offset: 23392b64580SVadim Pasternak ret = regmap_read(data->regmap, MAX6621_CONFIG2_REG, 23492b64580SVadim Pasternak ®val); 23592b64580SVadim Pasternak if (ret) 23692b64580SVadim Pasternak return ret; 23792b64580SVadim Pasternak 23892b64580SVadim Pasternak ret = max6621_verify_reg_data(dev, regval); 23992b64580SVadim Pasternak if (ret) 24092b64580SVadim Pasternak return ret; 24192b64580SVadim Pasternak 24292b64580SVadim Pasternak *val = (regval >> MAX6621_REG_TEMP_SHIFT) * 24392b64580SVadim Pasternak 1000L; 24492b64580SVadim Pasternak 24592b64580SVadim Pasternak break; 24692b64580SVadim Pasternak case hwmon_temp_crit: 24792b64580SVadim Pasternak channel -= MAX6621_TEMP_ALERT_CHAN_SHIFT; 24892b64580SVadim Pasternak reg = max6621_temp_alert_chan2reg[channel]; 24992b64580SVadim Pasternak ret = regmap_read(data->regmap, reg, ®val); 25092b64580SVadim Pasternak if (ret) 25192b64580SVadim Pasternak return ret; 25292b64580SVadim Pasternak 25392b64580SVadim Pasternak ret = max6621_verify_reg_data(dev, regval); 25492b64580SVadim Pasternak if (ret) 25592b64580SVadim Pasternak return ret; 25692b64580SVadim Pasternak 25792b64580SVadim Pasternak *val = regval * 1000L; 25892b64580SVadim Pasternak 25992b64580SVadim Pasternak break; 26092b64580SVadim Pasternak case hwmon_temp_crit_alarm: 26192b64580SVadim Pasternak /* 26292b64580SVadim Pasternak * Set val to zero to recover the case, when reading 26392b64580SVadim Pasternak * MAX6621_TEMP_ALERT_CAUSE_REG results in for example 26492b64580SVadim Pasternak * MAX6621_ALERT_DIS. Reading will return with error, 26592b64580SVadim Pasternak * but in such case alarm should be returned as 0. 26692b64580SVadim Pasternak */ 26792b64580SVadim Pasternak *val = 0; 26892b64580SVadim Pasternak ret = regmap_read(data->regmap, 26992b64580SVadim Pasternak MAX6621_TEMP_ALERT_CAUSE_REG, 27092b64580SVadim Pasternak ®val); 27192b64580SVadim Pasternak if (ret) 27292b64580SVadim Pasternak return ret; 27392b64580SVadim Pasternak 27492b64580SVadim Pasternak ret = max6621_verify_reg_data(dev, regval); 27592b64580SVadim Pasternak if (ret) { 27692b64580SVadim Pasternak /* Do not report error if alert is disabled. */ 27792b64580SVadim Pasternak if (regval == MAX6621_ALERT_DIS) 27892b64580SVadim Pasternak return 0; 27992b64580SVadim Pasternak else 28092b64580SVadim Pasternak return ret; 28192b64580SVadim Pasternak } 28292b64580SVadim Pasternak 28392b64580SVadim Pasternak /* 28492b64580SVadim Pasternak * Clear the alert automatically, using send-byte 28592b64580SVadim Pasternak * smbus protocol for clearing alert. 28692b64580SVadim Pasternak */ 28792b64580SVadim Pasternak if (regval) { 28892b64580SVadim Pasternak ret = i2c_smbus_write_byte(data->client, 28992b64580SVadim Pasternak MAX6621_CLEAR_ALERT_REG); 2905813da15SDan Carpenter if (ret) 29192b64580SVadim Pasternak return ret; 29292b64580SVadim Pasternak } 29392b64580SVadim Pasternak 29492b64580SVadim Pasternak *val = !!regval; 29592b64580SVadim Pasternak 29692b64580SVadim Pasternak break; 29792b64580SVadim Pasternak default: 29892b64580SVadim Pasternak return -EOPNOTSUPP; 29992b64580SVadim Pasternak } 30092b64580SVadim Pasternak break; 30192b64580SVadim Pasternak 30292b64580SVadim Pasternak default: 30392b64580SVadim Pasternak return -EOPNOTSUPP; 30492b64580SVadim Pasternak } 30592b64580SVadim Pasternak 30692b64580SVadim Pasternak return 0; 30792b64580SVadim Pasternak } 30892b64580SVadim Pasternak 30992b64580SVadim Pasternak static int 31092b64580SVadim Pasternak max6621_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, 31192b64580SVadim Pasternak int channel, long val) 31292b64580SVadim Pasternak { 31392b64580SVadim Pasternak struct max6621_data *data = dev_get_drvdata(dev); 31492b64580SVadim Pasternak u32 reg; 31592b64580SVadim Pasternak 31692b64580SVadim Pasternak switch (type) { 31792b64580SVadim Pasternak case hwmon_temp: 31892b64580SVadim Pasternak switch (attr) { 31992b64580SVadim Pasternak case hwmon_temp_offset: 32092b64580SVadim Pasternak /* Clamp to allowed range to prevent overflow. */ 32192b64580SVadim Pasternak val = clamp_val(val, MAX6621_TEMP_INPUT_MIN, 32292b64580SVadim Pasternak MAX6621_TEMP_INPUT_MAX); 32392b64580SVadim Pasternak val = max6621_temp_mc2reg(val); 32492b64580SVadim Pasternak 32592b64580SVadim Pasternak return regmap_write(data->regmap, 32692b64580SVadim Pasternak MAX6621_CONFIG2_REG, val); 32792b64580SVadim Pasternak case hwmon_temp_crit: 32892b64580SVadim Pasternak channel -= MAX6621_TEMP_ALERT_CHAN_SHIFT; 32992b64580SVadim Pasternak reg = max6621_temp_alert_chan2reg[channel]; 33092b64580SVadim Pasternak /* Clamp to allowed range to prevent overflow. */ 33192b64580SVadim Pasternak val = clamp_val(val, MAX6621_TEMP_INPUT_MIN, 33292b64580SVadim Pasternak MAX6621_TEMP_INPUT_MAX); 33392b64580SVadim Pasternak val = val / 1000L; 33492b64580SVadim Pasternak 33592b64580SVadim Pasternak return regmap_write(data->regmap, reg, val); 33692b64580SVadim Pasternak default: 33792b64580SVadim Pasternak return -EOPNOTSUPP; 33892b64580SVadim Pasternak } 33992b64580SVadim Pasternak break; 34092b64580SVadim Pasternak 34192b64580SVadim Pasternak default: 34292b64580SVadim Pasternak return -EOPNOTSUPP; 34392b64580SVadim Pasternak } 34492b64580SVadim Pasternak 34592b64580SVadim Pasternak return -EOPNOTSUPP; 34692b64580SVadim Pasternak } 34792b64580SVadim Pasternak 34892b64580SVadim Pasternak static int 34992b64580SVadim Pasternak max6621_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, 35092b64580SVadim Pasternak int channel, const char **str) 35192b64580SVadim Pasternak { 35292b64580SVadim Pasternak switch (type) { 35392b64580SVadim Pasternak case hwmon_temp: 35492b64580SVadim Pasternak switch (attr) { 35592b64580SVadim Pasternak case hwmon_temp_label: 35692b64580SVadim Pasternak *str = max6621_temp_labels[channel]; 35792b64580SVadim Pasternak return 0; 35892b64580SVadim Pasternak default: 35992b64580SVadim Pasternak return -EOPNOTSUPP; 36092b64580SVadim Pasternak } 36192b64580SVadim Pasternak break; 36292b64580SVadim Pasternak default: 36392b64580SVadim Pasternak return -EOPNOTSUPP; 36492b64580SVadim Pasternak } 36592b64580SVadim Pasternak 36692b64580SVadim Pasternak return -EOPNOTSUPP; 36792b64580SVadim Pasternak } 36892b64580SVadim Pasternak 36992b64580SVadim Pasternak static bool max6621_writeable_reg(struct device *dev, unsigned int reg) 37092b64580SVadim Pasternak { 37192b64580SVadim Pasternak switch (reg) { 37292b64580SVadim Pasternak case MAX6621_CONFIG0_REG: 37392b64580SVadim Pasternak case MAX6621_CONFIG1_REG: 37492b64580SVadim Pasternak case MAX6621_CONFIG2_REG: 37592b64580SVadim Pasternak case MAX6621_CONFIG3_REG: 37692b64580SVadim Pasternak case MAX6621_TEMP_S0_ALERT_REG: 37792b64580SVadim Pasternak case MAX6621_TEMP_S1_ALERT_REG: 37892b64580SVadim Pasternak case MAX6621_TEMP_S2_ALERT_REG: 37992b64580SVadim Pasternak case MAX6621_TEMP_S3_ALERT_REG: 38092b64580SVadim Pasternak case MAX6621_TEMP_ALERT_CAUSE_REG: 38192b64580SVadim Pasternak return true; 38292b64580SVadim Pasternak } 38392b64580SVadim Pasternak return false; 38492b64580SVadim Pasternak } 38592b64580SVadim Pasternak 38692b64580SVadim Pasternak static bool max6621_readable_reg(struct device *dev, unsigned int reg) 38792b64580SVadim Pasternak { 38892b64580SVadim Pasternak switch (reg) { 38992b64580SVadim Pasternak case MAX6621_TEMP_S0D0_REG: 39092b64580SVadim Pasternak case MAX6621_TEMP_S0D1_REG: 39192b64580SVadim Pasternak case MAX6621_TEMP_S1D0_REG: 39292b64580SVadim Pasternak case MAX6621_TEMP_S1D1_REG: 39392b64580SVadim Pasternak case MAX6621_TEMP_S2D0_REG: 39492b64580SVadim Pasternak case MAX6621_TEMP_S2D1_REG: 39592b64580SVadim Pasternak case MAX6621_TEMP_S3D0_REG: 39692b64580SVadim Pasternak case MAX6621_TEMP_S3D1_REG: 39792b64580SVadim Pasternak case MAX6621_TEMP_MAX_REG: 39892b64580SVadim Pasternak case MAX6621_TEMP_MAX_ADDR_REG: 39992b64580SVadim Pasternak case MAX6621_CONFIG0_REG: 40092b64580SVadim Pasternak case MAX6621_CONFIG1_REG: 40192b64580SVadim Pasternak case MAX6621_CONFIG2_REG: 40292b64580SVadim Pasternak case MAX6621_CONFIG3_REG: 40392b64580SVadim Pasternak case MAX6621_TEMP_S0_ALERT_REG: 40492b64580SVadim Pasternak case MAX6621_TEMP_S1_ALERT_REG: 40592b64580SVadim Pasternak case MAX6621_TEMP_S2_ALERT_REG: 40692b64580SVadim Pasternak case MAX6621_TEMP_S3_ALERT_REG: 40792b64580SVadim Pasternak return true; 40892b64580SVadim Pasternak } 40992b64580SVadim Pasternak return false; 41092b64580SVadim Pasternak } 41192b64580SVadim Pasternak 41292b64580SVadim Pasternak static bool max6621_volatile_reg(struct device *dev, unsigned int reg) 41392b64580SVadim Pasternak { 41492b64580SVadim Pasternak switch (reg) { 41592b64580SVadim Pasternak case MAX6621_TEMP_S0D0_REG: 41692b64580SVadim Pasternak case MAX6621_TEMP_S0D1_REG: 41792b64580SVadim Pasternak case MAX6621_TEMP_S1D0_REG: 41892b64580SVadim Pasternak case MAX6621_TEMP_S1D1_REG: 41992b64580SVadim Pasternak case MAX6621_TEMP_S2D0_REG: 42092b64580SVadim Pasternak case MAX6621_TEMP_S2D1_REG: 42192b64580SVadim Pasternak case MAX6621_TEMP_S3D0_REG: 42292b64580SVadim Pasternak case MAX6621_TEMP_S3D1_REG: 42392b64580SVadim Pasternak case MAX6621_TEMP_MAX_REG: 42492b64580SVadim Pasternak case MAX6621_TEMP_S0_ALERT_REG: 42592b64580SVadim Pasternak case MAX6621_TEMP_S1_ALERT_REG: 42692b64580SVadim Pasternak case MAX6621_TEMP_S2_ALERT_REG: 42792b64580SVadim Pasternak case MAX6621_TEMP_S3_ALERT_REG: 42892b64580SVadim Pasternak case MAX6621_TEMP_ALERT_CAUSE_REG: 42992b64580SVadim Pasternak return true; 43092b64580SVadim Pasternak } 43192b64580SVadim Pasternak return false; 43292b64580SVadim Pasternak } 43392b64580SVadim Pasternak 43492b64580SVadim Pasternak static const struct reg_default max6621_regmap_default[] = { 43592b64580SVadim Pasternak { MAX6621_CONFIG0_REG, MAX6621_CONFIG0_INIT }, 43692b64580SVadim Pasternak { MAX6621_CONFIG1_REG, MAX6621_CONFIG1_INIT }, 43792b64580SVadim Pasternak }; 43892b64580SVadim Pasternak 43992b64580SVadim Pasternak static const struct regmap_config max6621_regmap_config = { 44092b64580SVadim Pasternak .reg_bits = 8, 44192b64580SVadim Pasternak .val_bits = 16, 44292b64580SVadim Pasternak .max_register = MAX6621_REG_MAX, 44392b64580SVadim Pasternak .val_format_endian = REGMAP_ENDIAN_LITTLE, 44492b64580SVadim Pasternak .cache_type = REGCACHE_FLAT, 44592b64580SVadim Pasternak .writeable_reg = max6621_writeable_reg, 44692b64580SVadim Pasternak .readable_reg = max6621_readable_reg, 44792b64580SVadim Pasternak .volatile_reg = max6621_volatile_reg, 44892b64580SVadim Pasternak .reg_defaults = max6621_regmap_default, 44992b64580SVadim Pasternak .num_reg_defaults = ARRAY_SIZE(max6621_regmap_default), 45092b64580SVadim Pasternak }; 45192b64580SVadim Pasternak 452a7bae597SKrzysztof Kozlowski static const struct hwmon_channel_info * const max6621_info[] = { 453dcb00ee8SGuenter Roeck HWMON_CHANNEL_INFO(chip, 454dcb00ee8SGuenter Roeck HWMON_C_REGISTER_TZ), 455dcb00ee8SGuenter Roeck HWMON_CHANNEL_INFO(temp, 45692b64580SVadim Pasternak HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET, 45792b64580SVadim Pasternak HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL, 45892b64580SVadim Pasternak HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL, 45992b64580SVadim Pasternak HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL, 46092b64580SVadim Pasternak HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL, 46192b64580SVadim Pasternak HWMON_T_INPUT | HWMON_T_LABEL, 46292b64580SVadim Pasternak HWMON_T_INPUT | HWMON_T_LABEL, 46392b64580SVadim Pasternak HWMON_T_INPUT | HWMON_T_LABEL, 464dcb00ee8SGuenter Roeck HWMON_T_INPUT | HWMON_T_LABEL), 46592b64580SVadim Pasternak NULL 46692b64580SVadim Pasternak }; 46792b64580SVadim Pasternak 46892b64580SVadim Pasternak static const struct hwmon_ops max6621_hwmon_ops = { 46992b64580SVadim Pasternak .read = max6621_read, 47092b64580SVadim Pasternak .write = max6621_write, 47192b64580SVadim Pasternak .read_string = max6621_read_string, 47292b64580SVadim Pasternak .is_visible = max6621_is_visible, 47392b64580SVadim Pasternak }; 47492b64580SVadim Pasternak 47592b64580SVadim Pasternak static const struct hwmon_chip_info max6621_chip_info = { 47692b64580SVadim Pasternak .ops = &max6621_hwmon_ops, 47792b64580SVadim Pasternak .info = max6621_info, 47892b64580SVadim Pasternak }; 47992b64580SVadim Pasternak 48067487038SStephen Kitt static int max6621_probe(struct i2c_client *client) 48192b64580SVadim Pasternak { 48292b64580SVadim Pasternak struct device *dev = &client->dev; 48392b64580SVadim Pasternak struct max6621_data *data; 48492b64580SVadim Pasternak struct device *hwmon_dev; 48592b64580SVadim Pasternak int i; 48692b64580SVadim Pasternak int ret; 48792b64580SVadim Pasternak 48892b64580SVadim Pasternak data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 48992b64580SVadim Pasternak if (!data) 49092b64580SVadim Pasternak return -ENOMEM; 49192b64580SVadim Pasternak 49292b64580SVadim Pasternak data->regmap = devm_regmap_init_i2c(client, &max6621_regmap_config); 49392b64580SVadim Pasternak if (IS_ERR(data->regmap)) 49492b64580SVadim Pasternak return PTR_ERR(data->regmap); 49592b64580SVadim Pasternak 49692b64580SVadim Pasternak i2c_set_clientdata(client, data); 49792b64580SVadim Pasternak data->client = client; 49892b64580SVadim Pasternak 49992b64580SVadim Pasternak /* Set CONFIG0 register masking temperature alerts and PEC. */ 50092b64580SVadim Pasternak ret = regmap_write(data->regmap, MAX6621_CONFIG0_REG, 50192b64580SVadim Pasternak MAX6621_CONFIG0_INIT); 50292b64580SVadim Pasternak if (ret) 50392b64580SVadim Pasternak return ret; 50492b64580SVadim Pasternak 50592b64580SVadim Pasternak /* Set CONFIG1 register for PEC access retry number. */ 50692b64580SVadim Pasternak ret = regmap_write(data->regmap, MAX6621_CONFIG1_REG, 50792b64580SVadim Pasternak MAX6621_CONFIG1_INIT); 50892b64580SVadim Pasternak if (ret) 50992b64580SVadim Pasternak return ret; 51092b64580SVadim Pasternak 51192b64580SVadim Pasternak /* Sync registers with hardware. */ 51292b64580SVadim Pasternak regcache_mark_dirty(data->regmap); 51392b64580SVadim Pasternak ret = regcache_sync(data->regmap); 51492b64580SVadim Pasternak if (ret) 51592b64580SVadim Pasternak return ret; 51692b64580SVadim Pasternak 51792b64580SVadim Pasternak /* Verify which temperature input registers are enabled. */ 51892b64580SVadim Pasternak for (i = 0; i < MAX6621_TEMP_INPUT_REG_NUM; i++) { 51992b64580SVadim Pasternak ret = i2c_smbus_read_word_data(client, max6621_temp_regs[i]); 52092b64580SVadim Pasternak if (ret < 0) 52192b64580SVadim Pasternak return ret; 52292b64580SVadim Pasternak ret = max6621_verify_reg_data(dev, ret); 52392b64580SVadim Pasternak if (ret) { 52492b64580SVadim Pasternak data->input_chan2reg[i] = -1; 52592b64580SVadim Pasternak continue; 52692b64580SVadim Pasternak } 52792b64580SVadim Pasternak 52892b64580SVadim Pasternak data->input_chan2reg[i] = max6621_temp_regs[i]; 52992b64580SVadim Pasternak } 53092b64580SVadim Pasternak 53192b64580SVadim Pasternak hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, 53292b64580SVadim Pasternak data, 53392b64580SVadim Pasternak &max6621_chip_info, 53492b64580SVadim Pasternak NULL); 53592b64580SVadim Pasternak 53692b64580SVadim Pasternak return PTR_ERR_OR_ZERO(hwmon_dev); 53792b64580SVadim Pasternak } 53892b64580SVadim Pasternak 53992b64580SVadim Pasternak static const struct i2c_device_id max6621_id[] = { 54092b64580SVadim Pasternak { MAX6621_DRV_NAME, 0 }, 54192b64580SVadim Pasternak { } 54292b64580SVadim Pasternak }; 54392b64580SVadim Pasternak MODULE_DEVICE_TABLE(i2c, max6621_id); 54492b64580SVadim Pasternak 545969c45b9SGuenter Roeck static const struct of_device_id __maybe_unused max6621_of_match[] = { 54692b64580SVadim Pasternak { .compatible = "maxim,max6621" }, 54792b64580SVadim Pasternak { } 54892b64580SVadim Pasternak }; 54992b64580SVadim Pasternak MODULE_DEVICE_TABLE(of, max6621_of_match); 55092b64580SVadim Pasternak 55192b64580SVadim Pasternak static struct i2c_driver max6621_driver = { 55292b64580SVadim Pasternak .class = I2C_CLASS_HWMON, 55392b64580SVadim Pasternak .driver = { 55492b64580SVadim Pasternak .name = MAX6621_DRV_NAME, 55592b64580SVadim Pasternak .of_match_table = of_match_ptr(max6621_of_match), 55692b64580SVadim Pasternak }, 557*1975d167SUwe Kleine-König .probe = max6621_probe, 55892b64580SVadim Pasternak .id_table = max6621_id, 55992b64580SVadim Pasternak }; 56092b64580SVadim Pasternak 56192b64580SVadim Pasternak module_i2c_driver(max6621_driver); 56292b64580SVadim Pasternak 56392b64580SVadim Pasternak MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); 56492b64580SVadim Pasternak MODULE_DESCRIPTION("Driver for Maxim MAX6621"); 56592b64580SVadim Pasternak MODULE_LICENSE("GPL"); 566