xref: /linux/drivers/hwmon/max6621.c (revision 621cde16e49b3ecf7d59a8106a20aaebfb4a59a9)
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>
1539f03438SRob Herring #include <linux/of.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 
max6621_temp_mc2reg(long val)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
max6621_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)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 
max6621_verify_reg_data(struct device * dev,int regval)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
max6621_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)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, &regval);
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 					  &regval);
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, &regval);
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 					  &regval);
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
max6621_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)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
max6621_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)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 
max6621_writeable_reg(struct device * dev,unsigned int reg)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 
max6621_readable_reg(struct device * dev,unsigned int reg)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 
max6621_volatile_reg(struct device * dev,unsigned int reg)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 
max6621_probe(struct i2c_client * client)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[] = {
540*2fa36597SUwe Kleine-König 	{ MAX6621_DRV_NAME },
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 	.driver = {
55392b64580SVadim Pasternak 		.name = MAX6621_DRV_NAME,
55492b64580SVadim Pasternak 		.of_match_table = of_match_ptr(max6621_of_match),
55592b64580SVadim Pasternak 	},
5561975d167SUwe Kleine-König 	.probe		= max6621_probe,
55792b64580SVadim Pasternak 	.id_table	= max6621_id,
55892b64580SVadim Pasternak };
55992b64580SVadim Pasternak 
56092b64580SVadim Pasternak module_i2c_driver(max6621_driver);
56192b64580SVadim Pasternak 
56292b64580SVadim Pasternak MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
56392b64580SVadim Pasternak MODULE_DESCRIPTION("Driver for Maxim MAX6621");
56492b64580SVadim Pasternak MODULE_LICENSE("GPL");
565