From nobody Fri Oct 3 23:02:04 2025 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4CF1C23D297 for ; Fri, 22 Aug 2025 15:38:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755877084; cv=none; b=KhpYA5fzV/fWog5ZSJAbQpU8Oy1ofRwFj7Xg/XbxPul61+u+fCPhEfZUd5cDEZK9vp835Jvbn9rufRn8jWWsUVBoFjSFR8A/mcQ7mSZ0R8yyBUWsU2aqjRu+jWB1kx7iMOtmdV3dPHg1fG25nPLzxjHF1UQGdhf/Z1mpDQ3tvdo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755877084; c=relaxed/simple; bh=fNFPaFxaGIxv5Y8hCloKDpiUz2vCKZuJPCQSbCRT2CM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=COgRP8dqcikqwrF5ChLT2fttcX4dJO3/VTDWvb5TPjLVS+wOebm95hRSnirnlJgOjqBFmQ7IO/OvmO18p4bHfQm3goVNWFfuuS7LUdUcekausFnz89TCuL5rTk2LHdl86flh1E96UsCKwnV/LAuKeSLnidyEofw4FTRWfY1m2PI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=ZOvGqT6v; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="ZOvGqT6v" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id B0E6EC8EC60; Fri, 22 Aug 2025 15:37:45 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 8EAD7604AD; Fri, 22 Aug 2025 15:37:59 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id E88791C22D194; Fri, 22 Aug 2025 17:37:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1755877078; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=7PVWOEKulKe5NQD88m9aMzcwTOMAsDLujR1Ax84aCtE=; b=ZOvGqT6viS25r9BeVLxBHtz91CZ30Cx3LeFaFwaG1vqZ1qmgDqZAzDfl07afzAp4QQEBZC YkRl9Sq+81q6hbq9qPLPJqgfnaExwx5sR+cP+VgwiiC0RaGwjzfKG5/R+b70f6/Nf3gpbH aQH25DTAYlnqG9acUKMl41I2NR0zeVDh015nP9PH6xcrzlh0a1D/MroAA6zsf1CnkdoDK6 z9gxlDg1dVjdSYBoBAJM+B+12Wg3LHQtubqp80Wu1jV/EUC2D+mJtIH3yC5abtdgxWvW4X otJizU1BxTtDxdAHSZhTyCgzbPH43JB49Aa1HLbdIv9EkOs7DA1csz6bxP+pdg== From: Kory Maincent Date: Fri, 22 Aug 2025 17:37:01 +0200 Subject: [PATCH net-next 1/2] net: pse-pd: pd692x0: Separate configuration parsing from hardware setup Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250822-feature_poe_permanent_conf-v1-1-dcd41290254d@bootlin.com> References: <20250822-feature_poe_permanent_conf-v1-0-dcd41290254d@bootlin.com> In-Reply-To: <20250822-feature_poe_permanent_conf-v1-0-dcd41290254d@bootlin.com> To: Oleksij Rempel , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: kernel@pengutronix.de, Dent Project , Thomas Petazzoni , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Maxime Chevallier , "Kory Maincent (Dent Project)" X-Mailer: b4 0.15-dev-8cb71 X-Last-TLS-Session-Version: TLSv1.3 From: Kory Maincent (Dent Project) Cache the port matrix configuration in driver private data to enable PSE controller reconfiguration. This refactoring separates device tree parsing from hardware configuration application, allowing settings to be reapplied without reparsing the device tree. This prepares for upcoming permanent configuration support where cached settings can be restored after device resets or firmware updates. Signed-off-by: Kory Maincent --- drivers/net/pse-pd/pd692x0.c | 113 ++++++++++++++++++++++++++++-----------= ---- 1 file changed, 74 insertions(+), 39 deletions(-) diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c index f4e91ba64a66..8b94967bb4fb 100644 --- a/drivers/net/pse-pd/pd692x0.c +++ b/drivers/net/pse-pd/pd692x0.c @@ -85,6 +85,11 @@ enum { PD692X0_MSG_CNT }; =20 +struct pd692x0_matrix { + u8 hw_port_a; + u8 hw_port_b; +}; + struct pd692x0_priv { struct i2c_client *client; struct pse_controller_dev pcdev; @@ -101,6 +106,8 @@ struct pd692x0_priv { enum ethtool_c33_pse_admin_state admin_state[PD692X0_MAX_PIS]; struct regulator_dev *manager_reg[PD692X0_MAX_MANAGERS]; int manager_pw_budget[PD692X0_MAX_MANAGERS]; + int nmanagers; + struct pd692x0_matrix *port_matrix; }; =20 /* Template list of communication messages. The non-null bytes defined here @@ -809,11 +816,6 @@ struct pd692x0_manager { int nports; }; =20 -struct pd692x0_matrix { - u8 hw_port_a; - u8 hw_port_b; -}; - static int pd692x0_of_get_ports_manager(struct pd692x0_priv *priv, struct pd692x0_manager *manager, @@ -903,7 +905,8 @@ pd692x0_of_get_managers(struct pd692x0_priv *priv, } =20 of_node_put(managers_node); - return nmanagers; + priv->nmanagers =3D nmanagers; + return 0; =20 out: for (i =3D 0; i < nmanagers; i++) { @@ -963,8 +966,7 @@ pd692x0_register_manager_regulator(struct device *dev, = char *reg_name, =20 static int pd692x0_register_managers_regulator(struct pd692x0_priv *priv, - const struct pd692x0_manager *manager, - int nmanagers) + const struct pd692x0_manager *manager) { struct device *dev =3D &priv->client->dev; size_t reg_name_len; @@ -975,7 +977,7 @@ pd692x0_register_managers_regulator(struct pd692x0_priv= *priv, */ reg_name_len =3D strlen(dev_name(dev)) + 23; =20 - for (i =3D 0; i < nmanagers; i++) { + for (i =3D 0; i < priv->nmanagers; i++) { static const char * const regulators[] =3D { "vaux5", "vaux3p3" }; struct regulator_dev *rdev; char *reg_name; @@ -1008,10 +1010,14 @@ pd692x0_register_managers_regulator(struct pd692x0_= priv *priv, } =20 static int -pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id, int p= w) +pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id) { struct pd692x0_msg msg, buf; - int ret, pw_mW =3D pw / 1000; + int ret, pw_mW; + + pw_mW =3D priv->manager_pw_budget[id] / 1000; + if (!pw_mW) + return 0; =20 msg =3D pd692x0_msg_template_list[PD692X0_MSG_GET_POWER_BANK]; msg.data[0] =3D id; @@ -1032,11 +1038,11 @@ pd692x0_conf_manager_power_budget(struct pd692x0_pr= iv *priv, int id, int pw) } =20 static int -pd692x0_configure_managers(struct pd692x0_priv *priv, int nmanagers) +pd692x0_req_managers_pw_budget(struct pd692x0_priv *priv) { int i, ret; =20 - for (i =3D 0; i < nmanagers; i++) { + for (i =3D 0; i < priv->nmanagers; i++) { struct regulator *supply =3D priv->manager_reg[i]->supply; int pw_budget; =20 @@ -1053,7 +1059,18 @@ pd692x0_configure_managers(struct pd692x0_priv *priv= , int nmanagers) return ret; =20 priv->manager_pw_budget[i] =3D pw_budget; - ret =3D pd692x0_conf_manager_power_budget(priv, i, pw_budget); + } + + return 0; +} + +static int +pd692x0_configure_managers(struct pd692x0_priv *priv) +{ + int i, ret; + + for (i =3D 0; i < priv->nmanagers; i++) { + ret =3D pd692x0_conf_manager_power_budget(priv, i); if (ret < 0) return ret; } @@ -1101,10 +1118,9 @@ pd692x0_set_port_matrix(const struct pse_pi_pairset = *pairset, =20 static int pd692x0_set_ports_matrix(struct pd692x0_priv *priv, - const struct pd692x0_manager *manager, - int nmanagers, - struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS]) + const struct pd692x0_manager *manager) { + struct pd692x0_matrix *port_matrix =3D priv->port_matrix; struct pse_controller_dev *pcdev =3D &priv->pcdev; int i, ret; =20 @@ -1117,7 +1133,7 @@ pd692x0_set_ports_matrix(struct pd692x0_priv *priv, /* Update with values for every PSE PIs */ for (i =3D 0; i < pcdev->nr_lines; i++) { ret =3D pd692x0_set_port_matrix(&pcdev->pi[i].pairset[0], - manager, nmanagers, + manager, priv->nmanagers, &port_matrix[i]); if (ret) { dev_err(&priv->client->dev, @@ -1126,7 +1142,7 @@ pd692x0_set_ports_matrix(struct pd692x0_priv *priv, } =20 ret =3D pd692x0_set_port_matrix(&pcdev->pi[i].pairset[1], - manager, nmanagers, + manager, priv->nmanagers, &port_matrix[i]); if (ret) { dev_err(&priv->client->dev, @@ -1139,9 +1155,9 @@ pd692x0_set_ports_matrix(struct pd692x0_priv *priv, } =20 static int -pd692x0_write_ports_matrix(struct pd692x0_priv *priv, - const struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS]) +pd692x0_write_ports_matrix(struct pd692x0_priv *priv) { + struct pd692x0_matrix *port_matrix =3D priv->port_matrix; struct pd692x0_msg msg, buf; int ret, i; =20 @@ -1166,13 +1182,32 @@ pd692x0_write_ports_matrix(struct pd692x0_priv *pri= v, return 0; } =20 +static int pd692x0_hw_conf_init(struct pd692x0_priv *priv) +{ + int ret; + + /* Is PD692x0 ready to be configured? */ + if (priv->fw_state !=3D PD692X0_FW_OK && + priv->fw_state !=3D PD692X0_FW_COMPLETE) + return 0; + + ret =3D pd692x0_configure_managers(priv); + if (ret) + return ret; + + ret =3D pd692x0_write_ports_matrix(priv); + if (ret) + return ret; + + return 0; +} + static void pd692x0_of_put_managers(struct pd692x0_priv *priv, - struct pd692x0_manager *manager, - int nmanagers) + struct pd692x0_manager *manager) { int i, j; =20 - for (i =3D 0; i < nmanagers; i++) { + for (i =3D 0; i < priv->nmanagers; i++) { for (j =3D 0; j < manager[i].nports; j++) of_node_put(manager[i].port_node[j]); of_node_put(manager[i].node); @@ -1202,46 +1237,46 @@ static int pd692x0_setup_pi_matrix(struct pse_contr= oller_dev *pcdev) { struct pd692x0_manager *manager __free(kfree) =3D NULL; struct pd692x0_priv *priv =3D to_pd692x0_priv(pcdev); - struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS]; - int ret, nmanagers; - - /* Should we flash the port matrix */ - if (priv->fw_state !=3D PD692X0_FW_OK && - priv->fw_state !=3D PD692X0_FW_COMPLETE) - return 0; + struct pd692x0_matrix *port_matrix; + int ret; =20 manager =3D kcalloc(PD692X0_MAX_MANAGERS, sizeof(*manager), GFP_KERNEL); if (!manager) return -ENOMEM; =20 + port_matrix =3D devm_kcalloc(&priv->client->dev, PD692X0_MAX_PIS, + sizeof(*port_matrix), GFP_KERNEL); + if (!port_matrix) + return -ENOMEM; + priv->port_matrix =3D port_matrix; + ret =3D pd692x0_of_get_managers(priv, manager); if (ret < 0) return ret; =20 - nmanagers =3D ret; - ret =3D pd692x0_register_managers_regulator(priv, manager, nmanagers); + ret =3D pd692x0_register_managers_regulator(priv, manager); if (ret) goto err_of_managers; =20 - ret =3D pd692x0_configure_managers(priv, nmanagers); + ret =3D pd692x0_req_managers_pw_budget(priv); if (ret) goto err_of_managers; =20 - ret =3D pd692x0_set_ports_matrix(priv, manager, nmanagers, port_matrix); + ret =3D pd692x0_set_ports_matrix(priv, manager); if (ret) goto err_managers_req_pw; =20 - ret =3D pd692x0_write_ports_matrix(priv, port_matrix); + ret =3D pd692x0_hw_conf_init(priv); if (ret) goto err_managers_req_pw; =20 - pd692x0_of_put_managers(priv, manager, nmanagers); + pd692x0_of_put_managers(priv, manager); return 0; =20 err_managers_req_pw: pd692x0_managers_free_pw_budget(priv); err_of_managers: - pd692x0_of_put_managers(priv, manager, nmanagers); + pd692x0_of_put_managers(priv, manager); return ret; } =20 @@ -1644,7 +1679,7 @@ static enum fw_upload_err pd692x0_fw_poll_complete(st= ruct fw_upload *fwl) return FW_UPLOAD_ERR_FW_INVALID; } =20 - ret =3D pd692x0_setup_pi_matrix(&priv->pcdev); + ret =3D pd692x0_hw_conf_init(priv); if (ret < 0) { dev_err(&client->dev, "Error configuring ports matrix (%pe)\n", ERR_PTR(ret)); --=20 2.43.0 From nobody Fri Oct 3 23:02:04 2025 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 96723255F27; Fri, 22 Aug 2025 15:38:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755877084; cv=none; b=Sumt/UyIkfrlmYzZt+eYXt0JepnQ/KIbT8nOdD3M/6gD5FcSlNPcxU8OasjX6c5mdCKM9eQFO0P68wsj7gBCCCEssbofsq1UUNbWXz4U2bacTbch75fIIqX08kfeOmOd8StTgnTQSnjdRGVr6Jn0rF54y6rqVS8ANiYG3kWvyEA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755877084; c=relaxed/simple; bh=zTh2RQmsWjHi/W1F00068YysELVrAeFQd288EhULw5g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jKxoHvhLNF4vTbJrTLVDQ1K8HCG1UIuyzuAc142hFUviWRPfaeasMKhsVy69XzsWQP0SpjvDNEKTdp8XZBvBN+Sl4Rr+O2y120dDI7KiLHbX1NLrCXfQxmtSQQ1oXks3cJqe/BNnx/AgWhb+FNuQTw6a/yiUpTv2Rx0SQm+g6vE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=MuTKyEDi; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="MuTKyEDi" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id E4ED34E40BD2; Fri, 22 Aug 2025 15:38:00 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id C071A604AD; Fri, 22 Aug 2025 15:38:00 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 34C261C22D6AD; Fri, 22 Aug 2025 17:37:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1755877080; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=iQBT0xYYoJCEm5eXAEloAFRIdH+1WIddcidbneBHGHs=; b=MuTKyEDitUzw5CmkYkGFlUdOszfyVN9c8xMWnRobVYtbLXmPYb4NYgaQ2r6wR8i1oJFobn D+SGmX3MEFvkanxUE/fLxxw1kUl0XoGgfVEE+ZHCc8AEqaNlGCxKMJ5gY6d4SRALDwBJS/ DnvodW4LCKVCCD2SAy5T69u7sLd2i0gdlrcby105y23SKBfcYrGjvfnnCUpliFGC/VOL2Z rjwLiWTABer0/9vwn0n/wMi0v6UH1N2vo5b9zoTOw+yeD7ywmfHFTCmgkk768Okvj4gbYP YQuaLzv1L1aV4AmNOyOQD9BU2aJbrDuYTehqqXORfdwVn5vAIFOPg1zoAYyjUQ== From: Kory Maincent Date: Fri, 22 Aug 2025 17:37:02 +0200 Subject: [PATCH net-next 2/2] net: pse-pd: pd692x0: Add sysfs interface for configuration save/reset Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250822-feature_poe_permanent_conf-v1-2-dcd41290254d@bootlin.com> References: <20250822-feature_poe_permanent_conf-v1-0-dcd41290254d@bootlin.com> In-Reply-To: <20250822-feature_poe_permanent_conf-v1-0-dcd41290254d@bootlin.com> To: Oleksij Rempel , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: kernel@pengutronix.de, Dent Project , Thomas Petazzoni , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Maxime Chevallier , "Kory Maincent (Dent Project)" X-Mailer: b4 0.15-dev-8cb71 X-Last-TLS-Session-Version: TLSv1.3 From: Kory Maincent (Dent Project) Add sysfs attributes save_conf and reset_conf to enable userspace management of the PSE's permanent configuration stored in EEPROM. The save_conf attribute allows saving the current configuration to EEPROM by writing '1'. The reset_conf attribute restores factory defaults and reinitializes the port matrix configuration. Skip hardware configuration initialization on probe when a saved configuration is already present in EEPROM (detected via user byte 42). Signed-off-by: Kory Maincent --- drivers/net/pse-pd/pd692x0.c | 151 +++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 148 insertions(+), 3 deletions(-) diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c index 8b94967bb4fb..202e91ec9b9a 100644 --- a/drivers/net/pse-pd/pd692x0.c +++ b/drivers/net/pse-pd/pd692x0.c @@ -30,6 +30,8 @@ #define PD692X0_FW_MIN_VER 5 #define PD692X0_FW_PATCH_VER 5 =20 +#define PD692X0_USER_BYTE 42 + enum pd692x0_fw_state { PD692X0_FW_UNKNOWN, PD692X0_FW_OK, @@ -80,6 +82,9 @@ enum { PD692X0_MSG_GET_PORT_PARAM, PD692X0_MSG_GET_POWER_BANK, PD692X0_MSG_SET_POWER_BANK, + PD692X0_MSG_SET_USER_BYTE, + PD692X0_MSG_SAVE_SYS_SETTINGS, + PD692X0_MSG_RESTORE_FACTORY, =20 /* add new message above here */ PD692X0_MSG_CNT @@ -103,6 +108,7 @@ struct pd692x0_priv { bool last_cmd_key; unsigned long last_cmd_key_time; =20 + bool cfg_saved; enum ethtool_c33_pse_admin_state admin_state[PD692X0_MAX_PIS]; struct regulator_dev *manager_reg[PD692X0_MAX_MANAGERS]; int manager_pw_budget[PD692X0_MAX_MANAGERS]; @@ -193,6 +199,24 @@ static const struct pd692x0_msg pd692x0_msg_template_l= ist[PD692X0_MSG_CNT] =3D { .key =3D PD692X0_KEY_CMD, .sub =3D {0x07, 0x0b, 0x57}, }, + [PD692X0_MSG_SET_USER_BYTE] =3D { + .key =3D PD692X0_KEY_PRG, + .sub =3D {0x41, PD692X0_USER_BYTE}, + .data =3D {0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e}, + }, + [PD692X0_MSG_SAVE_SYS_SETTINGS] =3D { + .key =3D PD692X0_KEY_PRG, + .sub =3D {0x06, 0x0f}, + .data =3D {0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e}, + }, + [PD692X0_MSG_RESTORE_FACTORY] =3D { + .key =3D PD692X0_KEY_PRG, + .sub =3D {0x2d, 0x4e}, + .data =3D {0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e}, + }, }; =20 static u8 pd692x0_build_msg(struct pd692x0_msg *msg, u8 echo) @@ -1266,9 +1290,12 @@ static int pd692x0_setup_pi_matrix(struct pse_contro= ller_dev *pcdev) if (ret) goto err_managers_req_pw; =20 - ret =3D pd692x0_hw_conf_init(priv); - if (ret) - goto err_managers_req_pw; + /* Do not init the conf if it is already saved */ + if (!priv->cfg_saved) { + ret =3D pd692x0_hw_conf_init(priv); + if (ret) + goto err_managers_req_pw; + } =20 pd692x0_of_put_managers(priv, manager); return 0; @@ -1722,6 +1749,104 @@ static const struct fw_upload_ops pd692x0_fw_ops = =3D { .cleanup =3D pd692x0_fw_cleanup, }; =20 +static ssize_t save_conf_store(struct device *dev, + struct device_attribute *attr, + const char *save_buf, size_t count) +{ + struct pd692x0_priv *priv =3D dev_get_drvdata(dev); + struct pd692x0_msg msg, buf =3D {0}; + bool save; + int ret; + + if (kstrtobool(save_buf, &save) || !save) + return -EINVAL; + + mutex_lock(&priv->pcdev.lock); + ret =3D pd692x0_fw_unavailable(priv); + if (ret) + goto out; + + msg =3D pd692x0_msg_template_list[PD692X0_MSG_SET_USER_BYTE]; + ret =3D pd692x0_sendrecv_msg(priv, &msg, &buf); + if (ret) + goto out; + + msg =3D pd692x0_msg_template_list[PD692X0_MSG_SAVE_SYS_SETTINGS]; + ret =3D pd692x0_send_msg(priv, &msg); + if (ret) { + dev_err(&priv->client->dev, + "Failed to save the configuration (%pe)\n", + ERR_PTR(ret)); + goto out; + } + + msleep(50); /* Sleep 50ms as described in the datasheet */ + + ret =3D i2c_master_recv(priv->client, (u8 *)&buf, sizeof(buf)); + if (ret !=3D sizeof(buf)) { + if (ret >=3D 0) + ret =3D -EIO; + goto out; + } + + ret =3D count; +out: + mutex_unlock(&priv->pcdev.lock); + + return ret; +} +static DEVICE_ATTR_WO(save_conf); + +static ssize_t reset_conf_store(struct device *dev, + struct device_attribute *attr, + const char *reset_buf, size_t count) +{ + struct pd692x0_priv *priv =3D dev_get_drvdata(dev); + struct pd692x0_msg msg, buf =3D {0}; + bool reset; + int ret; + + if (kstrtobool(reset_buf, &reset) || !reset) + return -EINVAL; + + mutex_lock(&priv->pcdev.lock); + ret =3D pd692x0_fw_unavailable(priv); + if (ret) + goto out; + + msg =3D pd692x0_msg_template_list[PD692X0_MSG_RESTORE_FACTORY]; + ret =3D pd692x0_send_msg(priv, &msg); + if (ret) { + dev_err(&priv->client->dev, + "Failed to reset the configuration (%pe)\n", + ERR_PTR(ret)); + goto out; + } + + msleep(100); /* Sleep 100ms as described in the datasheet */ + + ret =3D i2c_master_recv(priv->client, (u8 *)&buf, sizeof(buf)); + if (ret !=3D sizeof(buf)) { + if (ret >=3D 0) + ret =3D -EIO; + goto out; + } + + ret =3D pd692x0_hw_conf_init(priv); + if (ret < 0) { + dev_err(&priv->client->dev, + "Error configuring ports matrix (%pe)\n", + ERR_PTR(ret)); + } + + ret =3D count; +out: + mutex_unlock(&priv->pcdev.lock); + + return ret; +} +static DEVICE_ATTR_WO(reset_conf); + static int pd692x0_i2c_probe(struct i2c_client *client) { static const char * const regulators[] =3D { "vdd", "vdda" }; @@ -1788,6 +1913,9 @@ static int pd692x0_i2c_probe(struct i2c_client *clien= t) } } =20 + if (buf.data[2] =3D=3D PD692X0_USER_BYTE) + priv->cfg_saved =3D true; + priv->np =3D dev->of_node; priv->pcdev.nr_lines =3D PD692X0_MAX_PIS; priv->pcdev.owner =3D THIS_MODULE; @@ -1808,7 +1936,22 @@ static int pd692x0_i2c_probe(struct i2c_client *clie= nt) "failed to register to the Firmware Upload API\n"); priv->fwl =3D fwl; =20 + ret =3D sysfs_create_file(&dev->kobj, &dev_attr_save_conf.attr); + if (ret) + goto err_sysfs; + + ret =3D sysfs_create_file(&dev->kobj, &dev_attr_reset_conf.attr); + if (ret) + goto err_sysfs_reset_conf; + return 0; + +err_sysfs_reset_conf: + sysfs_remove_file(&dev->kobj, &dev_attr_save_conf.attr); +err_sysfs: + firmware_upload_unregister(priv->fwl); + + return ret; } =20 static void pd692x0_i2c_remove(struct i2c_client *client) @@ -1816,6 +1959,8 @@ static void pd692x0_i2c_remove(struct i2c_client *cli= ent) struct pd692x0_priv *priv =3D i2c_get_clientdata(client); =20 pd692x0_managers_free_pw_budget(priv); + sysfs_remove_file(&client->dev.kobj, &dev_attr_reset_conf.attr); + sysfs_remove_file(&client->dev.kobj, &dev_attr_save_conf.attr); firmware_upload_unregister(priv->fwl); } =20 --=20 2.43.0