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) 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) 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) 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) 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) */ 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) 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) 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) 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) 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) 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) 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 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) 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) 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 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) 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) 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 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 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 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 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 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) 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) 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) 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) 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 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 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) 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) 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) 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) 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) 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) 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) 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) 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) 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