19a993845SKory Maincent (Dent Project) // SPDX-License-Identifier: GPL-2.0-only
29a993845SKory Maincent (Dent Project) /*
39a993845SKory Maincent (Dent Project) * Driver for the Microchip PD692X0 PoE PSE Controller driver (I2C bus)
49a993845SKory Maincent (Dent Project) *
59a993845SKory Maincent (Dent Project) * Copyright (c) 2023 Bootlin, Kory Maincent <kory.maincent@bootlin.com>
69a993845SKory Maincent (Dent Project) */
79a993845SKory Maincent (Dent Project)
89a993845SKory Maincent (Dent Project) #include <linux/delay.h>
99a993845SKory Maincent (Dent Project) #include <linux/firmware.h>
109a993845SKory Maincent (Dent Project) #include <linux/i2c.h>
119a993845SKory Maincent (Dent Project) #include <linux/module.h>
129a993845SKory Maincent (Dent Project) #include <linux/of.h>
139a993845SKory Maincent (Dent Project) #include <linux/platform_device.h>
149a993845SKory Maincent (Dent Project) #include <linux/pse-pd/pse.h>
159a993845SKory Maincent (Dent Project)
169a993845SKory Maincent (Dent Project) #define PD692X0_PSE_NAME "pd692x0_pse"
179a993845SKory Maincent (Dent Project)
189a993845SKory Maincent (Dent Project) #define PD692X0_MAX_PIS 48
199a993845SKory Maincent (Dent Project) #define PD692X0_MAX_MANAGERS 12
209a993845SKory Maincent (Dent Project) #define PD692X0_MAX_MANAGER_PORTS 8
219a993845SKory Maincent (Dent Project) #define PD692X0_MAX_HW_PORTS (PD692X0_MAX_MANAGERS * PD692X0_MAX_MANAGER_PORTS)
229a993845SKory Maincent (Dent Project)
239a993845SKory Maincent (Dent Project) #define PD69200_BT_PROD_VER 24
249a993845SKory Maincent (Dent Project) #define PD69210_BT_PROD_VER 26
259a993845SKory Maincent (Dent Project) #define PD69220_BT_PROD_VER 29
269a993845SKory Maincent (Dent Project)
279a993845SKory Maincent (Dent Project) #define PD692X0_FW_MAJ_VER 3
289a993845SKory Maincent (Dent Project) #define PD692X0_FW_MIN_VER 5
299a993845SKory Maincent (Dent Project) #define PD692X0_FW_PATCH_VER 5
309a993845SKory Maincent (Dent Project)
319a993845SKory Maincent (Dent Project) enum pd692x0_fw_state {
329a993845SKory Maincent (Dent Project) PD692X0_FW_UNKNOWN,
339a993845SKory Maincent (Dent Project) PD692X0_FW_OK,
349a993845SKory Maincent (Dent Project) PD692X0_FW_BROKEN,
359a993845SKory Maincent (Dent Project) PD692X0_FW_NEED_UPDATE,
369a993845SKory Maincent (Dent Project) PD692X0_FW_PREPARE,
379a993845SKory Maincent (Dent Project) PD692X0_FW_WRITE,
389a993845SKory Maincent (Dent Project) PD692X0_FW_COMPLETE,
399a993845SKory Maincent (Dent Project) };
409a993845SKory Maincent (Dent Project)
419a993845SKory Maincent (Dent Project) struct pd692x0_msg {
429a993845SKory Maincent (Dent Project) u8 key;
439a993845SKory Maincent (Dent Project) u8 echo;
449a993845SKory Maincent (Dent Project) u8 sub[3];
459a993845SKory Maincent (Dent Project) u8 data[8];
469a993845SKory Maincent (Dent Project) __be16 chksum;
479a993845SKory Maincent (Dent Project) } __packed;
489a993845SKory Maincent (Dent Project)
499a993845SKory Maincent (Dent Project) struct pd692x0_msg_ver {
509a993845SKory Maincent (Dent Project) u8 prod;
519a993845SKory Maincent (Dent Project) u8 maj_sw_ver;
529a993845SKory Maincent (Dent Project) u8 min_sw_ver;
539a993845SKory Maincent (Dent Project) u8 pa_sw_ver;
549a993845SKory Maincent (Dent Project) u8 param;
559a993845SKory Maincent (Dent Project) u8 build;
569a993845SKory Maincent (Dent Project) };
579a993845SKory Maincent (Dent Project)
589a993845SKory Maincent (Dent Project) enum {
599a993845SKory Maincent (Dent Project) PD692X0_KEY_CMD,
609a993845SKory Maincent (Dent Project) PD692X0_KEY_PRG,
619a993845SKory Maincent (Dent Project) PD692X0_KEY_REQ,
629a993845SKory Maincent (Dent Project) PD692X0_KEY_TLM,
639a993845SKory Maincent (Dent Project) PD692X0_KEY_TEST,
649a993845SKory Maincent (Dent Project) PD692X0_KEY_REPORT = 0x52
659a993845SKory Maincent (Dent Project) };
669a993845SKory Maincent (Dent Project)
679a993845SKory Maincent (Dent Project) enum {
689a993845SKory Maincent (Dent Project) PD692X0_MSG_RESET,
699a993845SKory Maincent (Dent Project) PD692X0_MSG_GET_SYS_STATUS,
709a993845SKory Maincent (Dent Project) PD692X0_MSG_GET_SW_VER,
719a993845SKory Maincent (Dent Project) PD692X0_MSG_SET_TMP_PORT_MATRIX,
729a993845SKory Maincent (Dent Project) PD692X0_MSG_PRG_PORT_MATRIX,
739a993845SKory Maincent (Dent Project) PD692X0_MSG_SET_PORT_PARAM,
749a993845SKory Maincent (Dent Project) PD692X0_MSG_GET_PORT_STATUS,
759a993845SKory Maincent (Dent Project) PD692X0_MSG_DOWNLOAD_CMD,
76ae37dc57SKory Maincent (Dent Project) PD692X0_MSG_GET_PORT_CLASS,
77a87e699cSKory Maincent (Dent Project) PD692X0_MSG_GET_PORT_MEAS,
78a87e699cSKory Maincent (Dent Project) PD692X0_MSG_GET_PORT_PARAM,
799a993845SKory Maincent (Dent Project)
809a993845SKory Maincent (Dent Project) /* add new message above here */
819a993845SKory Maincent (Dent Project) PD692X0_MSG_CNT
829a993845SKory Maincent (Dent Project) };
839a993845SKory Maincent (Dent Project)
849a993845SKory Maincent (Dent Project) struct pd692x0_priv {
859a993845SKory Maincent (Dent Project) struct i2c_client *client;
869a993845SKory Maincent (Dent Project) struct pse_controller_dev pcdev;
879a993845SKory Maincent (Dent Project) struct device_node *np;
889a993845SKory Maincent (Dent Project)
899a993845SKory Maincent (Dent Project) enum pd692x0_fw_state fw_state;
909a993845SKory Maincent (Dent Project) struct fw_upload *fwl;
919a993845SKory Maincent (Dent Project) bool cancel_request;
929a993845SKory Maincent (Dent Project)
939a993845SKory Maincent (Dent Project) u8 msg_id;
949a993845SKory Maincent (Dent Project) bool last_cmd_key;
959a993845SKory Maincent (Dent Project) unsigned long last_cmd_key_time;
969a993845SKory Maincent (Dent Project)
979a993845SKory Maincent (Dent Project) enum ethtool_c33_pse_admin_state admin_state[PD692X0_MAX_PIS];
989a993845SKory Maincent (Dent Project) };
999a993845SKory Maincent (Dent Project)
1009a993845SKory Maincent (Dent Project) /* Template list of communication messages. The non-null bytes defined here
1019a993845SKory Maincent (Dent Project) * constitute the fixed portion of the messages. The remaining bytes will
1029a993845SKory Maincent (Dent Project) * be configured later within the functions. Refer to the "PD692x0 BT Serial
1039a993845SKory Maincent (Dent Project) * Communication Protocol User Guide" for comprehensive details on messages
1049a993845SKory Maincent (Dent Project) * content.
1059a993845SKory Maincent (Dent Project) */
1069a993845SKory Maincent (Dent Project) static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = {
1079a993845SKory Maincent (Dent Project) [PD692X0_MSG_RESET] = {
1089a993845SKory Maincent (Dent Project) .key = PD692X0_KEY_CMD,
1099a993845SKory Maincent (Dent Project) .sub = {0x07, 0x55, 0x00},
1109a993845SKory Maincent (Dent Project) .data = {0x55, 0x00, 0x55, 0x4e,
1119a993845SKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
1129a993845SKory Maincent (Dent Project) },
1139a993845SKory Maincent (Dent Project) [PD692X0_MSG_GET_SYS_STATUS] = {
1149a993845SKory Maincent (Dent Project) .key = PD692X0_KEY_REQ,
1159a993845SKory Maincent (Dent Project) .sub = {0x07, 0xd0, 0x4e},
1169a993845SKory Maincent (Dent Project) .data = {0x4e, 0x4e, 0x4e, 0x4e,
1179a993845SKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
1189a993845SKory Maincent (Dent Project) },
1199a993845SKory Maincent (Dent Project) [PD692X0_MSG_GET_SW_VER] = {
1209a993845SKory Maincent (Dent Project) .key = PD692X0_KEY_REQ,
1219a993845SKory Maincent (Dent Project) .sub = {0x07, 0x1e, 0x21},
1229a993845SKory Maincent (Dent Project) .data = {0x4e, 0x4e, 0x4e, 0x4e,
1239a993845SKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
1249a993845SKory Maincent (Dent Project) },
1259a993845SKory Maincent (Dent Project) [PD692X0_MSG_SET_TMP_PORT_MATRIX] = {
1269a993845SKory Maincent (Dent Project) .key = PD692X0_KEY_CMD,
1279a993845SKory Maincent (Dent Project) .sub = {0x05, 0x43},
1289a993845SKory Maincent (Dent Project) .data = { 0, 0x4e, 0x4e, 0x4e,
1299a993845SKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
1309a993845SKory Maincent (Dent Project) },
1319a993845SKory Maincent (Dent Project) [PD692X0_MSG_PRG_PORT_MATRIX] = {
1329a993845SKory Maincent (Dent Project) .key = PD692X0_KEY_CMD,
1339a993845SKory Maincent (Dent Project) .sub = {0x07, 0x43, 0x4e},
1349a993845SKory Maincent (Dent Project) .data = {0x4e, 0x4e, 0x4e, 0x4e,
1359a993845SKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
1369a993845SKory Maincent (Dent Project) },
1379a993845SKory Maincent (Dent Project) [PD692X0_MSG_SET_PORT_PARAM] = {
1389a993845SKory Maincent (Dent Project) .key = PD692X0_KEY_CMD,
1399a993845SKory Maincent (Dent Project) .sub = {0x05, 0xc0},
140a87e699cSKory Maincent (Dent Project) .data = { 0xf, 0xff, 0xff, 0xff,
1419a993845SKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
1429a993845SKory Maincent (Dent Project) },
1439a993845SKory Maincent (Dent Project) [PD692X0_MSG_GET_PORT_STATUS] = {
1449a993845SKory Maincent (Dent Project) .key = PD692X0_KEY_REQ,
1459a993845SKory Maincent (Dent Project) .sub = {0x05, 0xc1},
1469a993845SKory Maincent (Dent Project) .data = {0x4e, 0x4e, 0x4e, 0x4e,
1479a993845SKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
1489a993845SKory Maincent (Dent Project) },
1499a993845SKory Maincent (Dent Project) [PD692X0_MSG_DOWNLOAD_CMD] = {
1509a993845SKory Maincent (Dent Project) .key = PD692X0_KEY_PRG,
1519a993845SKory Maincent (Dent Project) .sub = {0xff, 0x99, 0x15},
1529a993845SKory Maincent (Dent Project) .data = {0x16, 0x16, 0x99, 0x4e,
1539a993845SKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
1549a993845SKory Maincent (Dent Project) },
155ae37dc57SKory Maincent (Dent Project) [PD692X0_MSG_GET_PORT_CLASS] = {
156ae37dc57SKory Maincent (Dent Project) .key = PD692X0_KEY_REQ,
157ae37dc57SKory Maincent (Dent Project) .sub = {0x05, 0xc4},
158ae37dc57SKory Maincent (Dent Project) .data = {0x4e, 0x4e, 0x4e, 0x4e,
159ae37dc57SKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
160ae37dc57SKory Maincent (Dent Project) },
161a87e699cSKory Maincent (Dent Project) [PD692X0_MSG_GET_PORT_MEAS] = {
162a87e699cSKory Maincent (Dent Project) .key = PD692X0_KEY_REQ,
163a87e699cSKory Maincent (Dent Project) .sub = {0x05, 0xc5},
164a87e699cSKory Maincent (Dent Project) .data = {0x4e, 0x4e, 0x4e, 0x4e,
165a87e699cSKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
166a87e699cSKory Maincent (Dent Project) },
167a87e699cSKory Maincent (Dent Project) [PD692X0_MSG_GET_PORT_PARAM] = {
168a87e699cSKory Maincent (Dent Project) .key = PD692X0_KEY_REQ,
169a87e699cSKory Maincent (Dent Project) .sub = {0x05, 0xc0},
170a87e699cSKory Maincent (Dent Project) .data = {0x4e, 0x4e, 0x4e, 0x4e,
171a87e699cSKory Maincent (Dent Project) 0x4e, 0x4e, 0x4e, 0x4e},
172a87e699cSKory Maincent (Dent Project) },
1739a993845SKory Maincent (Dent Project) };
1749a993845SKory Maincent (Dent Project)
pd692x0_build_msg(struct pd692x0_msg * msg,u8 echo)1759a993845SKory Maincent (Dent Project) static u8 pd692x0_build_msg(struct pd692x0_msg *msg, u8 echo)
1769a993845SKory Maincent (Dent Project) {
1779a993845SKory Maincent (Dent Project) u8 *data = (u8 *)msg;
1789a993845SKory Maincent (Dent Project) u16 chksum = 0;
1799a993845SKory Maincent (Dent Project) int i;
1809a993845SKory Maincent (Dent Project)
1819a993845SKory Maincent (Dent Project) msg->echo = echo++;
1829a993845SKory Maincent (Dent Project) if (echo == 0xff)
1839a993845SKory Maincent (Dent Project) echo = 0;
1849a993845SKory Maincent (Dent Project)
1859a993845SKory Maincent (Dent Project) for (i = 0; i < sizeof(*msg) - sizeof(msg->chksum); i++)
1869a993845SKory Maincent (Dent Project) chksum += data[i];
1879a993845SKory Maincent (Dent Project)
1889a993845SKory Maincent (Dent Project) msg->chksum = cpu_to_be16(chksum);
1899a993845SKory Maincent (Dent Project)
1909a993845SKory Maincent (Dent Project) return echo;
1919a993845SKory Maincent (Dent Project) }
1929a993845SKory Maincent (Dent Project)
pd692x0_send_msg(struct pd692x0_priv * priv,struct pd692x0_msg * msg)1939a993845SKory Maincent (Dent Project) static int pd692x0_send_msg(struct pd692x0_priv *priv, struct pd692x0_msg *msg)
1949a993845SKory Maincent (Dent Project) {
1959a993845SKory Maincent (Dent Project) const struct i2c_client *client = priv->client;
1969a993845SKory Maincent (Dent Project) int ret;
1979a993845SKory Maincent (Dent Project)
1989a993845SKory Maincent (Dent Project) if (msg->key == PD692X0_KEY_CMD && priv->last_cmd_key) {
1999a993845SKory Maincent (Dent Project) int cmd_msleep;
2009a993845SKory Maincent (Dent Project)
2019a993845SKory Maincent (Dent Project) cmd_msleep = 30 - jiffies_to_msecs(jiffies - priv->last_cmd_key_time);
2029a993845SKory Maincent (Dent Project) if (cmd_msleep > 0)
2039a993845SKory Maincent (Dent Project) msleep(cmd_msleep);
2049a993845SKory Maincent (Dent Project) }
2059a993845SKory Maincent (Dent Project)
2069a993845SKory Maincent (Dent Project) /* Add echo and checksum bytes to the message */
2079a993845SKory Maincent (Dent Project) priv->msg_id = pd692x0_build_msg(msg, priv->msg_id);
2089a993845SKory Maincent (Dent Project)
2099a993845SKory Maincent (Dent Project) ret = i2c_master_send(client, (u8 *)msg, sizeof(*msg));
2109a993845SKory Maincent (Dent Project) if (ret != sizeof(*msg))
2119a993845SKory Maincent (Dent Project) return -EIO;
2129a993845SKory Maincent (Dent Project)
2139a993845SKory Maincent (Dent Project) return 0;
2149a993845SKory Maincent (Dent Project) }
2159a993845SKory Maincent (Dent Project)
pd692x0_reset(struct pd692x0_priv * priv)2169a993845SKory Maincent (Dent Project) static int pd692x0_reset(struct pd692x0_priv *priv)
2179a993845SKory Maincent (Dent Project) {
2189a993845SKory Maincent (Dent Project) const struct i2c_client *client = priv->client;
2199a993845SKory Maincent (Dent Project) struct pd692x0_msg msg, buf = {0};
2209a993845SKory Maincent (Dent Project) int ret;
2219a993845SKory Maincent (Dent Project)
2229a993845SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_RESET];
2239a993845SKory Maincent (Dent Project) ret = pd692x0_send_msg(priv, &msg);
2249a993845SKory Maincent (Dent Project) if (ret) {
2259a993845SKory Maincent (Dent Project) dev_err(&client->dev,
2269a993845SKory Maincent (Dent Project) "Failed to reset the controller (%pe)\n", ERR_PTR(ret));
2279a993845SKory Maincent (Dent Project) return ret;
2289a993845SKory Maincent (Dent Project) }
2299a993845SKory Maincent (Dent Project)
2309a993845SKory Maincent (Dent Project) msleep(30);
2319a993845SKory Maincent (Dent Project)
2329a993845SKory Maincent (Dent Project) ret = i2c_master_recv(client, (u8 *)&buf, sizeof(buf));
2339a993845SKory Maincent (Dent Project) if (ret != sizeof(buf))
2349a993845SKory Maincent (Dent Project) return ret < 0 ? ret : -EIO;
2359a993845SKory Maincent (Dent Project)
2369a993845SKory Maincent (Dent Project) /* Is the reply a successful report message */
2379a993845SKory Maincent (Dent Project) if (buf.key != PD692X0_KEY_REPORT || buf.sub[0] || buf.sub[1])
2389a993845SKory Maincent (Dent Project) return -EIO;
2399a993845SKory Maincent (Dent Project)
2409a993845SKory Maincent (Dent Project) msleep(300);
2419a993845SKory Maincent (Dent Project)
2429a993845SKory Maincent (Dent Project) ret = i2c_master_recv(client, (u8 *)&buf, sizeof(buf));
2439a993845SKory Maincent (Dent Project) if (ret != sizeof(buf))
2449a993845SKory Maincent (Dent Project) return ret < 0 ? ret : -EIO;
2459a993845SKory Maincent (Dent Project)
2469a993845SKory Maincent (Dent Project) /* Is the boot status without error */
2479a993845SKory Maincent (Dent Project) if (buf.key != 0x03 || buf.echo != 0xff || buf.sub[0] & 0x1) {
2489a993845SKory Maincent (Dent Project) dev_err(&client->dev, "PSE controller error\n");
2499a993845SKory Maincent (Dent Project) return -EIO;
2509a993845SKory Maincent (Dent Project) }
2519a993845SKory Maincent (Dent Project)
2529a993845SKory Maincent (Dent Project) return 0;
2539a993845SKory Maincent (Dent Project) }
2549a993845SKory Maincent (Dent Project)
pd692x0_try_recv_msg(const struct i2c_client * client,struct pd692x0_msg * msg,struct pd692x0_msg * buf)2559a993845SKory Maincent (Dent Project) static bool pd692x0_try_recv_msg(const struct i2c_client *client,
2569a993845SKory Maincent (Dent Project) struct pd692x0_msg *msg,
2579a993845SKory Maincent (Dent Project) struct pd692x0_msg *buf)
2589a993845SKory Maincent (Dent Project) {
2599a993845SKory Maincent (Dent Project) /* Wait 30ms before readback as mandated by the protocol */
2609a993845SKory Maincent (Dent Project) msleep(30);
2619a993845SKory Maincent (Dent Project)
2629a993845SKory Maincent (Dent Project) memset(buf, 0, sizeof(*buf));
2639a993845SKory Maincent (Dent Project) i2c_master_recv(client, (u8 *)buf, sizeof(*buf));
2649a993845SKory Maincent (Dent Project) if (buf->key)
2659a993845SKory Maincent (Dent Project) return 0;
2669a993845SKory Maincent (Dent Project)
2679a993845SKory Maincent (Dent Project) msleep(100);
2689a993845SKory Maincent (Dent Project)
2699a993845SKory Maincent (Dent Project) memset(buf, 0, sizeof(*buf));
2709a993845SKory Maincent (Dent Project) i2c_master_recv(client, (u8 *)buf, sizeof(*buf));
2719a993845SKory Maincent (Dent Project) if (buf->key)
2729a993845SKory Maincent (Dent Project) return 0;
2739a993845SKory Maincent (Dent Project)
2749a993845SKory Maincent (Dent Project) return 1;
2759a993845SKory Maincent (Dent Project) }
2769a993845SKory Maincent (Dent Project)
2779a993845SKory Maincent (Dent Project) /* Implementation of I2C communication, specifically addressing scenarios
2789a993845SKory Maincent (Dent Project) * involving communication loss. Refer to the "Synchronization During
2799a993845SKory Maincent (Dent Project) * Communication Loss" section in the Communication Protocol document for
2809a993845SKory Maincent (Dent Project) * further details.
2819a993845SKory Maincent (Dent Project) */
pd692x0_recv_msg(struct pd692x0_priv * priv,struct pd692x0_msg * msg,struct pd692x0_msg * buf)2829a993845SKory Maincent (Dent Project) static int pd692x0_recv_msg(struct pd692x0_priv *priv,
2839a993845SKory Maincent (Dent Project) struct pd692x0_msg *msg,
2849a993845SKory Maincent (Dent Project) struct pd692x0_msg *buf)
2859a993845SKory Maincent (Dent Project) {
2869a993845SKory Maincent (Dent Project) const struct i2c_client *client = priv->client;
2879a993845SKory Maincent (Dent Project) int ret;
2889a993845SKory Maincent (Dent Project)
2899a993845SKory Maincent (Dent Project) ret = pd692x0_try_recv_msg(client, msg, buf);
2909a993845SKory Maincent (Dent Project) if (!ret)
2919a993845SKory Maincent (Dent Project) goto out_success;
2929a993845SKory Maincent (Dent Project)
2939a993845SKory Maincent (Dent Project) dev_warn(&client->dev,
2949a993845SKory Maincent (Dent Project) "Communication lost, rtnl is locked until communication is back!");
2959a993845SKory Maincent (Dent Project)
2969a993845SKory Maincent (Dent Project) ret = pd692x0_send_msg(priv, msg);
2979a993845SKory Maincent (Dent Project) if (ret)
2989a993845SKory Maincent (Dent Project) return ret;
2999a993845SKory Maincent (Dent Project)
3009a993845SKory Maincent (Dent Project) ret = pd692x0_try_recv_msg(client, msg, buf);
3019a993845SKory Maincent (Dent Project) if (!ret)
3029a993845SKory Maincent (Dent Project) goto out_success2;
3039a993845SKory Maincent (Dent Project)
3049a993845SKory Maincent (Dent Project) msleep(10000);
3059a993845SKory Maincent (Dent Project)
3069a993845SKory Maincent (Dent Project) ret = pd692x0_send_msg(priv, msg);
3079a993845SKory Maincent (Dent Project) if (ret)
3089a993845SKory Maincent (Dent Project) return ret;
3099a993845SKory Maincent (Dent Project)
3109a993845SKory Maincent (Dent Project) ret = pd692x0_try_recv_msg(client, msg, buf);
3119a993845SKory Maincent (Dent Project) if (!ret)
3129a993845SKory Maincent (Dent Project) goto out_success2;
3139a993845SKory Maincent (Dent Project)
3149a993845SKory Maincent (Dent Project) return pd692x0_reset(priv);
3159a993845SKory Maincent (Dent Project)
3169a993845SKory Maincent (Dent Project) out_success2:
3179a993845SKory Maincent (Dent Project) dev_warn(&client->dev, "Communication is back, rtnl is unlocked!");
3189a993845SKory Maincent (Dent Project) out_success:
3199a993845SKory Maincent (Dent Project) if (msg->key == PD692X0_KEY_CMD) {
3209a993845SKory Maincent (Dent Project) priv->last_cmd_key = true;
3219a993845SKory Maincent (Dent Project) priv->last_cmd_key_time = jiffies;
3229a993845SKory Maincent (Dent Project) } else {
3239a993845SKory Maincent (Dent Project) priv->last_cmd_key = false;
3249a993845SKory Maincent (Dent Project) }
3259a993845SKory Maincent (Dent Project)
3269a993845SKory Maincent (Dent Project) return 0;
3279a993845SKory Maincent (Dent Project) }
3289a993845SKory Maincent (Dent Project)
pd692x0_sendrecv_msg(struct pd692x0_priv * priv,struct pd692x0_msg * msg,struct pd692x0_msg * buf)3299a993845SKory Maincent (Dent Project) static int pd692x0_sendrecv_msg(struct pd692x0_priv *priv,
3309a993845SKory Maincent (Dent Project) struct pd692x0_msg *msg,
3319a993845SKory Maincent (Dent Project) struct pd692x0_msg *buf)
3329a993845SKory Maincent (Dent Project) {
3339a993845SKory Maincent (Dent Project) struct device *dev = &priv->client->dev;
3349a993845SKory Maincent (Dent Project) int ret;
3359a993845SKory Maincent (Dent Project)
3369a993845SKory Maincent (Dent Project) ret = pd692x0_send_msg(priv, msg);
3379a993845SKory Maincent (Dent Project) if (ret)
3389a993845SKory Maincent (Dent Project) return ret;
3399a993845SKory Maincent (Dent Project)
3409a993845SKory Maincent (Dent Project) ret = pd692x0_recv_msg(priv, msg, buf);
3419a993845SKory Maincent (Dent Project) if (ret)
3429a993845SKory Maincent (Dent Project) return ret;
3439a993845SKory Maincent (Dent Project)
3449a993845SKory Maincent (Dent Project) if (msg->echo != buf->echo) {
3459a993845SKory Maincent (Dent Project) dev_err(dev,
3469a993845SKory Maincent (Dent Project) "Wrong match in message ID, expect %d received %d.\n",
3479a993845SKory Maincent (Dent Project) msg->echo, buf->echo);
3489a993845SKory Maincent (Dent Project) return -EIO;
3499a993845SKory Maincent (Dent Project) }
3509a993845SKory Maincent (Dent Project)
3519a993845SKory Maincent (Dent Project) /* If the reply is a report message is it successful */
3529a993845SKory Maincent (Dent Project) if (buf->key == PD692X0_KEY_REPORT &&
3539a993845SKory Maincent (Dent Project) (buf->sub[0] || buf->sub[1])) {
3549a993845SKory Maincent (Dent Project) return -EIO;
3559a993845SKory Maincent (Dent Project) }
3569a993845SKory Maincent (Dent Project)
3579a993845SKory Maincent (Dent Project) return 0;
3589a993845SKory Maincent (Dent Project) }
3599a993845SKory Maincent (Dent Project)
to_pd692x0_priv(struct pse_controller_dev * pcdev)3609a993845SKory Maincent (Dent Project) static struct pd692x0_priv *to_pd692x0_priv(struct pse_controller_dev *pcdev)
3619a993845SKory Maincent (Dent Project) {
3629a993845SKory Maincent (Dent Project) return container_of(pcdev, struct pd692x0_priv, pcdev);
3639a993845SKory Maincent (Dent Project) }
3649a993845SKory Maincent (Dent Project)
pd692x0_fw_unavailable(struct pd692x0_priv * priv)3659a993845SKory Maincent (Dent Project) static int pd692x0_fw_unavailable(struct pd692x0_priv *priv)
3669a993845SKory Maincent (Dent Project) {
3679a993845SKory Maincent (Dent Project) switch (priv->fw_state) {
3689a993845SKory Maincent (Dent Project) case PD692X0_FW_OK:
3699a993845SKory Maincent (Dent Project) return 0;
3709a993845SKory Maincent (Dent Project) case PD692X0_FW_PREPARE:
3719a993845SKory Maincent (Dent Project) case PD692X0_FW_WRITE:
3729a993845SKory Maincent (Dent Project) case PD692X0_FW_COMPLETE:
3739a993845SKory Maincent (Dent Project) dev_err(&priv->client->dev, "Firmware update in progress!\n");
3749a993845SKory Maincent (Dent Project) return -EBUSY;
3759a993845SKory Maincent (Dent Project) case PD692X0_FW_BROKEN:
3769a993845SKory Maincent (Dent Project) case PD692X0_FW_NEED_UPDATE:
3779a993845SKory Maincent (Dent Project) default:
3789a993845SKory Maincent (Dent Project) dev_err(&priv->client->dev,
3799a993845SKory Maincent (Dent Project) "Firmware issue. Please update it!\n");
3809a993845SKory Maincent (Dent Project) return -EOPNOTSUPP;
3819a993845SKory Maincent (Dent Project) }
3829a993845SKory Maincent (Dent Project) }
3839a993845SKory Maincent (Dent Project)
pd692x0_pi_enable(struct pse_controller_dev * pcdev,int id)3849a993845SKory Maincent (Dent Project) static int pd692x0_pi_enable(struct pse_controller_dev *pcdev, int id)
3859a993845SKory Maincent (Dent Project) {
3869a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
3879a993845SKory Maincent (Dent Project) struct pd692x0_msg msg, buf = {0};
3889a993845SKory Maincent (Dent Project) int ret;
3899a993845SKory Maincent (Dent Project)
3909a993845SKory Maincent (Dent Project) ret = pd692x0_fw_unavailable(priv);
3919a993845SKory Maincent (Dent Project) if (ret)
3929a993845SKory Maincent (Dent Project) return ret;
3939a993845SKory Maincent (Dent Project)
3949a993845SKory Maincent (Dent Project) if (priv->admin_state[id] == ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED)
3959a993845SKory Maincent (Dent Project) return 0;
3969a993845SKory Maincent (Dent Project)
3979a993845SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_SET_PORT_PARAM];
3989a993845SKory Maincent (Dent Project) msg.data[0] = 0x1;
3999a993845SKory Maincent (Dent Project) msg.sub[2] = id;
4009a993845SKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
4019a993845SKory Maincent (Dent Project) if (ret < 0)
4029a993845SKory Maincent (Dent Project) return ret;
4039a993845SKory Maincent (Dent Project)
4049a993845SKory Maincent (Dent Project) priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
4059a993845SKory Maincent (Dent Project)
4069a993845SKory Maincent (Dent Project) return 0;
4079a993845SKory Maincent (Dent Project) }
4089a993845SKory Maincent (Dent Project)
pd692x0_pi_disable(struct pse_controller_dev * pcdev,int id)4099a993845SKory Maincent (Dent Project) static int pd692x0_pi_disable(struct pse_controller_dev *pcdev, int id)
4109a993845SKory Maincent (Dent Project) {
4119a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
4129a993845SKory Maincent (Dent Project) struct pd692x0_msg msg, buf = {0};
4139a993845SKory Maincent (Dent Project) int ret;
4149a993845SKory Maincent (Dent Project)
4159a993845SKory Maincent (Dent Project) ret = pd692x0_fw_unavailable(priv);
4169a993845SKory Maincent (Dent Project) if (ret)
4179a993845SKory Maincent (Dent Project) return ret;
4189a993845SKory Maincent (Dent Project)
4199a993845SKory Maincent (Dent Project) if (priv->admin_state[id] == ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED)
4209a993845SKory Maincent (Dent Project) return 0;
4219a993845SKory Maincent (Dent Project)
4229a993845SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_SET_PORT_PARAM];
4239a993845SKory Maincent (Dent Project) msg.data[0] = 0x0;
4249a993845SKory Maincent (Dent Project) msg.sub[2] = id;
4259a993845SKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
4269a993845SKory Maincent (Dent Project) if (ret < 0)
4279a993845SKory Maincent (Dent Project) return ret;
4289a993845SKory Maincent (Dent Project)
4299a993845SKory Maincent (Dent Project) priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
4309a993845SKory Maincent (Dent Project)
4319a993845SKory Maincent (Dent Project) return 0;
4329a993845SKory Maincent (Dent Project) }
4339a993845SKory Maincent (Dent Project)
pd692x0_pi_is_enabled(struct pse_controller_dev * pcdev,int id)4349a993845SKory Maincent (Dent Project) static int pd692x0_pi_is_enabled(struct pse_controller_dev *pcdev, int id)
4359a993845SKory Maincent (Dent Project) {
4369a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
4379a993845SKory Maincent (Dent Project) struct pd692x0_msg msg, buf = {0};
4389a993845SKory Maincent (Dent Project) int ret;
4399a993845SKory Maincent (Dent Project)
4409a993845SKory Maincent (Dent Project) ret = pd692x0_fw_unavailable(priv);
4419a993845SKory Maincent (Dent Project) if (ret)
4429a993845SKory Maincent (Dent Project) return ret;
4439a993845SKory Maincent (Dent Project)
4449a993845SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
4459a993845SKory Maincent (Dent Project) msg.sub[2] = id;
4469a993845SKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
4479a993845SKory Maincent (Dent Project) if (ret < 0)
4489a993845SKory Maincent (Dent Project) return ret;
4499a993845SKory Maincent (Dent Project)
4509a993845SKory Maincent (Dent Project) if (buf.sub[1]) {
4519a993845SKory Maincent (Dent Project) priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
4529a993845SKory Maincent (Dent Project) return 1;
4539a993845SKory Maincent (Dent Project) } else {
4549a993845SKory Maincent (Dent Project) priv->admin_state[id] = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
4559a993845SKory Maincent (Dent Project) return 0;
4569a993845SKory Maincent (Dent Project) }
4579a993845SKory Maincent (Dent Project) }
4589a993845SKory Maincent (Dent Project)
459ae37dc57SKory Maincent (Dent Project) struct pd692x0_pse_ext_state_mapping {
460ae37dc57SKory Maincent (Dent Project) u32 status_code;
461ae37dc57SKory Maincent (Dent Project) enum ethtool_c33_pse_ext_state pse_ext_state;
462ae37dc57SKory Maincent (Dent Project) u32 pse_ext_substate;
463ae37dc57SKory Maincent (Dent Project) };
464ae37dc57SKory Maincent (Dent Project)
465ae37dc57SKory Maincent (Dent Project) static const struct pd692x0_pse_ext_state_mapping
466ae37dc57SKory Maincent (Dent Project) pd692x0_pse_ext_state_map[] = {
467ae37dc57SKory Maincent (Dent Project) {0x06, ETHTOOL_C33_PSE_EXT_STATE_OPTION_VPORT_LIM,
468ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_OPTION_VPORT_LIM_HIGH_VOLTAGE},
469ae37dc57SKory Maincent (Dent Project) {0x07, ETHTOOL_C33_PSE_EXT_STATE_OPTION_VPORT_LIM,
470ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_OPTION_VPORT_LIM_LOW_VOLTAGE},
471ae37dc57SKory Maincent (Dent Project) {0x08, ETHTOOL_C33_PSE_EXT_STATE_MR_PSE_ENABLE,
472ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_MR_PSE_ENABLE_DISABLE_PIN_ACTIVE},
473ae37dc57SKory Maincent (Dent Project) {0x0C, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
474ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_NON_EXISTING_PORT},
475ae37dc57SKory Maincent (Dent Project) {0x11, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
476ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_UNDEFINED_PORT},
477ae37dc57SKory Maincent (Dent Project) {0x12, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
478ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_INTERNAL_HW_FAULT},
479ae37dc57SKory Maincent (Dent Project) {0x1B, ETHTOOL_C33_PSE_EXT_STATE_OPTION_DETECT_TED,
480ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_OPTION_DETECT_TED_DET_IN_PROCESS},
481ae37dc57SKory Maincent (Dent Project) {0x1C, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
482ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_UNKNOWN_PORT_STATUS},
483ae37dc57SKory Maincent (Dent Project) {0x1E, ETHTOOL_C33_PSE_EXT_STATE_MR_MPS_VALID,
484ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_MR_MPS_VALID_DETECTED_UNDERLOAD},
485ae37dc57SKory Maincent (Dent Project) {0x1F, ETHTOOL_C33_PSE_EXT_STATE_OVLD_DETECTED,
486ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_OVLD_DETECTED_OVERLOAD},
487ae37dc57SKory Maincent (Dent Project) {0x20, ETHTOOL_C33_PSE_EXT_STATE_POWER_NOT_AVAILABLE,
488ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_POWER_NOT_AVAILABLE_BUDGET_EXCEEDED},
489ae37dc57SKory Maincent (Dent Project) {0x21, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
490ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_INTERNAL_HW_FAULT},
491ae37dc57SKory Maincent (Dent Project) {0x22, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
492ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_CONFIG_CHANGE},
493ae37dc57SKory Maincent (Dent Project) {0x24, ETHTOOL_C33_PSE_EXT_STATE_OPTION_VPORT_LIM,
494ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_OPTION_VPORT_LIM_VOLTAGE_INJECTION},
495ae37dc57SKory Maincent (Dent Project) {0x25, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
496ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_UNKNOWN_PORT_STATUS},
497ae37dc57SKory Maincent (Dent Project) {0x34, ETHTOOL_C33_PSE_EXT_STATE_SHORT_DETECTED,
498ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_SHORT_DETECTED_SHORT_CONDITION},
499ae37dc57SKory Maincent (Dent Project) {0x35, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
500ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_DETECTED_OVER_TEMP},
501ae37dc57SKory Maincent (Dent Project) {0x36, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
502ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_DETECTED_OVER_TEMP},
503ae37dc57SKory Maincent (Dent Project) {0x37, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
504ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_UNKNOWN_PORT_STATUS},
505ae37dc57SKory Maincent (Dent Project) {0x3C, ETHTOOL_C33_PSE_EXT_STATE_POWER_NOT_AVAILABLE,
506ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_POWER_NOT_AVAILABLE_PORT_PW_LIMIT_EXCEEDS_CONTROLLER_BUDGET},
507ae37dc57SKory Maincent (Dent Project) {0x3D, ETHTOOL_C33_PSE_EXT_STATE_POWER_NOT_AVAILABLE,
508ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_POWER_NOT_AVAILABLE_PD_REQUEST_EXCEEDS_PORT_LIMIT},
509ae37dc57SKory Maincent (Dent Project) {0x41, ETHTOOL_C33_PSE_EXT_STATE_POWER_NOT_AVAILABLE,
510ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_POWER_NOT_AVAILABLE_HW_PW_LIMIT},
511ae37dc57SKory Maincent (Dent Project) {0x43, ETHTOOL_C33_PSE_EXT_STATE_ERROR_CONDITION,
512ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_ERROR_CONDITION_UNKNOWN_PORT_STATUS},
513ae37dc57SKory Maincent (Dent Project) {0xA7, ETHTOOL_C33_PSE_EXT_STATE_OPTION_DETECT_TED,
514ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_OPTION_DETECT_TED_CONNECTION_CHECK_ERROR},
515ae37dc57SKory Maincent (Dent Project) {0xA8, ETHTOOL_C33_PSE_EXT_STATE_MR_MPS_VALID,
516ae37dc57SKory Maincent (Dent Project) ETHTOOL_C33_PSE_EXT_SUBSTATE_MR_MPS_VALID_CONNECTION_OPEN},
517ae37dc57SKory Maincent (Dent Project) { /* sentinel */ }
518ae37dc57SKory Maincent (Dent Project) };
519ae37dc57SKory Maincent (Dent Project)
520ae37dc57SKory Maincent (Dent Project) static void
pd692x0_get_ext_state(struct ethtool_c33_pse_ext_state_info * c33_ext_state_info,u32 status_code)521ae37dc57SKory Maincent (Dent Project) pd692x0_get_ext_state(struct ethtool_c33_pse_ext_state_info *c33_ext_state_info,
522ae37dc57SKory Maincent (Dent Project) u32 status_code)
523ae37dc57SKory Maincent (Dent Project) {
524ae37dc57SKory Maincent (Dent Project) const struct pd692x0_pse_ext_state_mapping *ext_state_map;
525ae37dc57SKory Maincent (Dent Project)
526ae37dc57SKory Maincent (Dent Project) ext_state_map = pd692x0_pse_ext_state_map;
527ae37dc57SKory Maincent (Dent Project) while (ext_state_map->status_code) {
528ae37dc57SKory Maincent (Dent Project) if (ext_state_map->status_code == status_code) {
529ae37dc57SKory Maincent (Dent Project) c33_ext_state_info->c33_pse_ext_state = ext_state_map->pse_ext_state;
530ae37dc57SKory Maincent (Dent Project) c33_ext_state_info->__c33_pse_ext_substate = ext_state_map->pse_ext_substate;
531ae37dc57SKory Maincent (Dent Project) return;
532ae37dc57SKory Maincent (Dent Project) }
533ae37dc57SKory Maincent (Dent Project) ext_state_map++;
534ae37dc57SKory Maincent (Dent Project) }
535ae37dc57SKory Maincent (Dent Project) }
536ae37dc57SKory Maincent (Dent Project)
537a87e699cSKory Maincent (Dent Project) struct pd692x0_class_pw {
538a87e699cSKory Maincent (Dent Project) int class;
539a87e699cSKory Maincent (Dent Project) int class_cfg_value;
540a87e699cSKory Maincent (Dent Project) int class_pw;
541a87e699cSKory Maincent (Dent Project) int max_added_class_pw;
542a87e699cSKory Maincent (Dent Project) };
543a87e699cSKory Maincent (Dent Project)
544a87e699cSKory Maincent (Dent Project) #define PD692X0_CLASS_PW_TABLE_SIZE 4
545a87e699cSKory Maincent (Dent Project) /* 4/2 pairs class configuration power table in compliance mode.
546a87e699cSKory Maincent (Dent Project) * Need to be arranged in ascending order of power support.
547a87e699cSKory Maincent (Dent Project) */
548a87e699cSKory Maincent (Dent Project) static const struct pd692x0_class_pw
549a87e699cSKory Maincent (Dent Project) pd692x0_class_pw_table[PD692X0_CLASS_PW_TABLE_SIZE] = {
550a87e699cSKory Maincent (Dent Project) {.class = 3, .class_cfg_value = 0x3, .class_pw = 15000, .max_added_class_pw = 3100},
551a87e699cSKory Maincent (Dent Project) {.class = 4, .class_cfg_value = 0x2, .class_pw = 30000, .max_added_class_pw = 8000},
552a87e699cSKory Maincent (Dent Project) {.class = 6, .class_cfg_value = 0x1, .class_pw = 60000, .max_added_class_pw = 5000},
553a87e699cSKory Maincent (Dent Project) {.class = 8, .class_cfg_value = 0x0, .class_pw = 90000, .max_added_class_pw = 7500},
554a87e699cSKory Maincent (Dent Project) };
555a87e699cSKory Maincent (Dent Project)
pd692x0_pi_get_pw_from_table(int op_mode,int added_pw)556a87e699cSKory Maincent (Dent Project) static int pd692x0_pi_get_pw_from_table(int op_mode, int added_pw)
557a87e699cSKory Maincent (Dent Project) {
558a87e699cSKory Maincent (Dent Project) const struct pd692x0_class_pw *pw_table;
559a87e699cSKory Maincent (Dent Project) int i;
560a87e699cSKory Maincent (Dent Project)
561a87e699cSKory Maincent (Dent Project) pw_table = pd692x0_class_pw_table;
562a87e699cSKory Maincent (Dent Project) for (i = 0; i < PD692X0_CLASS_PW_TABLE_SIZE; i++, pw_table++) {
563a87e699cSKory Maincent (Dent Project) if (pw_table->class_cfg_value == op_mode)
564a87e699cSKory Maincent (Dent Project) return pw_table->class_pw + added_pw * 100;
565a87e699cSKory Maincent (Dent Project) }
566a87e699cSKory Maincent (Dent Project)
567a87e699cSKory Maincent (Dent Project) return -ERANGE;
568a87e699cSKory Maincent (Dent Project) }
569a87e699cSKory Maincent (Dent Project)
pd692x0_pi_set_pw_from_table(struct device * dev,struct pd692x0_msg * msg,int pw)570a87e699cSKory Maincent (Dent Project) static int pd692x0_pi_set_pw_from_table(struct device *dev,
571a87e699cSKory Maincent (Dent Project) struct pd692x0_msg *msg, int pw)
572a87e699cSKory Maincent (Dent Project) {
573a87e699cSKory Maincent (Dent Project) const struct pd692x0_class_pw *pw_table;
574a87e699cSKory Maincent (Dent Project) int i;
575a87e699cSKory Maincent (Dent Project)
576a87e699cSKory Maincent (Dent Project) pw_table = pd692x0_class_pw_table;
577a87e699cSKory Maincent (Dent Project) if (pw < pw_table->class_pw) {
578a87e699cSKory Maincent (Dent Project) dev_err(dev,
579a87e699cSKory Maincent (Dent Project) "Power limit %dmW not supported. Ranges minimal available: [%d-%d]\n",
580a87e699cSKory Maincent (Dent Project) pw,
581a87e699cSKory Maincent (Dent Project) pw_table->class_pw,
582a87e699cSKory Maincent (Dent Project) pw_table->class_pw + pw_table->max_added_class_pw);
583a87e699cSKory Maincent (Dent Project) return -ERANGE;
584a87e699cSKory Maincent (Dent Project) }
585a87e699cSKory Maincent (Dent Project)
586a87e699cSKory Maincent (Dent Project) for (i = 0; i < PD692X0_CLASS_PW_TABLE_SIZE; i++, pw_table++) {
587a87e699cSKory Maincent (Dent Project) if (pw > (pw_table->class_pw + pw_table->max_added_class_pw))
588a87e699cSKory Maincent (Dent Project) continue;
589a87e699cSKory Maincent (Dent Project)
590a87e699cSKory Maincent (Dent Project) if (pw < pw_table->class_pw) {
591a87e699cSKory Maincent (Dent Project) dev_err(dev,
592*a6a9fcb1SColin Ian King "Power limit %dmW not supported. Ranges available: [%d-%d] or [%d-%d]\n",
593a87e699cSKory Maincent (Dent Project) pw,
594a87e699cSKory Maincent (Dent Project) (pw_table - 1)->class_pw,
595a87e699cSKory Maincent (Dent Project) (pw_table - 1)->class_pw + (pw_table - 1)->max_added_class_pw,
596a87e699cSKory Maincent (Dent Project) pw_table->class_pw,
597a87e699cSKory Maincent (Dent Project) pw_table->class_pw + pw_table->max_added_class_pw);
598a87e699cSKory Maincent (Dent Project) return -ERANGE;
599a87e699cSKory Maincent (Dent Project) }
600a87e699cSKory Maincent (Dent Project)
601a87e699cSKory Maincent (Dent Project) msg->data[2] = pw_table->class_cfg_value;
602a87e699cSKory Maincent (Dent Project) msg->data[3] = (pw - pw_table->class_pw) / 100;
603a87e699cSKory Maincent (Dent Project) return 0;
604a87e699cSKory Maincent (Dent Project) }
605a87e699cSKory Maincent (Dent Project)
606a87e699cSKory Maincent (Dent Project) pw_table--;
607a87e699cSKory Maincent (Dent Project) dev_warn(dev,
608a87e699cSKory Maincent (Dent Project) "Power limit %dmW not supported. Set to highest power limit %dmW\n",
609a87e699cSKory Maincent (Dent Project) pw, pw_table->class_pw + pw_table->max_added_class_pw);
610a87e699cSKory Maincent (Dent Project) msg->data[2] = pw_table->class_cfg_value;
611a87e699cSKory Maincent (Dent Project) msg->data[3] = pw_table->max_added_class_pw / 100;
612a87e699cSKory Maincent (Dent Project) return 0;
613a87e699cSKory Maincent (Dent Project) }
614a87e699cSKory Maincent (Dent Project)
615a87e699cSKory Maincent (Dent Project) static int
pd692x0_pi_get_pw_ranges(struct pse_control_status * st)616a87e699cSKory Maincent (Dent Project) pd692x0_pi_get_pw_ranges(struct pse_control_status *st)
617a87e699cSKory Maincent (Dent Project) {
618a87e699cSKory Maincent (Dent Project) const struct pd692x0_class_pw *pw_table;
619a87e699cSKory Maincent (Dent Project) int i;
620a87e699cSKory Maincent (Dent Project)
621a87e699cSKory Maincent (Dent Project) pw_table = pd692x0_class_pw_table;
622a87e699cSKory Maincent (Dent Project) st->c33_pw_limit_ranges = kcalloc(PD692X0_CLASS_PW_TABLE_SIZE,
623a87e699cSKory Maincent (Dent Project) sizeof(struct ethtool_c33_pse_pw_limit_range),
624a87e699cSKory Maincent (Dent Project) GFP_KERNEL);
625a87e699cSKory Maincent (Dent Project) if (!st->c33_pw_limit_ranges)
626a87e699cSKory Maincent (Dent Project) return -ENOMEM;
627a87e699cSKory Maincent (Dent Project)
628a87e699cSKory Maincent (Dent Project) for (i = 0; i < PD692X0_CLASS_PW_TABLE_SIZE; i++, pw_table++) {
629a87e699cSKory Maincent (Dent Project) st->c33_pw_limit_ranges[i].min = pw_table->class_pw;
630a87e699cSKory Maincent (Dent Project) st->c33_pw_limit_ranges[i].max = pw_table->class_pw + pw_table->max_added_class_pw;
631a87e699cSKory Maincent (Dent Project) }
632a87e699cSKory Maincent (Dent Project)
633a87e699cSKory Maincent (Dent Project) st->c33_pw_limit_nb_ranges = i;
634a87e699cSKory Maincent (Dent Project) return 0;
635a87e699cSKory Maincent (Dent Project) }
636a87e699cSKory Maincent (Dent Project)
pd692x0_ethtool_get_status(struct pse_controller_dev * pcdev,unsigned long id,struct netlink_ext_ack * extack,struct pse_control_status * status)6379a993845SKory Maincent (Dent Project) static int pd692x0_ethtool_get_status(struct pse_controller_dev *pcdev,
6389a993845SKory Maincent (Dent Project) unsigned long id,
6399a993845SKory Maincent (Dent Project) struct netlink_ext_ack *extack,
6409a993845SKory Maincent (Dent Project) struct pse_control_status *status)
6419a993845SKory Maincent (Dent Project) {
6429a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
6439a993845SKory Maincent (Dent Project) struct pd692x0_msg msg, buf = {0};
644ae37dc57SKory Maincent (Dent Project) u32 class;
6459a993845SKory Maincent (Dent Project) int ret;
6469a993845SKory Maincent (Dent Project)
6479a993845SKory Maincent (Dent Project) ret = pd692x0_fw_unavailable(priv);
6489a993845SKory Maincent (Dent Project) if (ret)
6499a993845SKory Maincent (Dent Project) return ret;
6509a993845SKory Maincent (Dent Project)
6519a993845SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_STATUS];
6529a993845SKory Maincent (Dent Project) msg.sub[2] = id;
6539a993845SKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
6549a993845SKory Maincent (Dent Project) if (ret < 0)
6559a993845SKory Maincent (Dent Project) return ret;
6569a993845SKory Maincent (Dent Project)
6579a993845SKory Maincent (Dent Project) /* Compare Port Status (Communication Protocol Document par. 7.1) */
6589a993845SKory Maincent (Dent Project) if ((buf.sub[0] & 0xf0) == 0x80 || (buf.sub[0] & 0xf0) == 0x90)
6599a993845SKory Maincent (Dent Project) status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING;
6609a993845SKory Maincent (Dent Project) else if (buf.sub[0] == 0x1b || buf.sub[0] == 0x22)
6619a993845SKory Maincent (Dent Project) status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_SEARCHING;
6629a993845SKory Maincent (Dent Project) else if (buf.sub[0] == 0x12)
6639a993845SKory Maincent (Dent Project) status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_FAULT;
6649a993845SKory Maincent (Dent Project) else
6659a993845SKory Maincent (Dent Project) status->c33_pw_status = ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED;
6669a993845SKory Maincent (Dent Project)
6679a993845SKory Maincent (Dent Project) if (buf.sub[1])
6689a993845SKory Maincent (Dent Project) status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED;
6699a993845SKory Maincent (Dent Project) else
6709a993845SKory Maincent (Dent Project) status->c33_admin_state = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED;
6719a993845SKory Maincent (Dent Project)
6729a993845SKory Maincent (Dent Project) priv->admin_state[id] = status->c33_admin_state;
6739a993845SKory Maincent (Dent Project)
674ae37dc57SKory Maincent (Dent Project) pd692x0_get_ext_state(&status->c33_ext_state_info, buf.sub[0]);
675ae37dc57SKory Maincent (Dent Project) status->c33_actual_pw = (buf.data[0] << 4 | buf.data[1]) * 100;
676ae37dc57SKory Maincent (Dent Project)
677a87e699cSKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_PARAM];
678a87e699cSKory Maincent (Dent Project) msg.sub[2] = id;
679a87e699cSKory Maincent (Dent Project) memset(&buf, 0, sizeof(buf));
680a87e699cSKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
681a87e699cSKory Maincent (Dent Project) if (ret < 0)
682a87e699cSKory Maincent (Dent Project) return ret;
683a87e699cSKory Maincent (Dent Project)
684a87e699cSKory Maincent (Dent Project) ret = pd692x0_pi_get_pw_from_table(buf.data[0], buf.data[1]);
685a87e699cSKory Maincent (Dent Project) if (ret < 0)
686a87e699cSKory Maincent (Dent Project) return ret;
687a87e699cSKory Maincent (Dent Project) status->c33_avail_pw_limit = ret;
688a87e699cSKory Maincent (Dent Project)
689ae37dc57SKory Maincent (Dent Project) memset(&buf, 0, sizeof(buf));
690ae37dc57SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_CLASS];
691ae37dc57SKory Maincent (Dent Project) msg.sub[2] = id;
692ae37dc57SKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
693ae37dc57SKory Maincent (Dent Project) if (ret < 0)
694ae37dc57SKory Maincent (Dent Project) return ret;
695ae37dc57SKory Maincent (Dent Project)
696ae37dc57SKory Maincent (Dent Project) class = buf.data[3] >> 4;
697ae37dc57SKory Maincent (Dent Project) if (class <= 8)
698ae37dc57SKory Maincent (Dent Project) status->c33_pw_class = class;
699ae37dc57SKory Maincent (Dent Project)
700a87e699cSKory Maincent (Dent Project) ret = pd692x0_pi_get_pw_ranges(status);
701a87e699cSKory Maincent (Dent Project) if (ret < 0)
702a87e699cSKory Maincent (Dent Project) return ret;
703a87e699cSKory Maincent (Dent Project)
7049a993845SKory Maincent (Dent Project) return 0;
7059a993845SKory Maincent (Dent Project) }
7069a993845SKory Maincent (Dent Project)
pd692x0_get_sw_version(struct pd692x0_priv * priv)7079a993845SKory Maincent (Dent Project) static struct pd692x0_msg_ver pd692x0_get_sw_version(struct pd692x0_priv *priv)
7089a993845SKory Maincent (Dent Project) {
7099a993845SKory Maincent (Dent Project) struct device *dev = &priv->client->dev;
7109a993845SKory Maincent (Dent Project) struct pd692x0_msg msg, buf = {0};
7119a993845SKory Maincent (Dent Project) struct pd692x0_msg_ver ver = {0};
7129a993845SKory Maincent (Dent Project) int ret;
7139a993845SKory Maincent (Dent Project)
7149a993845SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_GET_SW_VER];
7159a993845SKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
7169a993845SKory Maincent (Dent Project) if (ret < 0) {
7179a993845SKory Maincent (Dent Project) dev_err(dev, "Failed to get PSE version (%pe)\n", ERR_PTR(ret));
7189a993845SKory Maincent (Dent Project) return ver;
7199a993845SKory Maincent (Dent Project) }
7209a993845SKory Maincent (Dent Project)
7219a993845SKory Maincent (Dent Project) /* Extract version from the message */
7229a993845SKory Maincent (Dent Project) ver.prod = buf.sub[2];
7239a993845SKory Maincent (Dent Project) ver.maj_sw_ver = (buf.data[0] << 8 | buf.data[1]) / 100;
7249a993845SKory Maincent (Dent Project) ver.min_sw_ver = ((buf.data[0] << 8 | buf.data[1]) / 10) % 10;
7259a993845SKory Maincent (Dent Project) ver.pa_sw_ver = (buf.data[0] << 8 | buf.data[1]) % 10;
7269a993845SKory Maincent (Dent Project) ver.param = buf.data[2];
7279a993845SKory Maincent (Dent Project) ver.build = buf.data[3];
7289a993845SKory Maincent (Dent Project)
7299a993845SKory Maincent (Dent Project) return ver;
7309a993845SKory Maincent (Dent Project) }
7319a993845SKory Maincent (Dent Project)
7329a993845SKory Maincent (Dent Project) struct pd692x0_manager {
7339a993845SKory Maincent (Dent Project) struct device_node *port_node[PD692X0_MAX_MANAGER_PORTS];
7349a993845SKory Maincent (Dent Project) int nports;
7359a993845SKory Maincent (Dent Project) };
7369a993845SKory Maincent (Dent Project)
7379a993845SKory Maincent (Dent Project) struct pd692x0_matrix {
7389a993845SKory Maincent (Dent Project) u8 hw_port_a;
7399a993845SKory Maincent (Dent Project) u8 hw_port_b;
7409a993845SKory Maincent (Dent Project) };
7419a993845SKory Maincent (Dent Project)
7429a993845SKory Maincent (Dent Project) static int
pd692x0_of_get_ports_manager(struct pd692x0_priv * priv,struct pd692x0_manager * manager,struct device_node * np)7439a993845SKory Maincent (Dent Project) pd692x0_of_get_ports_manager(struct pd692x0_priv *priv,
7449a993845SKory Maincent (Dent Project) struct pd692x0_manager *manager,
7459a993845SKory Maincent (Dent Project) struct device_node *np)
7469a993845SKory Maincent (Dent Project) {
7479a993845SKory Maincent (Dent Project) struct device_node *node;
7489a993845SKory Maincent (Dent Project) int ret, nports, i;
7499a993845SKory Maincent (Dent Project)
7509a993845SKory Maincent (Dent Project) nports = 0;
7519a993845SKory Maincent (Dent Project) for_each_child_of_node(np, node) {
7529a993845SKory Maincent (Dent Project) u32 port;
7539a993845SKory Maincent (Dent Project)
7549a993845SKory Maincent (Dent Project) if (!of_node_name_eq(node, "port"))
7559a993845SKory Maincent (Dent Project) continue;
7569a993845SKory Maincent (Dent Project)
7579a993845SKory Maincent (Dent Project) ret = of_property_read_u32(node, "reg", &port);
7589a993845SKory Maincent (Dent Project) if (ret)
7599a993845SKory Maincent (Dent Project) goto out;
7609a993845SKory Maincent (Dent Project)
7619a993845SKory Maincent (Dent Project) if (port >= PD692X0_MAX_MANAGER_PORTS || port != nports) {
7629a993845SKory Maincent (Dent Project) dev_err(&priv->client->dev,
7639a993845SKory Maincent (Dent Project) "wrong number or order of manager ports (%d)\n",
7649a993845SKory Maincent (Dent Project) port);
7659a993845SKory Maincent (Dent Project) ret = -EINVAL;
7669a993845SKory Maincent (Dent Project) goto out;
7679a993845SKory Maincent (Dent Project) }
7689a993845SKory Maincent (Dent Project)
7699a993845SKory Maincent (Dent Project) of_node_get(node);
7709a993845SKory Maincent (Dent Project) manager->port_node[port] = node;
7719a993845SKory Maincent (Dent Project) nports++;
7729a993845SKory Maincent (Dent Project) }
7739a993845SKory Maincent (Dent Project)
7749a993845SKory Maincent (Dent Project) manager->nports = nports;
7759a993845SKory Maincent (Dent Project) return 0;
7769a993845SKory Maincent (Dent Project)
7779a993845SKory Maincent (Dent Project) out:
7789a993845SKory Maincent (Dent Project) for (i = 0; i < nports; i++) {
7799a993845SKory Maincent (Dent Project) of_node_put(manager->port_node[i]);
7809a993845SKory Maincent (Dent Project) manager->port_node[i] = NULL;
7819a993845SKory Maincent (Dent Project) }
7829a993845SKory Maincent (Dent Project) of_node_put(node);
7839a993845SKory Maincent (Dent Project) return ret;
7849a993845SKory Maincent (Dent Project) }
7859a993845SKory Maincent (Dent Project)
7869a993845SKory Maincent (Dent Project) static int
pd692x0_of_get_managers(struct pd692x0_priv * priv,struct pd692x0_manager manager[PD692X0_MAX_MANAGERS])7879a993845SKory Maincent (Dent Project) pd692x0_of_get_managers(struct pd692x0_priv *priv,
7889a993845SKory Maincent (Dent Project) struct pd692x0_manager manager[PD692X0_MAX_MANAGERS])
7899a993845SKory Maincent (Dent Project) {
7909a993845SKory Maincent (Dent Project) struct device_node *managers_node, *node;
7919a993845SKory Maincent (Dent Project) int ret, nmanagers, i, j;
7929a993845SKory Maincent (Dent Project)
7939a993845SKory Maincent (Dent Project) if (!priv->np)
7949a993845SKory Maincent (Dent Project) return -EINVAL;
7959a993845SKory Maincent (Dent Project)
7969a993845SKory Maincent (Dent Project) nmanagers = 0;
7979a993845SKory Maincent (Dent Project) managers_node = of_get_child_by_name(priv->np, "managers");
7989a993845SKory Maincent (Dent Project) if (!managers_node)
7999a993845SKory Maincent (Dent Project) return -EINVAL;
8009a993845SKory Maincent (Dent Project)
8019a993845SKory Maincent (Dent Project) for_each_child_of_node(managers_node, node) {
8029a993845SKory Maincent (Dent Project) u32 manager_id;
8039a993845SKory Maincent (Dent Project)
8049a993845SKory Maincent (Dent Project) if (!of_node_name_eq(node, "manager"))
8059a993845SKory Maincent (Dent Project) continue;
8069a993845SKory Maincent (Dent Project)
8079a993845SKory Maincent (Dent Project) ret = of_property_read_u32(node, "reg", &manager_id);
8089a993845SKory Maincent (Dent Project) if (ret)
8099a993845SKory Maincent (Dent Project) goto out;
8109a993845SKory Maincent (Dent Project)
8119a993845SKory Maincent (Dent Project) if (manager_id >= PD692X0_MAX_MANAGERS ||
8129a993845SKory Maincent (Dent Project) manager_id != nmanagers) {
8139a993845SKory Maincent (Dent Project) dev_err(&priv->client->dev,
8149a993845SKory Maincent (Dent Project) "wrong number or order of managers (%d)\n",
8159a993845SKory Maincent (Dent Project) manager_id);
8169a993845SKory Maincent (Dent Project) ret = -EINVAL;
8179a993845SKory Maincent (Dent Project) goto out;
8189a993845SKory Maincent (Dent Project) }
8199a993845SKory Maincent (Dent Project)
8209a993845SKory Maincent (Dent Project) ret = pd692x0_of_get_ports_manager(priv, &manager[manager_id],
8219a993845SKory Maincent (Dent Project) node);
8229a993845SKory Maincent (Dent Project) if (ret)
8239a993845SKory Maincent (Dent Project) goto out;
8249a993845SKory Maincent (Dent Project)
8259a993845SKory Maincent (Dent Project) nmanagers++;
8269a993845SKory Maincent (Dent Project) }
8279a993845SKory Maincent (Dent Project)
8289a993845SKory Maincent (Dent Project) of_node_put(managers_node);
8299a993845SKory Maincent (Dent Project) return nmanagers;
8309a993845SKory Maincent (Dent Project)
8319a993845SKory Maincent (Dent Project) out:
8329a993845SKory Maincent (Dent Project) for (i = 0; i < nmanagers; i++) {
8339a993845SKory Maincent (Dent Project) for (j = 0; j < manager[i].nports; j++) {
8349a993845SKory Maincent (Dent Project) of_node_put(manager[i].port_node[j]);
8359a993845SKory Maincent (Dent Project) manager[i].port_node[j] = NULL;
8369a993845SKory Maincent (Dent Project) }
8379a993845SKory Maincent (Dent Project) }
8389a993845SKory Maincent (Dent Project)
8399a993845SKory Maincent (Dent Project) of_node_put(node);
8409a993845SKory Maincent (Dent Project) of_node_put(managers_node);
8419a993845SKory Maincent (Dent Project) return ret;
8429a993845SKory Maincent (Dent Project) }
8439a993845SKory Maincent (Dent Project)
8449a993845SKory Maincent (Dent Project) static int
pd692x0_set_port_matrix(const struct pse_pi_pairset * pairset,const struct pd692x0_manager * manager,int nmanagers,struct pd692x0_matrix * port_matrix)8459a993845SKory Maincent (Dent Project) pd692x0_set_port_matrix(const struct pse_pi_pairset *pairset,
8469a993845SKory Maincent (Dent Project) const struct pd692x0_manager *manager,
8479a993845SKory Maincent (Dent Project) int nmanagers, struct pd692x0_matrix *port_matrix)
8489a993845SKory Maincent (Dent Project) {
8499a993845SKory Maincent (Dent Project) int i, j, port_cnt;
8509a993845SKory Maincent (Dent Project) bool found = false;
8519a993845SKory Maincent (Dent Project)
8529a993845SKory Maincent (Dent Project) if (!pairset->np)
8539a993845SKory Maincent (Dent Project) return 0;
8549a993845SKory Maincent (Dent Project)
8559a993845SKory Maincent (Dent Project) /* Look on every managers */
8569a993845SKory Maincent (Dent Project) port_cnt = 0;
8579a993845SKory Maincent (Dent Project) for (i = 0; i < nmanagers; i++) {
8589a993845SKory Maincent (Dent Project) /* Look on every ports of the manager */
8599a993845SKory Maincent (Dent Project) for (j = 0; j < manager[i].nports; j++) {
8609a993845SKory Maincent (Dent Project) if (pairset->np == manager[i].port_node[j]) {
8619a993845SKory Maincent (Dent Project) found = true;
8629a993845SKory Maincent (Dent Project) break;
8639a993845SKory Maincent (Dent Project) }
8649a993845SKory Maincent (Dent Project) }
8659a993845SKory Maincent (Dent Project) port_cnt += j;
8669a993845SKory Maincent (Dent Project)
8679a993845SKory Maincent (Dent Project) if (found)
8689a993845SKory Maincent (Dent Project) break;
8699a993845SKory Maincent (Dent Project) }
8709a993845SKory Maincent (Dent Project)
8719a993845SKory Maincent (Dent Project) if (!found)
8729a993845SKory Maincent (Dent Project) return -ENODEV;
8739a993845SKory Maincent (Dent Project)
8749a993845SKory Maincent (Dent Project) if (pairset->pinout == ALTERNATIVE_A)
8759a993845SKory Maincent (Dent Project) port_matrix->hw_port_a = port_cnt;
8769a993845SKory Maincent (Dent Project) else if (pairset->pinout == ALTERNATIVE_B)
8779a993845SKory Maincent (Dent Project) port_matrix->hw_port_b = port_cnt;
8789a993845SKory Maincent (Dent Project)
8799a993845SKory Maincent (Dent Project) return 0;
8809a993845SKory Maincent (Dent Project) }
8819a993845SKory Maincent (Dent Project)
8829a993845SKory Maincent (Dent Project) static int
pd692x0_set_ports_matrix(struct pd692x0_priv * priv,const struct pd692x0_manager * manager,int nmanagers,struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS])8839a993845SKory Maincent (Dent Project) pd692x0_set_ports_matrix(struct pd692x0_priv *priv,
8849a993845SKory Maincent (Dent Project) const struct pd692x0_manager *manager,
8859a993845SKory Maincent (Dent Project) int nmanagers,
8869a993845SKory Maincent (Dent Project) struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS])
8879a993845SKory Maincent (Dent Project) {
8889a993845SKory Maincent (Dent Project) struct pse_controller_dev *pcdev = &priv->pcdev;
8899a993845SKory Maincent (Dent Project) int i, ret;
8909a993845SKory Maincent (Dent Project)
8919a993845SKory Maincent (Dent Project) /* Init Matrix */
8929a993845SKory Maincent (Dent Project) for (i = 0; i < PD692X0_MAX_PIS; i++) {
8939a993845SKory Maincent (Dent Project) port_matrix[i].hw_port_a = 0xff;
8949a993845SKory Maincent (Dent Project) port_matrix[i].hw_port_b = 0xff;
8959a993845SKory Maincent (Dent Project) }
8969a993845SKory Maincent (Dent Project)
8979a993845SKory Maincent (Dent Project) /* Update with values for every PSE PIs */
8989a993845SKory Maincent (Dent Project) for (i = 0; i < pcdev->nr_lines; i++) {
8999a993845SKory Maincent (Dent Project) ret = pd692x0_set_port_matrix(&pcdev->pi[i].pairset[0],
9009a993845SKory Maincent (Dent Project) manager, nmanagers,
9019a993845SKory Maincent (Dent Project) &port_matrix[i]);
9029a993845SKory Maincent (Dent Project) if (ret) {
9039a993845SKory Maincent (Dent Project) dev_err(&priv->client->dev,
9049a993845SKory Maincent (Dent Project) "unable to configure pi %d pairset 0", i);
9059a993845SKory Maincent (Dent Project) return ret;
9069a993845SKory Maincent (Dent Project) }
9079a993845SKory Maincent (Dent Project)
9089a993845SKory Maincent (Dent Project) ret = pd692x0_set_port_matrix(&pcdev->pi[i].pairset[1],
9099a993845SKory Maincent (Dent Project) manager, nmanagers,
9109a993845SKory Maincent (Dent Project) &port_matrix[i]);
9119a993845SKory Maincent (Dent Project) if (ret) {
9129a993845SKory Maincent (Dent Project) dev_err(&priv->client->dev,
9139a993845SKory Maincent (Dent Project) "unable to configure pi %d pairset 1", i);
9149a993845SKory Maincent (Dent Project) return ret;
9159a993845SKory Maincent (Dent Project) }
9169a993845SKory Maincent (Dent Project) }
9179a993845SKory Maincent (Dent Project)
9189a993845SKory Maincent (Dent Project) return 0;
9199a993845SKory Maincent (Dent Project) }
9209a993845SKory Maincent (Dent Project)
9219a993845SKory Maincent (Dent Project) static int
pd692x0_write_ports_matrix(struct pd692x0_priv * priv,const struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS])9229a993845SKory Maincent (Dent Project) pd692x0_write_ports_matrix(struct pd692x0_priv *priv,
9239a993845SKory Maincent (Dent Project) const struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS])
9249a993845SKory Maincent (Dent Project) {
9259a993845SKory Maincent (Dent Project) struct pd692x0_msg msg, buf;
9269a993845SKory Maincent (Dent Project) int ret, i;
9279a993845SKory Maincent (Dent Project)
9289a993845SKory Maincent (Dent Project) /* Write temporary Matrix */
9299a993845SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_SET_TMP_PORT_MATRIX];
9309a993845SKory Maincent (Dent Project) for (i = 0; i < PD692X0_MAX_PIS; i++) {
9319a993845SKory Maincent (Dent Project) msg.sub[2] = i;
9329a993845SKory Maincent (Dent Project) msg.data[0] = port_matrix[i].hw_port_b;
9339a993845SKory Maincent (Dent Project) msg.data[1] = port_matrix[i].hw_port_a;
9349a993845SKory Maincent (Dent Project)
9359a993845SKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
9369a993845SKory Maincent (Dent Project) if (ret < 0)
9379a993845SKory Maincent (Dent Project) return ret;
9389a993845SKory Maincent (Dent Project) }
9399a993845SKory Maincent (Dent Project)
9409a993845SKory Maincent (Dent Project) /* Program Matrix */
9419a993845SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_PRG_PORT_MATRIX];
9429a993845SKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
9439a993845SKory Maincent (Dent Project) if (ret < 0)
9449a993845SKory Maincent (Dent Project) return ret;
9459a993845SKory Maincent (Dent Project)
9469a993845SKory Maincent (Dent Project) return 0;
9479a993845SKory Maincent (Dent Project) }
9489a993845SKory Maincent (Dent Project)
pd692x0_setup_pi_matrix(struct pse_controller_dev * pcdev)9499a993845SKory Maincent (Dent Project) static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev)
9509a993845SKory Maincent (Dent Project) {
9519a993845SKory Maincent (Dent Project) struct pd692x0_manager manager[PD692X0_MAX_MANAGERS] = {0};
9529a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
9539a993845SKory Maincent (Dent Project) struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS];
9549a993845SKory Maincent (Dent Project) int ret, i, j, nmanagers;
9559a993845SKory Maincent (Dent Project)
9569a993845SKory Maincent (Dent Project) /* Should we flash the port matrix */
9579a993845SKory Maincent (Dent Project) if (priv->fw_state != PD692X0_FW_OK &&
9589a993845SKory Maincent (Dent Project) priv->fw_state != PD692X0_FW_COMPLETE)
9599a993845SKory Maincent (Dent Project) return 0;
9609a993845SKory Maincent (Dent Project)
9619a993845SKory Maincent (Dent Project) ret = pd692x0_of_get_managers(priv, manager);
9629a993845SKory Maincent (Dent Project) if (ret < 0)
9639a993845SKory Maincent (Dent Project) return ret;
9649a993845SKory Maincent (Dent Project)
9659a993845SKory Maincent (Dent Project) nmanagers = ret;
9669a993845SKory Maincent (Dent Project) ret = pd692x0_set_ports_matrix(priv, manager, nmanagers, port_matrix);
9679a993845SKory Maincent (Dent Project) if (ret)
9689a993845SKory Maincent (Dent Project) goto out;
9699a993845SKory Maincent (Dent Project)
9709a993845SKory Maincent (Dent Project) ret = pd692x0_write_ports_matrix(priv, port_matrix);
9719a993845SKory Maincent (Dent Project) if (ret)
9729a993845SKory Maincent (Dent Project) goto out;
9739a993845SKory Maincent (Dent Project)
9749a993845SKory Maincent (Dent Project) out:
9759a993845SKory Maincent (Dent Project) for (i = 0; i < nmanagers; i++) {
9769a993845SKory Maincent (Dent Project) for (j = 0; j < manager[i].nports; j++)
9779a993845SKory Maincent (Dent Project) of_node_put(manager[i].port_node[j]);
9789a993845SKory Maincent (Dent Project) }
9799a993845SKory Maincent (Dent Project) return ret;
9809a993845SKory Maincent (Dent Project) }
9819a993845SKory Maincent (Dent Project)
pd692x0_pi_get_voltage(struct pse_controller_dev * pcdev,int id)982a87e699cSKory Maincent (Dent Project) static int pd692x0_pi_get_voltage(struct pse_controller_dev *pcdev, int id)
983a87e699cSKory Maincent (Dent Project) {
984a87e699cSKory Maincent (Dent Project) struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
985a87e699cSKory Maincent (Dent Project) struct pd692x0_msg msg, buf = {0};
986a87e699cSKory Maincent (Dent Project) int ret;
987a87e699cSKory Maincent (Dent Project)
988a87e699cSKory Maincent (Dent Project) ret = pd692x0_fw_unavailable(priv);
989a87e699cSKory Maincent (Dent Project) if (ret)
990a87e699cSKory Maincent (Dent Project) return ret;
991a87e699cSKory Maincent (Dent Project)
992a87e699cSKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_MEAS];
993a87e699cSKory Maincent (Dent Project) msg.sub[2] = id;
994a87e699cSKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
995a87e699cSKory Maincent (Dent Project) if (ret < 0)
996a87e699cSKory Maincent (Dent Project) return ret;
997a87e699cSKory Maincent (Dent Project)
998a87e699cSKory Maincent (Dent Project) /* Convert 0.1V unit to uV */
999a87e699cSKory Maincent (Dent Project) return (buf.sub[0] << 8 | buf.sub[1]) * 100000;
1000a87e699cSKory Maincent (Dent Project) }
1001a87e699cSKory Maincent (Dent Project)
pd692x0_pi_get_current_limit(struct pse_controller_dev * pcdev,int id)1002a87e699cSKory Maincent (Dent Project) static int pd692x0_pi_get_current_limit(struct pse_controller_dev *pcdev,
1003a87e699cSKory Maincent (Dent Project) int id)
1004a87e699cSKory Maincent (Dent Project) {
1005a87e699cSKory Maincent (Dent Project) struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
1006a87e699cSKory Maincent (Dent Project) struct pd692x0_msg msg, buf = {0};
1007a87e699cSKory Maincent (Dent Project) int mW, uV, uA, ret;
1008a87e699cSKory Maincent (Dent Project) s64 tmp_64;
1009a87e699cSKory Maincent (Dent Project)
1010a87e699cSKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_GET_PORT_PARAM];
1011a87e699cSKory Maincent (Dent Project) msg.sub[2] = id;
1012a87e699cSKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
1013a87e699cSKory Maincent (Dent Project) if (ret < 0)
1014a87e699cSKory Maincent (Dent Project) return ret;
1015a87e699cSKory Maincent (Dent Project)
1016a87e699cSKory Maincent (Dent Project) ret = pd692x0_pi_get_pw_from_table(buf.data[2], buf.data[3]);
1017a87e699cSKory Maincent (Dent Project) if (ret < 0)
1018a87e699cSKory Maincent (Dent Project) return ret;
1019a87e699cSKory Maincent (Dent Project) mW = ret;
1020a87e699cSKory Maincent (Dent Project)
1021a87e699cSKory Maincent (Dent Project) ret = pd692x0_pi_get_voltage(pcdev, id);
1022a87e699cSKory Maincent (Dent Project) if (ret < 0)
1023a87e699cSKory Maincent (Dent Project) return ret;
1024a87e699cSKory Maincent (Dent Project) uV = ret;
1025a87e699cSKory Maincent (Dent Project)
1026a87e699cSKory Maincent (Dent Project) tmp_64 = mW;
1027a87e699cSKory Maincent (Dent Project) tmp_64 *= 1000000000ull;
1028a87e699cSKory Maincent (Dent Project) /* uA = mW * 1000000000 / uV */
1029a87e699cSKory Maincent (Dent Project) uA = DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
1030a87e699cSKory Maincent (Dent Project) return uA;
1031a87e699cSKory Maincent (Dent Project) }
1032a87e699cSKory Maincent (Dent Project)
pd692x0_pi_set_current_limit(struct pse_controller_dev * pcdev,int id,int max_uA)1033a87e699cSKory Maincent (Dent Project) static int pd692x0_pi_set_current_limit(struct pse_controller_dev *pcdev,
1034a87e699cSKory Maincent (Dent Project) int id, int max_uA)
1035a87e699cSKory Maincent (Dent Project) {
1036a87e699cSKory Maincent (Dent Project) struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
1037a87e699cSKory Maincent (Dent Project) struct device *dev = &priv->client->dev;
1038a87e699cSKory Maincent (Dent Project) struct pd692x0_msg msg, buf = {0};
1039a87e699cSKory Maincent (Dent Project) int uV, ret, mW;
1040a87e699cSKory Maincent (Dent Project) s64 tmp_64;
1041a87e699cSKory Maincent (Dent Project)
1042a87e699cSKory Maincent (Dent Project) ret = pd692x0_fw_unavailable(priv);
1043a87e699cSKory Maincent (Dent Project) if (ret)
1044a87e699cSKory Maincent (Dent Project) return ret;
1045a87e699cSKory Maincent (Dent Project)
1046a87e699cSKory Maincent (Dent Project) ret = pd692x0_pi_get_voltage(pcdev, id);
1047a87e699cSKory Maincent (Dent Project) if (ret < 0)
1048a87e699cSKory Maincent (Dent Project) return ret;
1049a87e699cSKory Maincent (Dent Project) uV = ret;
1050a87e699cSKory Maincent (Dent Project)
1051a87e699cSKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_SET_PORT_PARAM];
1052a87e699cSKory Maincent (Dent Project) msg.sub[2] = id;
1053a87e699cSKory Maincent (Dent Project) tmp_64 = uV;
1054a87e699cSKory Maincent (Dent Project) tmp_64 *= max_uA;
1055a87e699cSKory Maincent (Dent Project) /* mW = uV * uA / 1000000000 */
1056a87e699cSKory Maincent (Dent Project) mW = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000000000);
1057a87e699cSKory Maincent (Dent Project) ret = pd692x0_pi_set_pw_from_table(dev, &msg, mW);
1058a87e699cSKory Maincent (Dent Project) if (ret)
1059a87e699cSKory Maincent (Dent Project) return ret;
1060a87e699cSKory Maincent (Dent Project)
1061a87e699cSKory Maincent (Dent Project) return pd692x0_sendrecv_msg(priv, &msg, &buf);
1062a87e699cSKory Maincent (Dent Project) }
1063a87e699cSKory Maincent (Dent Project)
10649a993845SKory Maincent (Dent Project) static const struct pse_controller_ops pd692x0_ops = {
10659a993845SKory Maincent (Dent Project) .setup_pi_matrix = pd692x0_setup_pi_matrix,
10669a993845SKory Maincent (Dent Project) .ethtool_get_status = pd692x0_ethtool_get_status,
10679a993845SKory Maincent (Dent Project) .pi_enable = pd692x0_pi_enable,
10689a993845SKory Maincent (Dent Project) .pi_disable = pd692x0_pi_disable,
10699a993845SKory Maincent (Dent Project) .pi_is_enabled = pd692x0_pi_is_enabled,
1070a87e699cSKory Maincent (Dent Project) .pi_get_voltage = pd692x0_pi_get_voltage,
1071a87e699cSKory Maincent (Dent Project) .pi_get_current_limit = pd692x0_pi_get_current_limit,
1072a87e699cSKory Maincent (Dent Project) .pi_set_current_limit = pd692x0_pi_set_current_limit,
10739a993845SKory Maincent (Dent Project) };
10749a993845SKory Maincent (Dent Project)
10759a993845SKory Maincent (Dent Project) #define PD692X0_FW_LINE_MAX_SZ 0xff
pd692x0_fw_get_next_line(const u8 * data,char * line,size_t size)10769a993845SKory Maincent (Dent Project) static int pd692x0_fw_get_next_line(const u8 *data,
10779a993845SKory Maincent (Dent Project) char *line, size_t size)
10789a993845SKory Maincent (Dent Project) {
10799a993845SKory Maincent (Dent Project) size_t line_size;
10809a993845SKory Maincent (Dent Project) int i;
10819a993845SKory Maincent (Dent Project)
10829a993845SKory Maincent (Dent Project) line_size = min_t(size_t, size, PD692X0_FW_LINE_MAX_SZ);
10839a993845SKory Maincent (Dent Project)
10849a993845SKory Maincent (Dent Project) memset(line, 0, PD692X0_FW_LINE_MAX_SZ);
10859a993845SKory Maincent (Dent Project) for (i = 0; i < line_size - 1; i++) {
10869a993845SKory Maincent (Dent Project) if (*data == '\r' && *(data + 1) == '\n') {
10879a993845SKory Maincent (Dent Project) line[i] = '\r';
10889a993845SKory Maincent (Dent Project) line[i + 1] = '\n';
10899a993845SKory Maincent (Dent Project) return i + 2;
10909a993845SKory Maincent (Dent Project) }
10919a993845SKory Maincent (Dent Project) line[i] = *data;
10929a993845SKory Maincent (Dent Project) data++;
10939a993845SKory Maincent (Dent Project) }
10949a993845SKory Maincent (Dent Project)
10959a993845SKory Maincent (Dent Project) return -EIO;
10969a993845SKory Maincent (Dent Project) }
10979a993845SKory Maincent (Dent Project)
10989a993845SKory Maincent (Dent Project) static enum fw_upload_err
pd692x0_fw_recv_resp(const struct i2c_client * client,unsigned long ms_timeout,const char * msg_ok,unsigned int msg_size)10999a993845SKory Maincent (Dent Project) pd692x0_fw_recv_resp(const struct i2c_client *client, unsigned long ms_timeout,
11009a993845SKory Maincent (Dent Project) const char *msg_ok, unsigned int msg_size)
11019a993845SKory Maincent (Dent Project) {
11029a993845SKory Maincent (Dent Project) /* Maximum controller response size */
11039a993845SKory Maincent (Dent Project) char fw_msg_buf[5] = {0};
11049a993845SKory Maincent (Dent Project) unsigned long timeout;
11059a993845SKory Maincent (Dent Project) int ret;
11069a993845SKory Maincent (Dent Project)
11079a993845SKory Maincent (Dent Project) if (msg_size > sizeof(fw_msg_buf))
11089a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_RW_ERROR;
11099a993845SKory Maincent (Dent Project)
11109a993845SKory Maincent (Dent Project) /* Read until we get something */
11119a993845SKory Maincent (Dent Project) timeout = msecs_to_jiffies(ms_timeout) + jiffies;
11129a993845SKory Maincent (Dent Project) while (true) {
11139a993845SKory Maincent (Dent Project) if (time_is_before_jiffies(timeout))
11149a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_TIMEOUT;
11159a993845SKory Maincent (Dent Project)
11169a993845SKory Maincent (Dent Project) ret = i2c_master_recv(client, fw_msg_buf, 1);
11179a993845SKory Maincent (Dent Project) if (ret < 0 || *fw_msg_buf == 0) {
11189a993845SKory Maincent (Dent Project) usleep_range(1000, 2000);
11199a993845SKory Maincent (Dent Project) continue;
11209a993845SKory Maincent (Dent Project) } else {
11219a993845SKory Maincent (Dent Project) break;
11229a993845SKory Maincent (Dent Project) }
11239a993845SKory Maincent (Dent Project) }
11249a993845SKory Maincent (Dent Project)
11259a993845SKory Maincent (Dent Project) /* Read remaining characters */
11269a993845SKory Maincent (Dent Project) ret = i2c_master_recv(client, fw_msg_buf + 1, msg_size - 1);
11279a993845SKory Maincent (Dent Project) if (strncmp(fw_msg_buf, msg_ok, msg_size)) {
11289a993845SKory Maincent (Dent Project) dev_err(&client->dev,
11299a993845SKory Maincent (Dent Project) "Wrong FW download process answer (%*pE)\n",
11309a993845SKory Maincent (Dent Project) msg_size, fw_msg_buf);
11319a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_HW_ERROR;
11329a993845SKory Maincent (Dent Project) }
11339a993845SKory Maincent (Dent Project)
11349a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_NONE;
11359a993845SKory Maincent (Dent Project) }
11369a993845SKory Maincent (Dent Project)
pd692x0_fw_write_line(const struct i2c_client * client,const char line[PD692X0_FW_LINE_MAX_SZ],const bool last_line)11379a993845SKory Maincent (Dent Project) static int pd692x0_fw_write_line(const struct i2c_client *client,
11389a993845SKory Maincent (Dent Project) const char line[PD692X0_FW_LINE_MAX_SZ],
11399a993845SKory Maincent (Dent Project) const bool last_line)
11409a993845SKory Maincent (Dent Project) {
11419a993845SKory Maincent (Dent Project) int ret;
11429a993845SKory Maincent (Dent Project)
11439a993845SKory Maincent (Dent Project) while (*line != 0) {
11449a993845SKory Maincent (Dent Project) ret = i2c_master_send(client, line, 1);
11459a993845SKory Maincent (Dent Project) if (ret < 0)
11469a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_RW_ERROR;
11479a993845SKory Maincent (Dent Project) line++;
11489a993845SKory Maincent (Dent Project) }
11499a993845SKory Maincent (Dent Project)
11509a993845SKory Maincent (Dent Project) if (last_line) {
11519a993845SKory Maincent (Dent Project) ret = pd692x0_fw_recv_resp(client, 100, "TP\r\n",
11529a993845SKory Maincent (Dent Project) sizeof("TP\r\n") - 1);
11539a993845SKory Maincent (Dent Project) if (ret)
11549a993845SKory Maincent (Dent Project) return ret;
11559a993845SKory Maincent (Dent Project) } else {
11569a993845SKory Maincent (Dent Project) ret = pd692x0_fw_recv_resp(client, 100, "T*\r\n",
11579a993845SKory Maincent (Dent Project) sizeof("T*\r\n") - 1);
11589a993845SKory Maincent (Dent Project) if (ret)
11599a993845SKory Maincent (Dent Project) return ret;
11609a993845SKory Maincent (Dent Project) }
11619a993845SKory Maincent (Dent Project)
11629a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_NONE;
11639a993845SKory Maincent (Dent Project) }
11649a993845SKory Maincent (Dent Project)
pd692x0_fw_reset(const struct i2c_client * client)11659a993845SKory Maincent (Dent Project) static enum fw_upload_err pd692x0_fw_reset(const struct i2c_client *client)
11669a993845SKory Maincent (Dent Project) {
11679a993845SKory Maincent (Dent Project) const struct pd692x0_msg zero = {0};
11689a993845SKory Maincent (Dent Project) struct pd692x0_msg buf = {0};
11699a993845SKory Maincent (Dent Project) unsigned long timeout;
11709a993845SKory Maincent (Dent Project) char cmd[] = "RST";
11719a993845SKory Maincent (Dent Project) int ret;
11729a993845SKory Maincent (Dent Project)
11739a993845SKory Maincent (Dent Project) ret = i2c_master_send(client, cmd, strlen(cmd));
11749a993845SKory Maincent (Dent Project) if (ret < 0) {
11759a993845SKory Maincent (Dent Project) dev_err(&client->dev,
11769a993845SKory Maincent (Dent Project) "Failed to reset the controller (%pe)\n",
11779a993845SKory Maincent (Dent Project) ERR_PTR(ret));
11789a993845SKory Maincent (Dent Project) return ret;
11799a993845SKory Maincent (Dent Project) }
11809a993845SKory Maincent (Dent Project)
11819a993845SKory Maincent (Dent Project) timeout = msecs_to_jiffies(10000) + jiffies;
11829a993845SKory Maincent (Dent Project) while (true) {
11839a993845SKory Maincent (Dent Project) if (time_is_before_jiffies(timeout))
11849a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_TIMEOUT;
11859a993845SKory Maincent (Dent Project)
11869a993845SKory Maincent (Dent Project) ret = i2c_master_recv(client, (u8 *)&buf, sizeof(buf));
11879a993845SKory Maincent (Dent Project) if (ret < 0 ||
11889a993845SKory Maincent (Dent Project) !memcmp(&buf, &zero, sizeof(buf)))
11899a993845SKory Maincent (Dent Project) usleep_range(1000, 2000);
11909a993845SKory Maincent (Dent Project) else
11919a993845SKory Maincent (Dent Project) break;
11929a993845SKory Maincent (Dent Project) }
11939a993845SKory Maincent (Dent Project)
11949a993845SKory Maincent (Dent Project) /* Is the reply a successful report message */
11959a993845SKory Maincent (Dent Project) if (buf.key != PD692X0_KEY_TLM || buf.echo != 0xff ||
11969a993845SKory Maincent (Dent Project) buf.sub[0] & 0x01) {
11979a993845SKory Maincent (Dent Project) dev_err(&client->dev, "PSE controller error\n");
11989a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_HW_ERROR;
11999a993845SKory Maincent (Dent Project) }
12009a993845SKory Maincent (Dent Project)
12019a993845SKory Maincent (Dent Project) /* Is the firmware operational */
12029a993845SKory Maincent (Dent Project) if (buf.sub[0] & 0x02) {
12039a993845SKory Maincent (Dent Project) dev_err(&client->dev,
12049a993845SKory Maincent (Dent Project) "PSE firmware error. Please update it.\n");
12059a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_HW_ERROR;
12069a993845SKory Maincent (Dent Project) }
12079a993845SKory Maincent (Dent Project)
12089a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_NONE;
12099a993845SKory Maincent (Dent Project) }
12109a993845SKory Maincent (Dent Project)
pd692x0_fw_prepare(struct fw_upload * fwl,const u8 * data,u32 size)12119a993845SKory Maincent (Dent Project) static enum fw_upload_err pd692x0_fw_prepare(struct fw_upload *fwl,
12129a993845SKory Maincent (Dent Project) const u8 *data, u32 size)
12139a993845SKory Maincent (Dent Project) {
12149a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = fwl->dd_handle;
12159a993845SKory Maincent (Dent Project) const struct i2c_client *client = priv->client;
12169a993845SKory Maincent (Dent Project) enum pd692x0_fw_state last_fw_state;
12179a993845SKory Maincent (Dent Project) int ret;
12189a993845SKory Maincent (Dent Project)
12199a993845SKory Maincent (Dent Project) priv->cancel_request = false;
12209a993845SKory Maincent (Dent Project) last_fw_state = priv->fw_state;
12219a993845SKory Maincent (Dent Project)
12229a993845SKory Maincent (Dent Project) priv->fw_state = PD692X0_FW_PREPARE;
12239a993845SKory Maincent (Dent Project)
12249a993845SKory Maincent (Dent Project) /* Enter program mode */
12259a993845SKory Maincent (Dent Project) if (last_fw_state == PD692X0_FW_BROKEN) {
12269a993845SKory Maincent (Dent Project) const char *msg = "ENTR";
12279a993845SKory Maincent (Dent Project) const char *c;
12289a993845SKory Maincent (Dent Project)
12299a993845SKory Maincent (Dent Project) c = msg;
12309a993845SKory Maincent (Dent Project) do {
12319a993845SKory Maincent (Dent Project) ret = i2c_master_send(client, c, 1);
12329a993845SKory Maincent (Dent Project) if (ret < 0)
12339a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_RW_ERROR;
12349a993845SKory Maincent (Dent Project) if (*(c + 1))
12359a993845SKory Maincent (Dent Project) usleep_range(10000, 20000);
12369a993845SKory Maincent (Dent Project) } while (*(++c));
12379a993845SKory Maincent (Dent Project) } else {
12389a993845SKory Maincent (Dent Project) struct pd692x0_msg msg, buf;
12399a993845SKory Maincent (Dent Project)
12409a993845SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_DOWNLOAD_CMD];
12419a993845SKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
12429a993845SKory Maincent (Dent Project) if (ret < 0) {
12439a993845SKory Maincent (Dent Project) dev_err(&client->dev,
12449a993845SKory Maincent (Dent Project) "Failed to enter programming mode (%pe)\n",
12459a993845SKory Maincent (Dent Project) ERR_PTR(ret));
12469a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_RW_ERROR;
12479a993845SKory Maincent (Dent Project) }
12489a993845SKory Maincent (Dent Project) }
12499a993845SKory Maincent (Dent Project)
12509a993845SKory Maincent (Dent Project) ret = pd692x0_fw_recv_resp(client, 100, "TPE\r\n", sizeof("TPE\r\n") - 1);
12519a993845SKory Maincent (Dent Project) if (ret)
12529a993845SKory Maincent (Dent Project) goto err_out;
12539a993845SKory Maincent (Dent Project)
12549a993845SKory Maincent (Dent Project) if (priv->cancel_request) {
12559a993845SKory Maincent (Dent Project) ret = FW_UPLOAD_ERR_CANCELED;
12569a993845SKory Maincent (Dent Project) goto err_out;
12579a993845SKory Maincent (Dent Project) }
12589a993845SKory Maincent (Dent Project)
12599a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_NONE;
12609a993845SKory Maincent (Dent Project)
12619a993845SKory Maincent (Dent Project) err_out:
12629a993845SKory Maincent (Dent Project) pd692x0_fw_reset(priv->client);
12639a993845SKory Maincent (Dent Project) priv->fw_state = last_fw_state;
12649a993845SKory Maincent (Dent Project) return ret;
12659a993845SKory Maincent (Dent Project) }
12669a993845SKory Maincent (Dent Project)
pd692x0_fw_write(struct fw_upload * fwl,const u8 * data,u32 offset,u32 size,u32 * written)12679a993845SKory Maincent (Dent Project) static enum fw_upload_err pd692x0_fw_write(struct fw_upload *fwl,
12689a993845SKory Maincent (Dent Project) const u8 *data, u32 offset,
12699a993845SKory Maincent (Dent Project) u32 size, u32 *written)
12709a993845SKory Maincent (Dent Project) {
12719a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = fwl->dd_handle;
12729a993845SKory Maincent (Dent Project) char line[PD692X0_FW_LINE_MAX_SZ];
12739a993845SKory Maincent (Dent Project) const struct i2c_client *client;
12749a993845SKory Maincent (Dent Project) int ret, i;
12759a993845SKory Maincent (Dent Project) char cmd;
12769a993845SKory Maincent (Dent Project)
12779a993845SKory Maincent (Dent Project) client = priv->client;
12789a993845SKory Maincent (Dent Project) priv->fw_state = PD692X0_FW_WRITE;
12799a993845SKory Maincent (Dent Project)
12809a993845SKory Maincent (Dent Project) /* Erase */
12819a993845SKory Maincent (Dent Project) cmd = 'E';
12829a993845SKory Maincent (Dent Project) ret = i2c_master_send(client, &cmd, 1);
12839a993845SKory Maincent (Dent Project) if (ret < 0) {
12849a993845SKory Maincent (Dent Project) dev_err(&client->dev,
12859a993845SKory Maincent (Dent Project) "Failed to boot programming mode (%pe)\n",
12869a993845SKory Maincent (Dent Project) ERR_PTR(ret));
12879a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_RW_ERROR;
12889a993845SKory Maincent (Dent Project) }
12899a993845SKory Maincent (Dent Project)
12909a993845SKory Maincent (Dent Project) ret = pd692x0_fw_recv_resp(client, 100, "TOE\r\n", sizeof("TOE\r\n") - 1);
12919a993845SKory Maincent (Dent Project) if (ret)
12929a993845SKory Maincent (Dent Project) return ret;
12939a993845SKory Maincent (Dent Project)
12949a993845SKory Maincent (Dent Project) ret = pd692x0_fw_recv_resp(client, 5000, "TE\r\n", sizeof("TE\r\n") - 1);
12959a993845SKory Maincent (Dent Project) if (ret)
12969a993845SKory Maincent (Dent Project) dev_warn(&client->dev,
12979a993845SKory Maincent (Dent Project) "Failed to erase internal memory, however still try to write Firmware\n");
12989a993845SKory Maincent (Dent Project)
12999a993845SKory Maincent (Dent Project) ret = pd692x0_fw_recv_resp(client, 100, "TPE\r\n", sizeof("TPE\r\n") - 1);
13009a993845SKory Maincent (Dent Project) if (ret)
13019a993845SKory Maincent (Dent Project) dev_warn(&client->dev,
13029a993845SKory Maincent (Dent Project) "Failed to erase internal memory, however still try to write Firmware\n");
13039a993845SKory Maincent (Dent Project)
13049a993845SKory Maincent (Dent Project) if (priv->cancel_request)
13059a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_CANCELED;
13069a993845SKory Maincent (Dent Project)
13079a993845SKory Maincent (Dent Project) /* Program */
13089a993845SKory Maincent (Dent Project) cmd = 'P';
13099a993845SKory Maincent (Dent Project) ret = i2c_master_send(client, &cmd, sizeof(char));
13109a993845SKory Maincent (Dent Project) if (ret < 0) {
13119a993845SKory Maincent (Dent Project) dev_err(&client->dev,
13129a993845SKory Maincent (Dent Project) "Failed to boot programming mode (%pe)\n",
13139a993845SKory Maincent (Dent Project) ERR_PTR(ret));
13149a993845SKory Maincent (Dent Project) return ret;
13159a993845SKory Maincent (Dent Project) }
13169a993845SKory Maincent (Dent Project)
13179a993845SKory Maincent (Dent Project) ret = pd692x0_fw_recv_resp(client, 100, "TOP\r\n", sizeof("TOP\r\n") - 1);
13189a993845SKory Maincent (Dent Project) if (ret)
13199a993845SKory Maincent (Dent Project) return ret;
13209a993845SKory Maincent (Dent Project)
13219a993845SKory Maincent (Dent Project) i = 0;
13229a993845SKory Maincent (Dent Project) while (i < size) {
13239a993845SKory Maincent (Dent Project) ret = pd692x0_fw_get_next_line(data, line, size - i);
13249a993845SKory Maincent (Dent Project) if (ret < 0) {
13259a993845SKory Maincent (Dent Project) ret = FW_UPLOAD_ERR_FW_INVALID;
13269a993845SKory Maincent (Dent Project) goto err;
13279a993845SKory Maincent (Dent Project) }
13289a993845SKory Maincent (Dent Project)
13299a993845SKory Maincent (Dent Project) i += ret;
13309a993845SKory Maincent (Dent Project) data += ret;
13319a993845SKory Maincent (Dent Project) if (line[0] == 'S' && line[1] == '0') {
13329a993845SKory Maincent (Dent Project) continue;
13339a993845SKory Maincent (Dent Project) } else if (line[0] == 'S' && line[1] == '7') {
13349a993845SKory Maincent (Dent Project) ret = pd692x0_fw_write_line(client, line, true);
13359a993845SKory Maincent (Dent Project) if (ret)
13369a993845SKory Maincent (Dent Project) goto err;
13379a993845SKory Maincent (Dent Project) } else {
13389a993845SKory Maincent (Dent Project) ret = pd692x0_fw_write_line(client, line, false);
13399a993845SKory Maincent (Dent Project) if (ret)
13409a993845SKory Maincent (Dent Project) goto err;
13419a993845SKory Maincent (Dent Project) }
13429a993845SKory Maincent (Dent Project)
13439a993845SKory Maincent (Dent Project) if (priv->cancel_request) {
13449a993845SKory Maincent (Dent Project) ret = FW_UPLOAD_ERR_CANCELED;
13459a993845SKory Maincent (Dent Project) goto err;
13469a993845SKory Maincent (Dent Project) }
13479a993845SKory Maincent (Dent Project) }
13489a993845SKory Maincent (Dent Project) *written = i;
13499a993845SKory Maincent (Dent Project)
13509a993845SKory Maincent (Dent Project) msleep(400);
13519a993845SKory Maincent (Dent Project)
13529a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_NONE;
13539a993845SKory Maincent (Dent Project)
13549a993845SKory Maincent (Dent Project) err:
13559a993845SKory Maincent (Dent Project) strscpy_pad(line, "S7\r\n", sizeof(line));
13569a993845SKory Maincent (Dent Project) pd692x0_fw_write_line(client, line, true);
13579a993845SKory Maincent (Dent Project) return ret;
13589a993845SKory Maincent (Dent Project) }
13599a993845SKory Maincent (Dent Project)
pd692x0_fw_poll_complete(struct fw_upload * fwl)13609a993845SKory Maincent (Dent Project) static enum fw_upload_err pd692x0_fw_poll_complete(struct fw_upload *fwl)
13619a993845SKory Maincent (Dent Project) {
13629a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = fwl->dd_handle;
13639a993845SKory Maincent (Dent Project) const struct i2c_client *client = priv->client;
13649a993845SKory Maincent (Dent Project) struct pd692x0_msg_ver ver;
13659a993845SKory Maincent (Dent Project) int ret;
13669a993845SKory Maincent (Dent Project)
13679a993845SKory Maincent (Dent Project) priv->fw_state = PD692X0_FW_COMPLETE;
13689a993845SKory Maincent (Dent Project)
13699a993845SKory Maincent (Dent Project) ret = pd692x0_fw_reset(client);
13709a993845SKory Maincent (Dent Project) if (ret)
13719a993845SKory Maincent (Dent Project) return ret;
13729a993845SKory Maincent (Dent Project)
13739a993845SKory Maincent (Dent Project) ver = pd692x0_get_sw_version(priv);
13749a993845SKory Maincent (Dent Project) if (ver.maj_sw_ver < PD692X0_FW_MAJ_VER) {
13759a993845SKory Maincent (Dent Project) dev_err(&client->dev,
13769a993845SKory Maincent (Dent Project) "Too old firmware version. Please update it\n");
13779a993845SKory Maincent (Dent Project) priv->fw_state = PD692X0_FW_NEED_UPDATE;
13789a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_FW_INVALID;
13799a993845SKory Maincent (Dent Project) }
13809a993845SKory Maincent (Dent Project)
13819a993845SKory Maincent (Dent Project) ret = pd692x0_setup_pi_matrix(&priv->pcdev);
13829a993845SKory Maincent (Dent Project) if (ret < 0) {
13839a993845SKory Maincent (Dent Project) dev_err(&client->dev, "Error configuring ports matrix (%pe)\n",
13849a993845SKory Maincent (Dent Project) ERR_PTR(ret));
13859a993845SKory Maincent (Dent Project) priv->fw_state = PD692X0_FW_NEED_UPDATE;
13869a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_HW_ERROR;
13879a993845SKory Maincent (Dent Project) }
13889a993845SKory Maincent (Dent Project)
13899a993845SKory Maincent (Dent Project) priv->fw_state = PD692X0_FW_OK;
13909a993845SKory Maincent (Dent Project) return FW_UPLOAD_ERR_NONE;
13919a993845SKory Maincent (Dent Project) }
13929a993845SKory Maincent (Dent Project)
pd692x0_fw_cancel(struct fw_upload * fwl)13939a993845SKory Maincent (Dent Project) static void pd692x0_fw_cancel(struct fw_upload *fwl)
13949a993845SKory Maincent (Dent Project) {
13959a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = fwl->dd_handle;
13969a993845SKory Maincent (Dent Project)
13979a993845SKory Maincent (Dent Project) priv->cancel_request = true;
13989a993845SKory Maincent (Dent Project) }
13999a993845SKory Maincent (Dent Project)
pd692x0_fw_cleanup(struct fw_upload * fwl)14009a993845SKory Maincent (Dent Project) static void pd692x0_fw_cleanup(struct fw_upload *fwl)
14019a993845SKory Maincent (Dent Project) {
14029a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = fwl->dd_handle;
14039a993845SKory Maincent (Dent Project)
14049a993845SKory Maincent (Dent Project) switch (priv->fw_state) {
14059a993845SKory Maincent (Dent Project) case PD692X0_FW_WRITE:
14069a993845SKory Maincent (Dent Project) pd692x0_fw_reset(priv->client);
14079a993845SKory Maincent (Dent Project) fallthrough;
14089a993845SKory Maincent (Dent Project) case PD692X0_FW_COMPLETE:
14099a993845SKory Maincent (Dent Project) priv->fw_state = PD692X0_FW_BROKEN;
14109a993845SKory Maincent (Dent Project) break;
14119a993845SKory Maincent (Dent Project) default:
14129a993845SKory Maincent (Dent Project) break;
14139a993845SKory Maincent (Dent Project) }
14149a993845SKory Maincent (Dent Project) }
14159a993845SKory Maincent (Dent Project)
14169a993845SKory Maincent (Dent Project) static const struct fw_upload_ops pd692x0_fw_ops = {
14179a993845SKory Maincent (Dent Project) .prepare = pd692x0_fw_prepare,
14189a993845SKory Maincent (Dent Project) .write = pd692x0_fw_write,
14199a993845SKory Maincent (Dent Project) .poll_complete = pd692x0_fw_poll_complete,
14209a993845SKory Maincent (Dent Project) .cancel = pd692x0_fw_cancel,
14219a993845SKory Maincent (Dent Project) .cleanup = pd692x0_fw_cleanup,
14229a993845SKory Maincent (Dent Project) };
14239a993845SKory Maincent (Dent Project)
pd692x0_i2c_probe(struct i2c_client * client)14249a993845SKory Maincent (Dent Project) static int pd692x0_i2c_probe(struct i2c_client *client)
14259a993845SKory Maincent (Dent Project) {
14269a993845SKory Maincent (Dent Project) struct pd692x0_msg msg, buf = {0}, zero = {0};
14279a993845SKory Maincent (Dent Project) struct device *dev = &client->dev;
14289a993845SKory Maincent (Dent Project) struct pd692x0_msg_ver ver;
14299a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv;
14309a993845SKory Maincent (Dent Project) struct fw_upload *fwl;
14319a993845SKory Maincent (Dent Project) int ret;
14329a993845SKory Maincent (Dent Project)
14339a993845SKory Maincent (Dent Project) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
14349a993845SKory Maincent (Dent Project) dev_err(dev, "i2c check functionality failed\n");
14359a993845SKory Maincent (Dent Project) return -ENXIO;
14369a993845SKory Maincent (Dent Project) }
14379a993845SKory Maincent (Dent Project)
14389a993845SKory Maincent (Dent Project) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
14399a993845SKory Maincent (Dent Project) if (!priv)
14409a993845SKory Maincent (Dent Project) return -ENOMEM;
14419a993845SKory Maincent (Dent Project)
14429a993845SKory Maincent (Dent Project) priv->client = client;
14439a993845SKory Maincent (Dent Project) i2c_set_clientdata(client, priv);
14449a993845SKory Maincent (Dent Project)
14459a993845SKory Maincent (Dent Project) ret = i2c_master_recv(client, (u8 *)&buf, sizeof(buf));
14469a993845SKory Maincent (Dent Project) if (ret != sizeof(buf)) {
14479a993845SKory Maincent (Dent Project) dev_err(dev, "Failed to get device status\n");
14489a993845SKory Maincent (Dent Project) return -EIO;
14499a993845SKory Maincent (Dent Project) }
14509a993845SKory Maincent (Dent Project)
14519a993845SKory Maincent (Dent Project) /* Probe has been already run and the status dumped */
14529a993845SKory Maincent (Dent Project) if (!memcmp(&buf, &zero, sizeof(buf))) {
14539a993845SKory Maincent (Dent Project) /* Ask again the controller status */
14549a993845SKory Maincent (Dent Project) msg = pd692x0_msg_template_list[PD692X0_MSG_GET_SYS_STATUS];
14559a993845SKory Maincent (Dent Project) ret = pd692x0_sendrecv_msg(priv, &msg, &buf);
14569a993845SKory Maincent (Dent Project) if (ret < 0) {
14579a993845SKory Maincent (Dent Project) dev_err(dev, "Failed to get device status\n");
14589a993845SKory Maincent (Dent Project) return ret;
14599a993845SKory Maincent (Dent Project) }
14609a993845SKory Maincent (Dent Project) }
14619a993845SKory Maincent (Dent Project)
14629a993845SKory Maincent (Dent Project) if (buf.key != 0x03 || buf.sub[0] & 0x01) {
14639a993845SKory Maincent (Dent Project) dev_err(dev, "PSE controller error\n");
14649a993845SKory Maincent (Dent Project) return -EIO;
14659a993845SKory Maincent (Dent Project) }
14669a993845SKory Maincent (Dent Project) if (buf.sub[0] & 0x02) {
14679a993845SKory Maincent (Dent Project) dev_err(dev, "PSE firmware error. Please update it.\n");
14689a993845SKory Maincent (Dent Project) priv->fw_state = PD692X0_FW_BROKEN;
14699a993845SKory Maincent (Dent Project) } else {
14709a993845SKory Maincent (Dent Project) ver = pd692x0_get_sw_version(priv);
14719a993845SKory Maincent (Dent Project) dev_info(&client->dev, "Software version %d.%02d.%d.%d\n",
14729a993845SKory Maincent (Dent Project) ver.prod, ver.maj_sw_ver, ver.min_sw_ver,
14739a993845SKory Maincent (Dent Project) ver.pa_sw_ver);
14749a993845SKory Maincent (Dent Project)
14759a993845SKory Maincent (Dent Project) if (ver.maj_sw_ver < PD692X0_FW_MAJ_VER) {
14769a993845SKory Maincent (Dent Project) dev_err(dev, "Too old firmware version. Please update it\n");
14779a993845SKory Maincent (Dent Project) priv->fw_state = PD692X0_FW_NEED_UPDATE;
14789a993845SKory Maincent (Dent Project) } else {
14799a993845SKory Maincent (Dent Project) priv->fw_state = PD692X0_FW_OK;
14809a993845SKory Maincent (Dent Project) }
14819a993845SKory Maincent (Dent Project) }
14829a993845SKory Maincent (Dent Project)
14839a993845SKory Maincent (Dent Project) priv->np = dev->of_node;
14849a993845SKory Maincent (Dent Project) priv->pcdev.nr_lines = PD692X0_MAX_PIS;
14859a993845SKory Maincent (Dent Project) priv->pcdev.owner = THIS_MODULE;
14869a993845SKory Maincent (Dent Project) priv->pcdev.ops = &pd692x0_ops;
14879a993845SKory Maincent (Dent Project) priv->pcdev.dev = dev;
14889a993845SKory Maincent (Dent Project) priv->pcdev.types = ETHTOOL_PSE_C33;
14899a993845SKory Maincent (Dent Project) ret = devm_pse_controller_register(dev, &priv->pcdev);
14909a993845SKory Maincent (Dent Project) if (ret)
14919a993845SKory Maincent (Dent Project) return dev_err_probe(dev, ret,
14929a993845SKory Maincent (Dent Project) "failed to register PSE controller\n");
14939a993845SKory Maincent (Dent Project)
14949a993845SKory Maincent (Dent Project) fwl = firmware_upload_register(THIS_MODULE, dev, dev_name(dev),
14959a993845SKory Maincent (Dent Project) &pd692x0_fw_ops, priv);
14969a993845SKory Maincent (Dent Project) if (IS_ERR(fwl))
14979a993845SKory Maincent (Dent Project) return dev_err_probe(dev, PTR_ERR(fwl),
14989a993845SKory Maincent (Dent Project) "failed to register to the Firmware Upload API\n");
14999a993845SKory Maincent (Dent Project) priv->fwl = fwl;
15009a993845SKory Maincent (Dent Project)
15019a993845SKory Maincent (Dent Project) return 0;
15029a993845SKory Maincent (Dent Project) }
15039a993845SKory Maincent (Dent Project)
pd692x0_i2c_remove(struct i2c_client * client)15049a993845SKory Maincent (Dent Project) static void pd692x0_i2c_remove(struct i2c_client *client)
15059a993845SKory Maincent (Dent Project) {
15069a993845SKory Maincent (Dent Project) struct pd692x0_priv *priv = i2c_get_clientdata(client);
15079a993845SKory Maincent (Dent Project)
15089a993845SKory Maincent (Dent Project) firmware_upload_unregister(priv->fwl);
15099a993845SKory Maincent (Dent Project) }
15109a993845SKory Maincent (Dent Project)
15119a993845SKory Maincent (Dent Project) static const struct i2c_device_id pd692x0_id[] = {
1512a6a6a980SUwe Kleine-König { PD692X0_PSE_NAME },
1513a6a6a980SUwe Kleine-König { }
15149a993845SKory Maincent (Dent Project) };
15159a993845SKory Maincent (Dent Project) MODULE_DEVICE_TABLE(i2c, pd692x0_id);
15169a993845SKory Maincent (Dent Project)
15179a993845SKory Maincent (Dent Project) static const struct of_device_id pd692x0_of_match[] = {
15189a993845SKory Maincent (Dent Project) { .compatible = "microchip,pd69200", },
15199a993845SKory Maincent (Dent Project) { .compatible = "microchip,pd69210", },
15209a993845SKory Maincent (Dent Project) { .compatible = "microchip,pd69220", },
15219a993845SKory Maincent (Dent Project) { },
15229a993845SKory Maincent (Dent Project) };
15239a993845SKory Maincent (Dent Project) MODULE_DEVICE_TABLE(of, pd692x0_of_match);
15249a993845SKory Maincent (Dent Project)
15259a993845SKory Maincent (Dent Project) static struct i2c_driver pd692x0_driver = {
15269a993845SKory Maincent (Dent Project) .probe = pd692x0_i2c_probe,
15279a993845SKory Maincent (Dent Project) .remove = pd692x0_i2c_remove,
15289a993845SKory Maincent (Dent Project) .id_table = pd692x0_id,
15299a993845SKory Maincent (Dent Project) .driver = {
15309a993845SKory Maincent (Dent Project) .name = PD692X0_PSE_NAME,
15319a993845SKory Maincent (Dent Project) .of_match_table = pd692x0_of_match,
15329a993845SKory Maincent (Dent Project) },
15339a993845SKory Maincent (Dent Project) };
15349a993845SKory Maincent (Dent Project) module_i2c_driver(pd692x0_driver);
15359a993845SKory Maincent (Dent Project)
15369a993845SKory Maincent (Dent Project) MODULE_AUTHOR("Kory Maincent <kory.maincent@bootlin.com>");
15379a993845SKory Maincent (Dent Project) MODULE_DESCRIPTION("Microchip PD692x0 PoE PSE Controller driver");
15389a993845SKory Maincent (Dent Project) MODULE_LICENSE("GPL");
1539