xref: /linux/drivers/hwmon/pmbus/mp29502.c (revision ec2e0fb07d789976c601bec19ecced7a501c3705)
1*90bad684SWensheng Wang // SPDX-License-Identifier: GPL-2.0-or-later
2*90bad684SWensheng Wang /*
3*90bad684SWensheng Wang  * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers(MP29502)
4*90bad684SWensheng Wang  */
5*90bad684SWensheng Wang 
6*90bad684SWensheng Wang #include <linux/bitfield.h>
7*90bad684SWensheng Wang #include <linux/i2c.h>
8*90bad684SWensheng Wang #include <linux/module.h>
9*90bad684SWensheng Wang #include <linux/of_device.h>
10*90bad684SWensheng Wang #include "pmbus.h"
11*90bad684SWensheng Wang 
12*90bad684SWensheng Wang #define MFR_VOUT_SCALE_LOOP	0x29
13*90bad684SWensheng Wang #define MFR_SVI3_IOUT_PRT	0x67
14*90bad684SWensheng Wang #define MFR_READ_PIN_EST	0x94
15*90bad684SWensheng Wang #define MFR_READ_IIN_EST	0x95
16*90bad684SWensheng Wang #define MFR_VOUT_PROT1	0x3D
17*90bad684SWensheng Wang #define MFR_VOUT_PROT2	0x51
18*90bad684SWensheng Wang #define MFR_SLOPE_CNT_SET	0xA8
19*90bad684SWensheng Wang #define MFR_TSNS_FLT_SET	0xBB
20*90bad684SWensheng Wang 
21*90bad684SWensheng Wang #define MP29502_VIN_OV_GAIN	4
22*90bad684SWensheng Wang #define MP29502_TEMP_LIMIT_OFFSET	40
23*90bad684SWensheng Wang #define MP29502_READ_VOUT_DIV	1024
24*90bad684SWensheng Wang #define MP29502_READ_IOUT_DIV	32
25*90bad684SWensheng Wang #define MP29502_IOUT_LIMIT_UINT	8
26*90bad684SWensheng Wang #define MP29502_OVUV_LIMIT_SCALE	10
27*90bad684SWensheng Wang #define MP28502_VOUT_OV_GAIN	512
28*90bad684SWensheng Wang #define MP28502_VOUT_OV_SCALE	40
29*90bad684SWensheng Wang #define MP29502_VOUT_UV_OFFSET	36
30*90bad684SWensheng Wang #define MP29502_PIN_GAIN	2
31*90bad684SWensheng Wang #define MP29502_IIN_DIV	2
32*90bad684SWensheng Wang 
33*90bad684SWensheng Wang #define MP29502_PAGE_NUM	1
34*90bad684SWensheng Wang 
35*90bad684SWensheng Wang #define MP29502_RAIL_FUNC	(PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | \
36*90bad684SWensheng Wang 							PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | \
37*90bad684SWensheng Wang 							PMBUS_HAVE_TEMP | PMBUS_HAVE_PIN | \
38*90bad684SWensheng Wang 							PMBUS_HAVE_IIN | \
39*90bad684SWensheng Wang 							PMBUS_HAVE_STATUS_VOUT | \
40*90bad684SWensheng Wang 							PMBUS_HAVE_STATUS_IOUT | \
41*90bad684SWensheng Wang 							PMBUS_HAVE_STATUS_TEMP | \
42*90bad684SWensheng Wang 							PMBUS_HAVE_STATUS_INPUT)
43*90bad684SWensheng Wang 
44*90bad684SWensheng Wang struct mp29502_data {
45*90bad684SWensheng Wang 	struct pmbus_driver_info info;
46*90bad684SWensheng Wang 	int vout_scale;
47*90bad684SWensheng Wang 	int vout_bottom_div;
48*90bad684SWensheng Wang 	int vout_top_div;
49*90bad684SWensheng Wang 	int ovp_div;
50*90bad684SWensheng Wang 	int iout_scale;
51*90bad684SWensheng Wang };
52*90bad684SWensheng Wang 
53*90bad684SWensheng Wang #define to_mp29502_data(x)	container_of(x, struct mp29502_data, info)
54*90bad684SWensheng Wang 
mp29502_reg2data_linear11(u16 word)55*90bad684SWensheng Wang static u16 mp29502_reg2data_linear11(u16 word)
56*90bad684SWensheng Wang {
57*90bad684SWensheng Wang 	s16 exponent;
58*90bad684SWensheng Wang 	s32 mantissa;
59*90bad684SWensheng Wang 	s64 val;
60*90bad684SWensheng Wang 
61*90bad684SWensheng Wang 	exponent = ((s16)word) >> 11;
62*90bad684SWensheng Wang 	mantissa = ((s16)((word & 0x7ff) << 5)) >> 5;
63*90bad684SWensheng Wang 	val = mantissa;
64*90bad684SWensheng Wang 
65*90bad684SWensheng Wang 	if (exponent >= 0)
66*90bad684SWensheng Wang 		val <<= exponent;
67*90bad684SWensheng Wang 	else
68*90bad684SWensheng Wang 		val >>= -exponent;
69*90bad684SWensheng Wang 
70*90bad684SWensheng Wang 	return val;
71*90bad684SWensheng Wang }
72*90bad684SWensheng Wang 
73*90bad684SWensheng Wang static int
mp29502_identify_vout_scale(struct i2c_client * client,struct pmbus_driver_info * info,int page)74*90bad684SWensheng Wang mp29502_identify_vout_scale(struct i2c_client *client, struct pmbus_driver_info *info,
75*90bad684SWensheng Wang 			    int page)
76*90bad684SWensheng Wang {
77*90bad684SWensheng Wang 	struct mp29502_data *data = to_mp29502_data(info);
78*90bad684SWensheng Wang 	int ret;
79*90bad684SWensheng Wang 
80*90bad684SWensheng Wang 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
81*90bad684SWensheng Wang 	if (ret < 0)
82*90bad684SWensheng Wang 		return ret;
83*90bad684SWensheng Wang 
84*90bad684SWensheng Wang 	ret = i2c_smbus_read_word_data(client, MFR_VOUT_SCALE_LOOP);
85*90bad684SWensheng Wang 	if (ret < 0)
86*90bad684SWensheng Wang 		return ret;
87*90bad684SWensheng Wang 
88*90bad684SWensheng Wang 	switch (FIELD_GET(GENMASK(12, 10), ret)) {
89*90bad684SWensheng Wang 	case 0:
90*90bad684SWensheng Wang 		data->vout_scale = 6400;
91*90bad684SWensheng Wang 		break;
92*90bad684SWensheng Wang 	case 1:
93*90bad684SWensheng Wang 		data->vout_scale = 5120;
94*90bad684SWensheng Wang 		break;
95*90bad684SWensheng Wang 	case 2:
96*90bad684SWensheng Wang 		data->vout_scale = 2560;
97*90bad684SWensheng Wang 		break;
98*90bad684SWensheng Wang 	case 3:
99*90bad684SWensheng Wang 		data->vout_scale = 2048;
100*90bad684SWensheng Wang 		break;
101*90bad684SWensheng Wang 	case 4:
102*90bad684SWensheng Wang 		data->vout_scale = 1024;
103*90bad684SWensheng Wang 		break;
104*90bad684SWensheng Wang 	case 5:
105*90bad684SWensheng Wang 		data->vout_scale = 4;
106*90bad684SWensheng Wang 		break;
107*90bad684SWensheng Wang 	case 6:
108*90bad684SWensheng Wang 		data->vout_scale = 2;
109*90bad684SWensheng Wang 		break;
110*90bad684SWensheng Wang 	case 7:
111*90bad684SWensheng Wang 		data->vout_scale = 1;
112*90bad684SWensheng Wang 		break;
113*90bad684SWensheng Wang 	default:
114*90bad684SWensheng Wang 		data->vout_scale = 1;
115*90bad684SWensheng Wang 		break;
116*90bad684SWensheng Wang 	}
117*90bad684SWensheng Wang 
118*90bad684SWensheng Wang 	return 0;
119*90bad684SWensheng Wang }
120*90bad684SWensheng Wang 
121*90bad684SWensheng Wang static int
mp29502_identify_vout_divider(struct i2c_client * client,struct pmbus_driver_info * info,int page)122*90bad684SWensheng Wang mp29502_identify_vout_divider(struct i2c_client *client, struct pmbus_driver_info *info,
123*90bad684SWensheng Wang 			      int page)
124*90bad684SWensheng Wang {
125*90bad684SWensheng Wang 	struct mp29502_data *data = to_mp29502_data(info);
126*90bad684SWensheng Wang 	int ret;
127*90bad684SWensheng Wang 
128*90bad684SWensheng Wang 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
129*90bad684SWensheng Wang 	if (ret < 0)
130*90bad684SWensheng Wang 		return ret;
131*90bad684SWensheng Wang 
132*90bad684SWensheng Wang 	ret = i2c_smbus_read_word_data(client, MFR_VOUT_PROT1);
133*90bad684SWensheng Wang 	if (ret < 0)
134*90bad684SWensheng Wang 		return ret;
135*90bad684SWensheng Wang 
136*90bad684SWensheng Wang 	data->vout_bottom_div = FIELD_GET(GENMASK(11, 0), ret);
137*90bad684SWensheng Wang 
138*90bad684SWensheng Wang 	ret = i2c_smbus_read_word_data(client, MFR_VOUT_PROT2);
139*90bad684SWensheng Wang 	if (ret < 0)
140*90bad684SWensheng Wang 		return ret;
141*90bad684SWensheng Wang 
142*90bad684SWensheng Wang 	data->vout_top_div = FIELD_GET(GENMASK(14, 0), ret);
143*90bad684SWensheng Wang 
144*90bad684SWensheng Wang 	return 0;
145*90bad684SWensheng Wang }
146*90bad684SWensheng Wang 
147*90bad684SWensheng Wang static int
mp29502_identify_ovp_divider(struct i2c_client * client,struct pmbus_driver_info * info,int page)148*90bad684SWensheng Wang mp29502_identify_ovp_divider(struct i2c_client *client, struct pmbus_driver_info *info,
149*90bad684SWensheng Wang 			     int page)
150*90bad684SWensheng Wang {
151*90bad684SWensheng Wang 	struct mp29502_data *data = to_mp29502_data(info);
152*90bad684SWensheng Wang 	int ret;
153*90bad684SWensheng Wang 
154*90bad684SWensheng Wang 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
155*90bad684SWensheng Wang 	if (ret < 0)
156*90bad684SWensheng Wang 		return ret;
157*90bad684SWensheng Wang 
158*90bad684SWensheng Wang 	ret = i2c_smbus_read_word_data(client, MFR_SLOPE_CNT_SET);
159*90bad684SWensheng Wang 	if (ret < 0)
160*90bad684SWensheng Wang 		return ret;
161*90bad684SWensheng Wang 
162*90bad684SWensheng Wang 	data->ovp_div = FIELD_GET(GENMASK(9, 0), ret);
163*90bad684SWensheng Wang 
164*90bad684SWensheng Wang 	return 0;
165*90bad684SWensheng Wang }
166*90bad684SWensheng Wang 
167*90bad684SWensheng Wang static int
mp29502_identify_iout_scale(struct i2c_client * client,struct pmbus_driver_info * info,int page)168*90bad684SWensheng Wang mp29502_identify_iout_scale(struct i2c_client *client, struct pmbus_driver_info *info,
169*90bad684SWensheng Wang 			    int page)
170*90bad684SWensheng Wang {
171*90bad684SWensheng Wang 	struct mp29502_data *data = to_mp29502_data(info);
172*90bad684SWensheng Wang 	int ret;
173*90bad684SWensheng Wang 
174*90bad684SWensheng Wang 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
175*90bad684SWensheng Wang 	if (ret < 0)
176*90bad684SWensheng Wang 		return ret;
177*90bad684SWensheng Wang 
178*90bad684SWensheng Wang 	ret = i2c_smbus_read_word_data(client, MFR_SVI3_IOUT_PRT);
179*90bad684SWensheng Wang 	if (ret < 0)
180*90bad684SWensheng Wang 		return ret;
181*90bad684SWensheng Wang 
182*90bad684SWensheng Wang 	switch (ret & GENMASK(2, 0)) {
183*90bad684SWensheng Wang 	case 0:
184*90bad684SWensheng Wang 	case 6:
185*90bad684SWensheng Wang 		data->iout_scale = 32;
186*90bad684SWensheng Wang 		break;
187*90bad684SWensheng Wang 	case 1:
188*90bad684SWensheng Wang 		data->iout_scale = 1;
189*90bad684SWensheng Wang 		break;
190*90bad684SWensheng Wang 	case 2:
191*90bad684SWensheng Wang 		data->iout_scale = 2;
192*90bad684SWensheng Wang 		break;
193*90bad684SWensheng Wang 	case 3:
194*90bad684SWensheng Wang 		data->iout_scale = 4;
195*90bad684SWensheng Wang 		break;
196*90bad684SWensheng Wang 	case 4:
197*90bad684SWensheng Wang 		data->iout_scale = 8;
198*90bad684SWensheng Wang 		break;
199*90bad684SWensheng Wang 	case 5:
200*90bad684SWensheng Wang 		data->iout_scale = 16;
201*90bad684SWensheng Wang 		break;
202*90bad684SWensheng Wang 	default:
203*90bad684SWensheng Wang 		data->iout_scale = 64;
204*90bad684SWensheng Wang 		break;
205*90bad684SWensheng Wang 	}
206*90bad684SWensheng Wang 
207*90bad684SWensheng Wang 	return 0;
208*90bad684SWensheng Wang }
209*90bad684SWensheng Wang 
mp29502_read_vout_ov_limit(struct i2c_client * client,struct mp29502_data * data)210*90bad684SWensheng Wang static int mp29502_read_vout_ov_limit(struct i2c_client *client, struct mp29502_data *data)
211*90bad684SWensheng Wang {
212*90bad684SWensheng Wang 	int ret;
213*90bad684SWensheng Wang 	int ov_value;
214*90bad684SWensheng Wang 
215*90bad684SWensheng Wang 	/*
216*90bad684SWensheng Wang 	 * This is because the vout ov fault limit value comes from
217*90bad684SWensheng Wang 	 * page1 MFR_TSNS_FLT_SET reg, and other telemetry and limit
218*90bad684SWensheng Wang 	 * value comes from page0 reg. So the page should be set to
219*90bad684SWensheng Wang 	 * 0 after the reading of vout ov limit.
220*90bad684SWensheng Wang 	 */
221*90bad684SWensheng Wang 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 1);
222*90bad684SWensheng Wang 	if (ret < 0)
223*90bad684SWensheng Wang 		return ret;
224*90bad684SWensheng Wang 
225*90bad684SWensheng Wang 	ret = i2c_smbus_read_word_data(client, MFR_TSNS_FLT_SET);
226*90bad684SWensheng Wang 	if (ret < 0)
227*90bad684SWensheng Wang 		return ret;
228*90bad684SWensheng Wang 
229*90bad684SWensheng Wang 	ov_value = DIV_ROUND_CLOSEST(FIELD_GET(GENMASK(12, 7), ret) *
230*90bad684SWensheng Wang 						   MP28502_VOUT_OV_GAIN * MP28502_VOUT_OV_SCALE,
231*90bad684SWensheng Wang 						   data->ovp_div);
232*90bad684SWensheng Wang 
233*90bad684SWensheng Wang 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
234*90bad684SWensheng Wang 	if (ret < 0)
235*90bad684SWensheng Wang 		return ret;
236*90bad684SWensheng Wang 
237*90bad684SWensheng Wang 	return ov_value;
238*90bad684SWensheng Wang }
239*90bad684SWensheng Wang 
mp29502_write_vout_ov_limit(struct i2c_client * client,u16 word,struct mp29502_data * data)240*90bad684SWensheng Wang static int mp29502_write_vout_ov_limit(struct i2c_client *client, u16 word,
241*90bad684SWensheng Wang 				       struct mp29502_data *data)
242*90bad684SWensheng Wang {
243*90bad684SWensheng Wang 	int ret;
244*90bad684SWensheng Wang 
245*90bad684SWensheng Wang 	/*
246*90bad684SWensheng Wang 	 * This is because the vout ov fault limit value comes from
247*90bad684SWensheng Wang 	 * page1 MFR_TSNS_FLT_SET reg, and other telemetry and limit
248*90bad684SWensheng Wang 	 * value comes from page0 reg. So the page should be set to
249*90bad684SWensheng Wang 	 * 0 after the writing of vout ov limit.
250*90bad684SWensheng Wang 	 */
251*90bad684SWensheng Wang 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 1);
252*90bad684SWensheng Wang 	if (ret < 0)
253*90bad684SWensheng Wang 		return ret;
254*90bad684SWensheng Wang 
255*90bad684SWensheng Wang 	ret = i2c_smbus_read_word_data(client, MFR_TSNS_FLT_SET);
256*90bad684SWensheng Wang 	if (ret < 0)
257*90bad684SWensheng Wang 		return ret;
258*90bad684SWensheng Wang 
259*90bad684SWensheng Wang 	ret = i2c_smbus_write_word_data(client, MFR_TSNS_FLT_SET,
260*90bad684SWensheng Wang 					(ret & ~GENMASK(12, 7)) |
261*90bad684SWensheng Wang 		FIELD_PREP(GENMASK(12, 7),
262*90bad684SWensheng Wang 			   DIV_ROUND_CLOSEST(word * data->ovp_div,
263*90bad684SWensheng Wang 					     MP28502_VOUT_OV_GAIN * MP28502_VOUT_OV_SCALE)));
264*90bad684SWensheng Wang 
265*90bad684SWensheng Wang 	return i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
266*90bad684SWensheng Wang }
267*90bad684SWensheng Wang 
mp29502_read_byte_data(struct i2c_client * client,int page,int reg)268*90bad684SWensheng Wang static int mp29502_read_byte_data(struct i2c_client *client, int page, int reg)
269*90bad684SWensheng Wang {
270*90bad684SWensheng Wang 	int ret;
271*90bad684SWensheng Wang 
272*90bad684SWensheng Wang 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
273*90bad684SWensheng Wang 	if (ret < 0)
274*90bad684SWensheng Wang 		return ret;
275*90bad684SWensheng Wang 
276*90bad684SWensheng Wang 	switch (reg) {
277*90bad684SWensheng Wang 	case PMBUS_VOUT_MODE:
278*90bad684SWensheng Wang 		ret = PB_VOUT_MODE_DIRECT;
279*90bad684SWensheng Wang 		break;
280*90bad684SWensheng Wang 	default:
281*90bad684SWensheng Wang 		ret = -ENODATA;
282*90bad684SWensheng Wang 		break;
283*90bad684SWensheng Wang 	}
284*90bad684SWensheng Wang 
285*90bad684SWensheng Wang 	return ret;
286*90bad684SWensheng Wang }
287*90bad684SWensheng Wang 
mp29502_read_word_data(struct i2c_client * client,int page,int phase,int reg)288*90bad684SWensheng Wang static int mp29502_read_word_data(struct i2c_client *client, int page,
289*90bad684SWensheng Wang 				  int phase, int reg)
290*90bad684SWensheng Wang {
291*90bad684SWensheng Wang 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
292*90bad684SWensheng Wang 	struct mp29502_data *data = to_mp29502_data(info);
293*90bad684SWensheng Wang 	int ret;
294*90bad684SWensheng Wang 
295*90bad684SWensheng Wang 	switch (reg) {
296*90bad684SWensheng Wang 	case PMBUS_STATUS_WORD:
297*90bad684SWensheng Wang 		ret = -ENODATA;
298*90bad684SWensheng Wang 		break;
299*90bad684SWensheng Wang 	case PMBUS_READ_VIN:
300*90bad684SWensheng Wang 		/*
301*90bad684SWensheng Wang 		 * The MP29502 PMBUS_READ_VIN[10:0] is the vin value, the vin scale is
302*90bad684SWensheng Wang 		 * 125mV/LSB. And the vin scale is set to 125mV/Lsb(using r/m/b scale)
303*90bad684SWensheng Wang 		 * in MP29502 pmbus_driver_info struct, so the word data bit0-bit10 can
304*90bad684SWensheng Wang 		 * be returned to pmbus core directly.
305*90bad684SWensheng Wang 		 */
306*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, reg);
307*90bad684SWensheng Wang 		if (ret < 0)
308*90bad684SWensheng Wang 			return ret;
309*90bad684SWensheng Wang 
310*90bad684SWensheng Wang 		ret = FIELD_GET(GENMASK(10, 0), ret);
311*90bad684SWensheng Wang 		break;
312*90bad684SWensheng Wang 	case PMBUS_READ_VOUT:
313*90bad684SWensheng Wang 		/*
314*90bad684SWensheng Wang 		 * The MP29502 PMBUS_READ_VOUT[11:0] is the vout value, and vout
315*90bad684SWensheng Wang 		 * value is calculated based on vout scale and vout divider.
316*90bad684SWensheng Wang 		 */
317*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, reg);
318*90bad684SWensheng Wang 		if (ret < 0)
319*90bad684SWensheng Wang 			return ret;
320*90bad684SWensheng Wang 
321*90bad684SWensheng Wang 		ret = DIV_ROUND_CLOSEST((ret &  GENMASK(11, 0)) *
322*90bad684SWensheng Wang 								data->vout_scale *
323*90bad684SWensheng Wang 								(data->vout_bottom_div +
324*90bad684SWensheng Wang 								4 * data->vout_top_div),
325*90bad684SWensheng Wang 								MP29502_READ_VOUT_DIV *
326*90bad684SWensheng Wang 								data->vout_bottom_div);
327*90bad684SWensheng Wang 		break;
328*90bad684SWensheng Wang 	case PMBUS_READ_IIN:
329*90bad684SWensheng Wang 		/*
330*90bad684SWensheng Wang 		 * The MP29502 MFR_READ_IIN_EST register is linear11 format, and the
331*90bad684SWensheng Wang 		 * exponent is not a constant value. But the iin scale is set to
332*90bad684SWensheng Wang 		 * 1A/Lsb(using r/m/b scale). As a result, the iin read from MP29502
333*90bad684SWensheng Wang 		 * should be calculated to A, then return the result to pmbus core.
334*90bad684SWensheng Wang 		 */
335*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, MFR_READ_IIN_EST);
336*90bad684SWensheng Wang 		if (ret < 0)
337*90bad684SWensheng Wang 			return ret;
338*90bad684SWensheng Wang 
339*90bad684SWensheng Wang 		ret = DIV_ROUND_CLOSEST(mp29502_reg2data_linear11(ret),
340*90bad684SWensheng Wang 					MP29502_IIN_DIV);
341*90bad684SWensheng Wang 		break;
342*90bad684SWensheng Wang 	case PMBUS_READ_PIN:
343*90bad684SWensheng Wang 		/*
344*90bad684SWensheng Wang 		 * The MP29502 MFR_READ_PIN_EST register is linear11 format, and the
345*90bad684SWensheng Wang 		 * exponent is not a constant value. But the pin scale is set to
346*90bad684SWensheng Wang 		 * 1W/Lsb(using r/m/b scale). As a result, the pout read from MP29502
347*90bad684SWensheng Wang 		 * should be calculated to W, then return the result to pmbus core.
348*90bad684SWensheng Wang 		 */
349*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, MFR_READ_PIN_EST);
350*90bad684SWensheng Wang 		if (ret < 0)
351*90bad684SWensheng Wang 			return ret;
352*90bad684SWensheng Wang 
353*90bad684SWensheng Wang 		ret = mp29502_reg2data_linear11(ret) * MP29502_PIN_GAIN;
354*90bad684SWensheng Wang 		break;
355*90bad684SWensheng Wang 	case PMBUS_READ_POUT:
356*90bad684SWensheng Wang 		/*
357*90bad684SWensheng Wang 		 * The MP29502 PMBUS_READ_POUT register is linear11 format, and the
358*90bad684SWensheng Wang 		 * exponent is not a constant value. But the pout scale is set to
359*90bad684SWensheng Wang 		 * 1W/Lsb(using r/m/b scale). As a result, the pout read from MP29502
360*90bad684SWensheng Wang 		 * should be calculated to W, then return the result to pmbus core.
361*90bad684SWensheng Wang 		 * And the pout is calculated based on vout divider.
362*90bad684SWensheng Wang 		 */
363*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, reg);
364*90bad684SWensheng Wang 		if (ret < 0)
365*90bad684SWensheng Wang 			return ret;
366*90bad684SWensheng Wang 
367*90bad684SWensheng Wang 		ret = DIV_ROUND_CLOSEST(mp29502_reg2data_linear11(ret) *
368*90bad684SWensheng Wang 					(data->vout_bottom_div +
369*90bad684SWensheng Wang 					4 * data->vout_top_div),
370*90bad684SWensheng Wang 					data->vout_bottom_div);
371*90bad684SWensheng Wang 		break;
372*90bad684SWensheng Wang 	case PMBUS_READ_IOUT:
373*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, reg);
374*90bad684SWensheng Wang 		if (ret < 0)
375*90bad684SWensheng Wang 			return ret;
376*90bad684SWensheng Wang 
377*90bad684SWensheng Wang 		ret = DIV_ROUND_CLOSEST((ret & GENMASK(10, 0)) * data->iout_scale,
378*90bad684SWensheng Wang 					MP29502_READ_IOUT_DIV);
379*90bad684SWensheng Wang 		break;
380*90bad684SWensheng Wang 	case PMBUS_READ_TEMPERATURE_1:
381*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, reg);
382*90bad684SWensheng Wang 		if (ret < 0)
383*90bad684SWensheng Wang 			return ret;
384*90bad684SWensheng Wang 
385*90bad684SWensheng Wang 		ret = FIELD_GET(GENMASK(10, 0), ret);
386*90bad684SWensheng Wang 		break;
387*90bad684SWensheng Wang 	case PMBUS_VIN_OV_FAULT_LIMIT:
388*90bad684SWensheng Wang 		/*
389*90bad684SWensheng Wang 		 * The MP29502 PMBUS_VIN_OV_FAULT_LIMIT is 500mV/Lsb, but
390*90bad684SWensheng Wang 		 * the vin  scale is set to 125mV/Lsb(using r/m/b scale),
391*90bad684SWensheng Wang 		 * so the word data should multiply by 4.
392*90bad684SWensheng Wang 		 */
393*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, reg);
394*90bad684SWensheng Wang 		if (ret < 0)
395*90bad684SWensheng Wang 			return ret;
396*90bad684SWensheng Wang 
397*90bad684SWensheng Wang 		ret = FIELD_GET(GENMASK(7, 0), ret) * MP29502_VIN_OV_GAIN;
398*90bad684SWensheng Wang 		break;
399*90bad684SWensheng Wang 	case PMBUS_VIN_UV_WARN_LIMIT:
400*90bad684SWensheng Wang 	case PMBUS_VIN_UV_FAULT_LIMIT:
401*90bad684SWensheng Wang 		/*
402*90bad684SWensheng Wang 		 * The MP29502 PMBUS_VIN_UV_WARN_LIMIT and PMBUS_VIN_UV_FAULT_LIMIT
403*90bad684SWensheng Wang 		 * scale is 125mV/Lsb, but the vin scale is set to 125mV/Lsb(using
404*90bad684SWensheng Wang 		 * r/m/b scale), so the word data bit0-bit9 can be returned to pmbus
405*90bad684SWensheng Wang 		 * core directly.
406*90bad684SWensheng Wang 		 */
407*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, reg);
408*90bad684SWensheng Wang 		if (ret < 0)
409*90bad684SWensheng Wang 			return ret;
410*90bad684SWensheng Wang 
411*90bad684SWensheng Wang 		ret = FIELD_GET(GENMASK(9, 0), ret);
412*90bad684SWensheng Wang 		break;
413*90bad684SWensheng Wang 	case PMBUS_VOUT_OV_FAULT_LIMIT:
414*90bad684SWensheng Wang 		/*
415*90bad684SWensheng Wang 		 * The MP29502 vout ov fault limit value comes from
416*90bad684SWensheng Wang 		 * page1 MFR_TSNS_FLT_SET[12:7].
417*90bad684SWensheng Wang 		 */
418*90bad684SWensheng Wang 		ret = mp29502_read_vout_ov_limit(client, data);
419*90bad684SWensheng Wang 		if (ret < 0)
420*90bad684SWensheng Wang 			return ret;
421*90bad684SWensheng Wang 
422*90bad684SWensheng Wang 		break;
423*90bad684SWensheng Wang 	case PMBUS_VOUT_UV_FAULT_LIMIT:
424*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, reg);
425*90bad684SWensheng Wang 		if (ret < 0)
426*90bad684SWensheng Wang 			return ret;
427*90bad684SWensheng Wang 
428*90bad684SWensheng Wang 		ret = DIV_ROUND_CLOSEST((FIELD_GET(GENMASK(8, 0), ret) *
429*90bad684SWensheng Wang 								MP29502_OVUV_LIMIT_SCALE -
430*90bad684SWensheng Wang 								MP29502_VOUT_UV_OFFSET) *
431*90bad684SWensheng Wang 								(data->vout_bottom_div +
432*90bad684SWensheng Wang 								4 * data->vout_top_div),
433*90bad684SWensheng Wang 								data->vout_bottom_div);
434*90bad684SWensheng Wang 		break;
435*90bad684SWensheng Wang 	case PMBUS_IOUT_OC_FAULT_LIMIT:
436*90bad684SWensheng Wang 	case PMBUS_IOUT_OC_WARN_LIMIT:
437*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, reg);
438*90bad684SWensheng Wang 		if (ret < 0)
439*90bad684SWensheng Wang 			return ret;
440*90bad684SWensheng Wang 
441*90bad684SWensheng Wang 		ret = DIV_ROUND_CLOSEST((ret & GENMASK(7, 0)) *
442*90bad684SWensheng Wang 								data->iout_scale *
443*90bad684SWensheng Wang 								MP29502_IOUT_LIMIT_UINT,
444*90bad684SWensheng Wang 								MP29502_READ_IOUT_DIV);
445*90bad684SWensheng Wang 		break;
446*90bad684SWensheng Wang 	case PMBUS_OT_FAULT_LIMIT:
447*90bad684SWensheng Wang 	case PMBUS_OT_WARN_LIMIT:
448*90bad684SWensheng Wang 		/*
449*90bad684SWensheng Wang 		 * The scale of MP29502 PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT
450*90bad684SWensheng Wang 		 * is 1°C/LSB and they have 40°C offset.
451*90bad684SWensheng Wang 		 */
452*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, phase, reg);
453*90bad684SWensheng Wang 		if (ret < 0)
454*90bad684SWensheng Wang 			return ret;
455*90bad684SWensheng Wang 
456*90bad684SWensheng Wang 		ret = (ret & GENMASK(7, 0)) - MP29502_TEMP_LIMIT_OFFSET;
457*90bad684SWensheng Wang 		break;
458*90bad684SWensheng Wang 	default:
459*90bad684SWensheng Wang 		ret = -EINVAL;
460*90bad684SWensheng Wang 		break;
461*90bad684SWensheng Wang 	}
462*90bad684SWensheng Wang 
463*90bad684SWensheng Wang 	return ret;
464*90bad684SWensheng Wang }
465*90bad684SWensheng Wang 
mp29502_write_word_data(struct i2c_client * client,int page,int reg,u16 word)466*90bad684SWensheng Wang static int mp29502_write_word_data(struct i2c_client *client, int page, int reg,
467*90bad684SWensheng Wang 				   u16 word)
468*90bad684SWensheng Wang {
469*90bad684SWensheng Wang 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
470*90bad684SWensheng Wang 	struct mp29502_data *data = to_mp29502_data(info);
471*90bad684SWensheng Wang 	int ret;
472*90bad684SWensheng Wang 
473*90bad684SWensheng Wang 	ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
474*90bad684SWensheng Wang 	if (ret < 0)
475*90bad684SWensheng Wang 		return ret;
476*90bad684SWensheng Wang 
477*90bad684SWensheng Wang 	switch (reg) {
478*90bad684SWensheng Wang 	case PMBUS_VIN_OV_FAULT_LIMIT:
479*90bad684SWensheng Wang 		/*
480*90bad684SWensheng Wang 		 * The PMBUS_VIN_OV_FAULT_LIMIT[7:0] is the limit value,
481*90bad684SWensheng Wang 		 * and bit8-bit15 should not be changed. The scale of
482*90bad684SWensheng Wang 		 * PMBUS_VIN_OV_FAULT_LIMIT is 500mV/Lsb, but the vin
483*90bad684SWensheng Wang 		 * scale is set to 125mV/Lsb(using r/m/b scale), so
484*90bad684SWensheng Wang 		 * the word data should divide by 4.
485*90bad684SWensheng Wang 		 */
486*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, 0xff, reg);
487*90bad684SWensheng Wang 		if (ret < 0)
488*90bad684SWensheng Wang 			return ret;
489*90bad684SWensheng Wang 
490*90bad684SWensheng Wang 		ret = pmbus_write_word_data(client, page, reg,
491*90bad684SWensheng Wang 					    (ret & ~GENMASK(7, 0)) |
492*90bad684SWensheng Wang 				FIELD_PREP(GENMASK(7, 0),
493*90bad684SWensheng Wang 					   DIV_ROUND_CLOSEST(word,
494*90bad684SWensheng Wang 							     MP29502_VIN_OV_GAIN)));
495*90bad684SWensheng Wang 		break;
496*90bad684SWensheng Wang 	case PMBUS_VIN_UV_WARN_LIMIT:
497*90bad684SWensheng Wang 	case PMBUS_VIN_UV_FAULT_LIMIT:
498*90bad684SWensheng Wang 		/*
499*90bad684SWensheng Wang 		 * The PMBUS_VIN_UV_WARN_LIMIT[9:0] and PMBUS_VIN_UV_FAULT_LIMIT[9:0]
500*90bad684SWensheng Wang 		 * are the limit value, and bit10-bit15 should not be changed.
501*90bad684SWensheng Wang 		 */
502*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, 0xff, reg);
503*90bad684SWensheng Wang 		if (ret < 0)
504*90bad684SWensheng Wang 			return ret;
505*90bad684SWensheng Wang 
506*90bad684SWensheng Wang 		ret = pmbus_write_word_data(client, page, reg,
507*90bad684SWensheng Wang 					    (ret & ~GENMASK(9, 0)) |
508*90bad684SWensheng Wang 							FIELD_PREP(GENMASK(9, 0),
509*90bad684SWensheng Wang 								   word));
510*90bad684SWensheng Wang 		break;
511*90bad684SWensheng Wang 	case PMBUS_VOUT_OV_FAULT_LIMIT:
512*90bad684SWensheng Wang 		ret = mp29502_write_vout_ov_limit(client, word, data);
513*90bad684SWensheng Wang 		if (ret < 0)
514*90bad684SWensheng Wang 			return ret;
515*90bad684SWensheng Wang 
516*90bad684SWensheng Wang 		break;
517*90bad684SWensheng Wang 	case PMBUS_VOUT_UV_FAULT_LIMIT:
518*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, 0xff, reg);
519*90bad684SWensheng Wang 		if (ret < 0)
520*90bad684SWensheng Wang 			return ret;
521*90bad684SWensheng Wang 
522*90bad684SWensheng Wang 		ret = pmbus_write_word_data(client, page, reg,
523*90bad684SWensheng Wang 					    (ret & ~GENMASK(8, 0)) |
524*90bad684SWensheng Wang 						FIELD_PREP(GENMASK(8, 0),
525*90bad684SWensheng Wang 							   DIV_ROUND_CLOSEST(word *
526*90bad684SWensheng Wang 									data->vout_bottom_div +
527*90bad684SWensheng Wang 									MP29502_VOUT_UV_OFFSET *
528*90bad684SWensheng Wang 									(data->vout_bottom_div +
529*90bad684SWensheng Wang 									4 * data->vout_top_div),
530*90bad684SWensheng Wang 									MP29502_OVUV_LIMIT_SCALE *
531*90bad684SWensheng Wang 									(data->vout_bottom_div +
532*90bad684SWensheng Wang 									4 * data->vout_top_div))));
533*90bad684SWensheng Wang 		break;
534*90bad684SWensheng Wang 	case PMBUS_IOUT_OC_FAULT_LIMIT:
535*90bad684SWensheng Wang 	case PMBUS_IOUT_OC_WARN_LIMIT:
536*90bad684SWensheng Wang 		ret = pmbus_write_word_data(client, page, reg,
537*90bad684SWensheng Wang 					    DIV_ROUND_CLOSEST(word *
538*90bad684SWensheng Wang 							MP29502_READ_IOUT_DIV,
539*90bad684SWensheng Wang 							MP29502_IOUT_LIMIT_UINT *
540*90bad684SWensheng Wang 							data->iout_scale));
541*90bad684SWensheng Wang 		break;
542*90bad684SWensheng Wang 	case PMBUS_OT_FAULT_LIMIT:
543*90bad684SWensheng Wang 	case PMBUS_OT_WARN_LIMIT:
544*90bad684SWensheng Wang 		/*
545*90bad684SWensheng Wang 		 * The PMBUS_OT_FAULT_LIMIT[7:0] and PMBUS_OT_WARN_LIMIT[7:0]
546*90bad684SWensheng Wang 		 * are the limit value, and bit8-bit15 should not be changed.
547*90bad684SWensheng Wang 		 */
548*90bad684SWensheng Wang 		ret = pmbus_read_word_data(client, page, 0xff, reg);
549*90bad684SWensheng Wang 		if (ret < 0)
550*90bad684SWensheng Wang 			return ret;
551*90bad684SWensheng Wang 
552*90bad684SWensheng Wang 		ret = pmbus_write_word_data(client, page, reg,
553*90bad684SWensheng Wang 					    (ret & ~GENMASK(7, 0)) |
554*90bad684SWensheng Wang 					FIELD_PREP(GENMASK(7, 0),
555*90bad684SWensheng Wang 						   word + MP29502_TEMP_LIMIT_OFFSET));
556*90bad684SWensheng Wang 		break;
557*90bad684SWensheng Wang 	default:
558*90bad684SWensheng Wang 		ret = -EINVAL;
559*90bad684SWensheng Wang 		break;
560*90bad684SWensheng Wang 	}
561*90bad684SWensheng Wang 
562*90bad684SWensheng Wang 	return ret;
563*90bad684SWensheng Wang }
564*90bad684SWensheng Wang 
mp29502_identify(struct i2c_client * client,struct pmbus_driver_info * info)565*90bad684SWensheng Wang static int mp29502_identify(struct i2c_client *client, struct pmbus_driver_info *info)
566*90bad684SWensheng Wang {
567*90bad684SWensheng Wang 	int ret;
568*90bad684SWensheng Wang 
569*90bad684SWensheng Wang 	/* Identify vout scale */
570*90bad684SWensheng Wang 	ret = mp29502_identify_vout_scale(client, info, 0);
571*90bad684SWensheng Wang 	if (ret < 0)
572*90bad684SWensheng Wang 		return ret;
573*90bad684SWensheng Wang 
574*90bad684SWensheng Wang 	/* Identify vout divider. */
575*90bad684SWensheng Wang 	ret = mp29502_identify_vout_divider(client, info, 1);
576*90bad684SWensheng Wang 	if (ret < 0)
577*90bad684SWensheng Wang 		return ret;
578*90bad684SWensheng Wang 
579*90bad684SWensheng Wang 	/* Identify ovp divider. */
580*90bad684SWensheng Wang 	ret = mp29502_identify_ovp_divider(client, info, 1);
581*90bad684SWensheng Wang 	if (ret < 0)
582*90bad684SWensheng Wang 		return ret;
583*90bad684SWensheng Wang 
584*90bad684SWensheng Wang 	/* Identify iout scale */
585*90bad684SWensheng Wang 	return mp29502_identify_iout_scale(client, info, 0);
586*90bad684SWensheng Wang }
587*90bad684SWensheng Wang 
588*90bad684SWensheng Wang static const struct pmbus_driver_info mp29502_info = {
589*90bad684SWensheng Wang 	.pages = MP29502_PAGE_NUM,
590*90bad684SWensheng Wang 	.format[PSC_VOLTAGE_IN] = direct,
591*90bad684SWensheng Wang 	.format[PSC_TEMPERATURE] = direct,
592*90bad684SWensheng Wang 	.format[PSC_CURRENT_IN] = direct,
593*90bad684SWensheng Wang 	.format[PSC_CURRENT_OUT] = direct,
594*90bad684SWensheng Wang 	.format[PSC_VOLTAGE_OUT] = direct,
595*90bad684SWensheng Wang 	.format[PSC_POWER] = direct,
596*90bad684SWensheng Wang 
597*90bad684SWensheng Wang 	.m[PSC_VOLTAGE_IN] = 8,
598*90bad684SWensheng Wang 	.R[PSC_VOLTAGE_IN] = 0,
599*90bad684SWensheng Wang 	.b[PSC_VOLTAGE_IN] = 0,
600*90bad684SWensheng Wang 
601*90bad684SWensheng Wang 	.m[PSC_VOLTAGE_OUT] = 1,
602*90bad684SWensheng Wang 	.R[PSC_VOLTAGE_OUT] = 3,
603*90bad684SWensheng Wang 	.b[PSC_VOLTAGE_OUT] = 0,
604*90bad684SWensheng Wang 
605*90bad684SWensheng Wang 	.m[PSC_TEMPERATURE] = 1,
606*90bad684SWensheng Wang 	.R[PSC_TEMPERATURE] = 0,
607*90bad684SWensheng Wang 	.b[PSC_TEMPERATURE] = 0,
608*90bad684SWensheng Wang 
609*90bad684SWensheng Wang 	.m[PSC_CURRENT_IN] = 1,
610*90bad684SWensheng Wang 	.R[PSC_CURRENT_IN] = 0,
611*90bad684SWensheng Wang 	.b[PSC_CURRENT_IN] = 0,
612*90bad684SWensheng Wang 
613*90bad684SWensheng Wang 	.m[PSC_CURRENT_OUT] = 1,
614*90bad684SWensheng Wang 	.R[PSC_CURRENT_OUT] = 0,
615*90bad684SWensheng Wang 	.b[PSC_CURRENT_OUT] = 0,
616*90bad684SWensheng Wang 
617*90bad684SWensheng Wang 	.m[PSC_POWER] = 1,
618*90bad684SWensheng Wang 	.R[PSC_POWER] = 0,
619*90bad684SWensheng Wang 	.b[PSC_POWER] = 0,
620*90bad684SWensheng Wang 
621*90bad684SWensheng Wang 	.func[0] = MP29502_RAIL_FUNC,
622*90bad684SWensheng Wang 	.read_word_data = mp29502_read_word_data,
623*90bad684SWensheng Wang 	.read_byte_data = mp29502_read_byte_data,
624*90bad684SWensheng Wang 	.write_word_data = mp29502_write_word_data,
625*90bad684SWensheng Wang 	.identify = mp29502_identify,
626*90bad684SWensheng Wang };
627*90bad684SWensheng Wang 
mp29502_probe(struct i2c_client * client)628*90bad684SWensheng Wang static int mp29502_probe(struct i2c_client *client)
629*90bad684SWensheng Wang {
630*90bad684SWensheng Wang 	struct pmbus_driver_info *info;
631*90bad684SWensheng Wang 	struct mp29502_data *data;
632*90bad684SWensheng Wang 
633*90bad684SWensheng Wang 	data = devm_kzalloc(&client->dev, sizeof(struct mp29502_data),
634*90bad684SWensheng Wang 			    GFP_KERNEL);
635*90bad684SWensheng Wang 	if (!data)
636*90bad684SWensheng Wang 		return -ENOMEM;
637*90bad684SWensheng Wang 
638*90bad684SWensheng Wang 	memcpy(&data->info, &mp29502_info, sizeof(*info));
639*90bad684SWensheng Wang 	info = &data->info;
640*90bad684SWensheng Wang 
641*90bad684SWensheng Wang 	return pmbus_do_probe(client, info);
642*90bad684SWensheng Wang }
643*90bad684SWensheng Wang 
644*90bad684SWensheng Wang static const struct i2c_device_id mp29502_id[] = {
645*90bad684SWensheng Wang 	{"mp29502", 0},
646*90bad684SWensheng Wang 	{}
647*90bad684SWensheng Wang };
648*90bad684SWensheng Wang MODULE_DEVICE_TABLE(i2c, mp29502_id);
649*90bad684SWensheng Wang 
650*90bad684SWensheng Wang static const struct of_device_id __maybe_unused mp29502_of_match[] = {
651*90bad684SWensheng Wang 	{.compatible = "mps,mp29502"},
652*90bad684SWensheng Wang 	{}
653*90bad684SWensheng Wang };
654*90bad684SWensheng Wang MODULE_DEVICE_TABLE(of, mp29502_of_match);
655*90bad684SWensheng Wang 
656*90bad684SWensheng Wang static struct i2c_driver mp29502_driver = {
657*90bad684SWensheng Wang 	.driver = {
658*90bad684SWensheng Wang 		.name = "mp29502",
659*90bad684SWensheng Wang 		.of_match_table = mp29502_of_match,
660*90bad684SWensheng Wang 	},
661*90bad684SWensheng Wang 	.probe = mp29502_probe,
662*90bad684SWensheng Wang 	.id_table = mp29502_id,
663*90bad684SWensheng Wang };
664*90bad684SWensheng Wang 
665*90bad684SWensheng Wang module_i2c_driver(mp29502_driver);
666*90bad684SWensheng Wang 
667*90bad684SWensheng Wang MODULE_AUTHOR("Wensheng Wang <wenswang@yeah.net");
668*90bad684SWensheng Wang MODULE_DESCRIPTION("PMBus driver for MPS MP29502");
669*90bad684SWensheng Wang MODULE_LICENSE("GPL");
670*90bad684SWensheng Wang MODULE_IMPORT_NS("PMBUS");
671