18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller
48c2ecf20Sopenharmony_ci * and Digital Power Monitor
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (c) 2011 Ericsson AB.
78c2ecf20Sopenharmony_ci * Copyright (c) 2018 Guenter Roeck
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/err.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/i2c.h>
168c2ecf20Sopenharmony_ci#include <linux/bitops.h>
178c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
188c2ecf20Sopenharmony_ci#include <linux/log2.h>
198c2ecf20Sopenharmony_ci#include "pmbus.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cienum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define ADM1275_MFR_STATUS_IOUT_WARN2	BIT(0)
248c2ecf20Sopenharmony_ci#define ADM1293_MFR_STATUS_VAUX_UV_WARN	BIT(5)
258c2ecf20Sopenharmony_ci#define ADM1293_MFR_STATUS_VAUX_OV_WARN	BIT(6)
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define ADM1275_PEAK_IOUT		0xd0
288c2ecf20Sopenharmony_ci#define ADM1275_PEAK_VIN		0xd1
298c2ecf20Sopenharmony_ci#define ADM1275_PEAK_VOUT		0xd2
308c2ecf20Sopenharmony_ci#define ADM1275_PMON_CONFIG		0xd4
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define ADM1275_VIN_VOUT_SELECT		BIT(6)
338c2ecf20Sopenharmony_ci#define ADM1275_VRANGE			BIT(5)
348c2ecf20Sopenharmony_ci#define ADM1075_IRANGE_50		BIT(4)
358c2ecf20Sopenharmony_ci#define ADM1075_IRANGE_25		BIT(3)
368c2ecf20Sopenharmony_ci#define ADM1075_IRANGE_MASK		(BIT(3) | BIT(4))
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define ADM1272_IRANGE			BIT(0)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define ADM1278_TSFILT			BIT(15)
418c2ecf20Sopenharmony_ci#define ADM1278_TEMP1_EN		BIT(3)
428c2ecf20Sopenharmony_ci#define ADM1278_VIN_EN			BIT(2)
438c2ecf20Sopenharmony_ci#define ADM1278_VOUT_EN			BIT(1)
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define ADM1278_PMON_DEFCONFIG		(ADM1278_VOUT_EN | ADM1278_TEMP1_EN | ADM1278_TSFILT)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define ADM1293_IRANGE_25		0
488c2ecf20Sopenharmony_ci#define ADM1293_IRANGE_50		BIT(6)
498c2ecf20Sopenharmony_ci#define ADM1293_IRANGE_100		BIT(7)
508c2ecf20Sopenharmony_ci#define ADM1293_IRANGE_200		(BIT(6) | BIT(7))
518c2ecf20Sopenharmony_ci#define ADM1293_IRANGE_MASK		(BIT(6) | BIT(7))
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define ADM1293_VIN_SEL_012		BIT(2)
548c2ecf20Sopenharmony_ci#define ADM1293_VIN_SEL_074		BIT(3)
558c2ecf20Sopenharmony_ci#define ADM1293_VIN_SEL_210		(BIT(2) | BIT(3))
568c2ecf20Sopenharmony_ci#define ADM1293_VIN_SEL_MASK		(BIT(2) | BIT(3))
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define ADM1293_VAUX_EN			BIT(1)
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define ADM1278_PEAK_TEMP		0xd7
618c2ecf20Sopenharmony_ci#define ADM1275_IOUT_WARN2_LIMIT	0xd7
628c2ecf20Sopenharmony_ci#define ADM1275_DEVICE_CONFIG		0xd8
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define ADM1275_IOUT_WARN2_SELECT	BIT(4)
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define ADM1276_PEAK_PIN		0xda
678c2ecf20Sopenharmony_ci#define ADM1075_READ_VAUX		0xdd
688c2ecf20Sopenharmony_ci#define ADM1075_VAUX_OV_WARN_LIMIT	0xde
698c2ecf20Sopenharmony_ci#define ADM1075_VAUX_UV_WARN_LIMIT	0xdf
708c2ecf20Sopenharmony_ci#define ADM1293_IOUT_MIN		0xe3
718c2ecf20Sopenharmony_ci#define ADM1293_PIN_MIN			0xe4
728c2ecf20Sopenharmony_ci#define ADM1075_VAUX_STATUS		0xf6
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define ADM1075_VAUX_OV_WARN		BIT(7)
758c2ecf20Sopenharmony_ci#define ADM1075_VAUX_UV_WARN		BIT(6)
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define ADM1275_VI_AVG_SHIFT		0
788c2ecf20Sopenharmony_ci#define ADM1275_VI_AVG_MASK		GENMASK(ADM1275_VI_AVG_SHIFT + 2, \
798c2ecf20Sopenharmony_ci						ADM1275_VI_AVG_SHIFT)
808c2ecf20Sopenharmony_ci#define ADM1275_SAMPLES_AVG_MAX		128
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#define ADM1278_PWR_AVG_SHIFT		11
838c2ecf20Sopenharmony_ci#define ADM1278_PWR_AVG_MASK		GENMASK(ADM1278_PWR_AVG_SHIFT + 2, \
848c2ecf20Sopenharmony_ci						ADM1278_PWR_AVG_SHIFT)
858c2ecf20Sopenharmony_ci#define ADM1278_VI_AVG_SHIFT		8
868c2ecf20Sopenharmony_ci#define ADM1278_VI_AVG_MASK		GENMASK(ADM1278_VI_AVG_SHIFT + 2, \
878c2ecf20Sopenharmony_ci						ADM1278_VI_AVG_SHIFT)
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistruct adm1275_data {
908c2ecf20Sopenharmony_ci	int id;
918c2ecf20Sopenharmony_ci	bool have_oc_fault;
928c2ecf20Sopenharmony_ci	bool have_uc_fault;
938c2ecf20Sopenharmony_ci	bool have_vout;
948c2ecf20Sopenharmony_ci	bool have_vaux_status;
958c2ecf20Sopenharmony_ci	bool have_mfr_vaux_status;
968c2ecf20Sopenharmony_ci	bool have_iout_min;
978c2ecf20Sopenharmony_ci	bool have_pin_min;
988c2ecf20Sopenharmony_ci	bool have_pin_max;
998c2ecf20Sopenharmony_ci	bool have_temp_max;
1008c2ecf20Sopenharmony_ci	bool have_power_sampling;
1018c2ecf20Sopenharmony_ci	struct pmbus_driver_info info;
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#define to_adm1275_data(x)  container_of(x, struct adm1275_data, info)
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistruct coefficients {
1078c2ecf20Sopenharmony_ci	s16 m;
1088c2ecf20Sopenharmony_ci	s16 b;
1098c2ecf20Sopenharmony_ci	s16 R;
1108c2ecf20Sopenharmony_ci};
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic const struct coefficients adm1075_coefficients[] = {
1138c2ecf20Sopenharmony_ci	[0] = { 27169, 0, -1 },		/* voltage */
1148c2ecf20Sopenharmony_ci	[1] = { 806, 20475, -1 },	/* current, irange25 */
1158c2ecf20Sopenharmony_ci	[2] = { 404, 20475, -1 },	/* current, irange50 */
1168c2ecf20Sopenharmony_ci	[3] = { 8549, 0, -1 },		/* power, irange25 */
1178c2ecf20Sopenharmony_ci	[4] = { 4279, 0, -1 },		/* power, irange50 */
1188c2ecf20Sopenharmony_ci};
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic const struct coefficients adm1272_coefficients[] = {
1218c2ecf20Sopenharmony_ci	[0] = { 6770, 0, -2 },		/* voltage, vrange 60V */
1228c2ecf20Sopenharmony_ci	[1] = { 4062, 0, -2 },		/* voltage, vrange 100V */
1238c2ecf20Sopenharmony_ci	[2] = { 1326, 20480, -1 },	/* current, vsense range 15mV */
1248c2ecf20Sopenharmony_ci	[3] = { 663, 20480, -1 },	/* current, vsense range 30mV */
1258c2ecf20Sopenharmony_ci	[4] = { 3512, 0, -2 },		/* power, vrange 60V, irange 15mV */
1268c2ecf20Sopenharmony_ci	[5] = { 21071, 0, -3 },		/* power, vrange 100V, irange 15mV */
1278c2ecf20Sopenharmony_ci	[6] = { 17561, 0, -3 },		/* power, vrange 60V, irange 30mV */
1288c2ecf20Sopenharmony_ci	[7] = { 10535, 0, -3 },		/* power, vrange 100V, irange 30mV */
1298c2ecf20Sopenharmony_ci	[8] = { 42, 31871, -1 },	/* temperature */
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci};
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic const struct coefficients adm1275_coefficients[] = {
1348c2ecf20Sopenharmony_ci	[0] = { 19199, 0, -2 },		/* voltage, vrange set */
1358c2ecf20Sopenharmony_ci	[1] = { 6720, 0, -1 },		/* voltage, vrange not set */
1368c2ecf20Sopenharmony_ci	[2] = { 807, 20475, -1 },	/* current */
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic const struct coefficients adm1276_coefficients[] = {
1408c2ecf20Sopenharmony_ci	[0] = { 19199, 0, -2 },		/* voltage, vrange set */
1418c2ecf20Sopenharmony_ci	[1] = { 6720, 0, -1 },		/* voltage, vrange not set */
1428c2ecf20Sopenharmony_ci	[2] = { 807, 20475, -1 },	/* current */
1438c2ecf20Sopenharmony_ci	[3] = { 6043, 0, -2 },		/* power, vrange set */
1448c2ecf20Sopenharmony_ci	[4] = { 2115, 0, -1 },		/* power, vrange not set */
1458c2ecf20Sopenharmony_ci};
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic const struct coefficients adm1278_coefficients[] = {
1488c2ecf20Sopenharmony_ci	[0] = { 19599, 0, -2 },		/* voltage */
1498c2ecf20Sopenharmony_ci	[1] = { 800, 20475, -1 },	/* current */
1508c2ecf20Sopenharmony_ci	[2] = { 6123, 0, -2 },		/* power */
1518c2ecf20Sopenharmony_ci	[3] = { 42, 31880, -1 },	/* temperature */
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic const struct coefficients adm1293_coefficients[] = {
1558c2ecf20Sopenharmony_ci	[0] = { 3333, -1, 0 },		/* voltage, vrange 1.2V */
1568c2ecf20Sopenharmony_ci	[1] = { 5552, -5, -1 },		/* voltage, vrange 7.4V */
1578c2ecf20Sopenharmony_ci	[2] = { 19604, -50, -2 },	/* voltage, vrange 21V */
1588c2ecf20Sopenharmony_ci	[3] = { 8000, -100, -2 },	/* current, irange25 */
1598c2ecf20Sopenharmony_ci	[4] = { 4000, -100, -2 },	/* current, irange50 */
1608c2ecf20Sopenharmony_ci	[5] = { 20000, -1000, -3 },	/* current, irange100 */
1618c2ecf20Sopenharmony_ci	[6] = { 10000, -1000, -3 },	/* current, irange200 */
1628c2ecf20Sopenharmony_ci	[7] = { 10417, 0, -1 },		/* power, 1.2V, irange25 */
1638c2ecf20Sopenharmony_ci	[8] = { 5208, 0, -1 },		/* power, 1.2V, irange50 */
1648c2ecf20Sopenharmony_ci	[9] = { 26042, 0, -2 },		/* power, 1.2V, irange100 */
1658c2ecf20Sopenharmony_ci	[10] = { 13021, 0, -2 },	/* power, 1.2V, irange200 */
1668c2ecf20Sopenharmony_ci	[11] = { 17351, 0, -2 },	/* power, 7.4V, irange25 */
1678c2ecf20Sopenharmony_ci	[12] = { 8676, 0, -2 },		/* power, 7.4V, irange50 */
1688c2ecf20Sopenharmony_ci	[13] = { 4338, 0, -2 },		/* power, 7.4V, irange100 */
1698c2ecf20Sopenharmony_ci	[14] = { 21689, 0, -3 },	/* power, 7.4V, irange200 */
1708c2ecf20Sopenharmony_ci	[15] = { 6126, 0, -2 },		/* power, 21V, irange25 */
1718c2ecf20Sopenharmony_ci	[16] = { 30631, 0, -3 },	/* power, 21V, irange50 */
1728c2ecf20Sopenharmony_ci	[17] = { 15316, 0, -3 },	/* power, 21V, irange100 */
1738c2ecf20Sopenharmony_ci	[18] = { 7658, 0, -3 },		/* power, 21V, irange200 */
1748c2ecf20Sopenharmony_ci};
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int adm1275_read_pmon_config(const struct adm1275_data *data,
1778c2ecf20Sopenharmony_ci				    struct i2c_client *client, bool is_power)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	int shift, ret;
1808c2ecf20Sopenharmony_ci	u16 mask;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/*
1838c2ecf20Sopenharmony_ci	 * The PMON configuration register is a 16-bit register only on chips
1848c2ecf20Sopenharmony_ci	 * supporting power average sampling. On other chips it is an 8-bit
1858c2ecf20Sopenharmony_ci	 * register.
1868c2ecf20Sopenharmony_ci	 */
1878c2ecf20Sopenharmony_ci	if (data->have_power_sampling) {
1888c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
1898c2ecf20Sopenharmony_ci		mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK;
1908c2ecf20Sopenharmony_ci		shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT;
1918c2ecf20Sopenharmony_ci	} else {
1928c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
1938c2ecf20Sopenharmony_ci		mask = ADM1275_VI_AVG_MASK;
1948c2ecf20Sopenharmony_ci		shift = ADM1275_VI_AVG_SHIFT;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci	if (ret < 0)
1978c2ecf20Sopenharmony_ci		return ret;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return (ret & mask) >> shift;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic int adm1275_write_pmon_config(const struct adm1275_data *data,
2038c2ecf20Sopenharmony_ci				     struct i2c_client *client,
2048c2ecf20Sopenharmony_ci				     bool is_power, u16 word)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	int shift, ret;
2078c2ecf20Sopenharmony_ci	u16 mask;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (data->have_power_sampling) {
2108c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
2118c2ecf20Sopenharmony_ci		mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK;
2128c2ecf20Sopenharmony_ci		shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT;
2138c2ecf20Sopenharmony_ci	} else {
2148c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
2158c2ecf20Sopenharmony_ci		mask = ADM1275_VI_AVG_MASK;
2168c2ecf20Sopenharmony_ci		shift = ADM1275_VI_AVG_SHIFT;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci	if (ret < 0)
2198c2ecf20Sopenharmony_ci		return ret;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	word = (ret & ~mask) | ((word << shift) & mask);
2228c2ecf20Sopenharmony_ci	if (data->have_power_sampling)
2238c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG,
2248c2ecf20Sopenharmony_ci						word);
2258c2ecf20Sopenharmony_ci	else
2268c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG,
2278c2ecf20Sopenharmony_ci						word);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	return ret;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic int adm1275_read_word_data(struct i2c_client *client, int page,
2338c2ecf20Sopenharmony_ci				  int phase, int reg)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
2368c2ecf20Sopenharmony_ci	const struct adm1275_data *data = to_adm1275_data(info);
2378c2ecf20Sopenharmony_ci	int ret = 0;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (page > 0)
2408c2ecf20Sopenharmony_ci		return -ENXIO;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	switch (reg) {
2438c2ecf20Sopenharmony_ci	case PMBUS_IOUT_UC_FAULT_LIMIT:
2448c2ecf20Sopenharmony_ci		if (!data->have_uc_fault)
2458c2ecf20Sopenharmony_ci			return -ENXIO;
2468c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
2478c2ecf20Sopenharmony_ci					   ADM1275_IOUT_WARN2_LIMIT);
2488c2ecf20Sopenharmony_ci		break;
2498c2ecf20Sopenharmony_ci	case PMBUS_IOUT_OC_FAULT_LIMIT:
2508c2ecf20Sopenharmony_ci		if (!data->have_oc_fault)
2518c2ecf20Sopenharmony_ci			return -ENXIO;
2528c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
2538c2ecf20Sopenharmony_ci					   ADM1275_IOUT_WARN2_LIMIT);
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci	case PMBUS_VOUT_OV_WARN_LIMIT:
2568c2ecf20Sopenharmony_ci		if (data->have_vout)
2578c2ecf20Sopenharmony_ci			return -ENODATA;
2588c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
2598c2ecf20Sopenharmony_ci					   ADM1075_VAUX_OV_WARN_LIMIT);
2608c2ecf20Sopenharmony_ci		break;
2618c2ecf20Sopenharmony_ci	case PMBUS_VOUT_UV_WARN_LIMIT:
2628c2ecf20Sopenharmony_ci		if (data->have_vout)
2638c2ecf20Sopenharmony_ci			return -ENODATA;
2648c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
2658c2ecf20Sopenharmony_ci					   ADM1075_VAUX_UV_WARN_LIMIT);
2668c2ecf20Sopenharmony_ci		break;
2678c2ecf20Sopenharmony_ci	case PMBUS_READ_VOUT:
2688c2ecf20Sopenharmony_ci		if (data->have_vout)
2698c2ecf20Sopenharmony_ci			return -ENODATA;
2708c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
2718c2ecf20Sopenharmony_ci					   ADM1075_READ_VAUX);
2728c2ecf20Sopenharmony_ci		break;
2738c2ecf20Sopenharmony_ci	case PMBUS_VIRT_READ_IOUT_MIN:
2748c2ecf20Sopenharmony_ci		if (!data->have_iout_min)
2758c2ecf20Sopenharmony_ci			return -ENXIO;
2768c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
2778c2ecf20Sopenharmony_ci					   ADM1293_IOUT_MIN);
2788c2ecf20Sopenharmony_ci		break;
2798c2ecf20Sopenharmony_ci	case PMBUS_VIRT_READ_IOUT_MAX:
2808c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
2818c2ecf20Sopenharmony_ci					   ADM1275_PEAK_IOUT);
2828c2ecf20Sopenharmony_ci		break;
2838c2ecf20Sopenharmony_ci	case PMBUS_VIRT_READ_VOUT_MAX:
2848c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
2858c2ecf20Sopenharmony_ci					   ADM1275_PEAK_VOUT);
2868c2ecf20Sopenharmony_ci		break;
2878c2ecf20Sopenharmony_ci	case PMBUS_VIRT_READ_VIN_MAX:
2888c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
2898c2ecf20Sopenharmony_ci					   ADM1275_PEAK_VIN);
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	case PMBUS_VIRT_READ_PIN_MIN:
2928c2ecf20Sopenharmony_ci		if (!data->have_pin_min)
2938c2ecf20Sopenharmony_ci			return -ENXIO;
2948c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
2958c2ecf20Sopenharmony_ci					   ADM1293_PIN_MIN);
2968c2ecf20Sopenharmony_ci		break;
2978c2ecf20Sopenharmony_ci	case PMBUS_VIRT_READ_PIN_MAX:
2988c2ecf20Sopenharmony_ci		if (!data->have_pin_max)
2998c2ecf20Sopenharmony_ci			return -ENXIO;
3008c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
3018c2ecf20Sopenharmony_ci					   ADM1276_PEAK_PIN);
3028c2ecf20Sopenharmony_ci		break;
3038c2ecf20Sopenharmony_ci	case PMBUS_VIRT_READ_TEMP_MAX:
3048c2ecf20Sopenharmony_ci		if (!data->have_temp_max)
3058c2ecf20Sopenharmony_ci			return -ENXIO;
3068c2ecf20Sopenharmony_ci		ret = pmbus_read_word_data(client, 0, 0xff,
3078c2ecf20Sopenharmony_ci					   ADM1278_PEAK_TEMP);
3088c2ecf20Sopenharmony_ci		break;
3098c2ecf20Sopenharmony_ci	case PMBUS_VIRT_RESET_IOUT_HISTORY:
3108c2ecf20Sopenharmony_ci	case PMBUS_VIRT_RESET_VOUT_HISTORY:
3118c2ecf20Sopenharmony_ci	case PMBUS_VIRT_RESET_VIN_HISTORY:
3128c2ecf20Sopenharmony_ci		break;
3138c2ecf20Sopenharmony_ci	case PMBUS_VIRT_RESET_PIN_HISTORY:
3148c2ecf20Sopenharmony_ci		if (!data->have_pin_max)
3158c2ecf20Sopenharmony_ci			return -ENXIO;
3168c2ecf20Sopenharmony_ci		break;
3178c2ecf20Sopenharmony_ci	case PMBUS_VIRT_RESET_TEMP_HISTORY:
3188c2ecf20Sopenharmony_ci		if (!data->have_temp_max)
3198c2ecf20Sopenharmony_ci			return -ENXIO;
3208c2ecf20Sopenharmony_ci		break;
3218c2ecf20Sopenharmony_ci	case PMBUS_VIRT_POWER_SAMPLES:
3228c2ecf20Sopenharmony_ci		if (!data->have_power_sampling)
3238c2ecf20Sopenharmony_ci			return -ENXIO;
3248c2ecf20Sopenharmony_ci		ret = adm1275_read_pmon_config(data, client, true);
3258c2ecf20Sopenharmony_ci		if (ret < 0)
3268c2ecf20Sopenharmony_ci			break;
3278c2ecf20Sopenharmony_ci		ret = BIT(ret);
3288c2ecf20Sopenharmony_ci		break;
3298c2ecf20Sopenharmony_ci	case PMBUS_VIRT_IN_SAMPLES:
3308c2ecf20Sopenharmony_ci	case PMBUS_VIRT_CURR_SAMPLES:
3318c2ecf20Sopenharmony_ci		ret = adm1275_read_pmon_config(data, client, false);
3328c2ecf20Sopenharmony_ci		if (ret < 0)
3338c2ecf20Sopenharmony_ci			break;
3348c2ecf20Sopenharmony_ci		ret = BIT(ret);
3358c2ecf20Sopenharmony_ci		break;
3368c2ecf20Sopenharmony_ci	default:
3378c2ecf20Sopenharmony_ci		ret = -ENODATA;
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci	return ret;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
3448c2ecf20Sopenharmony_ci				   u16 word)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
3478c2ecf20Sopenharmony_ci	const struct adm1275_data *data = to_adm1275_data(info);
3488c2ecf20Sopenharmony_ci	int ret;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (page > 0)
3518c2ecf20Sopenharmony_ci		return -ENXIO;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	switch (reg) {
3548c2ecf20Sopenharmony_ci	case PMBUS_IOUT_UC_FAULT_LIMIT:
3558c2ecf20Sopenharmony_ci	case PMBUS_IOUT_OC_FAULT_LIMIT:
3568c2ecf20Sopenharmony_ci		ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT,
3578c2ecf20Sopenharmony_ci					    word);
3588c2ecf20Sopenharmony_ci		break;
3598c2ecf20Sopenharmony_ci	case PMBUS_VIRT_RESET_IOUT_HISTORY:
3608c2ecf20Sopenharmony_ci		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0);
3618c2ecf20Sopenharmony_ci		if (!ret && data->have_iout_min)
3628c2ecf20Sopenharmony_ci			ret = pmbus_write_word_data(client, 0,
3638c2ecf20Sopenharmony_ci						    ADM1293_IOUT_MIN, 0);
3648c2ecf20Sopenharmony_ci		break;
3658c2ecf20Sopenharmony_ci	case PMBUS_VIRT_RESET_VOUT_HISTORY:
3668c2ecf20Sopenharmony_ci		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0);
3678c2ecf20Sopenharmony_ci		break;
3688c2ecf20Sopenharmony_ci	case PMBUS_VIRT_RESET_VIN_HISTORY:
3698c2ecf20Sopenharmony_ci		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0);
3708c2ecf20Sopenharmony_ci		break;
3718c2ecf20Sopenharmony_ci	case PMBUS_VIRT_RESET_PIN_HISTORY:
3728c2ecf20Sopenharmony_ci		ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0);
3738c2ecf20Sopenharmony_ci		if (!ret && data->have_pin_min)
3748c2ecf20Sopenharmony_ci			ret = pmbus_write_word_data(client, 0,
3758c2ecf20Sopenharmony_ci						    ADM1293_PIN_MIN, 0);
3768c2ecf20Sopenharmony_ci		break;
3778c2ecf20Sopenharmony_ci	case PMBUS_VIRT_RESET_TEMP_HISTORY:
3788c2ecf20Sopenharmony_ci		ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0);
3798c2ecf20Sopenharmony_ci		break;
3808c2ecf20Sopenharmony_ci	case PMBUS_VIRT_POWER_SAMPLES:
3818c2ecf20Sopenharmony_ci		if (!data->have_power_sampling)
3828c2ecf20Sopenharmony_ci			return -ENXIO;
3838c2ecf20Sopenharmony_ci		word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
3848c2ecf20Sopenharmony_ci		ret = adm1275_write_pmon_config(data, client, true,
3858c2ecf20Sopenharmony_ci						ilog2(word));
3868c2ecf20Sopenharmony_ci		break;
3878c2ecf20Sopenharmony_ci	case PMBUS_VIRT_IN_SAMPLES:
3888c2ecf20Sopenharmony_ci	case PMBUS_VIRT_CURR_SAMPLES:
3898c2ecf20Sopenharmony_ci		word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
3908c2ecf20Sopenharmony_ci		ret = adm1275_write_pmon_config(data, client, false,
3918c2ecf20Sopenharmony_ci						ilog2(word));
3928c2ecf20Sopenharmony_ci		break;
3938c2ecf20Sopenharmony_ci	default:
3948c2ecf20Sopenharmony_ci		ret = -ENODATA;
3958c2ecf20Sopenharmony_ci		break;
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci	return ret;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
4038c2ecf20Sopenharmony_ci	const struct adm1275_data *data = to_adm1275_data(info);
4048c2ecf20Sopenharmony_ci	int mfr_status, ret;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (page > 0)
4078c2ecf20Sopenharmony_ci		return -ENXIO;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	switch (reg) {
4108c2ecf20Sopenharmony_ci	case PMBUS_STATUS_IOUT:
4118c2ecf20Sopenharmony_ci		ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT);
4128c2ecf20Sopenharmony_ci		if (ret < 0)
4138c2ecf20Sopenharmony_ci			break;
4148c2ecf20Sopenharmony_ci		if (!data->have_oc_fault && !data->have_uc_fault)
4158c2ecf20Sopenharmony_ci			break;
4168c2ecf20Sopenharmony_ci		mfr_status = pmbus_read_byte_data(client, page,
4178c2ecf20Sopenharmony_ci						  PMBUS_STATUS_MFR_SPECIFIC);
4188c2ecf20Sopenharmony_ci		if (mfr_status < 0)
4198c2ecf20Sopenharmony_ci			return mfr_status;
4208c2ecf20Sopenharmony_ci		if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) {
4218c2ecf20Sopenharmony_ci			ret |= data->have_oc_fault ?
4228c2ecf20Sopenharmony_ci			  PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT;
4238c2ecf20Sopenharmony_ci		}
4248c2ecf20Sopenharmony_ci		break;
4258c2ecf20Sopenharmony_ci	case PMBUS_STATUS_VOUT:
4268c2ecf20Sopenharmony_ci		if (data->have_vout)
4278c2ecf20Sopenharmony_ci			return -ENODATA;
4288c2ecf20Sopenharmony_ci		ret = 0;
4298c2ecf20Sopenharmony_ci		if (data->have_vaux_status) {
4308c2ecf20Sopenharmony_ci			mfr_status = pmbus_read_byte_data(client, 0,
4318c2ecf20Sopenharmony_ci							  ADM1075_VAUX_STATUS);
4328c2ecf20Sopenharmony_ci			if (mfr_status < 0)
4338c2ecf20Sopenharmony_ci				return mfr_status;
4348c2ecf20Sopenharmony_ci			if (mfr_status & ADM1075_VAUX_OV_WARN)
4358c2ecf20Sopenharmony_ci				ret |= PB_VOLTAGE_OV_WARNING;
4368c2ecf20Sopenharmony_ci			if (mfr_status & ADM1075_VAUX_UV_WARN)
4378c2ecf20Sopenharmony_ci				ret |= PB_VOLTAGE_UV_WARNING;
4388c2ecf20Sopenharmony_ci		} else if (data->have_mfr_vaux_status) {
4398c2ecf20Sopenharmony_ci			mfr_status = pmbus_read_byte_data(client, page,
4408c2ecf20Sopenharmony_ci						PMBUS_STATUS_MFR_SPECIFIC);
4418c2ecf20Sopenharmony_ci			if (mfr_status < 0)
4428c2ecf20Sopenharmony_ci				return mfr_status;
4438c2ecf20Sopenharmony_ci			if (mfr_status & ADM1293_MFR_STATUS_VAUX_OV_WARN)
4448c2ecf20Sopenharmony_ci				ret |= PB_VOLTAGE_OV_WARNING;
4458c2ecf20Sopenharmony_ci			if (mfr_status & ADM1293_MFR_STATUS_VAUX_UV_WARN)
4468c2ecf20Sopenharmony_ci				ret |= PB_VOLTAGE_UV_WARNING;
4478c2ecf20Sopenharmony_ci		}
4488c2ecf20Sopenharmony_ci		break;
4498c2ecf20Sopenharmony_ci	default:
4508c2ecf20Sopenharmony_ci		ret = -ENODATA;
4518c2ecf20Sopenharmony_ci		break;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci	return ret;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic const struct i2c_device_id adm1275_id[] = {
4578c2ecf20Sopenharmony_ci	{ "adm1075", adm1075 },
4588c2ecf20Sopenharmony_ci	{ "adm1272", adm1272 },
4598c2ecf20Sopenharmony_ci	{ "adm1275", adm1275 },
4608c2ecf20Sopenharmony_ci	{ "adm1276", adm1276 },
4618c2ecf20Sopenharmony_ci	{ "adm1278", adm1278 },
4628c2ecf20Sopenharmony_ci	{ "adm1293", adm1293 },
4638c2ecf20Sopenharmony_ci	{ "adm1294", adm1294 },
4648c2ecf20Sopenharmony_ci	{ }
4658c2ecf20Sopenharmony_ci};
4668c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adm1275_id);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci/* Enable VOUT & TEMP1 if not enabled (disabled by default) */
4698c2ecf20Sopenharmony_cistatic int adm1275_enable_vout_temp(struct i2c_client *client, int config)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	int ret;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	if ((config & ADM1278_PMON_DEFCONFIG) != ADM1278_PMON_DEFCONFIG) {
4748c2ecf20Sopenharmony_ci		config |= ADM1278_PMON_DEFCONFIG;
4758c2ecf20Sopenharmony_ci		ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, config);
4768c2ecf20Sopenharmony_ci		if (ret < 0) {
4778c2ecf20Sopenharmony_ci			dev_err(&client->dev, "Failed to enable VOUT/TEMP1 monitoring\n");
4788c2ecf20Sopenharmony_ci			return ret;
4798c2ecf20Sopenharmony_ci		}
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci	return 0;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic int adm1275_probe(struct i2c_client *client)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	s32 (*config_read_fn)(const struct i2c_client *client, u8 reg);
4878c2ecf20Sopenharmony_ci	u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
4888c2ecf20Sopenharmony_ci	int config, device_config;
4898c2ecf20Sopenharmony_ci	int ret;
4908c2ecf20Sopenharmony_ci	struct pmbus_driver_info *info;
4918c2ecf20Sopenharmony_ci	struct adm1275_data *data;
4928c2ecf20Sopenharmony_ci	const struct i2c_device_id *mid;
4938c2ecf20Sopenharmony_ci	const struct coefficients *coefficients;
4948c2ecf20Sopenharmony_ci	int vindex = -1, voindex = -1, cindex = -1, pindex = -1;
4958c2ecf20Sopenharmony_ci	int tindex = -1;
4968c2ecf20Sopenharmony_ci	u32 shunt;
4978c2ecf20Sopenharmony_ci	u32 avg;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter,
5008c2ecf20Sopenharmony_ci				     I2C_FUNC_SMBUS_READ_BYTE_DATA
5018c2ecf20Sopenharmony_ci				     | I2C_FUNC_SMBUS_BLOCK_DATA))
5028c2ecf20Sopenharmony_ci		return -ENODEV;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer);
5058c2ecf20Sopenharmony_ci	if (ret < 0) {
5068c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Failed to read Manufacturer ID\n");
5078c2ecf20Sopenharmony_ci		return ret;
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci	if (ret != 3 || strncmp(block_buffer, "ADI", 3)) {
5108c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Unsupported Manufacturer ID\n");
5118c2ecf20Sopenharmony_ci		return -ENODEV;
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer);
5158c2ecf20Sopenharmony_ci	if (ret < 0) {
5168c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Failed to read Manufacturer Model\n");
5178c2ecf20Sopenharmony_ci		return ret;
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci	for (mid = adm1275_id; mid->name[0]; mid++) {
5208c2ecf20Sopenharmony_ci		if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
5218c2ecf20Sopenharmony_ci			break;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci	if (!mid->name[0]) {
5248c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Unsupported device\n");
5258c2ecf20Sopenharmony_ci		return -ENODEV;
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (strcmp(client->name, mid->name) != 0)
5298c2ecf20Sopenharmony_ci		dev_notice(&client->dev,
5308c2ecf20Sopenharmony_ci			   "Device mismatch: Configured %s, detected %s\n",
5318c2ecf20Sopenharmony_ci			   client->name, mid->name);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (mid->driver_data == adm1272 || mid->driver_data == adm1278 ||
5348c2ecf20Sopenharmony_ci	    mid->driver_data == adm1293 || mid->driver_data == adm1294)
5358c2ecf20Sopenharmony_ci		config_read_fn = i2c_smbus_read_word_data;
5368c2ecf20Sopenharmony_ci	else
5378c2ecf20Sopenharmony_ci		config_read_fn = i2c_smbus_read_byte_data;
5388c2ecf20Sopenharmony_ci	config = config_read_fn(client, ADM1275_PMON_CONFIG);
5398c2ecf20Sopenharmony_ci	if (config < 0)
5408c2ecf20Sopenharmony_ci		return config;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	device_config = config_read_fn(client, ADM1275_DEVICE_CONFIG);
5438c2ecf20Sopenharmony_ci	if (device_config < 0)
5448c2ecf20Sopenharmony_ci		return device_config;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data),
5478c2ecf20Sopenharmony_ci			    GFP_KERNEL);
5488c2ecf20Sopenharmony_ci	if (!data)
5498c2ecf20Sopenharmony_ci		return -ENOMEM;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	if (of_property_read_u32(client->dev.of_node,
5528c2ecf20Sopenharmony_ci				 "shunt-resistor-micro-ohms", &shunt))
5538c2ecf20Sopenharmony_ci		shunt = 1000; /* 1 mOhm if not set via DT */
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	if (shunt == 0)
5568c2ecf20Sopenharmony_ci		return -EINVAL;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	data->id = mid->driver_data;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	info = &data->info;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	info->pages = 1;
5638c2ecf20Sopenharmony_ci	info->format[PSC_VOLTAGE_IN] = direct;
5648c2ecf20Sopenharmony_ci	info->format[PSC_VOLTAGE_OUT] = direct;
5658c2ecf20Sopenharmony_ci	info->format[PSC_CURRENT_OUT] = direct;
5668c2ecf20Sopenharmony_ci	info->format[PSC_POWER] = direct;
5678c2ecf20Sopenharmony_ci	info->format[PSC_TEMPERATURE] = direct;
5688c2ecf20Sopenharmony_ci	info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
5698c2ecf20Sopenharmony_ci			PMBUS_HAVE_SAMPLES;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	info->read_word_data = adm1275_read_word_data;
5728c2ecf20Sopenharmony_ci	info->read_byte_data = adm1275_read_byte_data;
5738c2ecf20Sopenharmony_ci	info->write_word_data = adm1275_write_word_data;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	switch (data->id) {
5768c2ecf20Sopenharmony_ci	case adm1075:
5778c2ecf20Sopenharmony_ci		if (device_config & ADM1275_IOUT_WARN2_SELECT)
5788c2ecf20Sopenharmony_ci			data->have_oc_fault = true;
5798c2ecf20Sopenharmony_ci		else
5808c2ecf20Sopenharmony_ci			data->have_uc_fault = true;
5818c2ecf20Sopenharmony_ci		data->have_pin_max = true;
5828c2ecf20Sopenharmony_ci		data->have_vaux_status = true;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		coefficients = adm1075_coefficients;
5858c2ecf20Sopenharmony_ci		vindex = 0;
5868c2ecf20Sopenharmony_ci		switch (config & ADM1075_IRANGE_MASK) {
5878c2ecf20Sopenharmony_ci		case ADM1075_IRANGE_25:
5888c2ecf20Sopenharmony_ci			cindex = 1;
5898c2ecf20Sopenharmony_ci			pindex = 3;
5908c2ecf20Sopenharmony_ci			break;
5918c2ecf20Sopenharmony_ci		case ADM1075_IRANGE_50:
5928c2ecf20Sopenharmony_ci			cindex = 2;
5938c2ecf20Sopenharmony_ci			pindex = 4;
5948c2ecf20Sopenharmony_ci			break;
5958c2ecf20Sopenharmony_ci		default:
5968c2ecf20Sopenharmony_ci			dev_err(&client->dev, "Invalid input current range");
5978c2ecf20Sopenharmony_ci			break;
5988c2ecf20Sopenharmony_ci		}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci		info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
6018c2ecf20Sopenharmony_ci		  | PMBUS_HAVE_STATUS_INPUT;
6028c2ecf20Sopenharmony_ci		if (config & ADM1275_VIN_VOUT_SELECT)
6038c2ecf20Sopenharmony_ci			info->func[0] |=
6048c2ecf20Sopenharmony_ci			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
6058c2ecf20Sopenharmony_ci		break;
6068c2ecf20Sopenharmony_ci	case adm1272:
6078c2ecf20Sopenharmony_ci		data->have_vout = true;
6088c2ecf20Sopenharmony_ci		data->have_pin_max = true;
6098c2ecf20Sopenharmony_ci		data->have_temp_max = true;
6108c2ecf20Sopenharmony_ci		data->have_power_sampling = true;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci		coefficients = adm1272_coefficients;
6138c2ecf20Sopenharmony_ci		vindex = (config & ADM1275_VRANGE) ? 1 : 0;
6148c2ecf20Sopenharmony_ci		cindex = (config & ADM1272_IRANGE) ? 3 : 2;
6158c2ecf20Sopenharmony_ci		/* pindex depends on the combination of the above */
6168c2ecf20Sopenharmony_ci		switch (config & (ADM1275_VRANGE | ADM1272_IRANGE)) {
6178c2ecf20Sopenharmony_ci		case 0:
6188c2ecf20Sopenharmony_ci		default:
6198c2ecf20Sopenharmony_ci			pindex = 4;
6208c2ecf20Sopenharmony_ci			break;
6218c2ecf20Sopenharmony_ci		case ADM1275_VRANGE:
6228c2ecf20Sopenharmony_ci			pindex = 5;
6238c2ecf20Sopenharmony_ci			break;
6248c2ecf20Sopenharmony_ci		case ADM1272_IRANGE:
6258c2ecf20Sopenharmony_ci			pindex = 6;
6268c2ecf20Sopenharmony_ci			break;
6278c2ecf20Sopenharmony_ci		case ADM1275_VRANGE | ADM1272_IRANGE:
6288c2ecf20Sopenharmony_ci			pindex = 7;
6298c2ecf20Sopenharmony_ci			break;
6308c2ecf20Sopenharmony_ci		}
6318c2ecf20Sopenharmony_ci		tindex = 8;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci		info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
6348c2ecf20Sopenharmony_ci			PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
6358c2ecf20Sopenharmony_ci			PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci		ret = adm1275_enable_vout_temp(client, config);
6388c2ecf20Sopenharmony_ci		if (ret)
6398c2ecf20Sopenharmony_ci			return ret;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		if (config & ADM1278_VIN_EN)
6428c2ecf20Sopenharmony_ci			info->func[0] |= PMBUS_HAVE_VIN;
6438c2ecf20Sopenharmony_ci		break;
6448c2ecf20Sopenharmony_ci	case adm1275:
6458c2ecf20Sopenharmony_ci		if (device_config & ADM1275_IOUT_WARN2_SELECT)
6468c2ecf20Sopenharmony_ci			data->have_oc_fault = true;
6478c2ecf20Sopenharmony_ci		else
6488c2ecf20Sopenharmony_ci			data->have_uc_fault = true;
6498c2ecf20Sopenharmony_ci		data->have_vout = true;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci		coefficients = adm1275_coefficients;
6528c2ecf20Sopenharmony_ci		vindex = (config & ADM1275_VRANGE) ? 0 : 1;
6538c2ecf20Sopenharmony_ci		cindex = 2;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci		if (config & ADM1275_VIN_VOUT_SELECT)
6568c2ecf20Sopenharmony_ci			info->func[0] |=
6578c2ecf20Sopenharmony_ci			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
6588c2ecf20Sopenharmony_ci		else
6598c2ecf20Sopenharmony_ci			info->func[0] |=
6608c2ecf20Sopenharmony_ci			  PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
6618c2ecf20Sopenharmony_ci		break;
6628c2ecf20Sopenharmony_ci	case adm1276:
6638c2ecf20Sopenharmony_ci		if (device_config & ADM1275_IOUT_WARN2_SELECT)
6648c2ecf20Sopenharmony_ci			data->have_oc_fault = true;
6658c2ecf20Sopenharmony_ci		else
6668c2ecf20Sopenharmony_ci			data->have_uc_fault = true;
6678c2ecf20Sopenharmony_ci		data->have_vout = true;
6688c2ecf20Sopenharmony_ci		data->have_pin_max = true;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci		coefficients = adm1276_coefficients;
6718c2ecf20Sopenharmony_ci		vindex = (config & ADM1275_VRANGE) ? 0 : 1;
6728c2ecf20Sopenharmony_ci		cindex = 2;
6738c2ecf20Sopenharmony_ci		pindex = (config & ADM1275_VRANGE) ? 3 : 4;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
6768c2ecf20Sopenharmony_ci		  | PMBUS_HAVE_STATUS_INPUT;
6778c2ecf20Sopenharmony_ci		if (config & ADM1275_VIN_VOUT_SELECT)
6788c2ecf20Sopenharmony_ci			info->func[0] |=
6798c2ecf20Sopenharmony_ci			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
6808c2ecf20Sopenharmony_ci		break;
6818c2ecf20Sopenharmony_ci	case adm1278:
6828c2ecf20Sopenharmony_ci		data->have_vout = true;
6838c2ecf20Sopenharmony_ci		data->have_pin_max = true;
6848c2ecf20Sopenharmony_ci		data->have_temp_max = true;
6858c2ecf20Sopenharmony_ci		data->have_power_sampling = true;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci		coefficients = adm1278_coefficients;
6888c2ecf20Sopenharmony_ci		vindex = 0;
6898c2ecf20Sopenharmony_ci		cindex = 1;
6908c2ecf20Sopenharmony_ci		pindex = 2;
6918c2ecf20Sopenharmony_ci		tindex = 3;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci		info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
6948c2ecf20Sopenharmony_ci			PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
6958c2ecf20Sopenharmony_ci			PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci		ret = adm1275_enable_vout_temp(client, config);
6988c2ecf20Sopenharmony_ci		if (ret)
6998c2ecf20Sopenharmony_ci			return ret;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		if (config & ADM1278_VIN_EN)
7028c2ecf20Sopenharmony_ci			info->func[0] |= PMBUS_HAVE_VIN;
7038c2ecf20Sopenharmony_ci		break;
7048c2ecf20Sopenharmony_ci	case adm1293:
7058c2ecf20Sopenharmony_ci	case adm1294:
7068c2ecf20Sopenharmony_ci		data->have_iout_min = true;
7078c2ecf20Sopenharmony_ci		data->have_pin_min = true;
7088c2ecf20Sopenharmony_ci		data->have_pin_max = true;
7098c2ecf20Sopenharmony_ci		data->have_mfr_vaux_status = true;
7108c2ecf20Sopenharmony_ci		data->have_power_sampling = true;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci		coefficients = adm1293_coefficients;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci		voindex = 0;
7158c2ecf20Sopenharmony_ci		switch (config & ADM1293_VIN_SEL_MASK) {
7168c2ecf20Sopenharmony_ci		case ADM1293_VIN_SEL_012:	/* 1.2V */
7178c2ecf20Sopenharmony_ci			vindex = 0;
7188c2ecf20Sopenharmony_ci			break;
7198c2ecf20Sopenharmony_ci		case ADM1293_VIN_SEL_074:	/* 7.4V */
7208c2ecf20Sopenharmony_ci			vindex = 1;
7218c2ecf20Sopenharmony_ci			break;
7228c2ecf20Sopenharmony_ci		case ADM1293_VIN_SEL_210:	/* 21V */
7238c2ecf20Sopenharmony_ci			vindex = 2;
7248c2ecf20Sopenharmony_ci			break;
7258c2ecf20Sopenharmony_ci		default:			/* disabled */
7268c2ecf20Sopenharmony_ci			break;
7278c2ecf20Sopenharmony_ci		}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci		switch (config & ADM1293_IRANGE_MASK) {
7308c2ecf20Sopenharmony_ci		case ADM1293_IRANGE_25:
7318c2ecf20Sopenharmony_ci			cindex = 3;
7328c2ecf20Sopenharmony_ci			break;
7338c2ecf20Sopenharmony_ci		case ADM1293_IRANGE_50:
7348c2ecf20Sopenharmony_ci			cindex = 4;
7358c2ecf20Sopenharmony_ci			break;
7368c2ecf20Sopenharmony_ci		case ADM1293_IRANGE_100:
7378c2ecf20Sopenharmony_ci			cindex = 5;
7388c2ecf20Sopenharmony_ci			break;
7398c2ecf20Sopenharmony_ci		case ADM1293_IRANGE_200:
7408c2ecf20Sopenharmony_ci			cindex = 6;
7418c2ecf20Sopenharmony_ci			break;
7428c2ecf20Sopenharmony_ci		}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci		if (vindex >= 0)
7458c2ecf20Sopenharmony_ci			pindex = 7 + vindex * 4 + (cindex - 3);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci		if (config & ADM1293_VAUX_EN)
7488c2ecf20Sopenharmony_ci			info->func[0] |=
7498c2ecf20Sopenharmony_ci				PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		info->func[0] |= PMBUS_HAVE_PIN |
7528c2ecf20Sopenharmony_ci			PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci		break;
7558c2ecf20Sopenharmony_ci	default:
7568c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Unsupported device\n");
7578c2ecf20Sopenharmony_ci		return -ENODEV;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	if (data->have_power_sampling &&
7618c2ecf20Sopenharmony_ci	    of_property_read_u32(client->dev.of_node,
7628c2ecf20Sopenharmony_ci				 "adi,power-sample-average", &avg) == 0) {
7638c2ecf20Sopenharmony_ci		if (!avg || avg > ADM1275_SAMPLES_AVG_MAX ||
7648c2ecf20Sopenharmony_ci		    BIT(__fls(avg)) != avg) {
7658c2ecf20Sopenharmony_ci			dev_err(&client->dev,
7668c2ecf20Sopenharmony_ci				"Invalid number of power samples");
7678c2ecf20Sopenharmony_ci			return -EINVAL;
7688c2ecf20Sopenharmony_ci		}
7698c2ecf20Sopenharmony_ci		ret = adm1275_write_pmon_config(data, client, true,
7708c2ecf20Sopenharmony_ci						ilog2(avg));
7718c2ecf20Sopenharmony_ci		if (ret < 0) {
7728c2ecf20Sopenharmony_ci			dev_err(&client->dev,
7738c2ecf20Sopenharmony_ci				"Setting power sample averaging failed with error %d",
7748c2ecf20Sopenharmony_ci				ret);
7758c2ecf20Sopenharmony_ci			return ret;
7768c2ecf20Sopenharmony_ci		}
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (of_property_read_u32(client->dev.of_node,
7808c2ecf20Sopenharmony_ci				"adi,volt-curr-sample-average", &avg) == 0) {
7818c2ecf20Sopenharmony_ci		if (!avg || avg > ADM1275_SAMPLES_AVG_MAX ||
7828c2ecf20Sopenharmony_ci		    BIT(__fls(avg)) != avg) {
7838c2ecf20Sopenharmony_ci			dev_err(&client->dev,
7848c2ecf20Sopenharmony_ci				"Invalid number of voltage/current samples");
7858c2ecf20Sopenharmony_ci			return -EINVAL;
7868c2ecf20Sopenharmony_ci		}
7878c2ecf20Sopenharmony_ci		ret = adm1275_write_pmon_config(data, client, false,
7888c2ecf20Sopenharmony_ci						ilog2(avg));
7898c2ecf20Sopenharmony_ci		if (ret < 0) {
7908c2ecf20Sopenharmony_ci			dev_err(&client->dev,
7918c2ecf20Sopenharmony_ci				"Setting voltage and current sample averaging failed with error %d",
7928c2ecf20Sopenharmony_ci				ret);
7938c2ecf20Sopenharmony_ci			return ret;
7948c2ecf20Sopenharmony_ci		}
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	if (voindex < 0)
7988c2ecf20Sopenharmony_ci		voindex = vindex;
7998c2ecf20Sopenharmony_ci	if (vindex >= 0) {
8008c2ecf20Sopenharmony_ci		info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m;
8018c2ecf20Sopenharmony_ci		info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b;
8028c2ecf20Sopenharmony_ci		info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R;
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci	if (voindex >= 0) {
8058c2ecf20Sopenharmony_ci		info->m[PSC_VOLTAGE_OUT] = coefficients[voindex].m;
8068c2ecf20Sopenharmony_ci		info->b[PSC_VOLTAGE_OUT] = coefficients[voindex].b;
8078c2ecf20Sopenharmony_ci		info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R;
8088c2ecf20Sopenharmony_ci	}
8098c2ecf20Sopenharmony_ci	if (cindex >= 0) {
8108c2ecf20Sopenharmony_ci		/* Scale current with sense resistor value */
8118c2ecf20Sopenharmony_ci		info->m[PSC_CURRENT_OUT] =
8128c2ecf20Sopenharmony_ci			coefficients[cindex].m * shunt / 1000;
8138c2ecf20Sopenharmony_ci		info->b[PSC_CURRENT_OUT] = coefficients[cindex].b;
8148c2ecf20Sopenharmony_ci		info->R[PSC_CURRENT_OUT] = coefficients[cindex].R;
8158c2ecf20Sopenharmony_ci	}
8168c2ecf20Sopenharmony_ci	if (pindex >= 0) {
8178c2ecf20Sopenharmony_ci		info->m[PSC_POWER] =
8188c2ecf20Sopenharmony_ci			coefficients[pindex].m * shunt / 1000;
8198c2ecf20Sopenharmony_ci		info->b[PSC_POWER] = coefficients[pindex].b;
8208c2ecf20Sopenharmony_ci		info->R[PSC_POWER] = coefficients[pindex].R;
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci	if (tindex >= 0) {
8238c2ecf20Sopenharmony_ci		info->m[PSC_TEMPERATURE] = coefficients[tindex].m;
8248c2ecf20Sopenharmony_ci		info->b[PSC_TEMPERATURE] = coefficients[tindex].b;
8258c2ecf20Sopenharmony_ci		info->R[PSC_TEMPERATURE] = coefficients[tindex].R;
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	return pmbus_do_probe(client, info);
8298c2ecf20Sopenharmony_ci}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_cistatic struct i2c_driver adm1275_driver = {
8328c2ecf20Sopenharmony_ci	.driver = {
8338c2ecf20Sopenharmony_ci		   .name = "adm1275",
8348c2ecf20Sopenharmony_ci		   },
8358c2ecf20Sopenharmony_ci	.probe_new = adm1275_probe,
8368c2ecf20Sopenharmony_ci	.remove = pmbus_do_remove,
8378c2ecf20Sopenharmony_ci	.id_table = adm1275_id,
8388c2ecf20Sopenharmony_ci};
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cimodule_i2c_driver(adm1275_driver);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ciMODULE_AUTHOR("Guenter Roeck");
8438c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
8448c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
845