diff options
Diffstat (limited to 'drivers/net/pse-pd/pd692x0.c')
| -rw-r--r-- | drivers/net/pse-pd/pd692x0.c | 155 |
1 files changed, 112 insertions, 43 deletions
diff --git a/drivers/net/pse-pd/pd692x0.c b/drivers/net/pse-pd/pd692x0.c index f4e91ba64a66..134435e90073 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 +#define PD692X0_USER_BYTE 42 + enum pd692x0_fw_state { PD692X0_FW_UNKNOWN, PD692X0_FW_OK, @@ -80,11 +82,17 @@ enum { PD692X0_MSG_GET_PORT_PARAM, PD692X0_MSG_GET_POWER_BANK, PD692X0_MSG_SET_POWER_BANK, + PD692X0_MSG_SET_USER_BYTE, /* add new message above here */ PD692X0_MSG_CNT }; +struct pd692x0_matrix { + u8 hw_port_a; + u8 hw_port_b; +}; + struct pd692x0_priv { struct i2c_client *client; struct pse_controller_dev pcdev; @@ -98,9 +106,12 @@ struct pd692x0_priv { bool last_cmd_key; unsigned long last_cmd_key_time; + 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]; + int nmanagers; + struct pd692x0_matrix *port_matrix; }; /* Template list of communication messages. The non-null bytes defined here @@ -186,6 +197,12 @@ static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = { .key = PD692X0_KEY_CMD, .sub = {0x07, 0x0b, 0x57}, }, + [PD692X0_MSG_SET_USER_BYTE] = { + .key = PD692X0_KEY_PRG, + .sub = {0x41, PD692X0_USER_BYTE}, + .data = {0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e}, + }, }; static u8 pd692x0_build_msg(struct pd692x0_msg *msg, u8 echo) @@ -809,11 +826,6 @@ struct pd692x0_manager { int nports; }; -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 +915,8 @@ pd692x0_of_get_managers(struct pd692x0_priv *priv, } of_node_put(managers_node); - return nmanagers; + priv->nmanagers = nmanagers; + return 0; out: for (i = 0; i < nmanagers; i++) { @@ -963,8 +976,7 @@ pd692x0_register_manager_regulator(struct device *dev, char *reg_name, 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 = &priv->client->dev; size_t reg_name_len; @@ -975,7 +987,7 @@ pd692x0_register_managers_regulator(struct pd692x0_priv *priv, */ reg_name_len = strlen(dev_name(dev)) + 23; - for (i = 0; i < nmanagers; i++) { + for (i = 0; i < priv->nmanagers; i++) { static const char * const regulators[] = { "vaux5", "vaux3p3" }; struct regulator_dev *rdev; char *reg_name; @@ -1008,10 +1020,14 @@ pd692x0_register_managers_regulator(struct pd692x0_priv *priv, } static int -pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id, int pw) +pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id) { struct pd692x0_msg msg, buf; - int ret, pw_mW = pw / 1000; + int ret, pw_mW; + + pw_mW = priv->manager_pw_budget[id] / 1000; + if (!pw_mW) + return 0; msg = pd692x0_msg_template_list[PD692X0_MSG_GET_POWER_BANK]; msg.data[0] = id; @@ -1032,11 +1048,11 @@ pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id, int pw) } static int -pd692x0_configure_managers(struct pd692x0_priv *priv, int nmanagers) +pd692x0_req_managers_pw_budget(struct pd692x0_priv *priv) { int i, ret; - for (i = 0; i < nmanagers; i++) { + for (i = 0; i < priv->nmanagers; i++) { struct regulator *supply = priv->manager_reg[i]->supply; int pw_budget; @@ -1053,7 +1069,18 @@ pd692x0_configure_managers(struct pd692x0_priv *priv, int nmanagers) return ret; priv->manager_pw_budget[i] = pw_budget; - ret = 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 = 0; i < priv->nmanagers; i++) { + ret = pd692x0_conf_manager_power_budget(priv, i); if (ret < 0) return ret; } @@ -1101,10 +1128,9 @@ pd692x0_set_port_matrix(const struct pse_pi_pairset *pairset, 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 = priv->port_matrix; struct pse_controller_dev *pcdev = &priv->pcdev; int i, ret; @@ -1117,7 +1143,7 @@ pd692x0_set_ports_matrix(struct pd692x0_priv *priv, /* Update with values for every PSE PIs */ for (i = 0; i < pcdev->nr_lines; i++) { ret = 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 +1152,7 @@ pd692x0_set_ports_matrix(struct pd692x0_priv *priv, } ret = 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 +1165,9 @@ pd692x0_set_ports_matrix(struct pd692x0_priv *priv, } 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 = priv->port_matrix; struct pd692x0_msg msg, buf; int ret, i; @@ -1166,13 +1192,32 @@ pd692x0_write_ports_matrix(struct pd692x0_priv *priv, return 0; } +static int pd692x0_hw_conf_init(struct pd692x0_priv *priv) +{ + int ret; + + /* Is PD692x0 ready to be configured? */ + if (priv->fw_state != PD692X0_FW_OK && + priv->fw_state != PD692X0_FW_COMPLETE) + return 0; + + ret = pd692x0_configure_managers(priv); + if (ret) + return ret; + + ret = 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; - for (i = 0; i < nmanagers; i++) { + for (i = 0; i < priv->nmanagers; i++) { for (j = 0; j < manager[i].nports; j++) of_node_put(manager[i].port_node[j]); of_node_put(manager[i].node); @@ -1198,50 +1243,71 @@ static void pd692x0_managers_free_pw_budget(struct pd692x0_priv *priv) } } +static int +pd692x0_save_user_byte(struct pd692x0_priv *priv) +{ + struct pd692x0_msg msg, buf; + + msg = pd692x0_msg_template_list[PD692X0_MSG_SET_USER_BYTE]; + return pd692x0_sendrecv_msg(priv, &msg, &buf); +} + static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev) { - struct pd692x0_manager *manager __free(kfree) = NULL; struct pd692x0_priv *priv = 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 != PD692X0_FW_OK && - priv->fw_state != PD692X0_FW_COMPLETE) - return 0; + struct pd692x0_matrix *port_matrix; + struct pd692x0_manager *manager; + int ret; manager = kcalloc(PD692X0_MAX_MANAGERS, sizeof(*manager), GFP_KERNEL); if (!manager) return -ENOMEM; + port_matrix = devm_kcalloc(&priv->client->dev, PD692X0_MAX_PIS, + sizeof(*port_matrix), GFP_KERNEL); + if (!port_matrix) { + ret = -ENOMEM; + goto err_free_manager; + } + priv->port_matrix = port_matrix; + ret = pd692x0_of_get_managers(priv, manager); if (ret < 0) - return ret; + goto err_free_manager; - nmanagers = ret; - ret = pd692x0_register_managers_regulator(priv, manager, nmanagers); + ret = pd692x0_register_managers_regulator(priv, manager); if (ret) goto err_of_managers; - ret = pd692x0_configure_managers(priv, nmanagers); + ret = pd692x0_req_managers_pw_budget(priv); if (ret) goto err_of_managers; - ret = pd692x0_set_ports_matrix(priv, manager, nmanagers, port_matrix); + ret = pd692x0_set_ports_matrix(priv, manager); if (ret) goto err_managers_req_pw; - ret = pd692x0_write_ports_matrix(priv, port_matrix); - if (ret) - goto err_managers_req_pw; + /* Do not init the conf if it is already saved */ + if (!priv->cfg_saved) { + ret = pd692x0_hw_conf_init(priv); + if (ret) + goto err_managers_req_pw; - pd692x0_of_put_managers(priv, manager, nmanagers); + ret = pd692x0_save_user_byte(priv); + if (ret) + goto err_managers_req_pw; + } + + pd692x0_of_put_managers(priv, manager); + kfree(manager); return 0; 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); +err_free_manager: + kfree(manager); return ret; } @@ -1644,7 +1710,7 @@ static enum fw_upload_err pd692x0_fw_poll_complete(struct fw_upload *fwl) return FW_UPLOAD_ERR_FW_INVALID; } - ret = pd692x0_setup_pi_matrix(&priv->pcdev); + ret = pd692x0_hw_conf_init(priv); if (ret < 0) { dev_err(&client->dev, "Error configuring ports matrix (%pe)\n", ERR_PTR(ret)); @@ -1753,6 +1819,9 @@ static int pd692x0_i2c_probe(struct i2c_client *client) } } + if (buf.data[2] == PD692X0_USER_BYTE) + priv->cfg_saved = true; + priv->np = dev->of_node; priv->pcdev.nr_lines = PD692X0_MAX_PIS; priv->pcdev.owner = THIS_MODULE; |
