summaryrefslogtreecommitdiff
path: root/drivers/net/pse-pd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/pse-pd')
-rw-r--r--drivers/net/pse-pd/pd692x0.c155
-rw-r--r--drivers/net/pse-pd/tps23881.c69
2 files changed, 166 insertions, 58 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;
diff --git a/drivers/net/pse-pd/tps23881.c b/drivers/net/pse-pd/tps23881.c
index b724b222ab44..76ec1555d60d 100644
--- a/drivers/net/pse-pd/tps23881.c
+++ b/drivers/net/pse-pd/tps23881.c
@@ -55,8 +55,6 @@
#define TPS23881_REG_TPON BIT(0)
#define TPS23881_REG_FWREV 0x41
#define TPS23881_REG_DEVID 0x43
-#define TPS23881_REG_DEVID_MASK 0xF0
-#define TPS23881_DEVICE_ID 0x02
#define TPS23881_REG_CHAN1_CLASS 0x4c
#define TPS23881_REG_SRAM_CTRL 0x60
#define TPS23881_REG_SRAM_DATA 0x61
@@ -1012,8 +1010,28 @@ static const struct pse_controller_ops tps23881_ops = {
.pi_get_pw_req = tps23881_pi_get_pw_req,
};
-static const char fw_parity_name[] = "ti/tps23881/tps23881-parity-14.bin";
-static const char fw_sram_name[] = "ti/tps23881/tps23881-sram-14.bin";
+struct tps23881_info {
+ u8 dev_id; /* device ID and silicon revision */
+ const char *fw_parity_name; /* parity code firmware file name */
+ const char *fw_sram_name; /* SRAM code firmware file name */
+};
+
+enum tps23881_model {
+ TPS23881,
+ TPS23881B,
+};
+
+static const struct tps23881_info tps23881_info[] = {
+ [TPS23881] = {
+ .dev_id = 0x22,
+ .fw_parity_name = "ti/tps23881/tps23881-parity-14.bin",
+ .fw_sram_name = "ti/tps23881/tps23881-sram-14.bin",
+ },
+ [TPS23881B] = {
+ .dev_id = 0x24,
+ /* skip SRAM load, ROM provides Clause 145 hardware-level support */
+ },
+};
struct tps23881_fw_conf {
u8 reg;
@@ -1085,16 +1103,17 @@ out:
return ret;
}
-static int tps23881_flash_sram_fw(struct i2c_client *client)
+static int tps23881_flash_sram_fw(struct i2c_client *client,
+ const struct tps23881_info *info)
{
int ret;
- ret = tps23881_flash_sram_fw_part(client, fw_parity_name,
+ ret = tps23881_flash_sram_fw_part(client, info->fw_parity_name,
tps23881_fw_parity_conf);
if (ret)
return ret;
- ret = tps23881_flash_sram_fw_part(client, fw_sram_name,
+ ret = tps23881_flash_sram_fw_part(client, info->fw_sram_name,
tps23881_fw_sram_conf);
if (ret)
return ret;
@@ -1412,6 +1431,7 @@ static int tps23881_setup_irq(struct tps23881_priv *priv, int irq)
static int tps23881_i2c_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
+ const struct tps23881_info *info;
struct tps23881_priv *priv;
struct gpio_desc *reset;
int ret;
@@ -1422,6 +1442,10 @@ static int tps23881_i2c_probe(struct i2c_client *client)
return -ENXIO;
}
+ info = i2c_get_match_data(client);
+ if (!info)
+ return -EINVAL;
+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -1440,7 +1464,7 @@ static int tps23881_i2c_probe(struct i2c_client *client)
* to Load TPS2388x SRAM and Parity Code over I2C" (Rev E))
* indicates we should delay that programming by at least 50ms. So
* we'll wait the entire 50ms here to ensure we're safe to go to the
- * SRAM loading proceedure.
+ * SRAM loading procedure.
*/
msleep(50);
}
@@ -1449,20 +1473,27 @@ static int tps23881_i2c_probe(struct i2c_client *client)
if (ret < 0)
return ret;
- if (FIELD_GET(TPS23881_REG_DEVID_MASK, ret) != TPS23881_DEVICE_ID) {
+ if (ret != info->dev_id) {
dev_err(dev, "Wrong device ID\n");
return -ENXIO;
}
- ret = tps23881_flash_sram_fw(client);
- if (ret < 0)
- return ret;
+ if (info->fw_sram_name) {
+ ret = tps23881_flash_sram_fw(client, info);
+ if (ret < 0)
+ return ret;
+ }
ret = i2c_smbus_read_byte_data(client, TPS23881_REG_FWREV);
if (ret < 0)
return ret;
- dev_info(&client->dev, "Firmware revision 0x%x\n", ret);
+ if (ret == 0xFF) {
+ dev_err(&client->dev, "Device entered safe mode\n");
+ return -ENXIO;
+ }
+ dev_info(&client->dev, "Firmware revision 0x%x%s\n", ret,
+ ret == 0x00 ? " (ROM firmware)" : "");
/* Set configuration B, 16 bit access on a single device address */
ret = i2c_smbus_read_byte_data(client, TPS23881_REG_GEN_MASK);
@@ -1498,13 +1529,21 @@ static int tps23881_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id tps23881_id[] = {
- { "tps23881" },
+ { "tps23881", .driver_data = (kernel_ulong_t)&tps23881_info[TPS23881] },
+ { "tps23881b", .driver_data = (kernel_ulong_t)&tps23881_info[TPS23881B] },
{ }
};
MODULE_DEVICE_TABLE(i2c, tps23881_id);
static const struct of_device_id tps23881_of_match[] = {
- { .compatible = "ti,tps23881", },
+ {
+ .compatible = "ti,tps23881",
+ .data = &tps23881_info[TPS23881]
+ },
+ {
+ .compatible = "ti,tps23881b",
+ .data = &tps23881_info[TPS23881B]
+ },
{ },
};
MODULE_DEVICE_TABLE(of, tps23881_of_match);