xref: /OK3568_Linux_fs/u-boot/drivers/power/power_delivery/tcpci.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright 2015-2017 Google, Inc
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * USB Type-C Port Controller Interface.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <dm.h>
9*4882a593Smuzhiyun #include <i2c.h>
10*4882a593Smuzhiyun #include <asm/gpio.h>
11*4882a593Smuzhiyun #include <power/power_delivery/pd.h>
12*4882a593Smuzhiyun #include <power/power_delivery/tcpm.h>
13*4882a593Smuzhiyun #include <power/power_delivery/typec.h>
14*4882a593Smuzhiyun #include <power/power_delivery/power_delivery.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "tcpci.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #define PD_RETRY_COUNT 3
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define tcpc_presenting_cc1_rd(reg) \
21*4882a593Smuzhiyun 	(!(TCPC_ROLE_CTRL_DRP & (reg)) && \
22*4882a593Smuzhiyun 	 (((reg) & (TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT)) == \
23*4882a593Smuzhiyun 	  (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT)))
24*4882a593Smuzhiyun #define tcpc_presenting_cc2_rd(reg) \
25*4882a593Smuzhiyun 	(!(TCPC_ROLE_CTRL_DRP & (reg)) && \
26*4882a593Smuzhiyun 	 (((reg) & (TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT)) == \
27*4882a593Smuzhiyun 	  (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT)))
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun struct tcpci {
30*4882a593Smuzhiyun 	struct udevice *dev;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	struct tcpm_port *port;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	bool controls_vbus;
35*4882a593Smuzhiyun 	bool gpio_cc_int_present;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	struct tcpc_dev tcpc;
38*4882a593Smuzhiyun 	struct tcpci_data *data;
39*4882a593Smuzhiyun 	struct gpio_desc gpio_cc_int;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun struct tcpci_chip {
43*4882a593Smuzhiyun 	struct udevice *udev;
44*4882a593Smuzhiyun 	struct tcpci *tcpci;
45*4882a593Smuzhiyun 	struct tcpci_data data;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
tcpc_to_tcpci(struct tcpc_dev * tcpc)48*4882a593Smuzhiyun static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	return container_of(tcpc, struct tcpci, tcpc);
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
tcpci_read16(struct tcpci * tcpci,unsigned int reg,u16 * val)53*4882a593Smuzhiyun static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	int ret = 0;
56*4882a593Smuzhiyun 	u8 buffer[2];
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	ret = dm_i2c_read(tcpci->dev, reg, buffer, 2);
59*4882a593Smuzhiyun 	if (ret) {
60*4882a593Smuzhiyun 		printf("%s: cannot read %02x, ret=%d\n",
61*4882a593Smuzhiyun 			__func__, reg, ret);
62*4882a593Smuzhiyun 		return ret;
63*4882a593Smuzhiyun 	}
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	*val = ((buffer[1] << 8) & 0xFF00) | (buffer[0] & 0xFF);
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	return ret;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
tcpci_block_read(struct tcpci * tcpci,unsigned int reg,u8 * data,u8 length)70*4882a593Smuzhiyun static int tcpci_block_read(struct tcpci *tcpci, unsigned int reg,
71*4882a593Smuzhiyun 			    u8 *data, u8 length)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	int ret = 0;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	ret = dm_i2c_read(tcpci->dev, reg, data, length);
76*4882a593Smuzhiyun 	if (ret)
77*4882a593Smuzhiyun 		printf("%s: cannot block read 0x%02x, len=%d, ret=%d\n",
78*4882a593Smuzhiyun 			__func__, reg, length, ret);
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	return ret;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
tcpci_write16(struct tcpci * tcpci,unsigned int reg,u16 val)83*4882a593Smuzhiyun static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	int ret = 0;
86*4882a593Smuzhiyun 	u8 buffer[2];
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	buffer[0] = val & 0xFF;
89*4882a593Smuzhiyun 	buffer[1] = (val >> 8) & 0xFF;
90*4882a593Smuzhiyun 	ret = dm_i2c_write(tcpci->dev, reg, buffer, 2);
91*4882a593Smuzhiyun 	if (ret)
92*4882a593Smuzhiyun 		printf("%s: cannot write 0x%02x, ret=%d\n",
93*4882a593Smuzhiyun 			__func__, reg, ret);
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	return ret;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
tcpci_block_write(struct tcpci * tcpci,unsigned int reg,u8 * data,u8 length)98*4882a593Smuzhiyun static int tcpci_block_write(struct tcpci *tcpci, unsigned int reg,
99*4882a593Smuzhiyun 			     u8 *data, u8 length)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	int ret = 0;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	ret = dm_i2c_write(tcpci->dev, reg, data, length);
104*4882a593Smuzhiyun 	if (ret)
105*4882a593Smuzhiyun 		printf("%s: cannot block write 0x%02x, len=%d, ret=%d\n",
106*4882a593Smuzhiyun 			__func__, reg, length, ret);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	return ret;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
tcpci_set_cc(struct tcpc_dev * tcpc,enum typec_cc_status cc)111*4882a593Smuzhiyun static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
114*4882a593Smuzhiyun 	unsigned int reg;
115*4882a593Smuzhiyun 	int ret;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	switch (cc) {
118*4882a593Smuzhiyun 	case TYPEC_CC_RA:
119*4882a593Smuzhiyun 		reg = (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC1_SHIFT) |
120*4882a593Smuzhiyun 			(TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC2_SHIFT);
121*4882a593Smuzhiyun 		break;
122*4882a593Smuzhiyun 	case TYPEC_CC_RD:
123*4882a593Smuzhiyun 		reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
124*4882a593Smuzhiyun 			(TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
125*4882a593Smuzhiyun 		break;
126*4882a593Smuzhiyun 	case TYPEC_CC_RP_DEF:
127*4882a593Smuzhiyun 		reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
128*4882a593Smuzhiyun 			(TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) |
129*4882a593Smuzhiyun 			(TCPC_ROLE_CTRL_RP_VAL_DEF <<
130*4882a593Smuzhiyun 			 TCPC_ROLE_CTRL_RP_VAL_SHIFT);
131*4882a593Smuzhiyun 		break;
132*4882a593Smuzhiyun 	case TYPEC_CC_RP_1_5:
133*4882a593Smuzhiyun 		reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
134*4882a593Smuzhiyun 			(TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) |
135*4882a593Smuzhiyun 			(TCPC_ROLE_CTRL_RP_VAL_1_5 <<
136*4882a593Smuzhiyun 			 TCPC_ROLE_CTRL_RP_VAL_SHIFT);
137*4882a593Smuzhiyun 		break;
138*4882a593Smuzhiyun 	case TYPEC_CC_RP_3_0:
139*4882a593Smuzhiyun 		reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
140*4882a593Smuzhiyun 			(TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) |
141*4882a593Smuzhiyun 			(TCPC_ROLE_CTRL_RP_VAL_3_0 <<
142*4882a593Smuzhiyun 			 TCPC_ROLE_CTRL_RP_VAL_SHIFT);
143*4882a593Smuzhiyun 		break;
144*4882a593Smuzhiyun 	case TYPEC_CC_OPEN:
145*4882a593Smuzhiyun 	default:
146*4882a593Smuzhiyun 		reg = (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT) |
147*4882a593Smuzhiyun 			(TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT);
148*4882a593Smuzhiyun 		break;
149*4882a593Smuzhiyun 	}
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	ret = dm_i2c_reg_write(tcpci->dev, TCPC_ROLE_CTRL, reg);
152*4882a593Smuzhiyun 	if (ret)
153*4882a593Smuzhiyun 		return ret;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	return 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
tcpci_start_toggling(struct tcpc_dev * tcpc,enum typec_port_type port_type,enum typec_cc_status cc)158*4882a593Smuzhiyun static int tcpci_start_toggling(struct tcpc_dev *tcpc,
159*4882a593Smuzhiyun 				enum typec_port_type port_type,
160*4882a593Smuzhiyun 				enum typec_cc_status cc)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	int ret;
163*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
164*4882a593Smuzhiyun 	unsigned int reg = TCPC_ROLE_CTRL_DRP;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	if (port_type != TYPEC_PORT_DRP)
167*4882a593Smuzhiyun 		return -EOPNOTSUPP;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	/* Handle vendor drp toggling */
170*4882a593Smuzhiyun 	if (tcpci->data->start_drp_toggling) {
171*4882a593Smuzhiyun 		ret = tcpci->data->start_drp_toggling(tcpci, tcpci->data, cc);
172*4882a593Smuzhiyun 		if (ret < 0)
173*4882a593Smuzhiyun 			return ret;
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	switch (cc) {
177*4882a593Smuzhiyun 	default:
178*4882a593Smuzhiyun 	case TYPEC_CC_RP_DEF:
179*4882a593Smuzhiyun 		reg |= (TCPC_ROLE_CTRL_RP_VAL_DEF <<
180*4882a593Smuzhiyun 			TCPC_ROLE_CTRL_RP_VAL_SHIFT);
181*4882a593Smuzhiyun 		break;
182*4882a593Smuzhiyun 	case TYPEC_CC_RP_1_5:
183*4882a593Smuzhiyun 		reg |= (TCPC_ROLE_CTRL_RP_VAL_1_5 <<
184*4882a593Smuzhiyun 			TCPC_ROLE_CTRL_RP_VAL_SHIFT);
185*4882a593Smuzhiyun 		break;
186*4882a593Smuzhiyun 	case TYPEC_CC_RP_3_0:
187*4882a593Smuzhiyun 		reg |= (TCPC_ROLE_CTRL_RP_VAL_3_0 <<
188*4882a593Smuzhiyun 			TCPC_ROLE_CTRL_RP_VAL_SHIFT);
189*4882a593Smuzhiyun 		break;
190*4882a593Smuzhiyun 	}
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	if (cc == TYPEC_CC_RD)
193*4882a593Smuzhiyun 		reg |= (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
194*4882a593Smuzhiyun 			   (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
195*4882a593Smuzhiyun 	else
196*4882a593Smuzhiyun 		reg |= (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
197*4882a593Smuzhiyun 			   (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT);
198*4882a593Smuzhiyun 	ret = dm_i2c_reg_write(tcpci->dev, TCPC_ROLE_CTRL, reg);
199*4882a593Smuzhiyun 	if (ret < 0)
200*4882a593Smuzhiyun 		return ret;
201*4882a593Smuzhiyun 	return dm_i2c_reg_write(tcpci->dev, TCPC_COMMAND,
202*4882a593Smuzhiyun 				TCPC_CMD_LOOK4CONNECTION);
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
tcpci_to_typec_cc(unsigned int cc,bool sink)205*4882a593Smuzhiyun static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	switch (cc) {
208*4882a593Smuzhiyun 	case 0x1:
209*4882a593Smuzhiyun 		return sink ? TYPEC_CC_RP_DEF : TYPEC_CC_RA;
210*4882a593Smuzhiyun 	case 0x2:
211*4882a593Smuzhiyun 		return sink ? TYPEC_CC_RP_1_5 : TYPEC_CC_RD;
212*4882a593Smuzhiyun 	case 0x3:
213*4882a593Smuzhiyun 		if (sink)
214*4882a593Smuzhiyun 			return TYPEC_CC_RP_3_0;
215*4882a593Smuzhiyun 		/* fall through */
216*4882a593Smuzhiyun 	case 0x0:
217*4882a593Smuzhiyun 	default:
218*4882a593Smuzhiyun 		return TYPEC_CC_OPEN;
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
tcpci_get_cc(struct tcpc_dev * tcpc,enum typec_cc_status * cc1,enum typec_cc_status * cc2)222*4882a593Smuzhiyun static int tcpci_get_cc(struct tcpc_dev *tcpc,
223*4882a593Smuzhiyun 			enum typec_cc_status *cc1, enum typec_cc_status *cc2)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
226*4882a593Smuzhiyun 	unsigned int reg, role_control;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	role_control = dm_i2c_reg_read(tcpci->dev, TCPC_ROLE_CTRL);
229*4882a593Smuzhiyun 	if (role_control < 0)
230*4882a593Smuzhiyun 		return role_control;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	reg = dm_i2c_reg_read(tcpci->dev, TCPC_CC_STATUS);
233*4882a593Smuzhiyun 	if (reg < 0)
234*4882a593Smuzhiyun 		return reg;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	*cc1 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC1_SHIFT) &
237*4882a593Smuzhiyun 				 TCPC_CC_STATUS_CC1_MASK,
238*4882a593Smuzhiyun 				 reg & TCPC_CC_STATUS_TERM ||
239*4882a593Smuzhiyun 				 tcpc_presenting_cc1_rd(role_control));
240*4882a593Smuzhiyun 	*cc2 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC2_SHIFT) &
241*4882a593Smuzhiyun 				 TCPC_CC_STATUS_CC2_MASK,
242*4882a593Smuzhiyun 				 reg & TCPC_CC_STATUS_TERM ||
243*4882a593Smuzhiyun 				 tcpc_presenting_cc2_rd(role_control));
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	return 0;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
tcpci_set_polarity(struct tcpc_dev * tcpc,enum typec_cc_polarity polarity)248*4882a593Smuzhiyun static int tcpci_set_polarity(struct tcpc_dev *tcpc,
249*4882a593Smuzhiyun 			      enum typec_cc_polarity polarity)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
252*4882a593Smuzhiyun 	unsigned int reg;
253*4882a593Smuzhiyun 	int ret;
254*4882a593Smuzhiyun 	enum typec_cc_status cc1, cc2;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	/* Obtain Rp setting from role control */
257*4882a593Smuzhiyun 	reg = dm_i2c_reg_read(tcpci->dev, TCPC_ROLE_CTRL);
258*4882a593Smuzhiyun 	if (reg < 0)
259*4882a593Smuzhiyun 		return reg;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	ret = tcpci_get_cc(tcpc, &cc1, &cc2);
262*4882a593Smuzhiyun 	if (ret < 0)
263*4882a593Smuzhiyun 		return ret;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	/*
266*4882a593Smuzhiyun 	 * When port has drp toggling enabled, ROLE_CONTROL would only have the initial
267*4882a593Smuzhiyun 	 * terminations for the toggling and does not indicate the final cc
268*4882a593Smuzhiyun 	 * terminations when ConnectionResult is 0 i.e. drp toggling stops and
269*4882a593Smuzhiyun 	 * the connection is resolbed. Infer port role from TCPC_CC_STATUS based on the
270*4882a593Smuzhiyun 	 * terminations seen. The port role is then used to set the cc terminations.
271*4882a593Smuzhiyun 	 */
272*4882a593Smuzhiyun 	if (reg & TCPC_ROLE_CTRL_DRP) {
273*4882a593Smuzhiyun 		/* Disable DRP for the OPEN setting to take effect */
274*4882a593Smuzhiyun 		reg = reg & ~TCPC_ROLE_CTRL_DRP;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 		if (polarity == TYPEC_POLARITY_CC2) {
277*4882a593Smuzhiyun 			reg &= ~(TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT);
278*4882a593Smuzhiyun 			/* Local port is source */
279*4882a593Smuzhiyun 			if (cc2 == TYPEC_CC_RD)
280*4882a593Smuzhiyun 				/* Role control would have the Rp setting when DRP was enabled */
281*4882a593Smuzhiyun 				reg |= TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT;
282*4882a593Smuzhiyun 			else
283*4882a593Smuzhiyun 				reg |= TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT;
284*4882a593Smuzhiyun 		} else {
285*4882a593Smuzhiyun 			reg &= ~(TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT);
286*4882a593Smuzhiyun 			/* Local port is source */
287*4882a593Smuzhiyun 			if (cc1 == TYPEC_CC_RD)
288*4882a593Smuzhiyun 				/* Role control would have the Rp setting when DRP was enabled */
289*4882a593Smuzhiyun 				reg |= TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT;
290*4882a593Smuzhiyun 			else
291*4882a593Smuzhiyun 				reg |= TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT;
292*4882a593Smuzhiyun 		}
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (polarity == TYPEC_POLARITY_CC2)
296*4882a593Smuzhiyun 		reg |= TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT;
297*4882a593Smuzhiyun 	else
298*4882a593Smuzhiyun 		reg |= TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT;
299*4882a593Smuzhiyun 	ret = dm_i2c_reg_write(tcpci->dev, TCPC_ROLE_CTRL, reg);
300*4882a593Smuzhiyun 	if (ret < 0)
301*4882a593Smuzhiyun 		return ret;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	return dm_i2c_reg_write(tcpci->dev, TCPC_TCPC_CTRL,
304*4882a593Smuzhiyun 			(polarity == TYPEC_POLARITY_CC2) ?
305*4882a593Smuzhiyun 			 TCPC_TCPC_CTRL_ORIENTATION : 0);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
tcpci_set_vconn(struct tcpc_dev * tcpc,bool enable)308*4882a593Smuzhiyun static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
311*4882a593Smuzhiyun 	int ret;
312*4882a593Smuzhiyun 	unsigned int reg;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	/* Handle vendor set vconn */
315*4882a593Smuzhiyun 	if (tcpci->data->set_vconn) {
316*4882a593Smuzhiyun 		ret = tcpci->data->set_vconn(tcpci, tcpci->data, enable);
317*4882a593Smuzhiyun 		if (ret < 0)
318*4882a593Smuzhiyun 			return ret;
319*4882a593Smuzhiyun 	}
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	reg = dm_i2c_reg_read(tcpci->dev, TCPC_POWER_CTRL);
322*4882a593Smuzhiyun 	if (reg)
323*4882a593Smuzhiyun 		return reg;
324*4882a593Smuzhiyun 	reg &= ~TCPC_POWER_CTRL_VCONN_ENABLE;
325*4882a593Smuzhiyun 	reg |= enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0;
326*4882a593Smuzhiyun 	return dm_i2c_reg_write(tcpci->dev, TCPC_POWER_CTRL, reg);
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
tcpci_set_roles(struct tcpc_dev * tcpc,bool attached,enum typec_role role,enum typec_data_role data)329*4882a593Smuzhiyun static int tcpci_set_roles(struct tcpc_dev *tcpc, bool attached,
330*4882a593Smuzhiyun 			   enum typec_role role, enum typec_data_role data)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
333*4882a593Smuzhiyun 	unsigned int reg;
334*4882a593Smuzhiyun 	int ret;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	reg = PD_REV20 << TCPC_MSG_HDR_INFO_REV_SHIFT;
337*4882a593Smuzhiyun 	if (role == TYPEC_SOURCE)
338*4882a593Smuzhiyun 		reg |= TCPC_MSG_HDR_INFO_PWR_ROLE;
339*4882a593Smuzhiyun 	if (data == TYPEC_HOST)
340*4882a593Smuzhiyun 		reg |= TCPC_MSG_HDR_INFO_DATA_ROLE;
341*4882a593Smuzhiyun 	ret = dm_i2c_reg_write(tcpci->dev, TCPC_MSG_HDR_INFO, reg);
342*4882a593Smuzhiyun 	if (ret < 0)
343*4882a593Smuzhiyun 		return ret;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	return 0;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun 
tcpci_set_pd_rx(struct tcpc_dev * tcpc,bool enable)348*4882a593Smuzhiyun static int tcpci_set_pd_rx(struct tcpc_dev *tcpc, bool enable)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
351*4882a593Smuzhiyun 	unsigned int reg = 0;
352*4882a593Smuzhiyun 	int ret;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	if (enable)
355*4882a593Smuzhiyun 		reg = TCPC_RX_DETECT_SOP | TCPC_RX_DETECT_HARD_RESET;
356*4882a593Smuzhiyun 	ret = dm_i2c_reg_write(tcpci->dev, TCPC_RX_DETECT, reg);
357*4882a593Smuzhiyun 	if (ret < 0)
358*4882a593Smuzhiyun 		return ret;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	return 0;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun 
tcpci_get_vbus(struct tcpc_dev * tcpc)363*4882a593Smuzhiyun static int tcpci_get_vbus(struct tcpc_dev *tcpc)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
366*4882a593Smuzhiyun 	unsigned int reg;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	reg = dm_i2c_reg_read(tcpci->dev, TCPC_POWER_STATUS);
369*4882a593Smuzhiyun 	if (reg < 0)
370*4882a593Smuzhiyun 		return reg;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	return !!(reg & TCPC_POWER_STATUS_VBUS_PRES);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
tcpci_set_vbus(struct tcpc_dev * tcpc,bool source,bool sink)375*4882a593Smuzhiyun static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
378*4882a593Smuzhiyun 	int ret;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	/* Disable both source and sink first before enabling anything */
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	if (!source) {
383*4882a593Smuzhiyun 		ret = dm_i2c_reg_write(tcpci->dev, TCPC_COMMAND,
384*4882a593Smuzhiyun 				       TCPC_CMD_DISABLE_SRC_VBUS);
385*4882a593Smuzhiyun 		if (ret < 0)
386*4882a593Smuzhiyun 			return ret;
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	if (!sink) {
390*4882a593Smuzhiyun 		ret = dm_i2c_reg_write(tcpci->dev, TCPC_COMMAND,
391*4882a593Smuzhiyun 				       TCPC_CMD_DISABLE_SINK_VBUS);
392*4882a593Smuzhiyun 		if (ret < 0)
393*4882a593Smuzhiyun 			return ret;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	if (source) {
397*4882a593Smuzhiyun 		ret = dm_i2c_reg_write(tcpci->dev, TCPC_COMMAND,
398*4882a593Smuzhiyun 				       TCPC_CMD_SRC_VBUS_DEFAULT);
399*4882a593Smuzhiyun 		if (ret < 0)
400*4882a593Smuzhiyun 			return ret;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	if (sink) {
404*4882a593Smuzhiyun 		ret = dm_i2c_reg_write(tcpci->dev, TCPC_COMMAND,
405*4882a593Smuzhiyun 				       TCPC_CMD_SINK_VBUS);
406*4882a593Smuzhiyun 		if (ret < 0)
407*4882a593Smuzhiyun 			return ret;
408*4882a593Smuzhiyun 	}
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	return 0;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
tcpci_pd_transmit(struct tcpc_dev * tcpc,enum tcpm_transmit_type type,const struct pd_message * msg,unsigned int negotiated_rev)413*4882a593Smuzhiyun static int tcpci_pd_transmit(struct tcpc_dev *tcpc,
414*4882a593Smuzhiyun 			     enum tcpm_transmit_type type,
415*4882a593Smuzhiyun 			     const struct pd_message *msg,
416*4882a593Smuzhiyun 			     unsigned int negotiated_rev)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
419*4882a593Smuzhiyun 	u16 header = msg ? le16_to_cpu(msg->header) : 0;
420*4882a593Smuzhiyun 	unsigned int reg, cnt;
421*4882a593Smuzhiyun 	int ret;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	cnt = msg ? pd_header_cnt(header) * 4 : 0;
424*4882a593Smuzhiyun 	ret = dm_i2c_reg_write(tcpci->dev, TCPC_TX_BYTE_CNT, cnt + 2);
425*4882a593Smuzhiyun 	if (ret < 0)
426*4882a593Smuzhiyun 		return ret;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	ret = tcpci_write16(tcpci, TCPC_TX_HDR, header);
429*4882a593Smuzhiyun 	if (ret < 0)
430*4882a593Smuzhiyun 		return ret;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	if (cnt > 0) {
433*4882a593Smuzhiyun 		ret = tcpci_block_write(tcpci, TCPC_TX_DATA,
434*4882a593Smuzhiyun 				       (u8 *)&msg->payload, cnt);
435*4882a593Smuzhiyun 		if (ret < 0)
436*4882a593Smuzhiyun 			return ret;
437*4882a593Smuzhiyun 	}
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	reg = (PD_RETRY_COUNT << TCPC_TRANSMIT_RETRY_SHIFT) |
440*4882a593Smuzhiyun 		(type << TCPC_TRANSMIT_TYPE_SHIFT);
441*4882a593Smuzhiyun 	ret = dm_i2c_reg_write(tcpci->dev, TCPC_TRANSMIT, reg);
442*4882a593Smuzhiyun 	if (ret < 0)
443*4882a593Smuzhiyun 		return ret;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	return 0;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun 
tcpci_init(struct tcpc_dev * tcpc)448*4882a593Smuzhiyun static int tcpci_init(struct tcpc_dev *tcpc)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
451*4882a593Smuzhiyun 	unsigned int timeout = 0; /* XXX */
452*4882a593Smuzhiyun 	unsigned int reg;
453*4882a593Smuzhiyun 	int ret;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	while (timeout < 100) {
456*4882a593Smuzhiyun 		reg = dm_i2c_reg_read(tcpci->dev, TCPC_POWER_STATUS);
457*4882a593Smuzhiyun 		if (reg < 0)
458*4882a593Smuzhiyun 			return reg;
459*4882a593Smuzhiyun 		if (!(reg & TCPC_POWER_STATUS_UNINIT))
460*4882a593Smuzhiyun 			break;
461*4882a593Smuzhiyun 		timeout++;
462*4882a593Smuzhiyun 		udelay(200);
463*4882a593Smuzhiyun 	}
464*4882a593Smuzhiyun 	if (timeout >= 100)
465*4882a593Smuzhiyun 		return -ETIMEDOUT;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	/* Handle vendor init */
468*4882a593Smuzhiyun 	if (tcpci->data->init) {
469*4882a593Smuzhiyun 		ret = tcpci->data->init(tcpci, tcpci->data);
470*4882a593Smuzhiyun 		if (ret < 0)
471*4882a593Smuzhiyun 			return ret;
472*4882a593Smuzhiyun 	}
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	/* Clear all events */
475*4882a593Smuzhiyun 	ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
476*4882a593Smuzhiyun 	if (ret < 0)
477*4882a593Smuzhiyun 		return ret;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	if (tcpci->controls_vbus)
480*4882a593Smuzhiyun 		reg = TCPC_POWER_STATUS_VBUS_PRES;
481*4882a593Smuzhiyun 	else
482*4882a593Smuzhiyun 		reg = 0;
483*4882a593Smuzhiyun 	ret = dm_i2c_reg_write(tcpci->dev, TCPC_POWER_STATUS_MASK, reg);
484*4882a593Smuzhiyun 	if (ret < 0)
485*4882a593Smuzhiyun 		return ret;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	/* Enable Vbus detection */
488*4882a593Smuzhiyun 	ret = dm_i2c_reg_write(tcpci->dev, TCPC_COMMAND,
489*4882a593Smuzhiyun 			       TCPC_CMD_ENABLE_VBUS_DETECT);
490*4882a593Smuzhiyun 	if (ret < 0)
491*4882a593Smuzhiyun 		return ret;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	reg = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_FAILED |
494*4882a593Smuzhiyun 		TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_RX_STATUS |
495*4882a593Smuzhiyun 		TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS;
496*4882a593Smuzhiyun 	if (tcpci->controls_vbus)
497*4882a593Smuzhiyun 		reg |= TCPC_ALERT_POWER_STATUS;
498*4882a593Smuzhiyun 	return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
tcpci_poll_event(struct tcpc_dev * tcpc)501*4882a593Smuzhiyun static void tcpci_poll_event(struct tcpc_dev *tcpc)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	u16 status;
504*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	if (tcpci->gpio_cc_int_present)
507*4882a593Smuzhiyun 		if (!dm_gpio_get_value(&tcpci->gpio_cc_int))
508*4882a593Smuzhiyun 			return;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	tcpci_read16(tcpci, TCPC_ALERT, &status);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	/*
513*4882a593Smuzhiyun 	 * Clear alert status for everything except RX_STATUS, which shouldn't
514*4882a593Smuzhiyun 	 * be cleared until we have successfully retrieved message.
515*4882a593Smuzhiyun 	 */
516*4882a593Smuzhiyun 	if (status & ~TCPC_ALERT_RX_STATUS)
517*4882a593Smuzhiyun 		tcpci_write16(tcpci, TCPC_ALERT,
518*4882a593Smuzhiyun 			      status & ~TCPC_ALERT_RX_STATUS);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	if (status & TCPC_ALERT_CC_STATUS)
521*4882a593Smuzhiyun 		tcpm_cc_change(tcpci->port);
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	if (status & TCPC_ALERT_POWER_STATUS) {
524*4882a593Smuzhiyun 		unsigned int reg;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 		reg = dm_i2c_reg_read(tcpci->dev, TCPC_POWER_STATUS_MASK);
527*4882a593Smuzhiyun 		if (reg < 0)
528*4882a593Smuzhiyun 			return;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 		/*
531*4882a593Smuzhiyun 		 * If power status mask has been reset, then the TCPC
532*4882a593Smuzhiyun 		 * has reset.
533*4882a593Smuzhiyun 		 */
534*4882a593Smuzhiyun 		if (reg == 0xff)
535*4882a593Smuzhiyun 			tcpm_tcpc_reset(tcpci->port);
536*4882a593Smuzhiyun 		else
537*4882a593Smuzhiyun 			tcpm_vbus_change(tcpci->port);
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	if (status & TCPC_ALERT_RX_STATUS) {
541*4882a593Smuzhiyun 		struct pd_message msg;
542*4882a593Smuzhiyun 		unsigned int cnt, payload_cnt;
543*4882a593Smuzhiyun 		u16 header;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 		cnt = dm_i2c_reg_read(tcpci->dev, TCPC_RX_BYTE_CNT);
546*4882a593Smuzhiyun 		if (cnt < 0)
547*4882a593Smuzhiyun 			return;
548*4882a593Smuzhiyun 		/*
549*4882a593Smuzhiyun 		 * 'cnt' corresponds to READABLE_BYTE_COUNT in section 4.4.14
550*4882a593Smuzhiyun 		 * of the TCPCI spec [Rev 2.0 Ver 1.0 October 2017] and is
551*4882a593Smuzhiyun 		 * defined in table 4-36 as one greater than the number of
552*4882a593Smuzhiyun 		 * bytes received. And that number includes the header. So:
553*4882a593Smuzhiyun 		 */
554*4882a593Smuzhiyun 		if (cnt > 3)
555*4882a593Smuzhiyun 			payload_cnt = cnt - (1 + sizeof(msg.header));
556*4882a593Smuzhiyun 		else
557*4882a593Smuzhiyun 			payload_cnt = 0;
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 		tcpci_read16(tcpci, TCPC_RX_HDR, &header);
560*4882a593Smuzhiyun 		msg.header = cpu_to_le16(header);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 		if (WARN_ON(payload_cnt > sizeof(msg.payload)))
563*4882a593Smuzhiyun 			payload_cnt = sizeof(msg.payload);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 		if (payload_cnt > 0)
566*4882a593Smuzhiyun 			tcpci_block_read(tcpci, TCPC_RX_DATA,
567*4882a593Smuzhiyun 					(u8 *)&msg.payload, payload_cnt);
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 		/* Read complete, clear RX status alert bit */
570*4882a593Smuzhiyun 		tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 		tcpm_pd_receive(tcpci->port, &msg);
573*4882a593Smuzhiyun 	}
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	if (status & TCPC_ALERT_RX_HARD_RST)
576*4882a593Smuzhiyun 		tcpm_pd_hard_reset(tcpci->port);
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	if (status & TCPC_ALERT_TX_SUCCESS)
579*4882a593Smuzhiyun 		tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_SUCCESS);
580*4882a593Smuzhiyun 	else if (status & TCPC_ALERT_TX_DISCARDED)
581*4882a593Smuzhiyun 		tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_DISCARDED);
582*4882a593Smuzhiyun 	else if (status & TCPC_ALERT_TX_FAILED)
583*4882a593Smuzhiyun 		tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_FAILED);
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun 
tcpci_enter_low_power_mode(struct tcpc_dev * tcpc,bool attached,bool pd_capable)586*4882a593Smuzhiyun static int tcpci_enter_low_power_mode(struct tcpc_dev *tcpc,
587*4882a593Smuzhiyun 				      bool attached, bool pd_capable)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	int ret;
590*4882a593Smuzhiyun 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
591*4882a593Smuzhiyun 	unsigned int reg;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	/* Disable chip interrupts before unregistering port */
594*4882a593Smuzhiyun 	ret = tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
595*4882a593Smuzhiyun 	if (ret < 0)
596*4882a593Smuzhiyun 		return ret;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	reg = dm_i2c_reg_read(tcpci->dev, TCPC_BMCIO_CTRL);
599*4882a593Smuzhiyun 	if (reg < 0)
600*4882a593Smuzhiyun 		return reg;
601*4882a593Smuzhiyun 	/*
602*4882a593Smuzhiyun 	 * For Type-C devices with PD capability, Only disable VBUS detect,
603*4882a593Smuzhiyun 	 * do not diable 24M oscillator for BMC communication. Otherwise,
604*4882a593Smuzhiyun 	 * data packets cannot be received.
605*4882a593Smuzhiyun 	 */
606*4882a593Smuzhiyun 	if (attached && pd_capable)
607*4882a593Smuzhiyun 		reg &= ~TCPC_BMCIO_VBUS_DETECT_MASK;
608*4882a593Smuzhiyun 	else
609*4882a593Smuzhiyun 		reg &= ~(TCPC_BMCIO_VBUS_DETECT_MASK | TCPC_BMCIO_24M_OSC_MASK);
610*4882a593Smuzhiyun 	return dm_i2c_reg_write(tcpci->dev, TCPC_BMCIO_CTRL, reg);
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun 
tcpci_parse_config(struct tcpci * tcpci)613*4882a593Smuzhiyun static int tcpci_parse_config(struct tcpci *tcpci)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun 	tcpci->controls_vbus = true; /* XXX */
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	tcpci->tcpc.connector_node = dev_read_subnode(tcpci->dev, "connector");
618*4882a593Smuzhiyun 	if (!ofnode_valid(tcpci->tcpc.connector_node)) {
619*4882a593Smuzhiyun 		printf("%s: 'connector' node is not found\n", __func__);
620*4882a593Smuzhiyun 		return -EINVAL;
621*4882a593Smuzhiyun 	}
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	return 0;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun 
tcpci_register_port(struct udevice * dev,struct tcpci_data * data)626*4882a593Smuzhiyun struct tcpci *tcpci_register_port(struct udevice *dev, struct tcpci_data *data)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	struct tcpci *tcpci;
629*4882a593Smuzhiyun 	int err;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
632*4882a593Smuzhiyun 	if (!tcpci)
633*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	err = gpio_request_by_name(dev, "int-n-gpios", 0, &tcpci->gpio_cc_int, GPIOD_IS_IN);
636*4882a593Smuzhiyun 	if (err) {
637*4882a593Smuzhiyun 		printf("%s: fail to get int GPIO: err=%d\n", __func__, err);
638*4882a593Smuzhiyun 		tcpci->gpio_cc_int_present = false;
639*4882a593Smuzhiyun 	} else {
640*4882a593Smuzhiyun 		tcpci->gpio_cc_int_present = true;
641*4882a593Smuzhiyun 	}
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	tcpci->dev = dev;
644*4882a593Smuzhiyun 	tcpci->data = data;
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	tcpci->tcpc.init = tcpci_init;
647*4882a593Smuzhiyun 	tcpci->tcpc.get_vbus = tcpci_get_vbus;
648*4882a593Smuzhiyun 	tcpci->tcpc.set_vbus = tcpci_set_vbus;
649*4882a593Smuzhiyun 	tcpci->tcpc.set_cc = tcpci_set_cc;
650*4882a593Smuzhiyun 	tcpci->tcpc.get_cc = tcpci_get_cc;
651*4882a593Smuzhiyun 	tcpci->tcpc.set_polarity = tcpci_set_polarity;
652*4882a593Smuzhiyun 	tcpci->tcpc.set_vconn = tcpci_set_vconn;
653*4882a593Smuzhiyun 	tcpci->tcpc.start_toggling = tcpci_start_toggling;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx;
656*4882a593Smuzhiyun 	tcpci->tcpc.set_roles = tcpci_set_roles;
657*4882a593Smuzhiyun 	tcpci->tcpc.pd_transmit = tcpci_pd_transmit;
658*4882a593Smuzhiyun 	tcpci->tcpc.poll_event = tcpci_poll_event;
659*4882a593Smuzhiyun 	tcpci->tcpc.enter_low_power_mode = tcpci_enter_low_power_mode;
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	err = tcpci_parse_config(tcpci);
662*4882a593Smuzhiyun 	if (err < 0)
663*4882a593Smuzhiyun 		return ERR_PTR(err);
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	tcpci->port = tcpm_port_init(tcpci->dev, &tcpci->tcpc);
666*4882a593Smuzhiyun 	if (IS_ERR(tcpci->port)) {
667*4882a593Smuzhiyun 		printf("%s: failed to tcpm port init\n", __func__);
668*4882a593Smuzhiyun 		return ERR_CAST(tcpci->port);
669*4882a593Smuzhiyun 	}
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	tcpm_poll_event(tcpci->port);
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	return tcpci;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tcpci_register_port);
676*4882a593Smuzhiyun 
tcpci_unregister_port(struct tcpci * tcpci)677*4882a593Smuzhiyun void tcpci_unregister_port(struct tcpci *tcpci)
678*4882a593Smuzhiyun {
679*4882a593Smuzhiyun 	tcpm_uninit_port(tcpci->port);
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tcpci_unregister_port);
682*4882a593Smuzhiyun 
tcpci_get_voltage_fun(struct tcpci * tcpci)683*4882a593Smuzhiyun int tcpci_get_voltage_fun(struct tcpci *tcpci)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun 	return tcpm_get_voltage(tcpci->port);
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tcpci_get_voltage_fun);
688*4882a593Smuzhiyun 
tcpci_get_current_fun(struct tcpci * tcpci)689*4882a593Smuzhiyun int tcpci_get_current_fun(struct tcpci *tcpci)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun 	return tcpm_get_current(tcpci->port);
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tcpci_get_current_fun);
694*4882a593Smuzhiyun 
tcpci_get_online_fun(struct tcpci * tcpci)695*4882a593Smuzhiyun int tcpci_get_online_fun(struct tcpci *tcpci)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun 	return tcpm_get_online(tcpci->port);
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(tcpci_get_online_fun);
700*4882a593Smuzhiyun 
tcpci_probe(struct udevice * dev)701*4882a593Smuzhiyun static int tcpci_probe(struct udevice *dev)
702*4882a593Smuzhiyun {
703*4882a593Smuzhiyun 	struct tcpci_chip *chip = dev_get_priv(dev);
704*4882a593Smuzhiyun 	int err;
705*4882a593Smuzhiyun 	u16 val = 0;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	chip->udev = dev;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	/* Disable chip interrupts before requesting irq */
710*4882a593Smuzhiyun 	err = tcpci_write16(chip->tcpci, TCPC_ALERT_MASK, val);
711*4882a593Smuzhiyun 	if (err < 0)
712*4882a593Smuzhiyun 		return err;
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	chip->tcpci = tcpci_register_port(chip->udev, &chip->data);
715*4882a593Smuzhiyun 	if (IS_ERR(chip->tcpci))
716*4882a593Smuzhiyun 		return PTR_ERR(chip->tcpci);
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	return 0;
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun 
tcpci_remove(struct udevice * dev)721*4882a593Smuzhiyun static int tcpci_remove(struct udevice *dev)
722*4882a593Smuzhiyun {
723*4882a593Smuzhiyun 	struct tcpci_chip *chip = dev_get_priv(dev);
724*4882a593Smuzhiyun 	int err;
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	/* Disable chip interrupts before unregistering port */
727*4882a593Smuzhiyun 	err = tcpci_write16(chip->tcpci, TCPC_ALERT_MASK, 0);
728*4882a593Smuzhiyun 	if (err < 0)
729*4882a593Smuzhiyun 		return err;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	tcpci_unregister_port(chip->tcpci);
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	return 0;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
tcpci_get_voltage(struct udevice * dev)736*4882a593Smuzhiyun static int tcpci_get_voltage(struct udevice *dev)
737*4882a593Smuzhiyun {
738*4882a593Smuzhiyun 	struct tcpci_chip *chip = dev_get_priv(dev);
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	return tcpm_get_voltage(chip->tcpci->port);
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun 
tcpci_get_current(struct udevice * dev)743*4882a593Smuzhiyun static int tcpci_get_current(struct udevice *dev)
744*4882a593Smuzhiyun {
745*4882a593Smuzhiyun 	struct tcpci_chip *chip = dev_get_priv(dev);
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	return tcpm_get_current(chip->tcpci->port);
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun 
tcpci_get_online(struct udevice * dev)750*4882a593Smuzhiyun static int tcpci_get_online(struct udevice *dev)
751*4882a593Smuzhiyun {
752*4882a593Smuzhiyun 	struct tcpci_chip *chip = dev_get_priv(dev);
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	return tcpm_get_online(chip->tcpci->port);
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun static struct dm_power_delivery_ops tcpci_ops = {
758*4882a593Smuzhiyun 	.get_voltage = tcpci_get_voltage,
759*4882a593Smuzhiyun 	.get_current = tcpci_get_current,
760*4882a593Smuzhiyun 	.get_online = tcpci_get_online,
761*4882a593Smuzhiyun };
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun static const struct udevice_id tcpci_ids[] = {
764*4882a593Smuzhiyun 	{ .compatible = "nxp,ptn5110", },
765*4882a593Smuzhiyun 	{},
766*4882a593Smuzhiyun };
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun U_BOOT_DRIVER(tcpci) = {
769*4882a593Smuzhiyun 	.name = "tcpci",
770*4882a593Smuzhiyun 	.id = UCLASS_PD,
771*4882a593Smuzhiyun 	.of_match = tcpci_ids,
772*4882a593Smuzhiyun 	.ops = &tcpci_ops,
773*4882a593Smuzhiyun 	.probe = tcpci_probe,
774*4882a593Smuzhiyun 	.remove = tcpci_remove,
775*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct tcpci_chip),
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun MODULE_DESCRIPTION("USB Type-C Port Controller Interface driver");
779*4882a593Smuzhiyun MODULE_LICENSE("GPL");
780