xref: /linux/drivers/net/pse-pd/pd692x0.c (revision 9a993845189004a923b78d0df643e47970147337)
1*9a993845SKory Maincent (Dent Project) // SPDX-License-Identifier: GPL-2.0-only
2*9a993845SKory Maincent (Dent Project) /*
3*9a993845SKory Maincent (Dent Project)  * Driver for the Microchip PD692X0 PoE PSE Controller driver (I2C bus)
4*9a993845SKory Maincent (Dent Project)  *
5*9a993845SKory Maincent (Dent Project)  * Copyright (c) 2023 Bootlin, Kory Maincent <kory.maincent@bootlin.com>
6*9a993845SKory Maincent (Dent Project)  */
7*9a993845SKory Maincent (Dent Project) 
8*9a993845SKory Maincent (Dent Project) #include <linux/delay.h>
9*9a993845SKory Maincent (Dent Project) #include <linux/firmware.h>
10*9a993845SKory Maincent (Dent Project) #include <linux/i2c.h>
11*9a993845SKory Maincent (Dent Project) #include <linux/module.h>
12*9a993845SKory Maincent (Dent Project) #include <linux/of.h>
13*9a993845SKory Maincent (Dent Project) #include <linux/platform_device.h>
14*9a993845SKory Maincent (Dent Project) #include <linux/pse-pd/pse.h>
15*9a993845SKory Maincent (Dent Project) 
16*9a993845SKory Maincent (Dent Project) #define PD692X0_PSE_NAME "pd692x0_pse"
17*9a993845SKory Maincent (Dent Project) 
18*9a993845SKory Maincent (Dent Project) #define PD692X0_MAX_PIS	48
19*9a993845SKory Maincent (Dent Project) #define PD692X0_MAX_MANAGERS		12
20*9a993845SKory Maincent (Dent Project) #define PD692X0_MAX_MANAGER_PORTS	8
21*9a993845SKory Maincent (Dent Project) #define PD692X0_MAX_HW_PORTS	(PD692X0_MAX_MANAGERS * PD692X0_MAX_MANAGER_PORTS)
22*9a993845SKory Maincent (Dent Project) 
23*9a993845SKory Maincent (Dent Project) #define PD69200_BT_PROD_VER	24
24*9a993845SKory Maincent (Dent Project) #define PD69210_BT_PROD_VER	26
25*9a993845SKory Maincent (Dent Project) #define PD69220_BT_PROD_VER	29
26*9a993845SKory Maincent (Dent Project) 
27*9a993845SKory Maincent (Dent Project) #define PD692X0_FW_MAJ_VER	3
28*9a993845SKory Maincent (Dent Project) #define PD692X0_FW_MIN_VER	5
29*9a993845SKory Maincent (Dent Project) #define PD692X0_FW_PATCH_VER	5
30*9a993845SKory Maincent (Dent Project) 
31*9a993845SKory Maincent (Dent Project) enum pd692x0_fw_state {
32*9a993845SKory Maincent (Dent Project) 	PD692X0_FW_UNKNOWN,
33*9a993845SKory Maincent (Dent Project) 	PD692X0_FW_OK,
34*9a993845SKory Maincent (Dent Project) 	PD692X0_FW_BROKEN,
35*9a993845SKory Maincent (Dent Project) 	PD692X0_FW_NEED_UPDATE,
36*9a993845SKory Maincent (Dent Project) 	PD692X0_FW_PREPARE,
37*9a993845SKory Maincent (Dent Project) 	PD692X0_FW_WRITE,
38*9a993845SKory Maincent (Dent Project) 	PD692X0_FW_COMPLETE,
39*9a993845SKory Maincent (Dent Project) };
40*9a993845SKory Maincent (Dent Project) 
41*9a993845SKory Maincent (Dent Project) struct pd692x0_msg {
42*9a993845SKory Maincent (Dent Project) 	u8 key;
43*9a993845SKory Maincent (Dent Project) 	u8 echo;
44*9a993845SKory Maincent (Dent Project) 	u8 sub[3];
45*9a993845SKory Maincent (Dent Project) 	u8 data[8];
46*9a993845SKory Maincent (Dent Project) 	__be16 chksum;
47*9a993845SKory Maincent (Dent Project) } __packed;
48*9a993845SKory Maincent (Dent Project) 
49*9a993845SKory Maincent (Dent Project) struct pd692x0_msg_ver {
50*9a993845SKory Maincent (Dent Project) 	u8 prod;
51*9a993845SKory Maincent (Dent Project) 	u8 maj_sw_ver;
52*9a993845SKory Maincent (Dent Project) 	u8 min_sw_ver;
53*9a993845SKory Maincent (Dent Project) 	u8 pa_sw_ver;
54*9a993845SKory Maincent (Dent Project) 	u8 param;
55*9a993845SKory Maincent (Dent Project) 	u8 build;
56*9a993845SKory Maincent (Dent Project) };
57*9a993845SKory Maincent (Dent Project) 
58*9a993845SKory Maincent (Dent Project) enum {
59*9a993845SKory Maincent (Dent Project) 	PD692X0_KEY_CMD,
60*9a993845SKory Maincent (Dent Project) 	PD692X0_KEY_PRG,
61*9a993845SKory Maincent (Dent Project) 	PD692X0_KEY_REQ,
62*9a993845SKory Maincent (Dent Project) 	PD692X0_KEY_TLM,
63*9a993845SKory Maincent (Dent Project) 	PD692X0_KEY_TEST,
64*9a993845SKory Maincent (Dent Project) 	PD692X0_KEY_REPORT = 0x52
65*9a993845SKory Maincent (Dent Project) };
66*9a993845SKory Maincent (Dent Project) 
67*9a993845SKory Maincent (Dent Project) enum {
68*9a993845SKory Maincent (Dent Project) 	PD692X0_MSG_RESET,
69*9a993845SKory Maincent (Dent Project) 	PD692X0_MSG_GET_SYS_STATUS,
70*9a993845SKory Maincent (Dent Project) 	PD692X0_MSG_GET_SW_VER,
71*9a993845SKory Maincent (Dent Project) 	PD692X0_MSG_SET_TMP_PORT_MATRIX,
72*9a993845SKory Maincent (Dent Project) 	PD692X0_MSG_PRG_PORT_MATRIX,
73*9a993845SKory Maincent (Dent Project) 	PD692X0_MSG_SET_PORT_PARAM,
74*9a993845SKory Maincent (Dent Project) 	PD692X0_MSG_GET_PORT_STATUS,
75*9a993845SKory Maincent (Dent Project) 	PD692X0_MSG_DOWNLOAD_CMD,
76*9a993845SKory Maincent (Dent Project) 
77*9a993845SKory Maincent (Dent Project) 	/* add new message above here */
78*9a993845SKory Maincent (Dent Project) 	PD692X0_MSG_CNT
79*9a993845SKory Maincent (Dent Project) };
80*9a993845SKory Maincent (Dent Project) 
81*9a993845SKory Maincent (Dent Project) struct pd692x0_priv {
82*9a993845SKory Maincent (Dent Project) 	struct i2c_client *client;
83*9a993845SKory Maincent (Dent Project) 	struct pse_controller_dev pcdev;
84*9a993845SKory Maincent (Dent Project) 	struct device_node *np;
85*9a993845SKory Maincent (Dent Project) 
86*9a993845SKory Maincent (Dent Project) 	enum pd692x0_fw_state fw_state;
87*9a993845SKory Maincent (Dent Project) 	struct fw_upload *fwl;
88*9a993845SKory Maincent (Dent Project) 	bool cancel_request;
89*9a993845SKory Maincent (Dent Project) 
90*9a993845SKory Maincent (Dent Project) 	u8 msg_id;
91*9a993845SKory Maincent (Dent Project) 	bool last_cmd_key;
92*9a993845SKory Maincent (Dent Project) 	unsigned long last_cmd_key_time;
93*9a993845SKory Maincent (Dent Project) 
94*9a993845SKory Maincent (Dent Project) 	enum ethtool_c33_pse_admin_state admin_state[PD692X0_MAX_PIS];
95*9a993845SKory Maincent (Dent Project) };
96*9a993845SKory Maincent (Dent Project) 
97*9a993845SKory Maincent (Dent Project) /* Template list of communication messages. The non-null bytes defined here
98*9a993845SKory Maincent (Dent Project)  * constitute the fixed portion of the messages. The remaining bytes will
99*9a993845SKory Maincent (Dent Project)  * be configured later within the functions. Refer to the "PD692x0 BT Serial
100*9a993845SKory Maincent (Dent Project)  * Communication Protocol User Guide" for comprehensive details on messages
101*9a993845SKory Maincent (Dent Project)  * content.
102*9a993845SKory Maincent (Dent Project)  */
103*9a993845SKory Maincent (Dent Project) static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = {
104*9a993845SKory Maincent (Dent Project) 	[PD692X0_MSG_RESET] = {
105*9a993845SKory Maincent (Dent Project) 		.key = PD692X0_KEY_CMD,
106*9a993845SKory Maincent (Dent Project) 		.sub = {0x07, 0x55, 0x00},
107*9a993845SKory Maincent (Dent Project) 		.data = {0x55, 0x00, 0x55, 0x4e,
108*9a993845SKory Maincent (Dent Project) 			 0x4e, 0x4e, 0x4e, 0x4e},
109*9a993845SKory Maincent (Dent Project) 	},
110*9a993845SKory Maincent (Dent Project) 	[PD692X0_MSG_GET_SYS_STATUS] = {
111*9a993845SKory Maincent (Dent Project) 		.key = PD692X0_KEY_REQ,
112*9a993845SKory Maincent (Dent Project) 		.sub = {0x07, 0xd0, 0x4e},
113*9a993845SKory Maincent (Dent Project) 		.data = {0x4e, 0x4e, 0x4e, 0x4e,
114*9a993845SKory Maincent (Dent Project) 			 0x4e, 0x4e, 0x4e, 0x4e},
115*9a993845SKory Maincent (Dent Project) 	},
116*9a993845SKory Maincent (Dent Project) 	[PD692X0_MSG_GET_SW_VER] = {
117*9a993845SKory Maincent (Dent Project) 		.key = PD692X0_KEY_REQ,
118*9a993845SKory Maincent (Dent Project) 		.sub = {0x07, 0x1e, 0x21},
119*9a993845SKory Maincent (Dent Project) 		.data = {0x4e, 0x4e, 0x4e, 0x4e,
120*9a993845SKory Maincent (Dent Project) 			 0x4e, 0x4e, 0x4e, 0x4e},
121*9a993845SKory Maincent (Dent Project) 	},
122*9a993845SKory Maincent (Dent Project) 	[PD692X0_MSG_SET_TMP_PORT_MATRIX] = {
123*9a993845SKory Maincent (Dent Project) 		.key = PD692X0_KEY_CMD,
124*9a993845SKory Maincent (Dent Project) 		.sub	 = {0x05, 0x43},
125*9a993845SKory Maincent (Dent Project) 		.data = {   0, 0x4e, 0x4e, 0x4e,
126*9a993845SKory Maincent (Dent Project) 			 0x4e, 0x4e, 0x4e, 0x4e},
127*9a993845SKory Maincent (Dent Project) 	},
128*9a993845SKory Maincent (Dent Project) 	[PD692X0_MSG_PRG_PORT_MATRIX] = {
129*9a993845SKory Maincent (Dent Project) 		.key = PD692X0_KEY_CMD,
130*9a993845SKory Maincent (Dent Project) 		.sub = {0x07, 0x43, 0x4e},
131*9a993845SKory Maincent (Dent Project) 		.data = {0x4e, 0x4e, 0x4e, 0x4e,
132*9a993845SKory Maincent (Dent Project) 			 0x4e, 0x4e, 0x4e, 0x4e},
133*9a993845SKory Maincent (Dent Project) 	},
134*9a993845SKory Maincent (Dent Project) 	[PD692X0_MSG_SET_PORT_PARAM] = {
135*9a993845SKory Maincent (Dent Project) 		.key = PD692X0_KEY_CMD,
136*9a993845SKory Maincent (Dent Project) 		.sub = {0x05, 0xc0},
137*9a993845SKory Maincent (Dent Project) 		.data = {   0, 0xff, 0xff, 0xff,
138*9a993845SKory Maincent (Dent Project) 			 0x4e, 0x4e, 0x4e, 0x4e},
139*9a993845SKory Maincent (Dent Project) 	},
140*9a993845SKory Maincent (Dent Project) 	[PD692X0_MSG_GET_PORT_STATUS] = {
141*9a993845SKory Maincent (Dent Project) 		.key = PD692X0_KEY_REQ,
142*9a993845SKory Maincent (Dent Project) 		.sub = {0x05, 0xc1},
143*9a993845SKory Maincent (Dent Project) 		.data = {0x4e, 0x4e, 0x4e, 0x4e,
144*9a993845SKory Maincent (Dent Project) 			 0x4e, 0x4e, 0x4e, 0x4e},
145*9a993845SKory Maincent (Dent Project) 	},
146*9a993845SKory Maincent (Dent Project) 	[PD692X0_MSG_DOWNLOAD_CMD] = {
147*9a993845SKory Maincent (Dent Project) 		.key = PD692X0_KEY_PRG,
148*9a993845SKory Maincent (Dent Project) 		.sub = {0xff, 0x99, 0x15},
149*9a993845SKory Maincent (Dent Project) 		.data = {0x16, 0x16, 0x99, 0x4e,
150*9a993845SKory Maincent (Dent Project) 			 0x4e, 0x4e, 0x4e, 0x4e},
151*9a993845SKory Maincent (Dent Project) 	},
152*9a993845SKory Maincent (Dent Project) };
153*9a993845SKory Maincent (Dent Project) 
154*9a993845SKory Maincent (Dent Project) static u8 pd692x0_build_msg(struct pd692x0_msg *msg, u8 echo)
155*9a993845SKory Maincent (Dent Project) {
156*9a993845SKory Maincent (Dent Project) 	u8 *data = (u8 *)msg;
157*9a993845SKory Maincent (Dent Project) 	u16 chksum = 0;
158*9a993845SKory Maincent (Dent Project) 	int i;
159*9a993845SKory Maincent (Dent Project) 
160*9a993845SKory Maincent (Dent Project) 	msg->echo = echo++;
161*9a993845SKory Maincent (Dent Project) 	if (echo == 0xff)
162*9a993845SKory Maincent (Dent Project) 		echo = 0;
163*9a993845SKory Maincent (Dent Project) 
164*9a993845SKory Maincent (Dent Project) 	for (i = 0; i < sizeof(*msg) - sizeof(msg->chksum); i++)
165*9a993845SKory Maincent (Dent Project) 		chksum += data[i];
166*9a993845SKory Maincent (Dent Project) 
167*9a993845SKory Maincent (Dent Project) 	msg->chksum = cpu_to_be16(chksum);
168*9a993845SKory Maincent (Dent Project) 
169*9a993845SKory Maincent (Dent Project) 	return echo;
170*9a993845SKory Maincent (Dent Project) }
171*9a993845SKory Maincent (Dent Project) 
172*9a993845SKory Maincent (Dent Project) static int pd692x0_send_msg(struct pd692x0_priv *priv, struct pd692x0_msg *msg)
173*9a993845SKory Maincent (Dent Project) {
174*9a993845SKory Maincent (Dent Project) 	const struct i2c_client *client = priv->client;
175*9a993845SKory Maincent (Dent Project) 	int ret;
176*9a993845SKory Maincent (Dent Project) 
177*9a993845SKory Maincent (Dent Project) 	if (msg->key == PD692X0_KEY_CMD && priv->last_cmd_key) {
178*9a993845SKory Maincent (Dent Project) 		int cmd_msleep;
179*9a993845SKory Maincent (Dent Project) 
180*9a993845SKory Maincent (Dent Project) 		cmd_msleep = 30 - jiffies_to_msecs(jiffies - priv->last_cmd_key_time);
181*9a993845SKory Maincent (Dent Project) 		if (cmd_msleep > 0)
182*9a993845SKory Maincent (Dent Project) 			msleep(cmd_msleep);
183*9a993845SKory Maincent (Dent Project) 	}
184*9a993845SKory Maincent (Dent Project) 
185*9a993845SKory Maincent (Dent Project) 	/* Add echo and checksum bytes to the message */
186*9a993845SKory Maincent (Dent Project) 	priv->msg_id = pd692x0_build_msg(msg, priv->msg_id);
187*9a993845SKory Maincent (Dent Project) 
188*9a993845SKory Maincent (Dent Project) 	ret = i2c_master_send(client, (u8 *)msg, sizeof(*msg));
189*9a993845SKory Maincent (Dent Project) 	if (ret != sizeof(*msg))
190*9a993845SKory Maincent (Dent Project) 		return -EIO;
191*9a993845SKory Maincent (Dent Project) 
192*9a993845SKory Maincent (Dent Project) 	return 0;
193*9a993845SKory Maincent (Dent Project) }
194*9a993845SKory Maincent (Dent Project) 
195*9a993845SKory Maincent (Dent Project) static int pd692x0_reset(struct pd692x0_priv *priv)
196*9a993845SKory Maincent (Dent Project) {
197*9a993845SKory Maincent (Dent Project) 	const struct i2c_client *client = priv->client;
198*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg msg, buf = {0};
199*9a993845SKory Maincent (Dent Project) 	int ret;
200*9a993845SKory Maincent (Dent Project) 
201*9a993845SKory Maincent (Dent Project) 	msg = pd692x0_msg_template_list[PD692X0_MSG_RESET];
202*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_send_msg(priv, &msg);
203*9a993845SKory Maincent (Dent Project) 	if (ret) {
204*9a993845SKory Maincent (Dent Project) 		dev_err(&client->dev,
205*9a993845SKory Maincent (Dent Project) 			"Failed to reset the controller (%pe)\n", ERR_PTR(ret));
206*9a993845SKory Maincent (Dent Project) 		return ret;
207*9a993845SKory Maincent (Dent Project) 	}
208*9a993845SKory Maincent (Dent Project) 
209*9a993845SKory Maincent (Dent Project) 	msleep(30);
210*9a993845SKory Maincent (Dent Project) 
211*9a993845SKory Maincent (Dent Project) 	ret = i2c_master_recv(client, (u8 *)&buf, sizeof(buf));
212*9a993845SKory Maincent (Dent Project) 	if (ret != sizeof(buf))
213*9a993845SKory Maincent (Dent Project) 		return ret < 0 ? ret : -EIO;
214*9a993845SKory Maincent (Dent Project) 
215*9a993845SKory Maincent (Dent Project) 	/* Is the reply a successful report message */
216*9a993845SKory Maincent (Dent Project) 	if (buf.key != PD692X0_KEY_REPORT || buf.sub[0] || buf.sub[1])
217*9a993845SKory Maincent (Dent Project) 		return -EIO;
218*9a993845SKory Maincent (Dent Project) 
219*9a993845SKory Maincent (Dent Project) 	msleep(300);
220*9a993845SKory Maincent (Dent Project) 
221*9a993845SKory Maincent (Dent Project) 	ret = i2c_master_recv(client, (u8 *)&buf, sizeof(buf));
222*9a993845SKory Maincent (Dent Project) 	if (ret != sizeof(buf))
223*9a993845SKory Maincent (Dent Project) 		return ret < 0 ? ret : -EIO;
224*9a993845SKory Maincent (Dent Project) 
225*9a993845SKory Maincent (Dent Project) 	/* Is the boot status without error */
226*9a993845SKory Maincent (Dent Project) 	if (buf.key != 0x03 || buf.echo != 0xff || buf.sub[0] & 0x1) {
227*9a993845SKory Maincent (Dent Project) 		dev_err(&client->dev, "PSE controller error\n");
228*9a993845SKory Maincent (Dent Project) 		return -EIO;
229*9a993845SKory Maincent (Dent Project) 	}
230*9a993845SKory Maincent (Dent Project) 
231*9a993845SKory Maincent (Dent Project) 	return 0;
232*9a993845SKory Maincent (Dent Project) }
233*9a993845SKory Maincent (Dent Project) 
234*9a993845SKory Maincent (Dent Project) static bool pd692x0_try_recv_msg(const struct i2c_client *client,
235*9a993845SKory Maincent (Dent Project) 				 struct pd692x0_msg *msg,
236*9a993845SKory Maincent (Dent Project) 				 struct pd692x0_msg *buf)
237*9a993845SKory Maincent (Dent Project) {
238*9a993845SKory Maincent (Dent Project) 	/* Wait 30ms before readback as mandated by the protocol */
239*9a993845SKory Maincent (Dent Project) 	msleep(30);
240*9a993845SKory Maincent (Dent Project) 
241*9a993845SKory Maincent (Dent Project) 	memset(buf, 0, sizeof(*buf));
242*9a993845SKory Maincent (Dent Project) 	i2c_master_recv(client, (u8 *)buf, sizeof(*buf));
243*9a993845SKory Maincent (Dent Project) 	if (buf->key)
244*9a993845SKory Maincent (Dent Project) 		return 0;
245*9a993845SKory Maincent (Dent Project) 
246*9a993845SKory Maincent (Dent Project) 	msleep(100);
247*9a993845SKory Maincent (Dent Project) 
248*9a993845SKory Maincent (Dent Project) 	memset(buf, 0, sizeof(*buf));
249*9a993845SKory Maincent (Dent Project) 	i2c_master_recv(client, (u8 *)buf, sizeof(*buf));
250*9a993845SKory Maincent (Dent Project) 	if (buf->key)
251*9a993845SKory Maincent (Dent Project) 		return 0;
252*9a993845SKory Maincent (Dent Project) 
253*9a993845SKory Maincent (Dent Project) 	return 1;
254*9a993845SKory Maincent (Dent Project) }
255*9a993845SKory Maincent (Dent Project) 
256*9a993845SKory Maincent (Dent Project) /* Implementation of I2C communication, specifically addressing scenarios
257*9a993845SKory Maincent (Dent Project)  * involving communication loss. Refer to the "Synchronization During
258*9a993845SKory Maincent (Dent Project)  * Communication Loss" section in the Communication Protocol document for
259*9a993845SKory Maincent (Dent Project)  * further details.
260*9a993845SKory Maincent (Dent Project)  */
261*9a993845SKory Maincent (Dent Project) static int pd692x0_recv_msg(struct pd692x0_priv *priv,
262*9a993845SKory Maincent (Dent Project) 			    struct pd692x0_msg *msg,
263*9a993845SKory Maincent (Dent Project) 			    struct pd692x0_msg *buf)
264*9a993845SKory Maincent (Dent Project) {
265*9a993845SKory Maincent (Dent Project) 	const struct i2c_client *client = priv->client;
266*9a993845SKory Maincent (Dent Project) 	int ret;
267*9a993845SKory Maincent (Dent Project) 
268*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_try_recv_msg(client, msg, buf);
269*9a993845SKory Maincent (Dent Project) 	if (!ret)
270*9a993845SKory Maincent (Dent Project) 		goto out_success;
271*9a993845SKory Maincent (Dent Project) 
272*9a993845SKory Maincent (Dent Project) 	dev_warn(&client->dev,
273*9a993845SKory Maincent (Dent Project) 		 "Communication lost, rtnl is locked until communication is back!");
274*9a993845SKory Maincent (Dent Project) 
275*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_send_msg(priv, msg);
276*9a993845SKory Maincent (Dent Project) 	if (ret)
277*9a993845SKory Maincent (Dent Project) 		return ret;
278*9a993845SKory Maincent (Dent Project) 
279*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_try_recv_msg(client, msg, buf);
280*9a993845SKory Maincent (Dent Project) 	if (!ret)
281*9a993845SKory Maincent (Dent Project) 		goto out_success2;
282*9a993845SKory Maincent (Dent Project) 
283*9a993845SKory Maincent (Dent Project) 	msleep(10000);
284*9a993845SKory Maincent (Dent Project) 
285*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_send_msg(priv, msg);
286*9a993845SKory Maincent (Dent Project) 	if (ret)
287*9a993845SKory Maincent (Dent Project) 		return ret;
288*9a993845SKory Maincent (Dent Project) 
289*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_try_recv_msg(client, msg, buf);
290*9a993845SKory Maincent (Dent Project) 	if (!ret)
291*9a993845SKory Maincent (Dent Project) 		goto out_success2;
292*9a993845SKory Maincent (Dent Project) 
293*9a993845SKory Maincent (Dent Project) 	return pd692x0_reset(priv);
294*9a993845SKory Maincent (Dent Project) 
295*9a993845SKory Maincent (Dent Project) out_success2:
296*9a993845SKory Maincent (Dent Project) 	dev_warn(&client->dev, "Communication is back, rtnl is unlocked!");
297*9a993845SKory Maincent (Dent Project) out_success:
298*9a993845SKory Maincent (Dent Project) 	if (msg->key == PD692X0_KEY_CMD) {
299*9a993845SKory Maincent (Dent Project) 		priv->last_cmd_key = true;
300*9a993845SKory Maincent (Dent Project) 		priv->last_cmd_key_time = jiffies;
301*9a993845SKory Maincent (Dent Project) 	} else {
302*9a993845SKory Maincent (Dent Project) 		priv->last_cmd_key = false;
303*9a993845SKory Maincent (Dent Project) 	}
304*9a993845SKory Maincent (Dent Project) 
305*9a993845SKory Maincent (Dent Project) 	return 0;
306*9a993845SKory Maincent (Dent Project) }
307*9a993845SKory Maincent (Dent Project) 
308*9a993845SKory Maincent (Dent Project) static int pd692x0_sendrecv_msg(struct pd692x0_priv *priv,
309*9a993845SKory Maincent (Dent Project) 				struct pd692x0_msg *msg,
310*9a993845SKory Maincent (Dent Project) 				struct pd692x0_msg *buf)
311*9a993845SKory Maincent (Dent Project) {
312*9a993845SKory Maincent (Dent Project) 	struct device *dev = &priv->client->dev;
313*9a993845SKory Maincent (Dent Project) 	int ret;
314*9a993845SKory Maincent (Dent Project) 
315*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_send_msg(priv, msg);
316*9a993845SKory Maincent (Dent Project) 	if (ret)
317*9a993845SKory Maincent (Dent Project) 		return ret;
318*9a993845SKory Maincent (Dent Project) 
319*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_recv_msg(priv, msg, buf);
320*9a993845SKory Maincent (Dent Project) 	if (ret)
321*9a993845SKory Maincent (Dent Project) 		return ret;
322*9a993845SKory Maincent (Dent Project) 
323*9a993845SKory Maincent (Dent Project) 	if (msg->echo != buf->echo) {
324*9a993845SKory Maincent (Dent Project) 		dev_err(dev,
325*9a993845SKory Maincent (Dent Project) 			"Wrong match in message ID, expect %d received %d.\n",
326*9a993845SKory Maincent (Dent Project) 			msg->echo, buf->echo);
327*9a993845SKory Maincent (Dent Project) 		return -EIO;
328*9a993845SKory Maincent (Dent Project) 	}
329*9a993845SKory Maincent (Dent Project) 
330*9a993845SKory Maincent (Dent Project) 	/* If the reply is a report message is it successful */
331*9a993845SKory Maincent (Dent Project) 	if (buf->key == PD692X0_KEY_REPORT &&
332*9a993845SKory Maincent (Dent Project) 	    (buf->sub[0] || buf->sub[1])) {
333*9a993845SKory Maincent (Dent Project) 		return -EIO;
334*9a993845SKory Maincent (Dent Project) 	}
335*9a993845SKory Maincent (Dent Project) 
336*9a993845SKory Maincent (Dent Project) 	return 0;
337*9a993845SKory Maincent (Dent Project) }
338*9a993845SKory Maincent (Dent Project) 
339*9a993845SKory Maincent (Dent Project) static struct pd692x0_priv *to_pd692x0_priv(struct pse_controller_dev *pcdev)
340*9a993845SKory Maincent (Dent Project) {
341*9a993845SKory Maincent (Dent Project) 	return container_of(pcdev, struct pd692x0_priv, pcdev);
342*9a993845SKory Maincent (Dent Project) }
343*9a993845SKory Maincent (Dent Project) 
344*9a993845SKory Maincent (Dent Project) static int pd692x0_fw_unavailable(struct pd692x0_priv *priv)
345*9a993845SKory Maincent (Dent Project) {
346*9a993845SKory Maincent (Dent Project) 	switch (priv->fw_state) {
347*9a993845SKory Maincent (Dent Project) 	case PD692X0_FW_OK:
348*9a993845SKory Maincent (Dent Project) 		return 0;
349*9a993845SKory Maincent (Dent Project) 	case PD692X0_FW_PREPARE:
350*9a993845SKory Maincent (Dent Project) 	case PD692X0_FW_WRITE:
351*9a993845SKory Maincent (Dent Project) 	case PD692X0_FW_COMPLETE:
352*9a993845SKory Maincent (Dent Project) 		dev_err(&priv->client->dev, "Firmware update in progress!\n");
353*9a993845SKory Maincent (Dent Project) 		return -EBUSY;
354*9a993845SKory Maincent (Dent Project) 	case PD692X0_FW_BROKEN:
355*9a993845SKory Maincent (Dent Project) 	case PD692X0_FW_NEED_UPDATE:
356*9a993845SKory Maincent (Dent Project) 	default:
357*9a993845SKory Maincent (Dent Project) 		dev_err(&priv->client->dev,
358*9a993845SKory Maincent (Dent Project) 			"Firmware issue. Please update it!\n");
359*9a993845SKory Maincent (Dent Project) 		return -EOPNOTSUPP;
360*9a993845SKory Maincent (Dent Project) 	}
361*9a993845SKory Maincent (Dent Project) }
362*9a993845SKory Maincent (Dent Project) 
363*9a993845SKory Maincent (Dent Project) static int pd692x0_pi_enable(struct pse_controller_dev *pcdev, int id)
364*9a993845SKory Maincent (Dent Project) {
365*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
366*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg msg, buf = {0};
367*9a993845SKory Maincent (Dent Project) 	int ret;
368*9a993845SKory Maincent (Dent Project) 
369*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_fw_unavailable(priv);
370*9a993845SKory Maincent (Dent Project) 	if (ret)
371*9a993845SKory Maincent (Dent Project) 		return ret;
372*9a993845SKory Maincent (Dent Project) 
373*9a993845SKory Maincent (Dent Project) 	if (priv->admin_state[id] == ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED)
374*9a993845SKory Maincent (Dent Project) 		return 0;
375*9a993845SKory Maincent (Dent Project) 
376*9a993845SKory Maincent (Dent Project) 	msg = pd692x0_msg_template_list[PD692X0_MSG_SET_PORT_PARAM];
377*9a993845SKory Maincent (Dent Project) 	msg.data[0] = 0x1;
378*9a993845SKory Maincent (Dent Project) 	msg.sub[2] = id;
379*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
380*9a993845SKory Maincent (Dent Project) 	if (ret < 0)
381*9a993845SKory Maincent (Dent Project) 		return ret;
382*9a993845SKory Maincent (Dent Project) 
383*9a993845SKory Maincent (Dent Project) 	priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
384*9a993845SKory Maincent (Dent Project) 
385*9a993845SKory Maincent (Dent Project) 	return 0;
386*9a993845SKory Maincent (Dent Project) }
387*9a993845SKory Maincent (Dent Project) 
388*9a993845SKory Maincent (Dent Project) static int pd692x0_pi_disable(struct pse_controller_dev *pcdev, int id)
389*9a993845SKory Maincent (Dent Project) {
390*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
391*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg msg, buf = {0};
392*9a993845SKory Maincent (Dent Project) 	int ret;
393*9a993845SKory Maincent (Dent Project) 
394*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_fw_unavailable(priv);
395*9a993845SKory Maincent (Dent Project) 	if (ret)
396*9a993845SKory Maincent (Dent Project) 		return ret;
397*9a993845SKory Maincent (Dent Project) 
398*9a993845SKory Maincent (Dent Project) 	if (priv->admin_state[id] == ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED)
399*9a993845SKory Maincent (Dent Project) 		return 0;
400*9a993845SKory Maincent (Dent Project) 
401*9a993845SKory Maincent (Dent Project) 	msg = pd692x0_msg_template_list[PD692X0_MSG_SET_PORT_PARAM];
402*9a993845SKory Maincent (Dent Project) 	msg.data[0] = 0x0;
403*9a993845SKory Maincent (Dent Project) 	msg.sub[2] = id;
404*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
405*9a993845SKory Maincent (Dent Project) 	if (ret < 0)
406*9a993845SKory Maincent (Dent Project) 		return ret;
407*9a993845SKory Maincent (Dent Project) 
408*9a993845SKory Maincent (Dent Project) 	priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
409*9a993845SKory Maincent (Dent Project) 
410*9a993845SKory Maincent (Dent Project) 	return 0;
411*9a993845SKory Maincent (Dent Project) }
412*9a993845SKory Maincent (Dent Project) 
413*9a993845SKory Maincent (Dent Project) static int pd692x0_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
414*9a993845SKory Maincent (Dent Project) {
415*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
416*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg msg, buf = {0};
417*9a993845SKory Maincent (Dent Project) 	int ret;
418*9a993845SKory Maincent (Dent Project) 
419*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_fw_unavailable(priv);
420*9a993845SKory Maincent (Dent Project) 	if (ret)
421*9a993845SKory Maincent (Dent Project) 		return ret;
422*9a993845SKory Maincent (Dent Project) 
423*9a993845SKory Maincent (Dent Project) 	msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
424*9a993845SKory Maincent (Dent Project) 	msg.sub[2] = id;
425*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
426*9a993845SKory Maincent (Dent Project) 	if (ret < 0)
427*9a993845SKory Maincent (Dent Project) 		return ret;
428*9a993845SKory Maincent (Dent Project) 
429*9a993845SKory Maincent (Dent Project) 	if (buf.sub[1]) {
430*9a993845SKory Maincent (Dent Project) 		priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
431*9a993845SKory Maincent (Dent Project) 		return 1;
432*9a993845SKory Maincent (Dent Project) 	} else {
433*9a993845SKory Maincent (Dent Project) 		priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
434*9a993845SKory Maincent (Dent Project) 		return 0;
435*9a993845SKory Maincent (Dent Project) 	}
436*9a993845SKory Maincent (Dent Project) }
437*9a993845SKory Maincent (Dent Project) 
438*9a993845SKory Maincent (Dent Project) static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
439*9a993845SKory Maincent (Dent Project) 				      unsigned long id,
440*9a993845SKory Maincent (Dent Project) 				      struct netlink_ext_ack *extack,
441*9a993845SKory Maincent (Dent Project) 				      struct pse_control_status *status)
442*9a993845SKory Maincent (Dent Project) {
443*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
444*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg msg, buf = {0};
445*9a993845SKory Maincent (Dent Project) 	int ret;
446*9a993845SKory Maincent (Dent Project) 
447*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_fw_unavailable(priv);
448*9a993845SKory Maincent (Dent Project) 	if (ret)
449*9a993845SKory Maincent (Dent Project) 		return ret;
450*9a993845SKory Maincent (Dent Project) 
451*9a993845SKory Maincent (Dent Project) 	msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
452*9a993845SKory Maincent (Dent Project) 	msg.sub[2] = id;
453*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
454*9a993845SKory Maincent (Dent Project) 	if (ret < 0)
455*9a993845SKory Maincent (Dent Project) 		return ret;
456*9a993845SKory Maincent (Dent Project) 
457*9a993845SKory Maincent (Dent Project) 	/* Compare Port Status (Communication Protocol Document par. 7.1) */
458*9a993845SKory Maincent (Dent Project) 	if ((buf.sub[0] & 0xf0) == 0x80 || (buf.sub[0] & 0xf0) == 0x90)
459*9a993845SKory Maincent (Dent Project) 		status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING;
460*9a993845SKory Maincent (Dent Project) 	else if (buf.sub[0] == 0x1b || buf.sub[0] == 0x22)
461*9a993845SKory Maincent (Dent Project) 		status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_SEARCHING;
462*9a993845SKory Maincent (Dent Project) 	else if (buf.sub[0] == 0x12)
463*9a993845SKory Maincent (Dent Project) 		status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_FAULT;
464*9a993845SKory Maincent (Dent Project) 	else
465*9a993845SKory Maincent (Dent Project) 		status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED;
466*9a993845SKory Maincent (Dent Project) 
467*9a993845SKory Maincent (Dent Project) 	if (buf.sub[1])
468*9a993845SKory Maincent (Dent Project) 		status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
469*9a993845SKory Maincent (Dent Project) 	else
470*9a993845SKory Maincent (Dent Project) 		status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
471*9a993845SKory Maincent (Dent Project) 
472*9a993845SKory Maincent (Dent Project) 	priv->admin_state[id] = status->c33_admin_state;
473*9a993845SKory Maincent (Dent Project) 
474*9a993845SKory Maincent (Dent Project) 	return 0;
475*9a993845SKory Maincent (Dent Project) }
476*9a993845SKory Maincent (Dent Project) 
477*9a993845SKory Maincent (Dent Project) static struct pd692x0_msg_ver pd692x0_get_sw_version(struct pd692x0_priv *priv)
478*9a993845SKory Maincent (Dent Project) {
479*9a993845SKory Maincent (Dent Project) 	struct device *dev = &priv->client->dev;
480*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg msg, buf = {0};
481*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg_ver ver = {0};
482*9a993845SKory Maincent (Dent Project) 	int ret;
483*9a993845SKory Maincent (Dent Project) 
484*9a993845SKory Maincent (Dent Project) 	msg = pd692x0_msg_template_list[PD692X0_MSG_GET_SW_VER];
485*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
486*9a993845SKory Maincent (Dent Project) 	if (ret < 0) {
487*9a993845SKory Maincent (Dent Project) 		dev_err(dev, "Failed to get PSE version (%pe)\n", ERR_PTR(ret));
488*9a993845SKory Maincent (Dent Project) 		return ver;
489*9a993845SKory Maincent (Dent Project) 	}
490*9a993845SKory Maincent (Dent Project) 
491*9a993845SKory Maincent (Dent Project) 	/* Extract version from the message */
492*9a993845SKory Maincent (Dent Project) 	ver.prod = buf.sub[2];
493*9a993845SKory Maincent (Dent Project) 	ver.maj_sw_ver = (buf.data[0] << 8 | buf.data[1]) / 100;
494*9a993845SKory Maincent (Dent Project) 	ver.min_sw_ver = ((buf.data[0] << 8 | buf.data[1]) / 10) % 10;
495*9a993845SKory Maincent (Dent Project) 	ver.pa_sw_ver = (buf.data[0] << 8 | buf.data[1]) % 10;
496*9a993845SKory Maincent (Dent Project) 	ver.param = buf.data[2];
497*9a993845SKory Maincent (Dent Project) 	ver.build = buf.data[3];
498*9a993845SKory Maincent (Dent Project) 
499*9a993845SKory Maincent (Dent Project) 	return ver;
500*9a993845SKory Maincent (Dent Project) }
501*9a993845SKory Maincent (Dent Project) 
502*9a993845SKory Maincent (Dent Project) struct pd692x0_manager {
503*9a993845SKory Maincent (Dent Project) 	struct device_node *port_node[PD692X0_MAX_MANAGER_PORTS];
504*9a993845SKory Maincent (Dent Project) 	int nports;
505*9a993845SKory Maincent (Dent Project) };
506*9a993845SKory Maincent (Dent Project) 
507*9a993845SKory Maincent (Dent Project) struct pd692x0_matrix {
508*9a993845SKory Maincent (Dent Project) 	u8 hw_port_a;
509*9a993845SKory Maincent (Dent Project) 	u8 hw_port_b;
510*9a993845SKory Maincent (Dent Project) };
511*9a993845SKory Maincent (Dent Project) 
512*9a993845SKory Maincent (Dent Project) static int
513*9a993845SKory Maincent (Dent Project) pd692x0_of_get_ports_manager(struct pd692x0_priv *priv,
514*9a993845SKory Maincent (Dent Project) 			     struct pd692x0_manager *manager,
515*9a993845SKory Maincent (Dent Project) 			     struct device_node *np)
516*9a993845SKory Maincent (Dent Project) {
517*9a993845SKory Maincent (Dent Project) 	struct device_node *node;
518*9a993845SKory Maincent (Dent Project) 	int ret, nports, i;
519*9a993845SKory Maincent (Dent Project) 
520*9a993845SKory Maincent (Dent Project) 	nports = 0;
521*9a993845SKory Maincent (Dent Project) 	for_each_child_of_node(np, node) {
522*9a993845SKory Maincent (Dent Project) 		u32 port;
523*9a993845SKory Maincent (Dent Project) 
524*9a993845SKory Maincent (Dent Project) 		if (!of_node_name_eq(node, "port"))
525*9a993845SKory Maincent (Dent Project) 			continue;
526*9a993845SKory Maincent (Dent Project) 
527*9a993845SKory Maincent (Dent Project) 		ret = of_property_read_u32(node, "reg", &port);
528*9a993845SKory Maincent (Dent Project) 		if (ret)
529*9a993845SKory Maincent (Dent Project) 			goto out;
530*9a993845SKory Maincent (Dent Project) 
531*9a993845SKory Maincent (Dent Project) 		if (port >= PD692X0_MAX_MANAGER_PORTS || port != nports) {
532*9a993845SKory Maincent (Dent Project) 			dev_err(&priv->client->dev,
533*9a993845SKory Maincent (Dent Project) 				"wrong number or order of manager ports (%d)\n",
534*9a993845SKory Maincent (Dent Project) 				port);
535*9a993845SKory Maincent (Dent Project) 			ret = -EINVAL;
536*9a993845SKory Maincent (Dent Project) 			goto out;
537*9a993845SKory Maincent (Dent Project) 		}
538*9a993845SKory Maincent (Dent Project) 
539*9a993845SKory Maincent (Dent Project) 		of_node_get(node);
540*9a993845SKory Maincent (Dent Project) 		manager->port_node[port] = node;
541*9a993845SKory Maincent (Dent Project) 		nports++;
542*9a993845SKory Maincent (Dent Project) 	}
543*9a993845SKory Maincent (Dent Project) 
544*9a993845SKory Maincent (Dent Project) 	manager->nports = nports;
545*9a993845SKory Maincent (Dent Project) 	return 0;
546*9a993845SKory Maincent (Dent Project) 
547*9a993845SKory Maincent (Dent Project) out:
548*9a993845SKory Maincent (Dent Project) 	for (i = 0; i < nports; i++) {
549*9a993845SKory Maincent (Dent Project) 		of_node_put(manager->port_node[i]);
550*9a993845SKory Maincent (Dent Project) 		manager->port_node[i] = NULL;
551*9a993845SKory Maincent (Dent Project) 	}
552*9a993845SKory Maincent (Dent Project) 	of_node_put(node);
553*9a993845SKory Maincent (Dent Project) 	return ret;
554*9a993845SKory Maincent (Dent Project) }
555*9a993845SKory Maincent (Dent Project) 
556*9a993845SKory Maincent (Dent Project) static int
557*9a993845SKory Maincent (Dent Project) pd692x0_of_get_managers(struct pd692x0_priv *priv,
558*9a993845SKory Maincent (Dent Project) 			struct pd692x0_manager manager[PD692X0_MAX_MANAGERS])
559*9a993845SKory Maincent (Dent Project) {
560*9a993845SKory Maincent (Dent Project) 	struct device_node *managers_node, *node;
561*9a993845SKory Maincent (Dent Project) 	int ret, nmanagers, i, j;
562*9a993845SKory Maincent (Dent Project) 
563*9a993845SKory Maincent (Dent Project) 	if (!priv->np)
564*9a993845SKory Maincent (Dent Project) 		return -EINVAL;
565*9a993845SKory Maincent (Dent Project) 
566*9a993845SKory Maincent (Dent Project) 	nmanagers = 0;
567*9a993845SKory Maincent (Dent Project) 	managers_node = of_get_child_by_name(priv->np, "managers");
568*9a993845SKory Maincent (Dent Project) 	if (!managers_node)
569*9a993845SKory Maincent (Dent Project) 		return -EINVAL;
570*9a993845SKory Maincent (Dent Project) 
571*9a993845SKory Maincent (Dent Project) 	for_each_child_of_node(managers_node, node) {
572*9a993845SKory Maincent (Dent Project) 		u32 manager_id;
573*9a993845SKory Maincent (Dent Project) 
574*9a993845SKory Maincent (Dent Project) 		if (!of_node_name_eq(node, "manager"))
575*9a993845SKory Maincent (Dent Project) 			continue;
576*9a993845SKory Maincent (Dent Project) 
577*9a993845SKory Maincent (Dent Project) 		ret = of_property_read_u32(node, "reg", &manager_id);
578*9a993845SKory Maincent (Dent Project) 		if (ret)
579*9a993845SKory Maincent (Dent Project) 			goto out;
580*9a993845SKory Maincent (Dent Project) 
581*9a993845SKory Maincent (Dent Project) 		if (manager_id >= PD692X0_MAX_MANAGERS ||
582*9a993845SKory Maincent (Dent Project) 		    manager_id != nmanagers) {
583*9a993845SKory Maincent (Dent Project) 			dev_err(&priv->client->dev,
584*9a993845SKory Maincent (Dent Project) 				"wrong number or order of managers (%d)\n",
585*9a993845SKory Maincent (Dent Project) 				manager_id);
586*9a993845SKory Maincent (Dent Project) 			ret = -EINVAL;
587*9a993845SKory Maincent (Dent Project) 			goto out;
588*9a993845SKory Maincent (Dent Project) 		}
589*9a993845SKory Maincent (Dent Project) 
590*9a993845SKory Maincent (Dent Project) 		ret = pd692x0_of_get_ports_manager(priv, &manager[manager_id],
591*9a993845SKory Maincent (Dent Project) 						   node);
592*9a993845SKory Maincent (Dent Project) 		if (ret)
593*9a993845SKory Maincent (Dent Project) 			goto out;
594*9a993845SKory Maincent (Dent Project) 
595*9a993845SKory Maincent (Dent Project) 		nmanagers++;
596*9a993845SKory Maincent (Dent Project) 	}
597*9a993845SKory Maincent (Dent Project) 
598*9a993845SKory Maincent (Dent Project) 	of_node_put(managers_node);
599*9a993845SKory Maincent (Dent Project) 	return nmanagers;
600*9a993845SKory Maincent (Dent Project) 
601*9a993845SKory Maincent (Dent Project) out:
602*9a993845SKory Maincent (Dent Project) 	for (i = 0; i < nmanagers; i++) {
603*9a993845SKory Maincent (Dent Project) 		for (j = 0; j < manager[i].nports; j++) {
604*9a993845SKory Maincent (Dent Project) 			of_node_put(manager[i].port_node[j]);
605*9a993845SKory Maincent (Dent Project) 			manager[i].port_node[j] = NULL;
606*9a993845SKory Maincent (Dent Project) 		}
607*9a993845SKory Maincent (Dent Project) 	}
608*9a993845SKory Maincent (Dent Project) 
609*9a993845SKory Maincent (Dent Project) 	of_node_put(node);
610*9a993845SKory Maincent (Dent Project) 	of_node_put(managers_node);
611*9a993845SKory Maincent (Dent Project) 	return ret;
612*9a993845SKory Maincent (Dent Project) }
613*9a993845SKory Maincent (Dent Project) 
614*9a993845SKory Maincent (Dent Project) static int
615*9a993845SKory Maincent (Dent Project) pd692x0_set_port_matrix(const struct pse_pi_pairset *pairset,
616*9a993845SKory Maincent (Dent Project) 			const struct pd692x0_manager *manager,
617*9a993845SKory Maincent (Dent Project) 			int nmanagers, struct pd692x0_matrix *port_matrix)
618*9a993845SKory Maincent (Dent Project) {
619*9a993845SKory Maincent (Dent Project) 	int i, j, port_cnt;
620*9a993845SKory Maincent (Dent Project) 	bool found = false;
621*9a993845SKory Maincent (Dent Project) 
622*9a993845SKory Maincent (Dent Project) 	if (!pairset->np)
623*9a993845SKory Maincent (Dent Project) 		return 0;
624*9a993845SKory Maincent (Dent Project) 
625*9a993845SKory Maincent (Dent Project) 	/* Look on every managers */
626*9a993845SKory Maincent (Dent Project) 	port_cnt = 0;
627*9a993845SKory Maincent (Dent Project) 	for (i = 0; i < nmanagers; i++) {
628*9a993845SKory Maincent (Dent Project) 		/* Look on every ports of the manager */
629*9a993845SKory Maincent (Dent Project) 		for (j = 0; j < manager[i].nports; j++) {
630*9a993845SKory Maincent (Dent Project) 			if (pairset->np == manager[i].port_node[j]) {
631*9a993845SKory Maincent (Dent Project) 				found = true;
632*9a993845SKory Maincent (Dent Project) 				break;
633*9a993845SKory Maincent (Dent Project) 			}
634*9a993845SKory Maincent (Dent Project) 		}
635*9a993845SKory Maincent (Dent Project) 		port_cnt += j;
636*9a993845SKory Maincent (Dent Project) 
637*9a993845SKory Maincent (Dent Project) 		if (found)
638*9a993845SKory Maincent (Dent Project) 			break;
639*9a993845SKory Maincent (Dent Project) 	}
640*9a993845SKory Maincent (Dent Project) 
641*9a993845SKory Maincent (Dent Project) 	if (!found)
642*9a993845SKory Maincent (Dent Project) 		return -ENODEV;
643*9a993845SKory Maincent (Dent Project) 
644*9a993845SKory Maincent (Dent Project) 	if (pairset->pinout == ALTERNATIVE_A)
645*9a993845SKory Maincent (Dent Project) 		port_matrix->hw_port_a = port_cnt;
646*9a993845SKory Maincent (Dent Project) 	else if (pairset->pinout == ALTERNATIVE_B)
647*9a993845SKory Maincent (Dent Project) 		port_matrix->hw_port_b = port_cnt;
648*9a993845SKory Maincent (Dent Project) 
649*9a993845SKory Maincent (Dent Project) 	return 0;
650*9a993845SKory Maincent (Dent Project) }
651*9a993845SKory Maincent (Dent Project) 
652*9a993845SKory Maincent (Dent Project) static int
653*9a993845SKory Maincent (Dent Project) pd692x0_set_ports_matrix(struct pd692x0_priv *priv,
654*9a993845SKory Maincent (Dent Project) 			 const struct pd692x0_manager *manager,
655*9a993845SKory Maincent (Dent Project) 			 int nmanagers,
656*9a993845SKory Maincent (Dent Project) 			 struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS])
657*9a993845SKory Maincent (Dent Project) {
658*9a993845SKory Maincent (Dent Project) 	struct pse_controller_dev *pcdev = &priv->pcdev;
659*9a993845SKory Maincent (Dent Project) 	int i, ret;
660*9a993845SKory Maincent (Dent Project) 
661*9a993845SKory Maincent (Dent Project) 	/* Init Matrix */
662*9a993845SKory Maincent (Dent Project) 	for (i = 0; i < PD692X0_MAX_PIS; i++) {
663*9a993845SKory Maincent (Dent Project) 		port_matrix[i].hw_port_a = 0xff;
664*9a993845SKory Maincent (Dent Project) 		port_matrix[i].hw_port_b = 0xff;
665*9a993845SKory Maincent (Dent Project) 	}
666*9a993845SKory Maincent (Dent Project) 
667*9a993845SKory Maincent (Dent Project) 	/* Update with values for every PSE PIs */
668*9a993845SKory Maincent (Dent Project) 	for (i = 0; i < pcdev->nr_lines; i++) {
669*9a993845SKory Maincent (Dent Project) 		ret = pd692x0_set_port_matrix(&pcdev->pi[i].pairset[0],
670*9a993845SKory Maincent (Dent Project) 					      manager, nmanagers,
671*9a993845SKory Maincent (Dent Project) 					      &port_matrix[i]);
672*9a993845SKory Maincent (Dent Project) 		if (ret) {
673*9a993845SKory Maincent (Dent Project) 			dev_err(&priv->client->dev,
674*9a993845SKory Maincent (Dent Project) 				"unable to configure pi %d pairset 0", i);
675*9a993845SKory Maincent (Dent Project) 			return ret;
676*9a993845SKory Maincent (Dent Project) 		}
677*9a993845SKory Maincent (Dent Project) 
678*9a993845SKory Maincent (Dent Project) 		ret = pd692x0_set_port_matrix(&pcdev->pi[i].pairset[1],
679*9a993845SKory Maincent (Dent Project) 					      manager, nmanagers,
680*9a993845SKory Maincent (Dent Project) 					      &port_matrix[i]);
681*9a993845SKory Maincent (Dent Project) 		if (ret) {
682*9a993845SKory Maincent (Dent Project) 			dev_err(&priv->client->dev,
683*9a993845SKory Maincent (Dent Project) 				"unable to configure pi %d pairset 1", i);
684*9a993845SKory Maincent (Dent Project) 			return ret;
685*9a993845SKory Maincent (Dent Project) 		}
686*9a993845SKory Maincent (Dent Project) 	}
687*9a993845SKory Maincent (Dent Project) 
688*9a993845SKory Maincent (Dent Project) 	return 0;
689*9a993845SKory Maincent (Dent Project) }
690*9a993845SKory Maincent (Dent Project) 
691*9a993845SKory Maincent (Dent Project) static int
692*9a993845SKory Maincent (Dent Project) pd692x0_write_ports_matrix(struct pd692x0_priv *priv,
693*9a993845SKory Maincent (Dent Project) 			   const struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS])
694*9a993845SKory Maincent (Dent Project) {
695*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg msg, buf;
696*9a993845SKory Maincent (Dent Project) 	int ret, i;
697*9a993845SKory Maincent (Dent Project) 
698*9a993845SKory Maincent (Dent Project) 	/* Write temporary Matrix */
699*9a993845SKory Maincent (Dent Project) 	msg = pd692x0_msg_template_list[PD692X0_MSG_SET_TMP_PORT_MATRIX];
700*9a993845SKory Maincent (Dent Project) 	for (i = 0; i < PD692X0_MAX_PIS; i++) {
701*9a993845SKory Maincent (Dent Project) 		msg.sub[2] = i;
702*9a993845SKory Maincent (Dent Project) 		msg.data[0] = port_matrix[i].hw_port_b;
703*9a993845SKory Maincent (Dent Project) 		msg.data[1] = port_matrix[i].hw_port_a;
704*9a993845SKory Maincent (Dent Project) 
705*9a993845SKory Maincent (Dent Project) 		ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
706*9a993845SKory Maincent (Dent Project) 		if (ret < 0)
707*9a993845SKory Maincent (Dent Project) 			return ret;
708*9a993845SKory Maincent (Dent Project) 	}
709*9a993845SKory Maincent (Dent Project) 
710*9a993845SKory Maincent (Dent Project) 	/* Program Matrix */
711*9a993845SKory Maincent (Dent Project) 	msg = pd692x0_msg_template_list[PD692X0_MSG_PRG_PORT_MATRIX];
712*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
713*9a993845SKory Maincent (Dent Project) 	if (ret < 0)
714*9a993845SKory Maincent (Dent Project) 		return ret;
715*9a993845SKory Maincent (Dent Project) 
716*9a993845SKory Maincent (Dent Project) 	return 0;
717*9a993845SKory Maincent (Dent Project) }
718*9a993845SKory Maincent (Dent Project) 
719*9a993845SKory Maincent (Dent Project) static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev)
720*9a993845SKory Maincent (Dent Project) {
721*9a993845SKory Maincent (Dent Project) 	struct pd692x0_manager manager[PD692X0_MAX_MANAGERS] = {0};
722*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
723*9a993845SKory Maincent (Dent Project) 	struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS];
724*9a993845SKory Maincent (Dent Project) 	int ret, i, j, nmanagers;
725*9a993845SKory Maincent (Dent Project) 
726*9a993845SKory Maincent (Dent Project) 	/* Should we flash the port matrix */
727*9a993845SKory Maincent (Dent Project) 	if (priv->fw_state != PD692X0_FW_OK &&
728*9a993845SKory Maincent (Dent Project) 	    priv->fw_state != PD692X0_FW_COMPLETE)
729*9a993845SKory Maincent (Dent Project) 		return 0;
730*9a993845SKory Maincent (Dent Project) 
731*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_of_get_managers(priv, manager);
732*9a993845SKory Maincent (Dent Project) 	if (ret < 0)
733*9a993845SKory Maincent (Dent Project) 		return ret;
734*9a993845SKory Maincent (Dent Project) 
735*9a993845SKory Maincent (Dent Project) 	nmanagers = ret;
736*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_set_ports_matrix(priv, manager, nmanagers, port_matrix);
737*9a993845SKory Maincent (Dent Project) 	if (ret)
738*9a993845SKory Maincent (Dent Project) 		goto out;
739*9a993845SKory Maincent (Dent Project) 
740*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_write_ports_matrix(priv, port_matrix);
741*9a993845SKory Maincent (Dent Project) 	if (ret)
742*9a993845SKory Maincent (Dent Project) 		goto out;
743*9a993845SKory Maincent (Dent Project) 
744*9a993845SKory Maincent (Dent Project) out:
745*9a993845SKory Maincent (Dent Project) 	for (i = 0; i < nmanagers; i++) {
746*9a993845SKory Maincent (Dent Project) 		for (j = 0; j < manager[i].nports; j++)
747*9a993845SKory Maincent (Dent Project) 			of_node_put(manager[i].port_node[j]);
748*9a993845SKory Maincent (Dent Project) 	}
749*9a993845SKory Maincent (Dent Project) 	return ret;
750*9a993845SKory Maincent (Dent Project) }
751*9a993845SKory Maincent (Dent Project) 
752*9a993845SKory Maincent (Dent Project) static const struct pse_controller_ops pd692x0_ops = {
753*9a993845SKory Maincent (Dent Project) 	.setup_pi_matrix = pd692x0_setup_pi_matrix,
754*9a993845SKory Maincent (Dent Project) 	.ethtool_get_status = pd692x0_ethtool_get_status,
755*9a993845SKory Maincent (Dent Project) 	.pi_enable = pd692x0_pi_enable,
756*9a993845SKory Maincent (Dent Project) 	.pi_disable = pd692x0_pi_disable,
757*9a993845SKory Maincent (Dent Project) 	.pi_is_enabled = pd692x0_pi_is_enabled,
758*9a993845SKory Maincent (Dent Project) };
759*9a993845SKory Maincent (Dent Project) 
760*9a993845SKory Maincent (Dent Project) #define PD692X0_FW_LINE_MAX_SZ 0xff
761*9a993845SKory Maincent (Dent Project) static int pd692x0_fw_get_next_line(const u8 *data,
762*9a993845SKory Maincent (Dent Project) 				    char *line, size_t size)
763*9a993845SKory Maincent (Dent Project) {
764*9a993845SKory Maincent (Dent Project) 	size_t line_size;
765*9a993845SKory Maincent (Dent Project) 	int i;
766*9a993845SKory Maincent (Dent Project) 
767*9a993845SKory Maincent (Dent Project) 	line_size = min_t(size_t, size, PD692X0_FW_LINE_MAX_SZ);
768*9a993845SKory Maincent (Dent Project) 
769*9a993845SKory Maincent (Dent Project) 	memset(line, 0, PD692X0_FW_LINE_MAX_SZ);
770*9a993845SKory Maincent (Dent Project) 	for (i = 0; i < line_size - 1; i++) {
771*9a993845SKory Maincent (Dent Project) 		if (*data == '\r' && *(data + 1) == '\n') {
772*9a993845SKory Maincent (Dent Project) 			line[i] = '\r';
773*9a993845SKory Maincent (Dent Project) 			line[i + 1] = '\n';
774*9a993845SKory Maincent (Dent Project) 			return i + 2;
775*9a993845SKory Maincent (Dent Project) 		}
776*9a993845SKory Maincent (Dent Project) 		line[i] = *data;
777*9a993845SKory Maincent (Dent Project) 		data++;
778*9a993845SKory Maincent (Dent Project) 	}
779*9a993845SKory Maincent (Dent Project) 
780*9a993845SKory Maincent (Dent Project) 	return -EIO;
781*9a993845SKory Maincent (Dent Project) }
782*9a993845SKory Maincent (Dent Project) 
783*9a993845SKory Maincent (Dent Project) static enum fw_upload_err
784*9a993845SKory Maincent (Dent Project) pd692x0_fw_recv_resp(const struct i2c_client *client, unsigned long ms_timeout,
785*9a993845SKory Maincent (Dent Project) 		     const char *msg_ok, unsigned int msg_size)
786*9a993845SKory Maincent (Dent Project) {
787*9a993845SKory Maincent (Dent Project) 	/* Maximum controller response size */
788*9a993845SKory Maincent (Dent Project) 	char fw_msg_buf[5] = {0};
789*9a993845SKory Maincent (Dent Project) 	unsigned long timeout;
790*9a993845SKory Maincent (Dent Project) 	int ret;
791*9a993845SKory Maincent (Dent Project) 
792*9a993845SKory Maincent (Dent Project) 	if (msg_size > sizeof(fw_msg_buf))
793*9a993845SKory Maincent (Dent Project) 		return FW_UPLOAD_ERR_RW_ERROR;
794*9a993845SKory Maincent (Dent Project) 
795*9a993845SKory Maincent (Dent Project) 	/* Read until we get something */
796*9a993845SKory Maincent (Dent Project) 	timeout = msecs_to_jiffies(ms_timeout) + jiffies;
797*9a993845SKory Maincent (Dent Project) 	while (true) {
798*9a993845SKory Maincent (Dent Project) 		if (time_is_before_jiffies(timeout))
799*9a993845SKory Maincent (Dent Project) 			return FW_UPLOAD_ERR_TIMEOUT;
800*9a993845SKory Maincent (Dent Project) 
801*9a993845SKory Maincent (Dent Project) 		ret = i2c_master_recv(client, fw_msg_buf, 1);
802*9a993845SKory Maincent (Dent Project) 		if (ret < 0 || *fw_msg_buf == 0) {
803*9a993845SKory Maincent (Dent Project) 			usleep_range(1000, 2000);
804*9a993845SKory Maincent (Dent Project) 			continue;
805*9a993845SKory Maincent (Dent Project) 		} else {
806*9a993845SKory Maincent (Dent Project) 			break;
807*9a993845SKory Maincent (Dent Project) 		}
808*9a993845SKory Maincent (Dent Project) 	}
809*9a993845SKory Maincent (Dent Project) 
810*9a993845SKory Maincent (Dent Project) 	/* Read remaining characters */
811*9a993845SKory Maincent (Dent Project) 	ret = i2c_master_recv(client, fw_msg_buf + 1, msg_size - 1);
812*9a993845SKory Maincent (Dent Project) 	if (strncmp(fw_msg_buf, msg_ok, msg_size)) {
813*9a993845SKory Maincent (Dent Project) 		dev_err(&client->dev,
814*9a993845SKory Maincent (Dent Project) 			"Wrong FW download process answer (%*pE)\n",
815*9a993845SKory Maincent (Dent Project) 			msg_size, fw_msg_buf);
816*9a993845SKory Maincent (Dent Project) 		return FW_UPLOAD_ERR_HW_ERROR;
817*9a993845SKory Maincent (Dent Project) 	}
818*9a993845SKory Maincent (Dent Project) 
819*9a993845SKory Maincent (Dent Project) 	return FW_UPLOAD_ERR_NONE;
820*9a993845SKory Maincent (Dent Project) }
821*9a993845SKory Maincent (Dent Project) 
822*9a993845SKory Maincent (Dent Project) static int pd692x0_fw_write_line(const struct i2c_client *client,
823*9a993845SKory Maincent (Dent Project) 				 const char line[PD692X0_FW_LINE_MAX_SZ],
824*9a993845SKory Maincent (Dent Project) 				 const bool last_line)
825*9a993845SKory Maincent (Dent Project) {
826*9a993845SKory Maincent (Dent Project) 	int ret;
827*9a993845SKory Maincent (Dent Project) 
828*9a993845SKory Maincent (Dent Project) 	while (*line != 0) {
829*9a993845SKory Maincent (Dent Project) 		ret = i2c_master_send(client, line, 1);
830*9a993845SKory Maincent (Dent Project) 		if (ret < 0)
831*9a993845SKory Maincent (Dent Project) 			return FW_UPLOAD_ERR_RW_ERROR;
832*9a993845SKory Maincent (Dent Project) 		line++;
833*9a993845SKory Maincent (Dent Project) 	}
834*9a993845SKory Maincent (Dent Project) 
835*9a993845SKory Maincent (Dent Project) 	if (last_line) {
836*9a993845SKory Maincent (Dent Project) 		ret = pd692x0_fw_recv_resp(client, 100, "TP\r\n",
837*9a993845SKory Maincent (Dent Project) 					   sizeof("TP\r\n") - 1);
838*9a993845SKory Maincent (Dent Project) 		if (ret)
839*9a993845SKory Maincent (Dent Project) 			return ret;
840*9a993845SKory Maincent (Dent Project) 	} else {
841*9a993845SKory Maincent (Dent Project) 		ret = pd692x0_fw_recv_resp(client, 100, "T*\r\n",
842*9a993845SKory Maincent (Dent Project) 					   sizeof("T*\r\n") - 1);
843*9a993845SKory Maincent (Dent Project) 		if (ret)
844*9a993845SKory Maincent (Dent Project) 			return ret;
845*9a993845SKory Maincent (Dent Project) 	}
846*9a993845SKory Maincent (Dent Project) 
847*9a993845SKory Maincent (Dent Project) 	return FW_UPLOAD_ERR_NONE;
848*9a993845SKory Maincent (Dent Project) }
849*9a993845SKory Maincent (Dent Project) 
850*9a993845SKory Maincent (Dent Project) static enum fw_upload_err pd692x0_fw_reset(const struct i2c_client *client)
851*9a993845SKory Maincent (Dent Project) {
852*9a993845SKory Maincent (Dent Project) 	const struct pd692x0_msg zero = {0};
853*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg buf = {0};
854*9a993845SKory Maincent (Dent Project) 	unsigned long timeout;
855*9a993845SKory Maincent (Dent Project) 	char cmd[] = "RST";
856*9a993845SKory Maincent (Dent Project) 	int ret;
857*9a993845SKory Maincent (Dent Project) 
858*9a993845SKory Maincent (Dent Project) 	ret = i2c_master_send(client, cmd, strlen(cmd));
859*9a993845SKory Maincent (Dent Project) 	if (ret < 0) {
860*9a993845SKory Maincent (Dent Project) 		dev_err(&client->dev,
861*9a993845SKory Maincent (Dent Project) 			"Failed to reset the controller (%pe)\n",
862*9a993845SKory Maincent (Dent Project) 			ERR_PTR(ret));
863*9a993845SKory Maincent (Dent Project) 		return ret;
864*9a993845SKory Maincent (Dent Project) 	}
865*9a993845SKory Maincent (Dent Project) 
866*9a993845SKory Maincent (Dent Project) 	timeout = msecs_to_jiffies(10000) + jiffies;
867*9a993845SKory Maincent (Dent Project) 	while (true) {
868*9a993845SKory Maincent (Dent Project) 		if (time_is_before_jiffies(timeout))
869*9a993845SKory Maincent (Dent Project) 			return FW_UPLOAD_ERR_TIMEOUT;
870*9a993845SKory Maincent (Dent Project) 
871*9a993845SKory Maincent (Dent Project) 		ret = i2c_master_recv(client, (u8 *)&buf, sizeof(buf));
872*9a993845SKory Maincent (Dent Project) 		if (ret < 0 ||
873*9a993845SKory Maincent (Dent Project) 		    !memcmp(&buf, &zero, sizeof(buf)))
874*9a993845SKory Maincent (Dent Project) 			usleep_range(1000, 2000);
875*9a993845SKory Maincent (Dent Project) 		else
876*9a993845SKory Maincent (Dent Project) 			break;
877*9a993845SKory Maincent (Dent Project) 	}
878*9a993845SKory Maincent (Dent Project) 
879*9a993845SKory Maincent (Dent Project) 	/* Is the reply a successful report message */
880*9a993845SKory Maincent (Dent Project) 	if (buf.key != PD692X0_KEY_TLM || buf.echo != 0xff ||
881*9a993845SKory Maincent (Dent Project) 	    buf.sub[0] & 0x01) {
882*9a993845SKory Maincent (Dent Project) 		dev_err(&client->dev, "PSE controller error\n");
883*9a993845SKory Maincent (Dent Project) 		return FW_UPLOAD_ERR_HW_ERROR;
884*9a993845SKory Maincent (Dent Project) 	}
885*9a993845SKory Maincent (Dent Project) 
886*9a993845SKory Maincent (Dent Project) 	/* Is the firmware operational */
887*9a993845SKory Maincent (Dent Project) 	if (buf.sub[0] & 0x02) {
888*9a993845SKory Maincent (Dent Project) 		dev_err(&client->dev,
889*9a993845SKory Maincent (Dent Project) 			"PSE firmware error. Please update it.\n");
890*9a993845SKory Maincent (Dent Project) 		return FW_UPLOAD_ERR_HW_ERROR;
891*9a993845SKory Maincent (Dent Project) 	}
892*9a993845SKory Maincent (Dent Project) 
893*9a993845SKory Maincent (Dent Project) 	return FW_UPLOAD_ERR_NONE;
894*9a993845SKory Maincent (Dent Project) }
895*9a993845SKory Maincent (Dent Project) 
896*9a993845SKory Maincent (Dent Project) static enum fw_upload_err pd692x0_fw_prepare(struct fw_upload *fwl,
897*9a993845SKory Maincent (Dent Project) 					     const u8 *data, u32 size)
898*9a993845SKory Maincent (Dent Project) {
899*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = fwl->dd_handle;
900*9a993845SKory Maincent (Dent Project) 	const struct i2c_client *client = priv->client;
901*9a993845SKory Maincent (Dent Project) 	enum pd692x0_fw_state last_fw_state;
902*9a993845SKory Maincent (Dent Project) 	int ret;
903*9a993845SKory Maincent (Dent Project) 
904*9a993845SKory Maincent (Dent Project) 	priv->cancel_request = false;
905*9a993845SKory Maincent (Dent Project) 	last_fw_state = priv->fw_state;
906*9a993845SKory Maincent (Dent Project) 
907*9a993845SKory Maincent (Dent Project) 	priv->fw_state = PD692X0_FW_PREPARE;
908*9a993845SKory Maincent (Dent Project) 
909*9a993845SKory Maincent (Dent Project) 	/* Enter program mode */
910*9a993845SKory Maincent (Dent Project) 	if (last_fw_state == PD692X0_FW_BROKEN) {
911*9a993845SKory Maincent (Dent Project) 		const char *msg = "ENTR";
912*9a993845SKory Maincent (Dent Project) 		const char *c;
913*9a993845SKory Maincent (Dent Project) 
914*9a993845SKory Maincent (Dent Project) 		c = msg;
915*9a993845SKory Maincent (Dent Project) 		do {
916*9a993845SKory Maincent (Dent Project) 			ret = i2c_master_send(client, c, 1);
917*9a993845SKory Maincent (Dent Project) 			if (ret < 0)
918*9a993845SKory Maincent (Dent Project) 				return FW_UPLOAD_ERR_RW_ERROR;
919*9a993845SKory Maincent (Dent Project) 			if (*(c + 1))
920*9a993845SKory Maincent (Dent Project) 				usleep_range(10000, 20000);
921*9a993845SKory Maincent (Dent Project) 		} while (*(++c));
922*9a993845SKory Maincent (Dent Project) 	} else {
923*9a993845SKory Maincent (Dent Project) 		struct pd692x0_msg msg, buf;
924*9a993845SKory Maincent (Dent Project) 
925*9a993845SKory Maincent (Dent Project) 		msg = pd692x0_msg_template_list[PD692X0_MSG_DOWNLOAD_CMD];
926*9a993845SKory Maincent (Dent Project) 		ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
927*9a993845SKory Maincent (Dent Project) 		if (ret < 0) {
928*9a993845SKory Maincent (Dent Project) 			dev_err(&client->dev,
929*9a993845SKory Maincent (Dent Project) 				"Failed to enter programming mode (%pe)\n",
930*9a993845SKory Maincent (Dent Project) 				ERR_PTR(ret));
931*9a993845SKory Maincent (Dent Project) 			return FW_UPLOAD_ERR_RW_ERROR;
932*9a993845SKory Maincent (Dent Project) 		}
933*9a993845SKory Maincent (Dent Project) 	}
934*9a993845SKory Maincent (Dent Project) 
935*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_fw_recv_resp(client, 100, "TPE\r\n", sizeof("TPE\r\n") - 1);
936*9a993845SKory Maincent (Dent Project) 	if (ret)
937*9a993845SKory Maincent (Dent Project) 		goto err_out;
938*9a993845SKory Maincent (Dent Project) 
939*9a993845SKory Maincent (Dent Project) 	if (priv->cancel_request) {
940*9a993845SKory Maincent (Dent Project) 		ret = FW_UPLOAD_ERR_CANCELED;
941*9a993845SKory Maincent (Dent Project) 		goto err_out;
942*9a993845SKory Maincent (Dent Project) 	}
943*9a993845SKory Maincent (Dent Project) 
944*9a993845SKory Maincent (Dent Project) 	return FW_UPLOAD_ERR_NONE;
945*9a993845SKory Maincent (Dent Project) 
946*9a993845SKory Maincent (Dent Project) err_out:
947*9a993845SKory Maincent (Dent Project) 	pd692x0_fw_reset(priv->client);
948*9a993845SKory Maincent (Dent Project) 	priv->fw_state = last_fw_state;
949*9a993845SKory Maincent (Dent Project) 	return ret;
950*9a993845SKory Maincent (Dent Project) }
951*9a993845SKory Maincent (Dent Project) 
952*9a993845SKory Maincent (Dent Project) static enum fw_upload_err pd692x0_fw_write(struct fw_upload *fwl,
953*9a993845SKory Maincent (Dent Project) 					   const u8 *data, u32 offset,
954*9a993845SKory Maincent (Dent Project) 					   u32 size, u32 *written)
955*9a993845SKory Maincent (Dent Project) {
956*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = fwl->dd_handle;
957*9a993845SKory Maincent (Dent Project) 	char line[PD692X0_FW_LINE_MAX_SZ];
958*9a993845SKory Maincent (Dent Project) 	const struct i2c_client *client;
959*9a993845SKory Maincent (Dent Project) 	int ret, i;
960*9a993845SKory Maincent (Dent Project) 	char cmd;
961*9a993845SKory Maincent (Dent Project) 
962*9a993845SKory Maincent (Dent Project) 	client = priv->client;
963*9a993845SKory Maincent (Dent Project) 	priv->fw_state = PD692X0_FW_WRITE;
964*9a993845SKory Maincent (Dent Project) 
965*9a993845SKory Maincent (Dent Project) 	/* Erase */
966*9a993845SKory Maincent (Dent Project) 	cmd = 'E';
967*9a993845SKory Maincent (Dent Project) 	ret = i2c_master_send(client, &cmd, 1);
968*9a993845SKory Maincent (Dent Project) 	if (ret < 0) {
969*9a993845SKory Maincent (Dent Project) 		dev_err(&client->dev,
970*9a993845SKory Maincent (Dent Project) 			"Failed to boot programming mode (%pe)\n",
971*9a993845SKory Maincent (Dent Project) 			ERR_PTR(ret));
972*9a993845SKory Maincent (Dent Project) 		return FW_UPLOAD_ERR_RW_ERROR;
973*9a993845SKory Maincent (Dent Project) 	}
974*9a993845SKory Maincent (Dent Project) 
975*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_fw_recv_resp(client, 100, "TOE\r\n", sizeof("TOE\r\n") - 1);
976*9a993845SKory Maincent (Dent Project) 	if (ret)
977*9a993845SKory Maincent (Dent Project) 		return ret;
978*9a993845SKory Maincent (Dent Project) 
979*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_fw_recv_resp(client, 5000, "TE\r\n", sizeof("TE\r\n") - 1);
980*9a993845SKory Maincent (Dent Project) 	if (ret)
981*9a993845SKory Maincent (Dent Project) 		dev_warn(&client->dev,
982*9a993845SKory Maincent (Dent Project) 			 "Failed to erase internal memory, however still try to write Firmware\n");
983*9a993845SKory Maincent (Dent Project) 
984*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_fw_recv_resp(client, 100, "TPE\r\n", sizeof("TPE\r\n") - 1);
985*9a993845SKory Maincent (Dent Project) 	if (ret)
986*9a993845SKory Maincent (Dent Project) 		dev_warn(&client->dev,
987*9a993845SKory Maincent (Dent Project) 			 "Failed to erase internal memory, however still try to write Firmware\n");
988*9a993845SKory Maincent (Dent Project) 
989*9a993845SKory Maincent (Dent Project) 	if (priv->cancel_request)
990*9a993845SKory Maincent (Dent Project) 		return FW_UPLOAD_ERR_CANCELED;
991*9a993845SKory Maincent (Dent Project) 
992*9a993845SKory Maincent (Dent Project) 	/* Program */
993*9a993845SKory Maincent (Dent Project) 	cmd = 'P';
994*9a993845SKory Maincent (Dent Project) 	ret = i2c_master_send(client, &cmd, sizeof(char));
995*9a993845SKory Maincent (Dent Project) 	if (ret < 0) {
996*9a993845SKory Maincent (Dent Project) 		dev_err(&client->dev,
997*9a993845SKory Maincent (Dent Project) 			"Failed to boot programming mode (%pe)\n",
998*9a993845SKory Maincent (Dent Project) 			ERR_PTR(ret));
999*9a993845SKory Maincent (Dent Project) 		return ret;
1000*9a993845SKory Maincent (Dent Project) 	}
1001*9a993845SKory Maincent (Dent Project) 
1002*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_fw_recv_resp(client, 100, "TOP\r\n", sizeof("TOP\r\n") - 1);
1003*9a993845SKory Maincent (Dent Project) 	if (ret)
1004*9a993845SKory Maincent (Dent Project) 		return ret;
1005*9a993845SKory Maincent (Dent Project) 
1006*9a993845SKory Maincent (Dent Project) 	i = 0;
1007*9a993845SKory Maincent (Dent Project) 	while (i < size) {
1008*9a993845SKory Maincent (Dent Project) 		ret = pd692x0_fw_get_next_line(data, line, size - i);
1009*9a993845SKory Maincent (Dent Project) 		if (ret < 0) {
1010*9a993845SKory Maincent (Dent Project) 			ret = FW_UPLOAD_ERR_FW_INVALID;
1011*9a993845SKory Maincent (Dent Project) 			goto err;
1012*9a993845SKory Maincent (Dent Project) 		}
1013*9a993845SKory Maincent (Dent Project) 
1014*9a993845SKory Maincent (Dent Project) 		i += ret;
1015*9a993845SKory Maincent (Dent Project) 		data += ret;
1016*9a993845SKory Maincent (Dent Project) 		if (line[0] == 'S' && line[1] == '0') {
1017*9a993845SKory Maincent (Dent Project) 			continue;
1018*9a993845SKory Maincent (Dent Project) 		} else if (line[0] == 'S' && line[1] == '7') {
1019*9a993845SKory Maincent (Dent Project) 			ret = pd692x0_fw_write_line(client, line, true);
1020*9a993845SKory Maincent (Dent Project) 			if (ret)
1021*9a993845SKory Maincent (Dent Project) 				goto err;
1022*9a993845SKory Maincent (Dent Project) 		} else {
1023*9a993845SKory Maincent (Dent Project) 			ret = pd692x0_fw_write_line(client, line, false);
1024*9a993845SKory Maincent (Dent Project) 			if (ret)
1025*9a993845SKory Maincent (Dent Project) 				goto err;
1026*9a993845SKory Maincent (Dent Project) 		}
1027*9a993845SKory Maincent (Dent Project) 
1028*9a993845SKory Maincent (Dent Project) 		if (priv->cancel_request) {
1029*9a993845SKory Maincent (Dent Project) 			ret = FW_UPLOAD_ERR_CANCELED;
1030*9a993845SKory Maincent (Dent Project) 			goto err;
1031*9a993845SKory Maincent (Dent Project) 		}
1032*9a993845SKory Maincent (Dent Project) 	}
1033*9a993845SKory Maincent (Dent Project) 	*written = i;
1034*9a993845SKory Maincent (Dent Project) 
1035*9a993845SKory Maincent (Dent Project) 	msleep(400);
1036*9a993845SKory Maincent (Dent Project) 
1037*9a993845SKory Maincent (Dent Project) 	return FW_UPLOAD_ERR_NONE;
1038*9a993845SKory Maincent (Dent Project) 
1039*9a993845SKory Maincent (Dent Project) err:
1040*9a993845SKory Maincent (Dent Project) 	strscpy_pad(line, "S7\r\n", sizeof(line));
1041*9a993845SKory Maincent (Dent Project) 	pd692x0_fw_write_line(client, line, true);
1042*9a993845SKory Maincent (Dent Project) 	return ret;
1043*9a993845SKory Maincent (Dent Project) }
1044*9a993845SKory Maincent (Dent Project) 
1045*9a993845SKory Maincent (Dent Project) static enum fw_upload_err pd692x0_fw_poll_complete(struct fw_upload *fwl)
1046*9a993845SKory Maincent (Dent Project) {
1047*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = fwl->dd_handle;
1048*9a993845SKory Maincent (Dent Project) 	const struct i2c_client *client = priv->client;
1049*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg_ver ver;
1050*9a993845SKory Maincent (Dent Project) 	int ret;
1051*9a993845SKory Maincent (Dent Project) 
1052*9a993845SKory Maincent (Dent Project) 	priv->fw_state = PD692X0_FW_COMPLETE;
1053*9a993845SKory Maincent (Dent Project) 
1054*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_fw_reset(client);
1055*9a993845SKory Maincent (Dent Project) 	if (ret)
1056*9a993845SKory Maincent (Dent Project) 		return ret;
1057*9a993845SKory Maincent (Dent Project) 
1058*9a993845SKory Maincent (Dent Project) 	ver = pd692x0_get_sw_version(priv);
1059*9a993845SKory Maincent (Dent Project) 	if (ver.maj_sw_ver < PD692X0_FW_MAJ_VER) {
1060*9a993845SKory Maincent (Dent Project) 		dev_err(&client->dev,
1061*9a993845SKory Maincent (Dent Project) 			"Too old firmware version. Please update it\n");
1062*9a993845SKory Maincent (Dent Project) 		priv->fw_state = PD692X0_FW_NEED_UPDATE;
1063*9a993845SKory Maincent (Dent Project) 		return FW_UPLOAD_ERR_FW_INVALID;
1064*9a993845SKory Maincent (Dent Project) 	}
1065*9a993845SKory Maincent (Dent Project) 
1066*9a993845SKory Maincent (Dent Project) 	ret = pd692x0_setup_pi_matrix(&priv->pcdev);
1067*9a993845SKory Maincent (Dent Project) 	if (ret < 0) {
1068*9a993845SKory Maincent (Dent Project) 		dev_err(&client->dev, "Error configuring ports matrix (%pe)\n",
1069*9a993845SKory Maincent (Dent Project) 			ERR_PTR(ret));
1070*9a993845SKory Maincent (Dent Project) 		priv->fw_state = PD692X0_FW_NEED_UPDATE;
1071*9a993845SKory Maincent (Dent Project) 		return FW_UPLOAD_ERR_HW_ERROR;
1072*9a993845SKory Maincent (Dent Project) 	}
1073*9a993845SKory Maincent (Dent Project) 
1074*9a993845SKory Maincent (Dent Project) 	priv->fw_state = PD692X0_FW_OK;
1075*9a993845SKory Maincent (Dent Project) 	return FW_UPLOAD_ERR_NONE;
1076*9a993845SKory Maincent (Dent Project) }
1077*9a993845SKory Maincent (Dent Project) 
1078*9a993845SKory Maincent (Dent Project) static void pd692x0_fw_cancel(struct fw_upload *fwl)
1079*9a993845SKory Maincent (Dent Project) {
1080*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = fwl->dd_handle;
1081*9a993845SKory Maincent (Dent Project) 
1082*9a993845SKory Maincent (Dent Project) 	priv->cancel_request = true;
1083*9a993845SKory Maincent (Dent Project) }
1084*9a993845SKory Maincent (Dent Project) 
1085*9a993845SKory Maincent (Dent Project) static void pd692x0_fw_cleanup(struct fw_upload *fwl)
1086*9a993845SKory Maincent (Dent Project) {
1087*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = fwl->dd_handle;
1088*9a993845SKory Maincent (Dent Project) 
1089*9a993845SKory Maincent (Dent Project) 	switch (priv->fw_state) {
1090*9a993845SKory Maincent (Dent Project) 	case PD692X0_FW_WRITE:
1091*9a993845SKory Maincent (Dent Project) 		pd692x0_fw_reset(priv->client);
1092*9a993845SKory Maincent (Dent Project) 		fallthrough;
1093*9a993845SKory Maincent (Dent Project) 	case PD692X0_FW_COMPLETE:
1094*9a993845SKory Maincent (Dent Project) 		priv->fw_state = PD692X0_FW_BROKEN;
1095*9a993845SKory Maincent (Dent Project) 		break;
1096*9a993845SKory Maincent (Dent Project) 	default:
1097*9a993845SKory Maincent (Dent Project) 		break;
1098*9a993845SKory Maincent (Dent Project) 	}
1099*9a993845SKory Maincent (Dent Project) }
1100*9a993845SKory Maincent (Dent Project) 
1101*9a993845SKory Maincent (Dent Project) static const struct fw_upload_ops pd692x0_fw_ops = {
1102*9a993845SKory Maincent (Dent Project) 	.prepare = pd692x0_fw_prepare,
1103*9a993845SKory Maincent (Dent Project) 	.write = pd692x0_fw_write,
1104*9a993845SKory Maincent (Dent Project) 	.poll_complete = pd692x0_fw_poll_complete,
1105*9a993845SKory Maincent (Dent Project) 	.cancel = pd692x0_fw_cancel,
1106*9a993845SKory Maincent (Dent Project) 	.cleanup = pd692x0_fw_cleanup,
1107*9a993845SKory Maincent (Dent Project) };
1108*9a993845SKory Maincent (Dent Project) 
1109*9a993845SKory Maincent (Dent Project) static int pd692x0_i2c_probe(struct i2c_client *client)
1110*9a993845SKory Maincent (Dent Project) {
1111*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg msg, buf = {0}, zero = {0};
1112*9a993845SKory Maincent (Dent Project) 	struct device *dev = &client->dev;
1113*9a993845SKory Maincent (Dent Project) 	struct pd692x0_msg_ver ver;
1114*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv;
1115*9a993845SKory Maincent (Dent Project) 	struct fw_upload *fwl;
1116*9a993845SKory Maincent (Dent Project) 	int ret;
1117*9a993845SKory Maincent (Dent Project) 
1118*9a993845SKory Maincent (Dent Project) 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
1119*9a993845SKory Maincent (Dent Project) 		dev_err(dev, "i2c check functionality failed\n");
1120*9a993845SKory Maincent (Dent Project) 		return -ENXIO;
1121*9a993845SKory Maincent (Dent Project) 	}
1122*9a993845SKory Maincent (Dent Project) 
1123*9a993845SKory Maincent (Dent Project) 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1124*9a993845SKory Maincent (Dent Project) 	if (!priv)
1125*9a993845SKory Maincent (Dent Project) 		return -ENOMEM;
1126*9a993845SKory Maincent (Dent Project) 
1127*9a993845SKory Maincent (Dent Project) 	priv->client = client;
1128*9a993845SKory Maincent (Dent Project) 	i2c_set_clientdata(client, priv);
1129*9a993845SKory Maincent (Dent Project) 
1130*9a993845SKory Maincent (Dent Project) 	ret = i2c_master_recv(client, (u8 *)&buf, sizeof(buf));
1131*9a993845SKory Maincent (Dent Project) 	if (ret != sizeof(buf)) {
1132*9a993845SKory Maincent (Dent Project) 		dev_err(dev, "Failed to get device status\n");
1133*9a993845SKory Maincent (Dent Project) 		return -EIO;
1134*9a993845SKory Maincent (Dent Project) 	}
1135*9a993845SKory Maincent (Dent Project) 
1136*9a993845SKory Maincent (Dent Project) 	/* Probe has been already run and the status dumped */
1137*9a993845SKory Maincent (Dent Project) 	if (!memcmp(&buf, &zero, sizeof(buf))) {
1138*9a993845SKory Maincent (Dent Project) 		/* Ask again the controller status */
1139*9a993845SKory Maincent (Dent Project) 		msg = pd692x0_msg_template_list[PD692X0_MSG_GET_SYS_STATUS];
1140*9a993845SKory Maincent (Dent Project) 		ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
1141*9a993845SKory Maincent (Dent Project) 		if (ret < 0) {
1142*9a993845SKory Maincent (Dent Project) 			dev_err(dev, "Failed to get device status\n");
1143*9a993845SKory Maincent (Dent Project) 			return ret;
1144*9a993845SKory Maincent (Dent Project) 		}
1145*9a993845SKory Maincent (Dent Project) 	}
1146*9a993845SKory Maincent (Dent Project) 
1147*9a993845SKory Maincent (Dent Project) 	if (buf.key != 0x03 || buf.sub[0] & 0x01) {
1148*9a993845SKory Maincent (Dent Project) 		dev_err(dev, "PSE controller error\n");
1149*9a993845SKory Maincent (Dent Project) 		return -EIO;
1150*9a993845SKory Maincent (Dent Project) 	}
1151*9a993845SKory Maincent (Dent Project) 	if (buf.sub[0] & 0x02) {
1152*9a993845SKory Maincent (Dent Project) 		dev_err(dev, "PSE firmware error. Please update it.\n");
1153*9a993845SKory Maincent (Dent Project) 		priv->fw_state = PD692X0_FW_BROKEN;
1154*9a993845SKory Maincent (Dent Project) 	} else {
1155*9a993845SKory Maincent (Dent Project) 		ver = pd692x0_get_sw_version(priv);
1156*9a993845SKory Maincent (Dent Project) 		dev_info(&client->dev, "Software version %d.%02d.%d.%d\n",
1157*9a993845SKory Maincent (Dent Project) 			 ver.prod, ver.maj_sw_ver, ver.min_sw_ver,
1158*9a993845SKory Maincent (Dent Project) 			 ver.pa_sw_ver);
1159*9a993845SKory Maincent (Dent Project) 
1160*9a993845SKory Maincent (Dent Project) 		if (ver.maj_sw_ver < PD692X0_FW_MAJ_VER) {
1161*9a993845SKory Maincent (Dent Project) 			dev_err(dev, "Too old firmware version. Please update it\n");
1162*9a993845SKory Maincent (Dent Project) 			priv->fw_state = PD692X0_FW_NEED_UPDATE;
1163*9a993845SKory Maincent (Dent Project) 		} else {
1164*9a993845SKory Maincent (Dent Project) 			priv->fw_state = PD692X0_FW_OK;
1165*9a993845SKory Maincent (Dent Project) 		}
1166*9a993845SKory Maincent (Dent Project) 	}
1167*9a993845SKory Maincent (Dent Project) 
1168*9a993845SKory Maincent (Dent Project) 	priv->np = dev->of_node;
1169*9a993845SKory Maincent (Dent Project) 	priv->pcdev.nr_lines = PD692X0_MAX_PIS;
1170*9a993845SKory Maincent (Dent Project) 	priv->pcdev.owner = THIS_MODULE;
1171*9a993845SKory Maincent (Dent Project) 	priv->pcdev.ops = &pd692x0_ops;
1172*9a993845SKory Maincent (Dent Project) 	priv->pcdev.dev = dev;
1173*9a993845SKory Maincent (Dent Project) 	priv->pcdev.types = ETHTOOL_PSE_C33;
1174*9a993845SKory Maincent (Dent Project) 	ret = devm_pse_controller_register(dev, &priv->pcdev);
1175*9a993845SKory Maincent (Dent Project) 	if (ret)
1176*9a993845SKory Maincent (Dent Project) 		return dev_err_probe(dev, ret,
1177*9a993845SKory Maincent (Dent Project) 				     "failed to register PSE controller\n");
1178*9a993845SKory Maincent (Dent Project) 
1179*9a993845SKory Maincent (Dent Project) 	fwl = firmware_upload_register(THIS_MODULE, dev, dev_name(dev),
1180*9a993845SKory Maincent (Dent Project) 				       &pd692x0_fw_ops, priv);
1181*9a993845SKory Maincent (Dent Project) 	if (IS_ERR(fwl))
1182*9a993845SKory Maincent (Dent Project) 		return dev_err_probe(dev, PTR_ERR(fwl),
1183*9a993845SKory Maincent (Dent Project) 				     "failed to register to the Firmware Upload API\n");
1184*9a993845SKory Maincent (Dent Project) 	priv->fwl = fwl;
1185*9a993845SKory Maincent (Dent Project) 
1186*9a993845SKory Maincent (Dent Project) 	return 0;
1187*9a993845SKory Maincent (Dent Project) }
1188*9a993845SKory Maincent (Dent Project) 
1189*9a993845SKory Maincent (Dent Project) static void pd692x0_i2c_remove(struct i2c_client *client)
1190*9a993845SKory Maincent (Dent Project) {
1191*9a993845SKory Maincent (Dent Project) 	struct pd692x0_priv *priv = i2c_get_clientdata(client);
1192*9a993845SKory Maincent (Dent Project) 
1193*9a993845SKory Maincent (Dent Project) 	firmware_upload_unregister(priv->fwl);
1194*9a993845SKory Maincent (Dent Project) }
1195*9a993845SKory Maincent (Dent Project) 
1196*9a993845SKory Maincent (Dent Project) static const struct i2c_device_id pd692x0_id[] = {
1197*9a993845SKory Maincent (Dent Project) 	{ PD692X0_PSE_NAME, 0 },
1198*9a993845SKory Maincent (Dent Project) 	{ },
1199*9a993845SKory Maincent (Dent Project) };
1200*9a993845SKory Maincent (Dent Project) MODULE_DEVICE_TABLE(i2c, pd692x0_id);
1201*9a993845SKory Maincent (Dent Project) 
1202*9a993845SKory Maincent (Dent Project) static const struct of_device_id pd692x0_of_match[] = {
1203*9a993845SKory Maincent (Dent Project) 	{ .compatible = "microchip,pd69200", },
1204*9a993845SKory Maincent (Dent Project) 	{ .compatible = "microchip,pd69210", },
1205*9a993845SKory Maincent (Dent Project) 	{ .compatible = "microchip,pd69220", },
1206*9a993845SKory Maincent (Dent Project) 	{ },
1207*9a993845SKory Maincent (Dent Project) };
1208*9a993845SKory Maincent (Dent Project) MODULE_DEVICE_TABLE(of, pd692x0_of_match);
1209*9a993845SKory Maincent (Dent Project) 
1210*9a993845SKory Maincent (Dent Project) static struct i2c_driver pd692x0_driver = {
1211*9a993845SKory Maincent (Dent Project) 	.probe		= pd692x0_i2c_probe,
1212*9a993845SKory Maincent (Dent Project) 	.remove		= pd692x0_i2c_remove,
1213*9a993845SKory Maincent (Dent Project) 	.id_table	= pd692x0_id,
1214*9a993845SKory Maincent (Dent Project) 	.driver		= {
1215*9a993845SKory Maincent (Dent Project) 		.name		= PD692X0_PSE_NAME,
1216*9a993845SKory Maincent (Dent Project) 		.of_match_table = pd692x0_of_match,
1217*9a993845SKory Maincent (Dent Project) 	},
1218*9a993845SKory Maincent (Dent Project) };
1219*9a993845SKory Maincent (Dent Project) module_i2c_driver(pd692x0_driver);
1220*9a993845SKory Maincent (Dent Project) 
1221*9a993845SKory Maincent (Dent Project) MODULE_AUTHOR("Kory Maincent <kory.maincent@bootlin.com>");
1222*9a993845SKory Maincent (Dent Project) MODULE_DESCRIPTION("Microchip PD692x0 PoE PSE Controller driver");
1223*9a993845SKory Maincent (Dent Project) MODULE_LICENSE("GPL");
1224