162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Hardware monitoring driver for LTC2978 and compatible chips.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2011 Ericsson AB.
662306a36Sopenharmony_ci * Copyright (c) 2013, 2014, 2015 Guenter Roeck
762306a36Sopenharmony_ci * Copyright (c) 2015 Linear Technology
862306a36Sopenharmony_ci * Copyright (c) 2018 Analog Devices Inc.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/jiffies.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/init.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/i2c.h>
1962306a36Sopenharmony_ci#include <linux/regulator/driver.h>
2062306a36Sopenharmony_ci#include "pmbus.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cienum chips {
2362306a36Sopenharmony_ci	/* Managers */
2462306a36Sopenharmony_ci	ltc2972, ltc2974, ltc2975, ltc2977, ltc2978, ltc2979, ltc2980,
2562306a36Sopenharmony_ci	/* Controllers */
2662306a36Sopenharmony_ci	ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7132, ltc7880,
2762306a36Sopenharmony_ci	/* Modules */
2862306a36Sopenharmony_ci	ltm2987, ltm4664, ltm4675, ltm4676, ltm4677, ltm4678, ltm4680, ltm4686,
2962306a36Sopenharmony_ci	ltm4700,
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Common for all chips */
3362306a36Sopenharmony_ci#define LTC2978_MFR_VOUT_PEAK		0xdd
3462306a36Sopenharmony_ci#define LTC2978_MFR_VIN_PEAK		0xde
3562306a36Sopenharmony_ci#define LTC2978_MFR_TEMPERATURE_PEAK	0xdf
3662306a36Sopenharmony_ci#define LTC2978_MFR_SPECIAL_ID		0xe7	/* Undocumented on LTC3882 */
3762306a36Sopenharmony_ci#define LTC2978_MFR_COMMON		0xef
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* LTC2974, LTC2975, LCT2977, LTC2980, LTC2978, and LTM2987 */
4062306a36Sopenharmony_ci#define LTC2978_MFR_VOUT_MIN		0xfb
4162306a36Sopenharmony_ci#define LTC2978_MFR_VIN_MIN		0xfc
4262306a36Sopenharmony_ci#define LTC2978_MFR_TEMPERATURE_MIN	0xfd
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* LTC2974, LTC2975 */
4562306a36Sopenharmony_ci#define LTC2974_MFR_IOUT_PEAK		0xd7
4662306a36Sopenharmony_ci#define LTC2974_MFR_IOUT_MIN		0xd8
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, LTM4676, LTC7132 */
4962306a36Sopenharmony_ci#define LTC3880_MFR_IOUT_PEAK		0xd7
5062306a36Sopenharmony_ci#define LTC3880_MFR_CLEAR_PEAKS		0xe3
5162306a36Sopenharmony_ci#define LTC3880_MFR_TEMPERATURE2_PEAK	0xf4
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* LTC3883, LTC3884, LTC3886, LTC3889, LTC7132, LTC7880 */
5462306a36Sopenharmony_ci#define LTC3883_MFR_IIN_PEAK		0xe1
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* LTC2975 only */
5762306a36Sopenharmony_ci#define LTC2975_MFR_IIN_PEAK		0xc4
5862306a36Sopenharmony_ci#define LTC2975_MFR_IIN_MIN		0xc5
5962306a36Sopenharmony_ci#define LTC2975_MFR_PIN_PEAK		0xc6
6062306a36Sopenharmony_ci#define LTC2975_MFR_PIN_MIN		0xc7
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define LTC2978_ID_MASK			0xfff0
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define LTC2972_ID			0x0310
6562306a36Sopenharmony_ci#define LTC2974_ID			0x0210
6662306a36Sopenharmony_ci#define LTC2975_ID			0x0220
6762306a36Sopenharmony_ci#define LTC2977_ID			0x0130
6862306a36Sopenharmony_ci#define LTC2978_ID_REV1			0x0110	/* Early revision */
6962306a36Sopenharmony_ci#define LTC2978_ID_REV2			0x0120
7062306a36Sopenharmony_ci#define LTC2979_ID_A			0x8060
7162306a36Sopenharmony_ci#define LTC2979_ID_B			0x8070
7262306a36Sopenharmony_ci#define LTC2980_ID_A			0x8030	/* A/B for two die IDs */
7362306a36Sopenharmony_ci#define LTC2980_ID_B			0x8040
7462306a36Sopenharmony_ci#define LTC3880_ID			0x4020
7562306a36Sopenharmony_ci#define LTC3882_ID			0x4200
7662306a36Sopenharmony_ci#define LTC3882_ID_D1			0x4240	/* Dash 1 */
7762306a36Sopenharmony_ci#define LTC3883_ID			0x4300
7862306a36Sopenharmony_ci#define LTC3884_ID			0x4C00
7962306a36Sopenharmony_ci#define LTC3886_ID			0x4600
8062306a36Sopenharmony_ci#define LTC3887_ID			0x4700
8162306a36Sopenharmony_ci#define LTC3889_ID			0x4900
8262306a36Sopenharmony_ci#define LTC7132_ID			0x4CE0
8362306a36Sopenharmony_ci#define LTC7880_ID			0x49E0
8462306a36Sopenharmony_ci#define LTM2987_ID_A			0x8010	/* A/B for two die IDs */
8562306a36Sopenharmony_ci#define LTM2987_ID_B			0x8020
8662306a36Sopenharmony_ci#define LTM4664_ID			0x4120
8762306a36Sopenharmony_ci#define LTM4675_ID			0x47a0
8862306a36Sopenharmony_ci#define LTM4676_ID_REV1			0x4400
8962306a36Sopenharmony_ci#define LTM4676_ID_REV2			0x4480
9062306a36Sopenharmony_ci#define LTM4676A_ID			0x47e0
9162306a36Sopenharmony_ci#define LTM4677_ID_REV1			0x47B0
9262306a36Sopenharmony_ci#define LTM4677_ID_REV2			0x47D0
9362306a36Sopenharmony_ci#define LTM4678_ID_REV1			0x4100
9462306a36Sopenharmony_ci#define LTM4678_ID_REV2			0x4110
9562306a36Sopenharmony_ci#define LTM4680_ID			0x4140
9662306a36Sopenharmony_ci#define LTM4686_ID			0x4770
9762306a36Sopenharmony_ci#define LTM4700_ID			0x4130
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define LTC2972_NUM_PAGES		2
10062306a36Sopenharmony_ci#define LTC2974_NUM_PAGES		4
10162306a36Sopenharmony_ci#define LTC2978_NUM_PAGES		8
10262306a36Sopenharmony_ci#define LTC3880_NUM_PAGES		2
10362306a36Sopenharmony_ci#define LTC3883_NUM_PAGES		1
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define LTC_POLL_TIMEOUT		100	/* in milli-seconds */
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define LTC_NOT_BUSY			BIT(6)
10862306a36Sopenharmony_ci#define LTC_NOT_PENDING			BIT(5)
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/*
11162306a36Sopenharmony_ci * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
11262306a36Sopenharmony_ci * happens pretty much each time chip data is updated. Raw peak data therefore
11362306a36Sopenharmony_ci * does not provide much value. To be able to provide useful peak data, keep an
11462306a36Sopenharmony_ci * internal cache of measured peak data, which is only cleared if an explicit
11562306a36Sopenharmony_ci * "clear peak" command is executed for the sensor in question.
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistruct ltc2978_data {
11962306a36Sopenharmony_ci	enum chips id;
12062306a36Sopenharmony_ci	u16 vin_min, vin_max;
12162306a36Sopenharmony_ci	u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES];
12262306a36Sopenharmony_ci	u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES];
12362306a36Sopenharmony_ci	u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES];
12462306a36Sopenharmony_ci	u16 iin_min, iin_max;
12562306a36Sopenharmony_ci	u16 pin_min, pin_max;
12662306a36Sopenharmony_ci	u16 temp2_max;
12762306a36Sopenharmony_ci	struct pmbus_driver_info info;
12862306a36Sopenharmony_ci	u32 features;
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci#define to_ltc2978_data(x)  container_of(x, struct ltc2978_data, info)
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci#define FEAT_CLEAR_PEAKS	BIT(0)
13362306a36Sopenharmony_ci#define FEAT_NEEDS_POLLING	BIT(1)
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define has_clear_peaks(d)	((d)->features & FEAT_CLEAR_PEAKS)
13662306a36Sopenharmony_ci#define needs_polling(d)	((d)->features & FEAT_NEEDS_POLLING)
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic int ltc_wait_ready(struct i2c_client *client)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	unsigned long timeout = jiffies + msecs_to_jiffies(LTC_POLL_TIMEOUT);
14162306a36Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
14262306a36Sopenharmony_ci	struct ltc2978_data *data = to_ltc2978_data(info);
14362306a36Sopenharmony_ci	int status;
14462306a36Sopenharmony_ci	u8 mask;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (!needs_polling(data))
14762306a36Sopenharmony_ci		return 0;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/*
15062306a36Sopenharmony_ci	 * LTC3883 does not support LTC_NOT_PENDING, even though
15162306a36Sopenharmony_ci	 * the datasheet claims that it does.
15262306a36Sopenharmony_ci	 */
15362306a36Sopenharmony_ci	mask = LTC_NOT_BUSY;
15462306a36Sopenharmony_ci	if (data->id != ltc3883)
15562306a36Sopenharmony_ci		mask |= LTC_NOT_PENDING;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	do {
15862306a36Sopenharmony_ci		status = pmbus_read_byte_data(client, 0, LTC2978_MFR_COMMON);
15962306a36Sopenharmony_ci		if (status == -EBADMSG || status == -ENXIO) {
16062306a36Sopenharmony_ci			/* PEC error or NACK: chip may be busy, try again */
16162306a36Sopenharmony_ci			usleep_range(50, 100);
16262306a36Sopenharmony_ci			continue;
16362306a36Sopenharmony_ci		}
16462306a36Sopenharmony_ci		if (status < 0)
16562306a36Sopenharmony_ci			return status;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci		if ((status & mask) == mask)
16862306a36Sopenharmony_ci			return 0;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		usleep_range(50, 100);
17162306a36Sopenharmony_ci	} while (time_before(jiffies, timeout));
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return -ETIMEDOUT;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int ltc_read_word_data(struct i2c_client *client, int page, int phase,
17762306a36Sopenharmony_ci			      int reg)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	int ret;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	ret = ltc_wait_ready(client);
18262306a36Sopenharmony_ci	if (ret < 0)
18362306a36Sopenharmony_ci		return ret;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return pmbus_read_word_data(client, page, 0xff, reg);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic int ltc_read_byte_data(struct i2c_client *client, int page, int reg)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	int ret;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	ret = ltc_wait_ready(client);
19362306a36Sopenharmony_ci	if (ret < 0)
19462306a36Sopenharmony_ci		return ret;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return pmbus_read_byte_data(client, page, reg);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int ltc_write_byte_data(struct i2c_client *client, int page, int reg, u8 value)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	int ret;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	ret = ltc_wait_ready(client);
20462306a36Sopenharmony_ci	if (ret < 0)
20562306a36Sopenharmony_ci		return ret;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	return pmbus_write_byte_data(client, page, reg, value);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic int ltc_write_byte(struct i2c_client *client, int page, u8 byte)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	int ret;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	ret = ltc_wait_ready(client);
21562306a36Sopenharmony_ci	if (ret < 0)
21662306a36Sopenharmony_ci		return ret;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return pmbus_write_byte(client, page, byte);
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic inline int lin11_to_val(int data)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	s16 e = ((s16)data) >> 11;
22462306a36Sopenharmony_ci	s32 m = (((s16)(data << 5)) >> 5);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/*
22762306a36Sopenharmony_ci	 * mantissa is 10 bit + sign, exponent adds up to 15 bit.
22862306a36Sopenharmony_ci	 * Add 6 bit to exponent for maximum accuracy (10 + 15 + 6 = 31).
22962306a36Sopenharmony_ci	 */
23062306a36Sopenharmony_ci	e += 6;
23162306a36Sopenharmony_ci	return (e < 0 ? m >> -e : m << e);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic int ltc_get_max(struct ltc2978_data *data, struct i2c_client *client,
23562306a36Sopenharmony_ci		       int page, int reg, u16 *pmax)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	int ret;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	ret = ltc_read_word_data(client, page, 0xff, reg);
24062306a36Sopenharmony_ci	if (ret >= 0) {
24162306a36Sopenharmony_ci		if (lin11_to_val(ret) > lin11_to_val(*pmax))
24262306a36Sopenharmony_ci			*pmax = ret;
24362306a36Sopenharmony_ci		ret = *pmax;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci	return ret;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int ltc_get_min(struct ltc2978_data *data, struct i2c_client *client,
24962306a36Sopenharmony_ci		       int page, int reg, u16 *pmin)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	int ret;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	ret = ltc_read_word_data(client, page, 0xff, reg);
25462306a36Sopenharmony_ci	if (ret >= 0) {
25562306a36Sopenharmony_ci		if (lin11_to_val(ret) < lin11_to_val(*pmin))
25662306a36Sopenharmony_ci			*pmin = ret;
25762306a36Sopenharmony_ci		ret = *pmin;
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci	return ret;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic int ltc2978_read_word_data_common(struct i2c_client *client, int page,
26362306a36Sopenharmony_ci					 int reg)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
26662306a36Sopenharmony_ci	struct ltc2978_data *data = to_ltc2978_data(info);
26762306a36Sopenharmony_ci	int ret;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	switch (reg) {
27062306a36Sopenharmony_ci	case PMBUS_VIRT_READ_VIN_MAX:
27162306a36Sopenharmony_ci		ret = ltc_get_max(data, client, page, LTC2978_MFR_VIN_PEAK,
27262306a36Sopenharmony_ci				  &data->vin_max);
27362306a36Sopenharmony_ci		break;
27462306a36Sopenharmony_ci	case PMBUS_VIRT_READ_VOUT_MAX:
27562306a36Sopenharmony_ci		ret = ltc_read_word_data(client, page, 0xff,
27662306a36Sopenharmony_ci					 LTC2978_MFR_VOUT_PEAK);
27762306a36Sopenharmony_ci		if (ret >= 0) {
27862306a36Sopenharmony_ci			/*
27962306a36Sopenharmony_ci			 * VOUT is 16 bit unsigned with fixed exponent,
28062306a36Sopenharmony_ci			 * so we can compare it directly
28162306a36Sopenharmony_ci			 */
28262306a36Sopenharmony_ci			if (ret > data->vout_max[page])
28362306a36Sopenharmony_ci				data->vout_max[page] = ret;
28462306a36Sopenharmony_ci			ret = data->vout_max[page];
28562306a36Sopenharmony_ci		}
28662306a36Sopenharmony_ci		break;
28762306a36Sopenharmony_ci	case PMBUS_VIRT_READ_TEMP_MAX:
28862306a36Sopenharmony_ci		ret = ltc_get_max(data, client, page,
28962306a36Sopenharmony_ci				  LTC2978_MFR_TEMPERATURE_PEAK,
29062306a36Sopenharmony_ci				  &data->temp_max[page]);
29162306a36Sopenharmony_ci		break;
29262306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_VOUT_HISTORY:
29362306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_VIN_HISTORY:
29462306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_TEMP_HISTORY:
29562306a36Sopenharmony_ci		ret = 0;
29662306a36Sopenharmony_ci		break;
29762306a36Sopenharmony_ci	default:
29862306a36Sopenharmony_ci		ret = ltc_wait_ready(client);
29962306a36Sopenharmony_ci		if (ret < 0)
30062306a36Sopenharmony_ci			return ret;
30162306a36Sopenharmony_ci		ret = -ENODATA;
30262306a36Sopenharmony_ci		break;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci	return ret;
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic int ltc2978_read_word_data(struct i2c_client *client, int page,
30862306a36Sopenharmony_ci				  int phase, int reg)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
31162306a36Sopenharmony_ci	struct ltc2978_data *data = to_ltc2978_data(info);
31262306a36Sopenharmony_ci	int ret;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	switch (reg) {
31562306a36Sopenharmony_ci	case PMBUS_VIRT_READ_VIN_MIN:
31662306a36Sopenharmony_ci		ret = ltc_get_min(data, client, page, LTC2978_MFR_VIN_MIN,
31762306a36Sopenharmony_ci				  &data->vin_min);
31862306a36Sopenharmony_ci		break;
31962306a36Sopenharmony_ci	case PMBUS_VIRT_READ_VOUT_MIN:
32062306a36Sopenharmony_ci		ret = ltc_read_word_data(client, page, phase,
32162306a36Sopenharmony_ci					 LTC2978_MFR_VOUT_MIN);
32262306a36Sopenharmony_ci		if (ret >= 0) {
32362306a36Sopenharmony_ci			/*
32462306a36Sopenharmony_ci			 * VOUT_MIN is known to not be supported on some lots
32562306a36Sopenharmony_ci			 * of LTC2978 revision 1, and will return the maximum
32662306a36Sopenharmony_ci			 * possible voltage if read. If VOUT_MAX is valid and
32762306a36Sopenharmony_ci			 * lower than the reading of VOUT_MIN, use it instead.
32862306a36Sopenharmony_ci			 */
32962306a36Sopenharmony_ci			if (data->vout_max[page] && ret > data->vout_max[page])
33062306a36Sopenharmony_ci				ret = data->vout_max[page];
33162306a36Sopenharmony_ci			if (ret < data->vout_min[page])
33262306a36Sopenharmony_ci				data->vout_min[page] = ret;
33362306a36Sopenharmony_ci			ret = data->vout_min[page];
33462306a36Sopenharmony_ci		}
33562306a36Sopenharmony_ci		break;
33662306a36Sopenharmony_ci	case PMBUS_VIRT_READ_TEMP_MIN:
33762306a36Sopenharmony_ci		ret = ltc_get_min(data, client, page,
33862306a36Sopenharmony_ci				  LTC2978_MFR_TEMPERATURE_MIN,
33962306a36Sopenharmony_ci				  &data->temp_min[page]);
34062306a36Sopenharmony_ci		break;
34162306a36Sopenharmony_ci	case PMBUS_VIRT_READ_IOUT_MAX:
34262306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_IOUT_HISTORY:
34362306a36Sopenharmony_ci	case PMBUS_VIRT_READ_TEMP2_MAX:
34462306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_TEMP2_HISTORY:
34562306a36Sopenharmony_ci		ret = -ENXIO;
34662306a36Sopenharmony_ci		break;
34762306a36Sopenharmony_ci	default:
34862306a36Sopenharmony_ci		ret = ltc2978_read_word_data_common(client, page, reg);
34962306a36Sopenharmony_ci		break;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci	return ret;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic int ltc2974_read_word_data(struct i2c_client *client, int page,
35562306a36Sopenharmony_ci				  int phase, int reg)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
35862306a36Sopenharmony_ci	struct ltc2978_data *data = to_ltc2978_data(info);
35962306a36Sopenharmony_ci	int ret;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	switch (reg) {
36262306a36Sopenharmony_ci	case PMBUS_VIRT_READ_IOUT_MAX:
36362306a36Sopenharmony_ci		ret = ltc_get_max(data, client, page, LTC2974_MFR_IOUT_PEAK,
36462306a36Sopenharmony_ci				  &data->iout_max[page]);
36562306a36Sopenharmony_ci		break;
36662306a36Sopenharmony_ci	case PMBUS_VIRT_READ_IOUT_MIN:
36762306a36Sopenharmony_ci		ret = ltc_get_min(data, client, page, LTC2974_MFR_IOUT_MIN,
36862306a36Sopenharmony_ci				  &data->iout_min[page]);
36962306a36Sopenharmony_ci		break;
37062306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_IOUT_HISTORY:
37162306a36Sopenharmony_ci		ret = 0;
37262306a36Sopenharmony_ci		break;
37362306a36Sopenharmony_ci	default:
37462306a36Sopenharmony_ci		ret = ltc2978_read_word_data(client, page, phase, reg);
37562306a36Sopenharmony_ci		break;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci	return ret;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int ltc2975_read_word_data(struct i2c_client *client, int page,
38162306a36Sopenharmony_ci				  int phase, int reg)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
38462306a36Sopenharmony_ci	struct ltc2978_data *data = to_ltc2978_data(info);
38562306a36Sopenharmony_ci	int ret;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	switch (reg) {
38862306a36Sopenharmony_ci	case PMBUS_VIRT_READ_IIN_MAX:
38962306a36Sopenharmony_ci		ret = ltc_get_max(data, client, page, LTC2975_MFR_IIN_PEAK,
39062306a36Sopenharmony_ci				  &data->iin_max);
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci	case PMBUS_VIRT_READ_IIN_MIN:
39362306a36Sopenharmony_ci		ret = ltc_get_min(data, client, page, LTC2975_MFR_IIN_MIN,
39462306a36Sopenharmony_ci				  &data->iin_min);
39562306a36Sopenharmony_ci		break;
39662306a36Sopenharmony_ci	case PMBUS_VIRT_READ_PIN_MAX:
39762306a36Sopenharmony_ci		ret = ltc_get_max(data, client, page, LTC2975_MFR_PIN_PEAK,
39862306a36Sopenharmony_ci				  &data->pin_max);
39962306a36Sopenharmony_ci		break;
40062306a36Sopenharmony_ci	case PMBUS_VIRT_READ_PIN_MIN:
40162306a36Sopenharmony_ci		ret = ltc_get_min(data, client, page, LTC2975_MFR_PIN_MIN,
40262306a36Sopenharmony_ci				  &data->pin_min);
40362306a36Sopenharmony_ci		break;
40462306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_IIN_HISTORY:
40562306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_PIN_HISTORY:
40662306a36Sopenharmony_ci		ret = 0;
40762306a36Sopenharmony_ci		break;
40862306a36Sopenharmony_ci	default:
40962306a36Sopenharmony_ci		ret = ltc2978_read_word_data(client, page, phase, reg);
41062306a36Sopenharmony_ci		break;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci	return ret;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic int ltc3880_read_word_data(struct i2c_client *client, int page,
41662306a36Sopenharmony_ci				  int phase, int reg)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
41962306a36Sopenharmony_ci	struct ltc2978_data *data = to_ltc2978_data(info);
42062306a36Sopenharmony_ci	int ret;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	switch (reg) {
42362306a36Sopenharmony_ci	case PMBUS_VIRT_READ_IOUT_MAX:
42462306a36Sopenharmony_ci		ret = ltc_get_max(data, client, page, LTC3880_MFR_IOUT_PEAK,
42562306a36Sopenharmony_ci				  &data->iout_max[page]);
42662306a36Sopenharmony_ci		break;
42762306a36Sopenharmony_ci	case PMBUS_VIRT_READ_TEMP2_MAX:
42862306a36Sopenharmony_ci		ret = ltc_get_max(data, client, page,
42962306a36Sopenharmony_ci				  LTC3880_MFR_TEMPERATURE2_PEAK,
43062306a36Sopenharmony_ci				  &data->temp2_max);
43162306a36Sopenharmony_ci		break;
43262306a36Sopenharmony_ci	case PMBUS_VIRT_READ_VIN_MIN:
43362306a36Sopenharmony_ci	case PMBUS_VIRT_READ_VOUT_MIN:
43462306a36Sopenharmony_ci	case PMBUS_VIRT_READ_TEMP_MIN:
43562306a36Sopenharmony_ci		ret = -ENXIO;
43662306a36Sopenharmony_ci		break;
43762306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_IOUT_HISTORY:
43862306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_TEMP2_HISTORY:
43962306a36Sopenharmony_ci		ret = 0;
44062306a36Sopenharmony_ci		break;
44162306a36Sopenharmony_ci	default:
44262306a36Sopenharmony_ci		ret = ltc2978_read_word_data_common(client, page, reg);
44362306a36Sopenharmony_ci		break;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci	return ret;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic int ltc3883_read_word_data(struct i2c_client *client, int page,
44962306a36Sopenharmony_ci				  int phase, int reg)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
45262306a36Sopenharmony_ci	struct ltc2978_data *data = to_ltc2978_data(info);
45362306a36Sopenharmony_ci	int ret;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	switch (reg) {
45662306a36Sopenharmony_ci	case PMBUS_VIRT_READ_IIN_MAX:
45762306a36Sopenharmony_ci		ret = ltc_get_max(data, client, page, LTC3883_MFR_IIN_PEAK,
45862306a36Sopenharmony_ci				  &data->iin_max);
45962306a36Sopenharmony_ci		break;
46062306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_IIN_HISTORY:
46162306a36Sopenharmony_ci		ret = 0;
46262306a36Sopenharmony_ci		break;
46362306a36Sopenharmony_ci	default:
46462306a36Sopenharmony_ci		ret = ltc3880_read_word_data(client, page, phase, reg);
46562306a36Sopenharmony_ci		break;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci	return ret;
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic int ltc2978_clear_peaks(struct ltc2978_data *data,
47162306a36Sopenharmony_ci			       struct i2c_client *client, int page)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	int ret;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (has_clear_peaks(data))
47662306a36Sopenharmony_ci		ret = ltc_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
47762306a36Sopenharmony_ci	else
47862306a36Sopenharmony_ci		ret = ltc_write_byte(client, page, PMBUS_CLEAR_FAULTS);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	return ret;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic int ltc2978_write_word_data(struct i2c_client *client, int page,
48462306a36Sopenharmony_ci				    int reg, u16 word)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
48762306a36Sopenharmony_ci	struct ltc2978_data *data = to_ltc2978_data(info);
48862306a36Sopenharmony_ci	int ret;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	switch (reg) {
49162306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_IIN_HISTORY:
49262306a36Sopenharmony_ci		data->iin_max = 0x7c00;
49362306a36Sopenharmony_ci		data->iin_min = 0x7bff;
49462306a36Sopenharmony_ci		ret = ltc2978_clear_peaks(data, client, 0);
49562306a36Sopenharmony_ci		break;
49662306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_PIN_HISTORY:
49762306a36Sopenharmony_ci		data->pin_max = 0x7c00;
49862306a36Sopenharmony_ci		data->pin_min = 0x7bff;
49962306a36Sopenharmony_ci		ret = ltc2978_clear_peaks(data, client, 0);
50062306a36Sopenharmony_ci		break;
50162306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_IOUT_HISTORY:
50262306a36Sopenharmony_ci		data->iout_max[page] = 0x7c00;
50362306a36Sopenharmony_ci		data->iout_min[page] = 0xfbff;
50462306a36Sopenharmony_ci		ret = ltc2978_clear_peaks(data, client, page);
50562306a36Sopenharmony_ci		break;
50662306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_TEMP2_HISTORY:
50762306a36Sopenharmony_ci		data->temp2_max = 0x7c00;
50862306a36Sopenharmony_ci		ret = ltc2978_clear_peaks(data, client, page);
50962306a36Sopenharmony_ci		break;
51062306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_VOUT_HISTORY:
51162306a36Sopenharmony_ci		data->vout_min[page] = 0xffff;
51262306a36Sopenharmony_ci		data->vout_max[page] = 0;
51362306a36Sopenharmony_ci		ret = ltc2978_clear_peaks(data, client, page);
51462306a36Sopenharmony_ci		break;
51562306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_VIN_HISTORY:
51662306a36Sopenharmony_ci		data->vin_min = 0x7bff;
51762306a36Sopenharmony_ci		data->vin_max = 0x7c00;
51862306a36Sopenharmony_ci		ret = ltc2978_clear_peaks(data, client, page);
51962306a36Sopenharmony_ci		break;
52062306a36Sopenharmony_ci	case PMBUS_VIRT_RESET_TEMP_HISTORY:
52162306a36Sopenharmony_ci		data->temp_min[page] = 0x7bff;
52262306a36Sopenharmony_ci		data->temp_max[page] = 0x7c00;
52362306a36Sopenharmony_ci		ret = ltc2978_clear_peaks(data, client, page);
52462306a36Sopenharmony_ci		break;
52562306a36Sopenharmony_ci	default:
52662306a36Sopenharmony_ci		ret = ltc_wait_ready(client);
52762306a36Sopenharmony_ci		if (ret < 0)
52862306a36Sopenharmony_ci			return ret;
52962306a36Sopenharmony_ci		ret = -ENODATA;
53062306a36Sopenharmony_ci		break;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci	return ret;
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic const struct i2c_device_id ltc2978_id[] = {
53662306a36Sopenharmony_ci	{"ltc2972", ltc2972},
53762306a36Sopenharmony_ci	{"ltc2974", ltc2974},
53862306a36Sopenharmony_ci	{"ltc2975", ltc2975},
53962306a36Sopenharmony_ci	{"ltc2977", ltc2977},
54062306a36Sopenharmony_ci	{"ltc2978", ltc2978},
54162306a36Sopenharmony_ci	{"ltc2979", ltc2979},
54262306a36Sopenharmony_ci	{"ltc2980", ltc2980},
54362306a36Sopenharmony_ci	{"ltc3880", ltc3880},
54462306a36Sopenharmony_ci	{"ltc3882", ltc3882},
54562306a36Sopenharmony_ci	{"ltc3883", ltc3883},
54662306a36Sopenharmony_ci	{"ltc3884", ltc3884},
54762306a36Sopenharmony_ci	{"ltc3886", ltc3886},
54862306a36Sopenharmony_ci	{"ltc3887", ltc3887},
54962306a36Sopenharmony_ci	{"ltc3889", ltc3889},
55062306a36Sopenharmony_ci	{"ltc7132", ltc7132},
55162306a36Sopenharmony_ci	{"ltc7880", ltc7880},
55262306a36Sopenharmony_ci	{"ltm2987", ltm2987},
55362306a36Sopenharmony_ci	{"ltm4664", ltm4664},
55462306a36Sopenharmony_ci	{"ltm4675", ltm4675},
55562306a36Sopenharmony_ci	{"ltm4676", ltm4676},
55662306a36Sopenharmony_ci	{"ltm4677", ltm4677},
55762306a36Sopenharmony_ci	{"ltm4678", ltm4678},
55862306a36Sopenharmony_ci	{"ltm4680", ltm4680},
55962306a36Sopenharmony_ci	{"ltm4686", ltm4686},
56062306a36Sopenharmony_ci	{"ltm4700", ltm4700},
56162306a36Sopenharmony_ci	{}
56262306a36Sopenharmony_ci};
56362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ltc2978_id);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
56662306a36Sopenharmony_ci#define LTC2978_ADC_RES	0xFFFF
56762306a36Sopenharmony_ci#define LTC2978_N_ADC	122
56862306a36Sopenharmony_ci#define LTC2978_MAX_UV	(LTC2978_ADC_RES * LTC2978_N_ADC)
56962306a36Sopenharmony_ci#define LTC2978_UV_STEP	1000
57062306a36Sopenharmony_ci#define LTC2978_N_VOLTAGES	((LTC2978_MAX_UV / LTC2978_UV_STEP) + 1)
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic const struct regulator_desc ltc2978_reg_desc[] = {
57362306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
57462306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
57562306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
57662306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
57762306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
57862306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
57962306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
58062306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
58162306a36Sopenharmony_ci};
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic const struct regulator_desc ltc2978_reg_desc_default[] = {
58462306a36Sopenharmony_ci	PMBUS_REGULATOR("vout", 0),
58562306a36Sopenharmony_ci	PMBUS_REGULATOR("vout", 1),
58662306a36Sopenharmony_ci	PMBUS_REGULATOR("vout", 2),
58762306a36Sopenharmony_ci	PMBUS_REGULATOR("vout", 3),
58862306a36Sopenharmony_ci	PMBUS_REGULATOR("vout", 4),
58962306a36Sopenharmony_ci	PMBUS_REGULATOR("vout", 5),
59062306a36Sopenharmony_ci	PMBUS_REGULATOR("vout", 6),
59162306a36Sopenharmony_ci	PMBUS_REGULATOR("vout", 7),
59262306a36Sopenharmony_ci};
59362306a36Sopenharmony_ci#endif /* CONFIG_SENSORS_LTC2978_REGULATOR */
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic int ltc2978_get_id(struct i2c_client *client)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	int chip_id;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID);
60062306a36Sopenharmony_ci	if (chip_id < 0) {
60162306a36Sopenharmony_ci		const struct i2c_device_id *id;
60262306a36Sopenharmony_ci		u8 buf[I2C_SMBUS_BLOCK_MAX];
60362306a36Sopenharmony_ci		int ret;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci		if (!i2c_check_functionality(client->adapter,
60662306a36Sopenharmony_ci					     I2C_FUNC_SMBUS_READ_BLOCK_DATA))
60762306a36Sopenharmony_ci			return -ENODEV;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
61062306a36Sopenharmony_ci		if (ret < 0)
61162306a36Sopenharmony_ci			return ret;
61262306a36Sopenharmony_ci		if (ret < 3 || strncmp(buf, "LTC", 3))
61362306a36Sopenharmony_ci			return -ENODEV;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
61662306a36Sopenharmony_ci		if (ret < 0)
61762306a36Sopenharmony_ci			return ret;
61862306a36Sopenharmony_ci		for (id = &ltc2978_id[0]; strlen(id->name); id++) {
61962306a36Sopenharmony_ci			if (!strncasecmp(id->name, buf, strlen(id->name)))
62062306a36Sopenharmony_ci				return (int)id->driver_data;
62162306a36Sopenharmony_ci		}
62262306a36Sopenharmony_ci		return -ENODEV;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	chip_id &= LTC2978_ID_MASK;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (chip_id == LTC2972_ID)
62862306a36Sopenharmony_ci		return ltc2972;
62962306a36Sopenharmony_ci	else if (chip_id == LTC2974_ID)
63062306a36Sopenharmony_ci		return ltc2974;
63162306a36Sopenharmony_ci	else if (chip_id == LTC2975_ID)
63262306a36Sopenharmony_ci		return ltc2975;
63362306a36Sopenharmony_ci	else if (chip_id == LTC2977_ID)
63462306a36Sopenharmony_ci		return ltc2977;
63562306a36Sopenharmony_ci	else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2)
63662306a36Sopenharmony_ci		return ltc2978;
63762306a36Sopenharmony_ci	else if (chip_id == LTC2979_ID_A || chip_id == LTC2979_ID_B)
63862306a36Sopenharmony_ci		return ltc2979;
63962306a36Sopenharmony_ci	else if (chip_id == LTC2980_ID_A || chip_id == LTC2980_ID_B)
64062306a36Sopenharmony_ci		return ltc2980;
64162306a36Sopenharmony_ci	else if (chip_id == LTC3880_ID)
64262306a36Sopenharmony_ci		return ltc3880;
64362306a36Sopenharmony_ci	else if (chip_id == LTC3882_ID || chip_id == LTC3882_ID_D1)
64462306a36Sopenharmony_ci		return ltc3882;
64562306a36Sopenharmony_ci	else if (chip_id == LTC3883_ID)
64662306a36Sopenharmony_ci		return ltc3883;
64762306a36Sopenharmony_ci	else if (chip_id == LTC3884_ID)
64862306a36Sopenharmony_ci		return ltc3884;
64962306a36Sopenharmony_ci	else if (chip_id == LTC3886_ID)
65062306a36Sopenharmony_ci		return ltc3886;
65162306a36Sopenharmony_ci	else if (chip_id == LTC3887_ID)
65262306a36Sopenharmony_ci		return ltc3887;
65362306a36Sopenharmony_ci	else if (chip_id == LTC3889_ID)
65462306a36Sopenharmony_ci		return ltc3889;
65562306a36Sopenharmony_ci	else if (chip_id == LTC7132_ID)
65662306a36Sopenharmony_ci		return ltc7132;
65762306a36Sopenharmony_ci	else if (chip_id == LTC7880_ID)
65862306a36Sopenharmony_ci		return ltc7880;
65962306a36Sopenharmony_ci	else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B)
66062306a36Sopenharmony_ci		return ltm2987;
66162306a36Sopenharmony_ci	else if (chip_id == LTM4664_ID)
66262306a36Sopenharmony_ci		return ltm4664;
66362306a36Sopenharmony_ci	else if (chip_id == LTM4675_ID)
66462306a36Sopenharmony_ci		return ltm4675;
66562306a36Sopenharmony_ci	else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 ||
66662306a36Sopenharmony_ci		 chip_id == LTM4676A_ID)
66762306a36Sopenharmony_ci		return ltm4676;
66862306a36Sopenharmony_ci	else if (chip_id == LTM4677_ID_REV1 || chip_id == LTM4677_ID_REV2)
66962306a36Sopenharmony_ci		return ltm4677;
67062306a36Sopenharmony_ci	else if (chip_id == LTM4678_ID_REV1 || chip_id == LTM4678_ID_REV2)
67162306a36Sopenharmony_ci		return ltm4678;
67262306a36Sopenharmony_ci	else if (chip_id == LTM4680_ID)
67362306a36Sopenharmony_ci		return ltm4680;
67462306a36Sopenharmony_ci	else if (chip_id == LTM4686_ID)
67562306a36Sopenharmony_ci		return ltm4686;
67662306a36Sopenharmony_ci	else if (chip_id == LTM4700_ID)
67762306a36Sopenharmony_ci		return ltm4700;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
68062306a36Sopenharmony_ci	return -ENODEV;
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cistatic int ltc2978_probe(struct i2c_client *client)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	int i, chip_id;
68662306a36Sopenharmony_ci	struct ltc2978_data *data;
68762306a36Sopenharmony_ci	struct pmbus_driver_info *info;
68862306a36Sopenharmony_ci	const struct i2c_device_id *id;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (!i2c_check_functionality(client->adapter,
69162306a36Sopenharmony_ci				     I2C_FUNC_SMBUS_READ_WORD_DATA))
69262306a36Sopenharmony_ci		return -ENODEV;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	data = devm_kzalloc(&client->dev, sizeof(struct ltc2978_data),
69562306a36Sopenharmony_ci			    GFP_KERNEL);
69662306a36Sopenharmony_ci	if (!data)
69762306a36Sopenharmony_ci		return -ENOMEM;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	chip_id = ltc2978_get_id(client);
70062306a36Sopenharmony_ci	if (chip_id < 0)
70162306a36Sopenharmony_ci		return chip_id;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	data->id = chip_id;
70462306a36Sopenharmony_ci	id = i2c_match_id(ltc2978_id, client);
70562306a36Sopenharmony_ci	if (data->id != id->driver_data)
70662306a36Sopenharmony_ci		dev_warn(&client->dev,
70762306a36Sopenharmony_ci			 "Device mismatch: Configured %s (%d), detected %d\n",
70862306a36Sopenharmony_ci			 id->name,
70962306a36Sopenharmony_ci			 (int) id->driver_data,
71062306a36Sopenharmony_ci			 chip_id);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	info = &data->info;
71362306a36Sopenharmony_ci	info->write_word_data = ltc2978_write_word_data;
71462306a36Sopenharmony_ci	info->write_byte = ltc_write_byte;
71562306a36Sopenharmony_ci	info->write_byte_data = ltc_write_byte_data;
71662306a36Sopenharmony_ci	info->read_word_data = ltc_read_word_data;
71762306a36Sopenharmony_ci	info->read_byte_data = ltc_read_byte_data;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	data->vin_min = 0x7bff;
72062306a36Sopenharmony_ci	data->vin_max = 0x7c00;
72162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->vout_min); i++)
72262306a36Sopenharmony_ci		data->vout_min[i] = 0xffff;
72362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->iout_min); i++)
72462306a36Sopenharmony_ci		data->iout_min[i] = 0xfbff;
72562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->iout_max); i++)
72662306a36Sopenharmony_ci		data->iout_max[i] = 0x7c00;
72762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->temp_min); i++)
72862306a36Sopenharmony_ci		data->temp_min[i] = 0x7bff;
72962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->temp_max); i++)
73062306a36Sopenharmony_ci		data->temp_max[i] = 0x7c00;
73162306a36Sopenharmony_ci	data->temp2_max = 0x7c00;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	switch (data->id) {
73462306a36Sopenharmony_ci	case ltc2972:
73562306a36Sopenharmony_ci		info->read_word_data = ltc2975_read_word_data;
73662306a36Sopenharmony_ci		info->pages = LTC2972_NUM_PAGES;
73762306a36Sopenharmony_ci		info->func[0] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN
73862306a36Sopenharmony_ci		  | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
73962306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP2;
74062306a36Sopenharmony_ci		for (i = 0; i < info->pages; i++) {
74162306a36Sopenharmony_ci			info->func[i] |= PMBUS_HAVE_VOUT
74262306a36Sopenharmony_ci			  | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
74362306a36Sopenharmony_ci			  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
74462306a36Sopenharmony_ci			  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
74562306a36Sopenharmony_ci		}
74662306a36Sopenharmony_ci		break;
74762306a36Sopenharmony_ci	case ltc2974:
74862306a36Sopenharmony_ci		info->read_word_data = ltc2974_read_word_data;
74962306a36Sopenharmony_ci		info->pages = LTC2974_NUM_PAGES;
75062306a36Sopenharmony_ci		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
75162306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP2;
75262306a36Sopenharmony_ci		for (i = 0; i < info->pages; i++) {
75362306a36Sopenharmony_ci			info->func[i] |= PMBUS_HAVE_VOUT
75462306a36Sopenharmony_ci			  | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
75562306a36Sopenharmony_ci			  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
75662306a36Sopenharmony_ci			  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
75762306a36Sopenharmony_ci		}
75862306a36Sopenharmony_ci		break;
75962306a36Sopenharmony_ci	case ltc2975:
76062306a36Sopenharmony_ci		info->read_word_data = ltc2975_read_word_data;
76162306a36Sopenharmony_ci		info->pages = LTC2974_NUM_PAGES;
76262306a36Sopenharmony_ci		info->func[0] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN
76362306a36Sopenharmony_ci		  | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
76462306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP2;
76562306a36Sopenharmony_ci		for (i = 0; i < info->pages; i++) {
76662306a36Sopenharmony_ci			info->func[i] |= PMBUS_HAVE_VOUT
76762306a36Sopenharmony_ci			  | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
76862306a36Sopenharmony_ci			  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
76962306a36Sopenharmony_ci			  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
77062306a36Sopenharmony_ci		}
77162306a36Sopenharmony_ci		break;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	case ltc2977:
77462306a36Sopenharmony_ci	case ltc2978:
77562306a36Sopenharmony_ci	case ltc2979:
77662306a36Sopenharmony_ci	case ltc2980:
77762306a36Sopenharmony_ci	case ltm2987:
77862306a36Sopenharmony_ci		info->read_word_data = ltc2978_read_word_data;
77962306a36Sopenharmony_ci		info->pages = LTC2978_NUM_PAGES;
78062306a36Sopenharmony_ci		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
78162306a36Sopenharmony_ci		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
78262306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
78362306a36Sopenharmony_ci		for (i = 1; i < LTC2978_NUM_PAGES; i++) {
78462306a36Sopenharmony_ci			info->func[i] = PMBUS_HAVE_VOUT
78562306a36Sopenharmony_ci			  | PMBUS_HAVE_STATUS_VOUT;
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci		break;
78862306a36Sopenharmony_ci	case ltc3880:
78962306a36Sopenharmony_ci	case ltc3887:
79062306a36Sopenharmony_ci	case ltm4675:
79162306a36Sopenharmony_ci	case ltm4676:
79262306a36Sopenharmony_ci	case ltm4677:
79362306a36Sopenharmony_ci	case ltm4686:
79462306a36Sopenharmony_ci		data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
79562306a36Sopenharmony_ci		info->read_word_data = ltc3880_read_word_data;
79662306a36Sopenharmony_ci		info->pages = LTC3880_NUM_PAGES;
79762306a36Sopenharmony_ci		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
79862306a36Sopenharmony_ci		  | PMBUS_HAVE_STATUS_INPUT
79962306a36Sopenharmony_ci		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
80062306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
80162306a36Sopenharmony_ci		  | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
80262306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
80362306a36Sopenharmony_ci		info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
80462306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
80562306a36Sopenharmony_ci		  | PMBUS_HAVE_POUT
80662306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
80762306a36Sopenharmony_ci		break;
80862306a36Sopenharmony_ci	case ltc3882:
80962306a36Sopenharmony_ci		data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
81062306a36Sopenharmony_ci		info->read_word_data = ltc3880_read_word_data;
81162306a36Sopenharmony_ci		info->pages = LTC3880_NUM_PAGES;
81262306a36Sopenharmony_ci		info->func[0] = PMBUS_HAVE_VIN
81362306a36Sopenharmony_ci		  | PMBUS_HAVE_STATUS_INPUT
81462306a36Sopenharmony_ci		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
81562306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
81662306a36Sopenharmony_ci		  | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
81762306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
81862306a36Sopenharmony_ci		info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
81962306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
82062306a36Sopenharmony_ci		  | PMBUS_HAVE_POUT
82162306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
82262306a36Sopenharmony_ci		break;
82362306a36Sopenharmony_ci	case ltc3883:
82462306a36Sopenharmony_ci		data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
82562306a36Sopenharmony_ci		info->read_word_data = ltc3883_read_word_data;
82662306a36Sopenharmony_ci		info->pages = LTC3883_NUM_PAGES;
82762306a36Sopenharmony_ci		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
82862306a36Sopenharmony_ci		  | PMBUS_HAVE_STATUS_INPUT
82962306a36Sopenharmony_ci		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
83062306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
83162306a36Sopenharmony_ci		  | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
83262306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
83362306a36Sopenharmony_ci		break;
83462306a36Sopenharmony_ci	case ltc3884:
83562306a36Sopenharmony_ci	case ltc3886:
83662306a36Sopenharmony_ci	case ltc3889:
83762306a36Sopenharmony_ci	case ltc7132:
83862306a36Sopenharmony_ci	case ltc7880:
83962306a36Sopenharmony_ci	case ltm4664:
84062306a36Sopenharmony_ci	case ltm4678:
84162306a36Sopenharmony_ci	case ltm4680:
84262306a36Sopenharmony_ci	case ltm4700:
84362306a36Sopenharmony_ci		data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
84462306a36Sopenharmony_ci		info->read_word_data = ltc3883_read_word_data;
84562306a36Sopenharmony_ci		info->pages = LTC3880_NUM_PAGES;
84662306a36Sopenharmony_ci		info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
84762306a36Sopenharmony_ci		  | PMBUS_HAVE_STATUS_INPUT
84862306a36Sopenharmony_ci		  | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
84962306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
85062306a36Sopenharmony_ci		  | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
85162306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
85262306a36Sopenharmony_ci		info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
85362306a36Sopenharmony_ci		  | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
85462306a36Sopenharmony_ci		  | PMBUS_HAVE_POUT
85562306a36Sopenharmony_ci		  | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
85662306a36Sopenharmony_ci		break;
85762306a36Sopenharmony_ci	default:
85862306a36Sopenharmony_ci		return -ENODEV;
85962306a36Sopenharmony_ci	}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
86262306a36Sopenharmony_ci	info->num_regulators = info->pages;
86362306a36Sopenharmony_ci	switch (data->id) {
86462306a36Sopenharmony_ci	case ltc2972:
86562306a36Sopenharmony_ci	case ltc2974:
86662306a36Sopenharmony_ci	case ltc2975:
86762306a36Sopenharmony_ci	case ltc2977:
86862306a36Sopenharmony_ci	case ltc2978:
86962306a36Sopenharmony_ci	case ltc2979:
87062306a36Sopenharmony_ci	case ltc2980:
87162306a36Sopenharmony_ci	case ltm2987:
87262306a36Sopenharmony_ci		info->reg_desc = ltc2978_reg_desc;
87362306a36Sopenharmony_ci		if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc)) {
87462306a36Sopenharmony_ci			dev_warn(&client->dev, "num_regulators too large!");
87562306a36Sopenharmony_ci			info->num_regulators = ARRAY_SIZE(ltc2978_reg_desc);
87662306a36Sopenharmony_ci		}
87762306a36Sopenharmony_ci		break;
87862306a36Sopenharmony_ci	default:
87962306a36Sopenharmony_ci		info->reg_desc = ltc2978_reg_desc_default;
88062306a36Sopenharmony_ci		if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc_default)) {
88162306a36Sopenharmony_ci			dev_warn(&client->dev, "num_regulators too large!");
88262306a36Sopenharmony_ci			info->num_regulators =
88362306a36Sopenharmony_ci			    ARRAY_SIZE(ltc2978_reg_desc_default);
88462306a36Sopenharmony_ci		}
88562306a36Sopenharmony_ci		break;
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci#endif
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	return pmbus_do_probe(client, info);
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci#ifdef CONFIG_OF
89462306a36Sopenharmony_cistatic const struct of_device_id ltc2978_of_match[] = {
89562306a36Sopenharmony_ci	{ .compatible = "lltc,ltc2972" },
89662306a36Sopenharmony_ci	{ .compatible = "lltc,ltc2974" },
89762306a36Sopenharmony_ci	{ .compatible = "lltc,ltc2975" },
89862306a36Sopenharmony_ci	{ .compatible = "lltc,ltc2977" },
89962306a36Sopenharmony_ci	{ .compatible = "lltc,ltc2978" },
90062306a36Sopenharmony_ci	{ .compatible = "lltc,ltc2979" },
90162306a36Sopenharmony_ci	{ .compatible = "lltc,ltc2980" },
90262306a36Sopenharmony_ci	{ .compatible = "lltc,ltc3880" },
90362306a36Sopenharmony_ci	{ .compatible = "lltc,ltc3882" },
90462306a36Sopenharmony_ci	{ .compatible = "lltc,ltc3883" },
90562306a36Sopenharmony_ci	{ .compatible = "lltc,ltc3884" },
90662306a36Sopenharmony_ci	{ .compatible = "lltc,ltc3886" },
90762306a36Sopenharmony_ci	{ .compatible = "lltc,ltc3887" },
90862306a36Sopenharmony_ci	{ .compatible = "lltc,ltc3889" },
90962306a36Sopenharmony_ci	{ .compatible = "lltc,ltc7132" },
91062306a36Sopenharmony_ci	{ .compatible = "lltc,ltc7880" },
91162306a36Sopenharmony_ci	{ .compatible = "lltc,ltm2987" },
91262306a36Sopenharmony_ci	{ .compatible = "lltc,ltm4664" },
91362306a36Sopenharmony_ci	{ .compatible = "lltc,ltm4675" },
91462306a36Sopenharmony_ci	{ .compatible = "lltc,ltm4676" },
91562306a36Sopenharmony_ci	{ .compatible = "lltc,ltm4677" },
91662306a36Sopenharmony_ci	{ .compatible = "lltc,ltm4678" },
91762306a36Sopenharmony_ci	{ .compatible = "lltc,ltm4680" },
91862306a36Sopenharmony_ci	{ .compatible = "lltc,ltm4686" },
91962306a36Sopenharmony_ci	{ .compatible = "lltc,ltm4700" },
92062306a36Sopenharmony_ci	{ }
92162306a36Sopenharmony_ci};
92262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ltc2978_of_match);
92362306a36Sopenharmony_ci#endif
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic struct i2c_driver ltc2978_driver = {
92662306a36Sopenharmony_ci	.driver = {
92762306a36Sopenharmony_ci		   .name = "ltc2978",
92862306a36Sopenharmony_ci		   .of_match_table = of_match_ptr(ltc2978_of_match),
92962306a36Sopenharmony_ci		   },
93062306a36Sopenharmony_ci	.probe = ltc2978_probe,
93162306a36Sopenharmony_ci	.id_table = ltc2978_id,
93262306a36Sopenharmony_ci};
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cimodule_i2c_driver(ltc2978_driver);
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ciMODULE_AUTHOR("Guenter Roeck");
93762306a36Sopenharmony_ciMODULE_DESCRIPTION("PMBus driver for LTC2978 and compatible chips");
93862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
93962306a36Sopenharmony_ciMODULE_IMPORT_NS(PMBUS);
940