summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/phy/ti/phy-gmii-sel.c44
1 files changed, 33 insertions, 11 deletions
diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
index a6b7f22e85c4..5fd2e8a08bfc 100644
--- a/drivers/phy/ti/phy-gmii-sel.c
+++ b/drivers/phy/ti/phy-gmii-sel.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/phy/phy.h>
@@ -41,6 +42,7 @@ struct phy_gmii_sel_soc_data {
u32 num_ports;
u32 features;
const struct reg_field (*regfields)[PHY_GMII_SEL_LAST];
+ bool use_of_data;
};
struct phy_gmii_sel_priv {
@@ -49,6 +51,8 @@ struct phy_gmii_sel_priv {
struct regmap *regmap;
struct phy_provider *phy_provider;
struct phy_gmii_sel_phy_priv *if_phys;
+ u32 num_ports;
+ u32 reg_offset;
};
static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
@@ -168,14 +172,19 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814 = {
static const
struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = {
- {
- [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4040, 0, 1),
- },
+ { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x0, 0, 2), },
+ { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4, 0, 2), },
+ { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x8, 0, 2), },
+ { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0xC, 0, 2), },
+ { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x10, 0, 2), },
+ { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x14, 0, 2), },
+ { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x18, 0, 2), },
+ { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x1C, 0, 2), },
};
static const
struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
- .num_ports = 1,
+ .use_of_data = true,
.regfields = phy_gmii_sel_fields_am654,
};
@@ -222,7 +231,7 @@ static struct phy *phy_gmii_sel_of_xlate(struct device *dev,
if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
args->args_count < 2)
return ERR_PTR(-EINVAL);
- if (phy_id > priv->soc_data->num_ports)
+ if (phy_id > priv->num_ports)
return ERR_PTR(-EINVAL);
if (phy_id != priv->if_phys[phy_id - 1].id)
return ERR_PTR(-EINVAL);
@@ -251,6 +260,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
fields = soc_data->regfields[port - 1];
field = *fields++;
+ field.reg += priv->reg_offset;
dev_dbg(dev, "%s field %x %d %d\n", __func__,
field.reg, field.msb, field.lsb);
@@ -260,6 +270,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield;
field = *fields++;
+ field.reg += priv->reg_offset;
if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) {
regfield = devm_regmap_field_alloc(dev,
priv->regmap,
@@ -272,6 +283,7 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
}
field = *fields;
+ field.reg += priv->reg_offset;
if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) {
regfield = devm_regmap_field_alloc(dev,
priv->regmap,
@@ -299,19 +311,28 @@ static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
{
const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
- struct device *dev = priv->dev;
struct phy_gmii_sel_phy_priv *if_phys;
- int i, num_ports, ret;
+ struct device *dev = priv->dev;
+ int i, ret;
+
+ if (soc_data->use_of_data) {
+ const __be32 *offset;
+ u64 size;
- num_ports = soc_data->num_ports;
+ offset = of_get_address(dev->of_node, 0, &size, NULL);
+ priv->num_ports = size / sizeof(u32);
+ if (!priv->num_ports)
+ return -EINVAL;
+ priv->reg_offset = __be32_to_cpu(*offset);
+ }
- if_phys = devm_kcalloc(priv->dev, num_ports,
+ if_phys = devm_kcalloc(dev, priv->num_ports,
sizeof(*if_phys), GFP_KERNEL);
if (!if_phys)
return -ENOMEM;
- dev_dbg(dev, "%s %d\n", __func__, num_ports);
+ dev_dbg(dev, "%s %d\n", __func__, priv->num_ports);
- for (i = 0; i < num_ports; i++) {
+ for (i = 0; i < priv->num_ports; i++) {
ret = phy_gmii_init_phy(priv, i + 1, &if_phys[i]);
if (ret)
return ret;
@@ -339,6 +360,7 @@ static int phy_gmii_sel_probe(struct platform_device *pdev)
priv->dev = &pdev->dev;
priv->soc_data = of_id->data;
+ priv->num_ports = priv->soc_data->num_ports;
priv->regmap = syscon_node_to_regmap(node->parent);
if (IS_ERR(priv->regmap)) {