xref: /linux/drivers/hwmon/pmbus/adm1275.c (revision c83529c17e12046ac4a8d8fbbc49c51255c7b4da)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29d2ecfb7SGuenter Roeck /*
39d2ecfb7SGuenter Roeck  * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller
49d2ecfb7SGuenter Roeck  * and Digital Power Monitor
59d2ecfb7SGuenter Roeck  *
69d2ecfb7SGuenter Roeck  * Copyright (c) 2011 Ericsson AB.
74ff0ce22SGuenter Roeck  * Copyright (c) 2018 Guenter Roeck
89d2ecfb7SGuenter Roeck  */
99d2ecfb7SGuenter Roeck 
109d2ecfb7SGuenter Roeck #include <linux/kernel.h>
119d2ecfb7SGuenter Roeck #include <linux/module.h>
129d2ecfb7SGuenter Roeck #include <linux/init.h>
139d2ecfb7SGuenter Roeck #include <linux/err.h>
149d2ecfb7SGuenter Roeck #include <linux/slab.h>
159d2ecfb7SGuenter Roeck #include <linux/i2c.h>
1699b41608SGuenter Roeck #include <linux/bitops.h>
17*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) #include <linux/bitfield.h>
18*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) #include <linux/log2.h>
199d2ecfb7SGuenter Roeck #include "pmbus.h"
209d2ecfb7SGuenter Roeck 
214ff0ce22SGuenter Roeck enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
2268a40382SGuenter Roeck 
2368a40382SGuenter Roeck #define ADM1275_MFR_STATUS_IOUT_WARN2	BIT(0)
2468a40382SGuenter Roeck #define ADM1293_MFR_STATUS_VAUX_UV_WARN	BIT(5)
2568a40382SGuenter Roeck #define ADM1293_MFR_STATUS_VAUX_OV_WARN	BIT(6)
265cf231a3SGuenter Roeck 
27c576e30cSGuenter Roeck #define ADM1275_PEAK_IOUT		0xd0
28c576e30cSGuenter Roeck #define ADM1275_PEAK_VIN		0xd1
29c576e30cSGuenter Roeck #define ADM1275_PEAK_VOUT		0xd2
309d2ecfb7SGuenter Roeck #define ADM1275_PMON_CONFIG		0xd4
319d2ecfb7SGuenter Roeck 
3299b41608SGuenter Roeck #define ADM1275_VIN_VOUT_SELECT		BIT(6)
3399b41608SGuenter Roeck #define ADM1275_VRANGE			BIT(5)
3499b41608SGuenter Roeck #define ADM1075_IRANGE_50		BIT(4)
3599b41608SGuenter Roeck #define ADM1075_IRANGE_25		BIT(3)
3699b41608SGuenter Roeck #define ADM1075_IRANGE_MASK		(BIT(3) | BIT(4))
379d2ecfb7SGuenter Roeck 
384ff0ce22SGuenter Roeck #define ADM1272_IRANGE			BIT(0)
394ff0ce22SGuenter Roeck 
40709066acSGuenter Roeck #define ADM1278_TEMP1_EN		BIT(3)
41709066acSGuenter Roeck #define ADM1278_VIN_EN			BIT(2)
42709066acSGuenter Roeck #define ADM1278_VOUT_EN			BIT(1)
43709066acSGuenter Roeck 
4468a40382SGuenter Roeck #define ADM1293_IRANGE_25		0
4568a40382SGuenter Roeck #define ADM1293_IRANGE_50		BIT(6)
4668a40382SGuenter Roeck #define ADM1293_IRANGE_100		BIT(7)
4768a40382SGuenter Roeck #define ADM1293_IRANGE_200		(BIT(6) | BIT(7))
4868a40382SGuenter Roeck #define ADM1293_IRANGE_MASK		(BIT(6) | BIT(7))
4968a40382SGuenter Roeck 
5068a40382SGuenter Roeck #define ADM1293_VIN_SEL_012		BIT(2)
5168a40382SGuenter Roeck #define ADM1293_VIN_SEL_074		BIT(3)
5268a40382SGuenter Roeck #define ADM1293_VIN_SEL_210		(BIT(2) | BIT(3))
5368a40382SGuenter Roeck #define ADM1293_VIN_SEL_MASK		(BIT(2) | BIT(3))
5468a40382SGuenter Roeck 
5568a40382SGuenter Roeck #define ADM1293_VAUX_EN			BIT(1)
5668a40382SGuenter Roeck 
57709066acSGuenter Roeck #define ADM1278_PEAK_TEMP		0xd7
58c5e67636SGuenter Roeck #define ADM1275_IOUT_WARN2_LIMIT	0xd7
59c5e67636SGuenter Roeck #define ADM1275_DEVICE_CONFIG		0xd8
60c5e67636SGuenter Roeck 
6199b41608SGuenter Roeck #define ADM1275_IOUT_WARN2_SELECT	BIT(4)
62c5e67636SGuenter Roeck 
635cf231a3SGuenter Roeck #define ADM1276_PEAK_PIN		0xda
6492711269SGuenter Roeck #define ADM1075_READ_VAUX		0xdd
6592711269SGuenter Roeck #define ADM1075_VAUX_OV_WARN_LIMIT	0xde
6692711269SGuenter Roeck #define ADM1075_VAUX_UV_WARN_LIMIT	0xdf
6768a40382SGuenter Roeck #define ADM1293_IOUT_MIN		0xe3
6868a40382SGuenter Roeck #define ADM1293_PIN_MIN			0xe4
6992711269SGuenter Roeck #define ADM1075_VAUX_STATUS		0xf6
7092711269SGuenter Roeck 
7199b41608SGuenter Roeck #define ADM1075_VAUX_OV_WARN		BIT(7)
7299b41608SGuenter Roeck #define ADM1075_VAUX_UV_WARN		BIT(6)
7392711269SGuenter Roeck 
74*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) #define ADM1275_PWR_AVG_MASK		GENMASK(13, 11)
75*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) #define ADM1275_VI_AVG_MASK		GENMASK(10, 8)
76*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) #define ADM1275_SAMPLES_AVG_MAX	128
77*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 
78c5e67636SGuenter Roeck struct adm1275_data {
795cf231a3SGuenter Roeck 	int id;
80c5e67636SGuenter Roeck 	bool have_oc_fault;
819048539bSGuenter Roeck 	bool have_uc_fault;
829048539bSGuenter Roeck 	bool have_vout;
839048539bSGuenter Roeck 	bool have_vaux_status;
8468a40382SGuenter Roeck 	bool have_mfr_vaux_status;
8568a40382SGuenter Roeck 	bool have_iout_min;
8668a40382SGuenter Roeck 	bool have_pin_min;
879048539bSGuenter Roeck 	bool have_pin_max;
88709066acSGuenter Roeck 	bool have_temp_max;
89c5e67636SGuenter Roeck 	struct pmbus_driver_info info;
90c5e67636SGuenter Roeck };
91c5e67636SGuenter Roeck 
92c5e67636SGuenter Roeck #define to_adm1275_data(x)  container_of(x, struct adm1275_data, info)
93c5e67636SGuenter Roeck 
94904b296fSGuenter Roeck struct coefficients {
95904b296fSGuenter Roeck 	s16 m;
96904b296fSGuenter Roeck 	s16 b;
97904b296fSGuenter Roeck 	s16 R;
98904b296fSGuenter Roeck };
99904b296fSGuenter Roeck 
100904b296fSGuenter Roeck static const struct coefficients adm1075_coefficients[] = {
101904b296fSGuenter Roeck 	[0] = { 27169, 0, -1 },		/* voltage */
102904b296fSGuenter Roeck 	[1] = { 806, 20475, -1 },	/* current, irange25 */
103904b296fSGuenter Roeck 	[2] = { 404, 20475, -1 },	/* current, irange50 */
1046faecba0SShikhar Dogra 	[3] = { 8549, 0, -1 },		/* power, irange25 */
1056faecba0SShikhar Dogra 	[4] = { 4279, 0, -1 },		/* power, irange50 */
106904b296fSGuenter Roeck };
107904b296fSGuenter Roeck 
1084ff0ce22SGuenter Roeck static const struct coefficients adm1272_coefficients[] = {
1094ff0ce22SGuenter Roeck 	[0] = { 6770, 0, -2 },		/* voltage, vrange 60V */
1104ff0ce22SGuenter Roeck 	[1] = { 4062, 0, -2 },		/* voltage, vrange 100V */
1114ff0ce22SGuenter Roeck 	[2] = { 1326, 20480, -1 },	/* current, vsense range 15mV */
1124ff0ce22SGuenter Roeck 	[3] = { 663, 20480, -1 },	/* current, vsense range 30mV */
1134ff0ce22SGuenter Roeck 	[4] = { 3512, 0, -2 },		/* power, vrange 60V, irange 15mV */
1144ff0ce22SGuenter Roeck 	[5] = { 21071, 0, -3 },		/* power, vrange 100V, irange 15mV */
1154ff0ce22SGuenter Roeck 	[6] = { 17561, 0, -3 },		/* power, vrange 60V, irange 30mV */
1164ff0ce22SGuenter Roeck 	[7] = { 10535, 0, -3 },		/* power, vrange 100V, irange 30mV */
1174ff0ce22SGuenter Roeck 	[8] = { 42, 31871, -1 },	/* temperature */
1184ff0ce22SGuenter Roeck 
1194ff0ce22SGuenter Roeck };
1204ff0ce22SGuenter Roeck 
121904b296fSGuenter Roeck static const struct coefficients adm1275_coefficients[] = {
122904b296fSGuenter Roeck 	[0] = { 19199, 0, -2 },		/* voltage, vrange set */
123904b296fSGuenter Roeck 	[1] = { 6720, 0, -1 },		/* voltage, vrange not set */
124904b296fSGuenter Roeck 	[2] = { 807, 20475, -1 },	/* current */
125904b296fSGuenter Roeck };
126904b296fSGuenter Roeck 
127904b296fSGuenter Roeck static const struct coefficients adm1276_coefficients[] = {
128904b296fSGuenter Roeck 	[0] = { 19199, 0, -2 },		/* voltage, vrange set */
129904b296fSGuenter Roeck 	[1] = { 6720, 0, -1 },		/* voltage, vrange not set */
130904b296fSGuenter Roeck 	[2] = { 807, 20475, -1 },	/* current */
131904b296fSGuenter Roeck 	[3] = { 6043, 0, -2 },		/* power, vrange set */
132904b296fSGuenter Roeck 	[4] = { 2115, 0, -1 },		/* power, vrange not set */
133904b296fSGuenter Roeck };
134904b296fSGuenter Roeck 
135709066acSGuenter Roeck static const struct coefficients adm1278_coefficients[] = {
136709066acSGuenter Roeck 	[0] = { 19599, 0, -2 },		/* voltage */
137709066acSGuenter Roeck 	[1] = { 800, 20475, -1 },	/* current */
138709066acSGuenter Roeck 	[2] = { 6123, 0, -2 },		/* power */
139709066acSGuenter Roeck 	[3] = { 42, 31880, -1 },	/* temperature */
140709066acSGuenter Roeck };
141709066acSGuenter Roeck 
14268a40382SGuenter Roeck static const struct coefficients adm1293_coefficients[] = {
14368a40382SGuenter Roeck 	[0] = { 3333, -1, 0 },		/* voltage, vrange 1.2V */
14468a40382SGuenter Roeck 	[1] = { 5552, -5, -1 },		/* voltage, vrange 7.4V */
14568a40382SGuenter Roeck 	[2] = { 19604, -50, -2 },	/* voltage, vrange 21V */
14668a40382SGuenter Roeck 	[3] = { 8000, -100, -2 },	/* current, irange25 */
14768a40382SGuenter Roeck 	[4] = { 4000, -100, -2 },	/* current, irange50 */
14868a40382SGuenter Roeck 	[5] = { 20000, -1000, -3 },	/* current, irange100 */
14968a40382SGuenter Roeck 	[6] = { 10000, -1000, -3 },	/* current, irange200 */
15068a40382SGuenter Roeck 	[7] = { 10417, 0, -1 },		/* power, 1.2V, irange25 */
15168a40382SGuenter Roeck 	[8] = { 5208, 0, -1 },		/* power, 1.2V, irange50 */
15268a40382SGuenter Roeck 	[9] = { 26042, 0, -2 },		/* power, 1.2V, irange100 */
15368a40382SGuenter Roeck 	[10] = { 13021, 0, -2 },	/* power, 1.2V, irange200 */
15468a40382SGuenter Roeck 	[11] = { 17351, 0, -2 },	/* power, 7.4V, irange25 */
15568a40382SGuenter Roeck 	[12] = { 8676, 0, -2 },		/* power, 7.4V, irange50 */
15668a40382SGuenter Roeck 	[13] = { 4338, 0, -2 },		/* power, 7.4V, irange100 */
15768a40382SGuenter Roeck 	[14] = { 21689, 0, -3 },	/* power, 7.4V, irange200 */
15868a40382SGuenter Roeck 	[15] = { 6126, 0, -2 },		/* power, 21V, irange25 */
15968a40382SGuenter Roeck 	[16] = { 30631, 0, -3 },	/* power, 21V, irange50 */
16068a40382SGuenter Roeck 	[17] = { 15316, 0, -3 },	/* power, 21V, irange100 */
16168a40382SGuenter Roeck 	[18] = { 7658, 0, -3 },		/* power, 21V, irange200 */
16268a40382SGuenter Roeck };
16368a40382SGuenter Roeck 
164*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) static inline int adm1275_read_pmon_config(struct i2c_client *client, u16 mask)
165*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) {
166*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	int ret;
167*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 
168*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
169*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	if (ret < 0)
170*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		return ret;
171*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 
172*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	return FIELD_GET(mask, (u16)ret);
173*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) }
174*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 
175*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) static inline int adm1275_write_pmon_config(struct i2c_client *client, u16 mask,
176*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 					    u16 word)
177*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) {
178*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	int ret;
179*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 
180*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG);
181*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	if (ret < 0)
182*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		return ret;
183*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 
184*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	word = FIELD_PREP(mask, word) | (ret & ~mask);
185*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, word);
186*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 
187*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	return ret;
188*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) }
189*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 
190c576e30cSGuenter Roeck static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
191c576e30cSGuenter Roeck {
192c5e67636SGuenter Roeck 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
193c5e67636SGuenter Roeck 	const struct adm1275_data *data = to_adm1275_data(info);
1945cf231a3SGuenter Roeck 	int ret = 0;
195c576e30cSGuenter Roeck 
196ecb29abdSGuenter Roeck 	if (page > 0)
197c5e67636SGuenter Roeck 		return -ENXIO;
198c576e30cSGuenter Roeck 
199c576e30cSGuenter Roeck 	switch (reg) {
200c5e67636SGuenter Roeck 	case PMBUS_IOUT_UC_FAULT_LIMIT:
2019048539bSGuenter Roeck 		if (!data->have_uc_fault)
2029048539bSGuenter Roeck 			return -ENXIO;
203c5e67636SGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
204c5e67636SGuenter Roeck 		break;
205c5e67636SGuenter Roeck 	case PMBUS_IOUT_OC_FAULT_LIMIT:
2069048539bSGuenter Roeck 		if (!data->have_oc_fault)
2079048539bSGuenter Roeck 			return -ENXIO;
208c5e67636SGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
209c5e67636SGuenter Roeck 		break;
21092711269SGuenter Roeck 	case PMBUS_VOUT_OV_WARN_LIMIT:
2119048539bSGuenter Roeck 		if (data->have_vout)
2129048539bSGuenter Roeck 			return -ENODATA;
21392711269SGuenter Roeck 		ret = pmbus_read_word_data(client, 0,
21492711269SGuenter Roeck 					   ADM1075_VAUX_OV_WARN_LIMIT);
21592711269SGuenter Roeck 		break;
21692711269SGuenter Roeck 	case PMBUS_VOUT_UV_WARN_LIMIT:
2179048539bSGuenter Roeck 		if (data->have_vout)
2189048539bSGuenter Roeck 			return -ENODATA;
21992711269SGuenter Roeck 		ret = pmbus_read_word_data(client, 0,
22092711269SGuenter Roeck 					   ADM1075_VAUX_UV_WARN_LIMIT);
22192711269SGuenter Roeck 		break;
22292711269SGuenter Roeck 	case PMBUS_READ_VOUT:
2239048539bSGuenter Roeck 		if (data->have_vout)
2249048539bSGuenter Roeck 			return -ENODATA;
22592711269SGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX);
22692711269SGuenter Roeck 		break;
22768a40382SGuenter Roeck 	case PMBUS_VIRT_READ_IOUT_MIN:
22868a40382SGuenter Roeck 		if (!data->have_iout_min)
22968a40382SGuenter Roeck 			return -ENXIO;
23068a40382SGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1293_IOUT_MIN);
23168a40382SGuenter Roeck 		break;
232c576e30cSGuenter Roeck 	case PMBUS_VIRT_READ_IOUT_MAX:
233c576e30cSGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
234c576e30cSGuenter Roeck 		break;
235c576e30cSGuenter Roeck 	case PMBUS_VIRT_READ_VOUT_MAX:
236c576e30cSGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT);
237c576e30cSGuenter Roeck 		break;
238c576e30cSGuenter Roeck 	case PMBUS_VIRT_READ_VIN_MAX:
239c576e30cSGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
240c576e30cSGuenter Roeck 		break;
24168a40382SGuenter Roeck 	case PMBUS_VIRT_READ_PIN_MIN:
24268a40382SGuenter Roeck 		if (!data->have_pin_min)
24368a40382SGuenter Roeck 			return -ENXIO;
24468a40382SGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1293_PIN_MIN);
24568a40382SGuenter Roeck 		break;
2465cf231a3SGuenter Roeck 	case PMBUS_VIRT_READ_PIN_MAX:
2479048539bSGuenter Roeck 		if (!data->have_pin_max)
2489048539bSGuenter Roeck 			return -ENXIO;
2495cf231a3SGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN);
2505cf231a3SGuenter Roeck 		break;
251709066acSGuenter Roeck 	case PMBUS_VIRT_READ_TEMP_MAX:
252709066acSGuenter Roeck 		if (!data->have_temp_max)
253709066acSGuenter Roeck 			return -ENXIO;
254709066acSGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1278_PEAK_TEMP);
255709066acSGuenter Roeck 		break;
256c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_IOUT_HISTORY:
257c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_VOUT_HISTORY:
258c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_VIN_HISTORY:
2595cf231a3SGuenter Roeck 		break;
2605cf231a3SGuenter Roeck 	case PMBUS_VIRT_RESET_PIN_HISTORY:
2619048539bSGuenter Roeck 		if (!data->have_pin_max)
2629048539bSGuenter Roeck 			return -ENXIO;
263c576e30cSGuenter Roeck 		break;
264709066acSGuenter Roeck 	case PMBUS_VIRT_RESET_TEMP_HISTORY:
265709066acSGuenter Roeck 		if (!data->have_temp_max)
266709066acSGuenter Roeck 			return -ENXIO;
267709066acSGuenter Roeck 		break;
268*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	case PMBUS_VIRT_POWER_SAMPLES:
269*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		ret = adm1275_read_pmon_config(client, ADM1275_PWR_AVG_MASK);
270*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		if (ret < 0)
271*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 			break;
272*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		ret = BIT(ret);
273*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		break;
274*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	case PMBUS_VIRT_IN_SAMPLES:
275*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	case PMBUS_VIRT_CURR_SAMPLES:
276*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		ret = adm1275_read_pmon_config(client, ADM1275_VI_AVG_MASK);
277*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		if (ret < 0)
278*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 			break;
279*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		ret = BIT(ret);
280*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		break;
281c576e30cSGuenter Roeck 	default:
282c576e30cSGuenter Roeck 		ret = -ENODATA;
283c576e30cSGuenter Roeck 		break;
284c576e30cSGuenter Roeck 	}
285c576e30cSGuenter Roeck 	return ret;
286c576e30cSGuenter Roeck }
287c576e30cSGuenter Roeck 
288c576e30cSGuenter Roeck static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
289c576e30cSGuenter Roeck 				   u16 word)
290c576e30cSGuenter Roeck {
29168a40382SGuenter Roeck 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
29268a40382SGuenter Roeck 	const struct adm1275_data *data = to_adm1275_data(info);
293c576e30cSGuenter Roeck 	int ret;
294c576e30cSGuenter Roeck 
295ecb29abdSGuenter Roeck 	if (page > 0)
296c5e67636SGuenter Roeck 		return -ENXIO;
297c576e30cSGuenter Roeck 
298c576e30cSGuenter Roeck 	switch (reg) {
299c5e67636SGuenter Roeck 	case PMBUS_IOUT_UC_FAULT_LIMIT:
300c5e67636SGuenter Roeck 	case PMBUS_IOUT_OC_FAULT_LIMIT:
301c5e67636SGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT,
302c5e67636SGuenter Roeck 					    word);
303c5e67636SGuenter Roeck 		break;
304c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_IOUT_HISTORY:
305c576e30cSGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0);
30668a40382SGuenter Roeck 		if (!ret && data->have_iout_min)
30768a40382SGuenter Roeck 			ret = pmbus_write_word_data(client, 0,
30868a40382SGuenter Roeck 						    ADM1293_IOUT_MIN, 0);
309c576e30cSGuenter Roeck 		break;
310c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_VOUT_HISTORY:
311c576e30cSGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0);
312c576e30cSGuenter Roeck 		break;
313c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_VIN_HISTORY:
314c576e30cSGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0);
315c576e30cSGuenter Roeck 		break;
3165cf231a3SGuenter Roeck 	case PMBUS_VIRT_RESET_PIN_HISTORY:
3175cf231a3SGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0);
31868a40382SGuenter Roeck 		if (!ret && data->have_pin_min)
31968a40382SGuenter Roeck 			ret = pmbus_write_word_data(client, 0,
32068a40382SGuenter Roeck 						    ADM1293_PIN_MIN, 0);
3215cf231a3SGuenter Roeck 		break;
322709066acSGuenter Roeck 	case PMBUS_VIRT_RESET_TEMP_HISTORY:
323709066acSGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0);
324709066acSGuenter Roeck 		break;
325*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	case PMBUS_VIRT_POWER_SAMPLES:
326*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
327*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		ret = adm1275_write_pmon_config(client, ADM1275_PWR_AVG_MASK,
328*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 						ilog2(word));
329*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		break;
330*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	case PMBUS_VIRT_IN_SAMPLES:
331*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	case PMBUS_VIRT_CURR_SAMPLES:
332*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
333*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		ret = adm1275_write_pmon_config(client, ADM1275_VI_AVG_MASK,
334*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 						ilog2(word));
335*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 		break;
336c576e30cSGuenter Roeck 	default:
337c576e30cSGuenter Roeck 		ret = -ENODATA;
338c576e30cSGuenter Roeck 		break;
339c576e30cSGuenter Roeck 	}
340c576e30cSGuenter Roeck 	return ret;
341c576e30cSGuenter Roeck }
342c576e30cSGuenter Roeck 
343c5e67636SGuenter Roeck static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
344c5e67636SGuenter Roeck {
345c5e67636SGuenter Roeck 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
346c5e67636SGuenter Roeck 	const struct adm1275_data *data = to_adm1275_data(info);
347c5e67636SGuenter Roeck 	int mfr_status, ret;
348c5e67636SGuenter Roeck 
349da8e48abSGuenter Roeck 	if (page > 0)
350c5e67636SGuenter Roeck 		return -ENXIO;
351c5e67636SGuenter Roeck 
352c5e67636SGuenter Roeck 	switch (reg) {
353c5e67636SGuenter Roeck 	case PMBUS_STATUS_IOUT:
354c5e67636SGuenter Roeck 		ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT);
355c5e67636SGuenter Roeck 		if (ret < 0)
356c5e67636SGuenter Roeck 			break;
3579048539bSGuenter Roeck 		if (!data->have_oc_fault && !data->have_uc_fault)
3589048539bSGuenter Roeck 			break;
359c5e67636SGuenter Roeck 		mfr_status = pmbus_read_byte_data(client, page,
360c5e67636SGuenter Roeck 						  PMBUS_STATUS_MFR_SPECIFIC);
3619048539bSGuenter Roeck 		if (mfr_status < 0)
3629048539bSGuenter Roeck 			return mfr_status;
363c5e67636SGuenter Roeck 		if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) {
364c5e67636SGuenter Roeck 			ret |= data->have_oc_fault ?
365c5e67636SGuenter Roeck 			  PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT;
366c5e67636SGuenter Roeck 		}
367c5e67636SGuenter Roeck 		break;
36892711269SGuenter Roeck 	case PMBUS_STATUS_VOUT:
3699048539bSGuenter Roeck 		if (data->have_vout)
3709048539bSGuenter Roeck 			return -ENODATA;
37192711269SGuenter Roeck 		ret = 0;
3729048539bSGuenter Roeck 		if (data->have_vaux_status) {
37392711269SGuenter Roeck 			mfr_status = pmbus_read_byte_data(client, 0,
37492711269SGuenter Roeck 							  ADM1075_VAUX_STATUS);
3759048539bSGuenter Roeck 			if (mfr_status < 0)
3769048539bSGuenter Roeck 				return mfr_status;
37792711269SGuenter Roeck 			if (mfr_status & ADM1075_VAUX_OV_WARN)
37892711269SGuenter Roeck 				ret |= PB_VOLTAGE_OV_WARNING;
37992711269SGuenter Roeck 			if (mfr_status & ADM1075_VAUX_UV_WARN)
38092711269SGuenter Roeck 				ret |= PB_VOLTAGE_UV_WARNING;
38168a40382SGuenter Roeck 		} else if (data->have_mfr_vaux_status) {
38268a40382SGuenter Roeck 			mfr_status = pmbus_read_byte_data(client, page,
38368a40382SGuenter Roeck 						PMBUS_STATUS_MFR_SPECIFIC);
38468a40382SGuenter Roeck 			if (mfr_status < 0)
38568a40382SGuenter Roeck 				return mfr_status;
38668a40382SGuenter Roeck 			if (mfr_status & ADM1293_MFR_STATUS_VAUX_OV_WARN)
38768a40382SGuenter Roeck 				ret |= PB_VOLTAGE_OV_WARNING;
38868a40382SGuenter Roeck 			if (mfr_status & ADM1293_MFR_STATUS_VAUX_UV_WARN)
38968a40382SGuenter Roeck 				ret |= PB_VOLTAGE_UV_WARNING;
3909048539bSGuenter Roeck 		}
39192711269SGuenter Roeck 		break;
392c5e67636SGuenter Roeck 	default:
393c5e67636SGuenter Roeck 		ret = -ENODATA;
394c5e67636SGuenter Roeck 		break;
395c5e67636SGuenter Roeck 	}
396c5e67636SGuenter Roeck 	return ret;
397c5e67636SGuenter Roeck }
398c5e67636SGuenter Roeck 
39987102808SGuenter Roeck static const struct i2c_device_id adm1275_id[] = {
40092711269SGuenter Roeck 	{ "adm1075", adm1075 },
4014ff0ce22SGuenter Roeck 	{ "adm1272", adm1272 },
40287102808SGuenter Roeck 	{ "adm1275", adm1275 },
40387102808SGuenter Roeck 	{ "adm1276", adm1276 },
404709066acSGuenter Roeck 	{ "adm1278", adm1278 },
40568a40382SGuenter Roeck 	{ "adm1293", adm1293 },
40668a40382SGuenter Roeck 	{ "adm1294", adm1294 },
40787102808SGuenter Roeck 	{ }
40887102808SGuenter Roeck };
40987102808SGuenter Roeck MODULE_DEVICE_TABLE(i2c, adm1275_id);
41087102808SGuenter Roeck 
4119d2ecfb7SGuenter Roeck static int adm1275_probe(struct i2c_client *client,
4129d2ecfb7SGuenter Roeck 			 const struct i2c_device_id *id)
4139d2ecfb7SGuenter Roeck {
41487102808SGuenter Roeck 	u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
415c5e67636SGuenter Roeck 	int config, device_config;
4169d2ecfb7SGuenter Roeck 	int ret;
4179d2ecfb7SGuenter Roeck 	struct pmbus_driver_info *info;
418c5e67636SGuenter Roeck 	struct adm1275_data *data;
41987102808SGuenter Roeck 	const struct i2c_device_id *mid;
420904b296fSGuenter Roeck 	const struct coefficients *coefficients;
42168a40382SGuenter Roeck 	int vindex = -1, voindex = -1, cindex = -1, pindex = -1;
422709066acSGuenter Roeck 	int tindex = -1;
4236e5c06adSKun Yi 	u32 shunt;
4249d2ecfb7SGuenter Roeck 
4259d2ecfb7SGuenter Roeck 	if (!i2c_check_functionality(client->adapter,
42687102808SGuenter Roeck 				     I2C_FUNC_SMBUS_READ_BYTE_DATA
42787102808SGuenter Roeck 				     | I2C_FUNC_SMBUS_BLOCK_DATA))
4289d2ecfb7SGuenter Roeck 		return -ENODEV;
4299d2ecfb7SGuenter Roeck 
43087102808SGuenter Roeck 	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer);
43187102808SGuenter Roeck 	if (ret < 0) {
43287102808SGuenter Roeck 		dev_err(&client->dev, "Failed to read Manufacturer ID\n");
43387102808SGuenter Roeck 		return ret;
43487102808SGuenter Roeck 	}
43587102808SGuenter Roeck 	if (ret != 3 || strncmp(block_buffer, "ADI", 3)) {
43687102808SGuenter Roeck 		dev_err(&client->dev, "Unsupported Manufacturer ID\n");
43787102808SGuenter Roeck 		return -ENODEV;
43887102808SGuenter Roeck 	}
43987102808SGuenter Roeck 
44087102808SGuenter Roeck 	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer);
44187102808SGuenter Roeck 	if (ret < 0) {
44287102808SGuenter Roeck 		dev_err(&client->dev, "Failed to read Manufacturer Model\n");
44387102808SGuenter Roeck 		return ret;
44487102808SGuenter Roeck 	}
44587102808SGuenter Roeck 	for (mid = adm1275_id; mid->name[0]; mid++) {
44687102808SGuenter Roeck 		if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
44787102808SGuenter Roeck 			break;
44887102808SGuenter Roeck 	}
44987102808SGuenter Roeck 	if (!mid->name[0]) {
45087102808SGuenter Roeck 		dev_err(&client->dev, "Unsupported device\n");
45187102808SGuenter Roeck 		return -ENODEV;
45287102808SGuenter Roeck 	}
45387102808SGuenter Roeck 
45487102808SGuenter Roeck 	if (id->driver_data != mid->driver_data)
45587102808SGuenter Roeck 		dev_notice(&client->dev,
45687102808SGuenter Roeck 			   "Device mismatch: Configured %s, detected %s\n",
45787102808SGuenter Roeck 			   id->name, mid->name);
45887102808SGuenter Roeck 
45987102808SGuenter Roeck 	config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
46087102808SGuenter Roeck 	if (config < 0)
46187102808SGuenter Roeck 		return config;
46287102808SGuenter Roeck 
46387102808SGuenter Roeck 	device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG);
46487102808SGuenter Roeck 	if (device_config < 0)
46587102808SGuenter Roeck 		return device_config;
46687102808SGuenter Roeck 
4678b313ca7SGuenter Roeck 	data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data),
4688b313ca7SGuenter Roeck 			    GFP_KERNEL);
469c5e67636SGuenter Roeck 	if (!data)
4709d2ecfb7SGuenter Roeck 		return -ENOMEM;
4719d2ecfb7SGuenter Roeck 
4726e5c06adSKun Yi 	if (of_property_read_u32(client->dev.of_node,
4736e5c06adSKun Yi 				 "shunt-resistor-micro-ohms", &shunt))
4746e5c06adSKun Yi 		shunt = 1000; /* 1 mOhm if not set via DT */
4756e5c06adSKun Yi 
4766e5c06adSKun Yi 	if (shunt == 0)
4776e5c06adSKun Yi 		return -EINVAL;
4786e5c06adSKun Yi 
47987102808SGuenter Roeck 	data->id = mid->driver_data;
4809d2ecfb7SGuenter Roeck 
481c5e67636SGuenter Roeck 	info = &data->info;
482c5e67636SGuenter Roeck 
4839d2ecfb7SGuenter Roeck 	info->pages = 1;
4841061d851SGuenter Roeck 	info->format[PSC_VOLTAGE_IN] = direct;
4851061d851SGuenter Roeck 	info->format[PSC_VOLTAGE_OUT] = direct;
4861061d851SGuenter Roeck 	info->format[PSC_CURRENT_OUT] = direct;
487904b296fSGuenter Roeck 	info->format[PSC_POWER] = direct;
488709066acSGuenter Roeck 	info->format[PSC_TEMPERATURE] = direct;
489*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 	info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
490*c83529c1SAdamski, Krzysztof (Nokia - PL/Wroclaw) 			PMBUS_HAVE_SAMPLES;
4919d2ecfb7SGuenter Roeck 
492c576e30cSGuenter Roeck 	info->read_word_data = adm1275_read_word_data;
493c5e67636SGuenter Roeck 	info->read_byte_data = adm1275_read_byte_data;
494c576e30cSGuenter Roeck 	info->write_word_data = adm1275_write_word_data;
495c576e30cSGuenter Roeck 
49687102808SGuenter Roeck 	switch (data->id) {
49792711269SGuenter Roeck 	case adm1075:
4989048539bSGuenter Roeck 		if (device_config & ADM1275_IOUT_WARN2_SELECT)
4999048539bSGuenter Roeck 			data->have_oc_fault = true;
5009048539bSGuenter Roeck 		else
5019048539bSGuenter Roeck 			data->have_uc_fault = true;
5029048539bSGuenter Roeck 		data->have_pin_max = true;
5039048539bSGuenter Roeck 		data->have_vaux_status = true;
5049048539bSGuenter Roeck 
505904b296fSGuenter Roeck 		coefficients = adm1075_coefficients;
506904b296fSGuenter Roeck 		vindex = 0;
50792711269SGuenter Roeck 		switch (config & ADM1075_IRANGE_MASK) {
50892711269SGuenter Roeck 		case ADM1075_IRANGE_25:
509904b296fSGuenter Roeck 			cindex = 1;
510904b296fSGuenter Roeck 			pindex = 3;
51192711269SGuenter Roeck 			break;
51292711269SGuenter Roeck 		case ADM1075_IRANGE_50:
513904b296fSGuenter Roeck 			cindex = 2;
514904b296fSGuenter Roeck 			pindex = 4;
51592711269SGuenter Roeck 			break;
51692711269SGuenter Roeck 		default:
51792711269SGuenter Roeck 			dev_err(&client->dev, "Invalid input current range");
51892711269SGuenter Roeck 			break;
51992711269SGuenter Roeck 		}
520904b296fSGuenter Roeck 
52192711269SGuenter Roeck 		info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
52292711269SGuenter Roeck 		  | PMBUS_HAVE_STATUS_INPUT;
52392711269SGuenter Roeck 		if (config & ADM1275_VIN_VOUT_SELECT)
52492711269SGuenter Roeck 			info->func[0] |=
52592711269SGuenter Roeck 			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
52692711269SGuenter Roeck 		break;
5274ff0ce22SGuenter Roeck 	case adm1272:
5284ff0ce22SGuenter Roeck 		data->have_vout = true;
5294ff0ce22SGuenter Roeck 		data->have_pin_max = true;
5304ff0ce22SGuenter Roeck 		data->have_temp_max = true;
5314ff0ce22SGuenter Roeck 
5324ff0ce22SGuenter Roeck 		coefficients = adm1272_coefficients;
5334ff0ce22SGuenter Roeck 		vindex = (config & ADM1275_VRANGE) ? 1 : 0;
5344ff0ce22SGuenter Roeck 		cindex = (config & ADM1272_IRANGE) ? 3 : 2;
5354ff0ce22SGuenter Roeck 		/* pindex depends on the combination of the above */
5364ff0ce22SGuenter Roeck 		switch (config & (ADM1275_VRANGE | ADM1272_IRANGE)) {
5374ff0ce22SGuenter Roeck 		case 0:
5384ff0ce22SGuenter Roeck 		default:
5394ff0ce22SGuenter Roeck 			pindex = 4;
5404ff0ce22SGuenter Roeck 			break;
5414ff0ce22SGuenter Roeck 		case ADM1275_VRANGE:
5424ff0ce22SGuenter Roeck 			pindex = 5;
5434ff0ce22SGuenter Roeck 			break;
5444ff0ce22SGuenter Roeck 		case ADM1272_IRANGE:
5454ff0ce22SGuenter Roeck 			pindex = 6;
5464ff0ce22SGuenter Roeck 			break;
5474ff0ce22SGuenter Roeck 		case ADM1275_VRANGE | ADM1272_IRANGE:
5484ff0ce22SGuenter Roeck 			pindex = 7;
5494ff0ce22SGuenter Roeck 			break;
5504ff0ce22SGuenter Roeck 		}
5514ff0ce22SGuenter Roeck 		tindex = 8;
5524ff0ce22SGuenter Roeck 
5534ff0ce22SGuenter Roeck 		info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
5544ff0ce22SGuenter Roeck 			PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
5554ff0ce22SGuenter Roeck 
5564ff0ce22SGuenter Roeck 		/* Enable VOUT if not enabled (it is disabled by default) */
5574ff0ce22SGuenter Roeck 		if (!(config & ADM1278_VOUT_EN)) {
5584ff0ce22SGuenter Roeck 			config |= ADM1278_VOUT_EN;
5594ff0ce22SGuenter Roeck 			ret = i2c_smbus_write_byte_data(client,
5604ff0ce22SGuenter Roeck 							ADM1275_PMON_CONFIG,
5614ff0ce22SGuenter Roeck 							config);
5624ff0ce22SGuenter Roeck 			if (ret < 0) {
5634ff0ce22SGuenter Roeck 				dev_err(&client->dev,
5644ff0ce22SGuenter Roeck 					"Failed to enable VOUT monitoring\n");
5654ff0ce22SGuenter Roeck 				return -ENODEV;
5664ff0ce22SGuenter Roeck 			}
5674ff0ce22SGuenter Roeck 		}
5684ff0ce22SGuenter Roeck 
5694ff0ce22SGuenter Roeck 		if (config & ADM1278_TEMP1_EN)
5704ff0ce22SGuenter Roeck 			info->func[0] |=
5714ff0ce22SGuenter Roeck 				PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
5724ff0ce22SGuenter Roeck 		if (config & ADM1278_VIN_EN)
5734ff0ce22SGuenter Roeck 			info->func[0] |= PMBUS_HAVE_VIN;
5744ff0ce22SGuenter Roeck 		break;
5755cf231a3SGuenter Roeck 	case adm1275:
5769048539bSGuenter Roeck 		if (device_config & ADM1275_IOUT_WARN2_SELECT)
5779048539bSGuenter Roeck 			data->have_oc_fault = true;
5789048539bSGuenter Roeck 		else
5799048539bSGuenter Roeck 			data->have_uc_fault = true;
5809048539bSGuenter Roeck 		data->have_vout = true;
5819048539bSGuenter Roeck 
582904b296fSGuenter Roeck 		coefficients = adm1275_coefficients;
583904b296fSGuenter Roeck 		vindex = (config & ADM1275_VRANGE) ? 0 : 1;
584904b296fSGuenter Roeck 		cindex = 2;
585904b296fSGuenter Roeck 
5869d2ecfb7SGuenter Roeck 		if (config & ADM1275_VIN_VOUT_SELECT)
5875cf231a3SGuenter Roeck 			info->func[0] |=
5885cf231a3SGuenter Roeck 			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
5899d2ecfb7SGuenter Roeck 		else
5905cf231a3SGuenter Roeck 			info->func[0] |=
5915cf231a3SGuenter Roeck 			  PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
5925cf231a3SGuenter Roeck 		break;
5935cf231a3SGuenter Roeck 	case adm1276:
5949048539bSGuenter Roeck 		if (device_config & ADM1275_IOUT_WARN2_SELECT)
5959048539bSGuenter Roeck 			data->have_oc_fault = true;
5969048539bSGuenter Roeck 		else
5979048539bSGuenter Roeck 			data->have_uc_fault = true;
5989048539bSGuenter Roeck 		data->have_vout = true;
5999048539bSGuenter Roeck 		data->have_pin_max = true;
6009048539bSGuenter Roeck 
601904b296fSGuenter Roeck 		coefficients = adm1276_coefficients;
602904b296fSGuenter Roeck 		vindex = (config & ADM1275_VRANGE) ? 0 : 1;
603904b296fSGuenter Roeck 		cindex = 2;
604904b296fSGuenter Roeck 		pindex = (config & ADM1275_VRANGE) ? 3 : 4;
605904b296fSGuenter Roeck 
6065cf231a3SGuenter Roeck 		info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
6075cf231a3SGuenter Roeck 		  | PMBUS_HAVE_STATUS_INPUT;
6085cf231a3SGuenter Roeck 		if (config & ADM1275_VIN_VOUT_SELECT)
6095cf231a3SGuenter Roeck 			info->func[0] |=
6105cf231a3SGuenter Roeck 			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
6115cf231a3SGuenter Roeck 		break;
612709066acSGuenter Roeck 	case adm1278:
613709066acSGuenter Roeck 		data->have_vout = true;
614709066acSGuenter Roeck 		data->have_pin_max = true;
615709066acSGuenter Roeck 		data->have_temp_max = true;
616709066acSGuenter Roeck 
617709066acSGuenter Roeck 		coefficients = adm1278_coefficients;
618709066acSGuenter Roeck 		vindex = 0;
619709066acSGuenter Roeck 		cindex = 1;
620709066acSGuenter Roeck 		pindex = 2;
621709066acSGuenter Roeck 		tindex = 3;
622709066acSGuenter Roeck 
6232b3d0c19SYi Li 		info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
6242b3d0c19SYi Li 			PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
6252b3d0c19SYi Li 
6262b3d0c19SYi Li 		/* Enable VOUT if not enabled (it is disabled by default) */
6272b3d0c19SYi Li 		if (!(config & ADM1278_VOUT_EN)) {
6282b3d0c19SYi Li 			config |= ADM1278_VOUT_EN;
6292b3d0c19SYi Li 			ret = i2c_smbus_write_byte_data(client,
6302b3d0c19SYi Li 							ADM1275_PMON_CONFIG,
6312b3d0c19SYi Li 							config);
6322b3d0c19SYi Li 			if (ret < 0) {
6332b3d0c19SYi Li 				dev_err(&client->dev,
6342b3d0c19SYi Li 					"Failed to enable VOUT monitoring\n");
6352b3d0c19SYi Li 				return -ENODEV;
6362b3d0c19SYi Li 			}
6372b3d0c19SYi Li 		}
6382b3d0c19SYi Li 
639709066acSGuenter Roeck 		if (config & ADM1278_TEMP1_EN)
640709066acSGuenter Roeck 			info->func[0] |=
641709066acSGuenter Roeck 				PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
642709066acSGuenter Roeck 		if (config & ADM1278_VIN_EN)
643709066acSGuenter Roeck 			info->func[0] |= PMBUS_HAVE_VIN;
644709066acSGuenter Roeck 		break;
64568a40382SGuenter Roeck 	case adm1293:
64668a40382SGuenter Roeck 	case adm1294:
64768a40382SGuenter Roeck 		data->have_iout_min = true;
64868a40382SGuenter Roeck 		data->have_pin_min = true;
64968a40382SGuenter Roeck 		data->have_pin_max = true;
65068a40382SGuenter Roeck 		data->have_mfr_vaux_status = true;
65168a40382SGuenter Roeck 
65268a40382SGuenter Roeck 		coefficients = adm1293_coefficients;
65368a40382SGuenter Roeck 
65468a40382SGuenter Roeck 		voindex = 0;
65568a40382SGuenter Roeck 		switch (config & ADM1293_VIN_SEL_MASK) {
65668a40382SGuenter Roeck 		case ADM1293_VIN_SEL_012:	/* 1.2V */
65768a40382SGuenter Roeck 			vindex = 0;
65868a40382SGuenter Roeck 			break;
65968a40382SGuenter Roeck 		case ADM1293_VIN_SEL_074:	/* 7.4V */
66068a40382SGuenter Roeck 			vindex = 1;
66168a40382SGuenter Roeck 			break;
66268a40382SGuenter Roeck 		case ADM1293_VIN_SEL_210:	/* 21V */
66368a40382SGuenter Roeck 			vindex = 2;
66468a40382SGuenter Roeck 			break;
66568a40382SGuenter Roeck 		default:			/* disabled */
66668a40382SGuenter Roeck 			break;
66768a40382SGuenter Roeck 		}
66868a40382SGuenter Roeck 
66968a40382SGuenter Roeck 		switch (config & ADM1293_IRANGE_MASK) {
67068a40382SGuenter Roeck 		case ADM1293_IRANGE_25:
67168a40382SGuenter Roeck 			cindex = 3;
67268a40382SGuenter Roeck 			break;
67368a40382SGuenter Roeck 		case ADM1293_IRANGE_50:
67468a40382SGuenter Roeck 			cindex = 4;
67568a40382SGuenter Roeck 			break;
67668a40382SGuenter Roeck 		case ADM1293_IRANGE_100:
67768a40382SGuenter Roeck 			cindex = 5;
67868a40382SGuenter Roeck 			break;
67968a40382SGuenter Roeck 		case ADM1293_IRANGE_200:
68068a40382SGuenter Roeck 			cindex = 6;
68168a40382SGuenter Roeck 			break;
68268a40382SGuenter Roeck 		}
68368a40382SGuenter Roeck 
68468a40382SGuenter Roeck 		if (vindex >= 0)
68568a40382SGuenter Roeck 			pindex = 7 + vindex * 4 + (cindex - 3);
68668a40382SGuenter Roeck 
68768a40382SGuenter Roeck 		if (config & ADM1293_VAUX_EN)
68868a40382SGuenter Roeck 			info->func[0] |=
68968a40382SGuenter Roeck 				PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
69068a40382SGuenter Roeck 
69168a40382SGuenter Roeck 		info->func[0] |= PMBUS_HAVE_PIN |
69268a40382SGuenter Roeck 			PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
69368a40382SGuenter Roeck 
69468a40382SGuenter Roeck 		break;
695904b296fSGuenter Roeck 	default:
696904b296fSGuenter Roeck 		dev_err(&client->dev, "Unsupported device\n");
697904b296fSGuenter Roeck 		return -ENODEV;
698904b296fSGuenter Roeck 	}
69968a40382SGuenter Roeck 
70068a40382SGuenter Roeck 	if (voindex < 0)
70168a40382SGuenter Roeck 		voindex = vindex;
702904b296fSGuenter Roeck 	if (vindex >= 0) {
703904b296fSGuenter Roeck 		info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m;
704904b296fSGuenter Roeck 		info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b;
705904b296fSGuenter Roeck 		info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R;
70668a40382SGuenter Roeck 	}
70768a40382SGuenter Roeck 	if (voindex >= 0) {
70868a40382SGuenter Roeck 		info->m[PSC_VOLTAGE_OUT] = coefficients[voindex].m;
70968a40382SGuenter Roeck 		info->b[PSC_VOLTAGE_OUT] = coefficients[voindex].b;
71068a40382SGuenter Roeck 		info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R;
711904b296fSGuenter Roeck 	}
712904b296fSGuenter Roeck 	if (cindex >= 0) {
7136e5c06adSKun Yi 		/* Scale current with sense resistor value */
7146e5c06adSKun Yi 		info->m[PSC_CURRENT_OUT] =
7156e5c06adSKun Yi 			coefficients[cindex].m * shunt / 1000;
716904b296fSGuenter Roeck 		info->b[PSC_CURRENT_OUT] = coefficients[cindex].b;
717904b296fSGuenter Roeck 		info->R[PSC_CURRENT_OUT] = coefficients[cindex].R;
718904b296fSGuenter Roeck 	}
719904b296fSGuenter Roeck 	if (pindex >= 0) {
7206e5c06adSKun Yi 		info->m[PSC_POWER] =
7216e5c06adSKun Yi 			coefficients[pindex].m * shunt / 1000;
722904b296fSGuenter Roeck 		info->b[PSC_POWER] = coefficients[pindex].b;
723904b296fSGuenter Roeck 		info->R[PSC_POWER] = coefficients[pindex].R;
7245cf231a3SGuenter Roeck 	}
725709066acSGuenter Roeck 	if (tindex >= 0) {
726709066acSGuenter Roeck 		info->m[PSC_TEMPERATURE] = coefficients[tindex].m;
727709066acSGuenter Roeck 		info->b[PSC_TEMPERATURE] = coefficients[tindex].b;
728709066acSGuenter Roeck 		info->R[PSC_TEMPERATURE] = coefficients[tindex].R;
729709066acSGuenter Roeck 	}
7309d2ecfb7SGuenter Roeck 
7318b313ca7SGuenter Roeck 	return pmbus_do_probe(client, id, info);
7329d2ecfb7SGuenter Roeck }
7339d2ecfb7SGuenter Roeck 
7349d2ecfb7SGuenter Roeck static struct i2c_driver adm1275_driver = {
7359d2ecfb7SGuenter Roeck 	.driver = {
7369d2ecfb7SGuenter Roeck 		   .name = "adm1275",
7379d2ecfb7SGuenter Roeck 		   },
7389d2ecfb7SGuenter Roeck 	.probe = adm1275_probe,
739dd285ad7SGuenter Roeck 	.remove = pmbus_do_remove,
7409d2ecfb7SGuenter Roeck 	.id_table = adm1275_id,
7419d2ecfb7SGuenter Roeck };
7429d2ecfb7SGuenter Roeck 
743f0967eeaSAxel Lin module_i2c_driver(adm1275_driver);
7449d2ecfb7SGuenter Roeck 
7459d2ecfb7SGuenter Roeck MODULE_AUTHOR("Guenter Roeck");
7465cf231a3SGuenter Roeck MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
7479d2ecfb7SGuenter Roeck MODULE_LICENSE("GPL");
748