netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] add TJA1102 support
@ 2020-03-09  7:40 Oleksij Rempel
  2020-03-09  7:40 ` [PATCH v2 1/2] net: phy: tja11xx: " Oleksij Rempel
  2020-03-09  7:40 ` [PATCH v2 2/2] net: phy: tja11xx: add delayed registration of TJA1102 PHY1 Oleksij Rempel
  0 siblings, 2 replies; 8+ messages in thread
From: Oleksij Rempel @ 2020-03-09  7:40 UTC (permalink / raw)
  To: Andrew Lunn, Florian Fainelli, Heiner Kallweit
  Cc: Oleksij Rempel, Pengutronix Kernel Team, linux-kernel,
	David S. Miller, netdev, Marek Vasut, David Jander

changes v2:
- use .match_phy_device
- add irq support
- add add delayed registration for PHY1

Oleksij Rempel (2):
  net: phy: tja11xx: add TJA1102 support
  net: phy: tja11xx: add delayed registration of TJA1102 PHY1

 drivers/net/phy/nxp-tja11xx.c | 216 +++++++++++++++++++++++++++++++++-
 1 file changed, 210 insertions(+), 6 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/2] net: phy: tja11xx: add TJA1102 support
  2020-03-09  7:40 [PATCH v2 0/2] add TJA1102 support Oleksij Rempel
@ 2020-03-09  7:40 ` Oleksij Rempel
  2020-03-09 17:14   ` Andrew Lunn
  2020-03-09 19:45   ` Heiner Kallweit
  2020-03-09  7:40 ` [PATCH v2 2/2] net: phy: tja11xx: add delayed registration of TJA1102 PHY1 Oleksij Rempel
  1 sibling, 2 replies; 8+ messages in thread
From: Oleksij Rempel @ 2020-03-09  7:40 UTC (permalink / raw)
  To: Andrew Lunn, Florian Fainelli, Heiner Kallweit
  Cc: Oleksij Rempel, Pengutronix Kernel Team, linux-kernel,
	David S. Miller, netdev, Marek Vasut, David Jander

TJA1102 is an dual T1 PHY chip. Both PHYs are separately addressable.
PHY 0 can be identified by PHY ID. PHY 1 has no PHY ID and can be
configured in device tree by setting compatible = "ethernet-phy-id0180.dc81".

PHY 1 has less supported registers and functionality. For current driver
it will affect only the HWMON support.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/net/phy/nxp-tja11xx.c | 102 ++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
index b705d0bd798b..f79c9aa051ed 100644
--- a/drivers/net/phy/nxp-tja11xx.c
+++ b/drivers/net/phy/nxp-tja11xx.c
@@ -15,6 +15,7 @@
 #define PHY_ID_MASK			0xfffffff0
 #define PHY_ID_TJA1100			0x0180dc40
 #define PHY_ID_TJA1101			0x0180dd00
+#define PHY_ID_TJA1102			0x0180dc80
 
 #define MII_ECTRL			17
 #define MII_ECTRL_LINK_CONTROL		BIT(15)
@@ -40,6 +41,10 @@
 #define MII_INTSRC_TEMP_ERR		BIT(1)
 #define MII_INTSRC_UV_ERR		BIT(3)
 
+#define MII_INTEN			22
+#define MII_INTEN_LINK_FAIL		BIT(10)
+#define MII_INTEN_LINK_UP		BIT(9)
+
 #define MII_COMMSTAT			23
 #define MII_COMMSTAT_LINK_UP		BIT(15)
 
@@ -190,6 +195,7 @@ static int tja11xx_config_init(struct phy_device *phydev)
 			return ret;
 		break;
 	case PHY_ID_TJA1101:
+	case PHY_ID_TJA1102:
 		ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
 		if (ret)
 			return ret;
@@ -354,6 +360,66 @@ static int tja11xx_probe(struct phy_device *phydev)
 	return PTR_ERR_OR_ZERO(priv->hwmon_dev);
 }
 
+static int tja1102_match_phy_device(struct phy_device *phydev, bool port0)
+{
+	int ret;
+
+	if ((phydev->phy_id & PHY_ID_MASK) != PHY_ID_TJA1102)
+		return 0;
+
+	ret = phy_read(phydev, MII_PHYSID2);
+	if (ret < 0)
+		return ret;
+
+	/* TJA1102 Port 1 has phyid 0 and doesn't support temperature
+	 * and undervoltage alarms.
+	 */
+	if (port0)
+		return ret ? 1 : 0;
+
+	return !ret;
+}
+
+static int tja1102_p0_match_phy_device(struct phy_device *phydev)
+{
+	return tja1102_match_phy_device(phydev, true);
+}
+
+static int tja1102_p1_match_phy_device(struct phy_device *phydev)
+{
+	return tja1102_match_phy_device(phydev, false);
+}
+
+static int tja11xx_ack_interrupt(struct phy_device *phydev)
+{
+	int ret;
+
+	ret = phy_read(phydev, MII_INTSRC);
+
+	return (ret < 0) ? ret : 0;
+}
+
+static int tja11xx_config_intr(struct phy_device *phydev)
+{
+	int value;
+	int ret;
+
+	value = phy_read(phydev, MII_INTEN);
+	if (value < 0)
+		return value;
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+		value |= MII_INTEN_LINK_FAIL;
+		value |= MII_INTEN_LINK_UP;
+
+		ret = phy_write(phydev, MII_INTEN, value);
+	}
+	else
+		ret = phy_write(phydev, MII_INTEN, 0);
+
+	return ret;
+}
+
 static struct phy_driver tja11xx_driver[] = {
 	{
 		PHY_ID_MATCH_MODEL(PHY_ID_TJA1100),
@@ -385,6 +451,41 @@ static struct phy_driver tja11xx_driver[] = {
 		.get_sset_count = tja11xx_get_sset_count,
 		.get_strings	= tja11xx_get_strings,
 		.get_stats	= tja11xx_get_stats,
+	}, {
+		.name		= "NXP TJA1102 Port 0",
+		.features       = PHY_BASIC_T1_FEATURES,
+		.probe		= tja11xx_probe,
+		.soft_reset	= tja11xx_soft_reset,
+		.config_init	= tja11xx_config_init,
+		.read_status	= tja11xx_read_status,
+		.match_phy_device = tja1102_p0_match_phy_device,
+		.suspend	= genphy_suspend,
+		.resume		= genphy_resume,
+		.set_loopback   = genphy_loopback,
+		/* Statistics */
+		.get_sset_count = tja11xx_get_sset_count,
+		.get_strings	= tja11xx_get_strings,
+		.get_stats	= tja11xx_get_stats,
+		.ack_interrupt	= tja11xx_ack_interrupt,
+		.config_intr	= tja11xx_config_intr,
+
+	}, {
+		.name		= "NXP TJA1102 Port 1",
+		.features       = PHY_BASIC_T1_FEATURES,
+		/* currently no probe for Port 1 is need */
+		.soft_reset	= tja11xx_soft_reset,
+		.config_init	= tja11xx_config_init,
+		.read_status	= tja11xx_read_status,
+		.match_phy_device = tja1102_p1_match_phy_device,
+		.suspend	= genphy_suspend,
+		.resume		= genphy_resume,
+		.set_loopback   = genphy_loopback,
+		/* Statistics */
+		.get_sset_count = tja11xx_get_sset_count,
+		.get_strings	= tja11xx_get_strings,
+		.get_stats	= tja11xx_get_stats,
+		.ack_interrupt	= tja11xx_ack_interrupt,
+		.config_intr	= tja11xx_config_intr,
 	}
 };
 
@@ -393,6 +494,7 @@ module_phy_driver(tja11xx_driver);
 static struct mdio_device_id __maybe_unused tja11xx_tbl[] = {
 	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1100) },
 	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1101) },
+	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1102) },
 	{ }
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/2] net: phy: tja11xx: add delayed registration of TJA1102 PHY1
  2020-03-09  7:40 [PATCH v2 0/2] add TJA1102 support Oleksij Rempel
  2020-03-09  7:40 ` [PATCH v2 1/2] net: phy: tja11xx: " Oleksij Rempel
@ 2020-03-09  7:40 ` Oleksij Rempel
  2020-03-09 16:58   ` David Miller
  2020-03-09 17:28   ` Andrew Lunn
  1 sibling, 2 replies; 8+ messages in thread
From: Oleksij Rempel @ 2020-03-09  7:40 UTC (permalink / raw)
  To: Andrew Lunn, Florian Fainelli, Heiner Kallweit
  Cc: Oleksij Rempel, Pengutronix Kernel Team, linux-kernel,
	David S. Miller, netdev, Marek Vasut, David Jander

TJA1102 is a dual PHY package with PHY0 having proper PHYID and PHY1
having no ID. On one hand it is possible to for PHY detection by
compatible, on other hand we should be able to reset complete chip
before PHY1 configured it, and we need to define dependencies for proper
power management.

We can solve it by defining PHY1 as child of PHY0:
	tja1102_phy0: ethernet-phy@4 {
		reg = <0x4>;

		interrupts-extended = <&gpio5 8 IRQ_TYPE_LEVEL_LOW>;

		reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
		reset-assert-us = <20>;
		reset-deassert-us = <2000>;

		tja1102_phy1: ethernet-phy@5 {
			reg = <0x5>;

			interrupts-extended = <&gpio5 8 IRQ_TYPE_LEVEL_LOW>;
		};
	};

The PHY1 should be a subnode of PHY0 and registered only after PHY0 was
completely reset and initialized.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/net/phy/nxp-tja11xx.c | 116 ++++++++++++++++++++++++++++++++--
 1 file changed, 109 insertions(+), 7 deletions(-)

diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
index f79c9aa051ed..53e9e0aa9b5b 100644
--- a/drivers/net/phy/nxp-tja11xx.c
+++ b/drivers/net/phy/nxp-tja11xx.c
@@ -6,11 +6,14 @@
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/kernel.h>
+#include <linux/mdio.h>
 #include <linux/mii.h>
 #include <linux/module.h>
 #include <linux/phy.h>
 #include <linux/hwmon.h>
 #include <linux/bitfield.h>
+#include <linux/of_mdio.h>
+#include <linux/of_irq.h>
 
 #define PHY_ID_MASK			0xfffffff0
 #define PHY_ID_TJA1100			0x0180dc40
@@ -57,6 +60,8 @@
 struct tja11xx_priv {
 	char		*hwmon_name;
 	struct device	*hwmon_dev;
+	struct phy_device *phydev;
+	struct work_struct phy_register_work;
 };
 
 struct tja11xx_phy_stats {
@@ -333,16 +338,12 @@ static const struct hwmon_chip_info tja11xx_hwmon_chip_info = {
 	.info		= tja11xx_hwmon_info,
 };
 
-static int tja11xx_probe(struct phy_device *phydev)
+static int tja11xx_hwmon_register(struct phy_device *phydev,
+				  struct tja11xx_priv *priv)
 {
 	struct device *dev = &phydev->mdio.dev;
-	struct tja11xx_priv *priv;
 	int i;
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
 	priv->hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
 	if (!priv->hwmon_name)
 		return -ENOMEM;
@@ -360,6 +361,107 @@ static int tja11xx_probe(struct phy_device *phydev)
 	return PTR_ERR_OR_ZERO(priv->hwmon_dev);
 }
 
+static int tja11xx_probe(struct phy_device *phydev)
+{
+	struct device *dev = &phydev->mdio.dev;
+	struct tja11xx_priv *priv;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->phydev = phydev;
+
+	return tja11xx_hwmon_register(phydev, priv);
+}
+
+static void tja1102_p1_register(struct work_struct *work)
+{
+	struct tja11xx_priv *priv = container_of(work, struct tja11xx_priv,
+						 phy_register_work);
+
+	struct phy_device *phydev_phy0 = priv->phydev;
+        struct mii_bus *bus = phydev_phy0->mdio.bus;
+	struct device *dev = &phydev_phy0->mdio.dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *child;
+	int ret;
+
+	for_each_available_child_of_node(np, child) {
+		struct phy_device *phy;
+		int addr;
+
+		addr = of_mdio_parse_addr(dev, child);
+		if (addr < 0) {
+			dev_err(dev, "Can't parse addr\n");
+			continue;
+		}
+
+		/* skip already registered PHYs */
+		if (mdiobus_is_registered_device(bus, addr)) {
+			dev_err(dev, "device is already registred \n");
+			continue;
+		}
+
+		phy = phy_device_create(bus, addr, PHY_ID_TJA1102,
+						false, NULL);
+		if (IS_ERR(phy)) {
+			dev_err(dev, "Can't register Port : %i\n", addr);
+			continue;
+		}
+
+		ret = of_irq_get(child, 0);
+		/* can we be deferred here? */
+		if (ret > 0) {
+			phy->irq = ret;
+			bus->irq[addr] = ret;
+		} else {
+			phy->irq = bus->irq[addr];
+		}
+
+		/* overwrite parent phy_device_create() set parent to the
+		 * mii_bus->dev
+		 */
+		phy->mdio.dev.parent = dev;
+
+		/* Associate the OF node with the device structure so it
+		 * can be looked up later */
+		of_node_get(child);
+		phy->mdio.dev.of_node = child;
+		phy->mdio.dev.fwnode = of_fwnode_handle(child);
+
+		/* All data is now stored in the phy struct;
+		 * register it */
+		ret = phy_device_register(phy);
+		if (ret) {
+			phy_device_free(phy);
+			of_node_put(child);
+		}
+	}
+}
+
+static int tja1102_p0_probe(struct phy_device *phydev)
+{
+	struct device *dev = &phydev->mdio.dev;
+	struct tja11xx_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->phydev = phydev;
+	INIT_WORK(&priv->phy_register_work, tja1102_p1_register);
+
+	ret = tja11xx_hwmon_register(phydev, priv);
+	if (ret)
+		return ret;
+
+	schedule_work(&priv->phy_register_work);
+
+	return 0;
+}
+
 static int tja1102_match_phy_device(struct phy_device *phydev, bool port0)
 {
 	int ret;
@@ -454,7 +556,7 @@ static struct phy_driver tja11xx_driver[] = {
 	}, {
 		.name		= "NXP TJA1102 Port 0",
 		.features       = PHY_BASIC_T1_FEATURES,
-		.probe		= tja11xx_probe,
+		.probe		= tja1102_p0_probe,
 		.soft_reset	= tja11xx_soft_reset,
 		.config_init	= tja11xx_config_init,
 		.read_status	= tja11xx_read_status,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] net: phy: tja11xx: add delayed registration of TJA1102 PHY1
  2020-03-09  7:40 ` [PATCH v2 2/2] net: phy: tja11xx: add delayed registration of TJA1102 PHY1 Oleksij Rempel
@ 2020-03-09 16:58   ` David Miller
  2020-03-09 17:28   ` Andrew Lunn
  1 sibling, 0 replies; 8+ messages in thread
From: David Miller @ 2020-03-09 16:58 UTC (permalink / raw)
  To: o.rempel
  Cc: andrew, f.fainelli, hkallweit1, kernel, linux-kernel, netdev,
	marex, david

From: Oleksij Rempel <o.rempel@pengutronix.de>
Date: Mon,  9 Mar 2020 08:40:44 +0100

> +
> +static void tja1102_p1_register(struct work_struct *work)
> +{
> +	struct tja11xx_priv *priv = container_of(work, struct tja11xx_priv,
> +						 phy_register_work);
> +
> +	struct phy_device *phydev_phy0 = priv->phydev;
> +        struct mii_bus *bus = phydev_phy0->mdio.bus;
> +	struct device *dev = &phydev_phy0->mdio.dev;

Please fix the indentation of the 'bus' variable declaration.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/2] net: phy: tja11xx: add TJA1102 support
  2020-03-09  7:40 ` [PATCH v2 1/2] net: phy: tja11xx: " Oleksij Rempel
@ 2020-03-09 17:14   ` Andrew Lunn
  2020-03-09 19:45   ` Heiner Kallweit
  1 sibling, 0 replies; 8+ messages in thread
From: Andrew Lunn @ 2020-03-09 17:14 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Florian Fainelli, Heiner Kallweit, Pengutronix Kernel Team,
	linux-kernel, David S. Miller, netdev, Marek Vasut, David Jander

On Mon, Mar 09, 2020 at 08:40:43AM +0100, Oleksij Rempel wrote:
> TJA1102 is an dual T1 PHY chip. Both PHYs are separately addressable.
> PHY 0 can be identified by PHY ID. PHY 1 has no PHY ID and can be
> configured in device tree by setting compatible = "ethernet-phy-id0180.dc81".

Hi Oleksij

Given what the second patch does, there is no need to set the
compatible. So please reword this.

	    Andrew

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] net: phy: tja11xx: add delayed registration of TJA1102 PHY1
  2020-03-09  7:40 ` [PATCH v2 2/2] net: phy: tja11xx: add delayed registration of TJA1102 PHY1 Oleksij Rempel
  2020-03-09 16:58   ` David Miller
@ 2020-03-09 17:28   ` Andrew Lunn
  1 sibling, 0 replies; 8+ messages in thread
From: Andrew Lunn @ 2020-03-09 17:28 UTC (permalink / raw)
  To: Oleksij Rempel
  Cc: Florian Fainelli, Heiner Kallweit, Pengutronix Kernel Team,
	linux-kernel, David S. Miller, netdev, Marek Vasut, David Jander

On Mon, Mar 09, 2020 at 08:40:44AM +0100, Oleksij Rempel wrote:
> TJA1102 is a dual PHY package with PHY0 having proper PHYID and PHY1
> having no ID. On one hand it is possible to for PHY detection by
> compatible, on other hand we should be able to reset complete chip
> before PHY1 configured it, and we need to define dependencies for proper
> power management.
> 
> We can solve it by defining PHY1 as child of PHY0:
> 	tja1102_phy0: ethernet-phy@4 {
> 		reg = <0x4>;
> 
> 		interrupts-extended = <&gpio5 8 IRQ_TYPE_LEVEL_LOW>;
> 
> 		reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
> 		reset-assert-us = <20>;
> 		reset-deassert-us = <2000>;
> 
> 		tja1102_phy1: ethernet-phy@5 {
> 			reg = <0x5>;
> 
> 			interrupts-extended = <&gpio5 8 IRQ_TYPE_LEVEL_LOW>;
> 		};
> 	};
> 
> The PHY1 should be a subnode of PHY0 and registered only after PHY0 was
> completely reset and initialized.

Hi Oleksij

Please add a binding document for this.

> +static void tja1102_p1_register(struct work_struct *work)
> +{
> +	struct tja11xx_priv *priv = container_of(work, struct tja11xx_priv,
> +						 phy_register_work);
> +
> +	struct phy_device *phydev_phy0 = priv->phydev;
> +        struct mii_bus *bus = phydev_phy0->mdio.bus;
> +	struct device *dev = &phydev_phy0->mdio.dev;
> +	struct device_node *np = dev->of_node;
> +	struct device_node *child;
> +	int ret;
> +
> +	for_each_available_child_of_node(np, child) {
> +		struct phy_device *phy;
> +		int addr;
> +
> +		addr = of_mdio_parse_addr(dev, child);
> +		if (addr < 0) {
> +			dev_err(dev, "Can't parse addr\n");
> +			continue;
> +		}

It would also be good to check that addr is one more than the parent
device. That seems to be a silicon constraint.

> +
> +		/* skip already registered PHYs */
> +		if (mdiobus_is_registered_device(bus, addr)) {
> +			dev_err(dev, "device is already registred \n");
> +			continue;
> +		}
> +
> +		phy = phy_device_create(bus, addr, PHY_ID_TJA1102,
> +						false, NULL);
> +		if (IS_ERR(phy)) {
> +			dev_err(dev, "Can't register Port : %i\n", addr);

You are not registering at this step, just allocating.

> +			continue;
> +		}
> +
> +		ret = of_irq_get(child, 0);
> +		/* can we be deferred here? */

Yes.

commit 66bdede495c71da9c5ce18542976fae53642880b
Author: Geert Uytterhoeven <geert+renesas@glider.be>
Date:   Wed Oct 18 13:54:03 2017 +0200

    of_mdio: Fix broken PHY IRQ in case of probe deferral
    
    If an Ethernet PHY is initialized before the interrupt controller it is
    connected to, a message like the following is printed:
    
        irq: no irq domain found for /interrupt-controller@e61c0000 !


> +		if (ret > 0) {
> +			phy->irq = ret;
> +			bus->irq[addr] = ret;
> +		} else {
> +			phy->irq = bus->irq[addr];
> +		}
> +
> +		/* overwrite parent phy_device_create() set parent to the
> +		 * mii_bus->dev
> +		 */
> +		phy->mdio.dev.parent = dev;
> +
> +		/* Associate the OF node with the device structure so it
> +		 * can be looked up later */
> +		of_node_get(child);
> +		phy->mdio.dev.of_node = child;
> +		phy->mdio.dev.fwnode = of_fwnode_handle(child);
> +
> +		/* All data is now stored in the phy struct;
> +		 * register it */
> +		ret = phy_device_register(phy);
> +		if (ret) {
> +			phy_device_free(phy);
> +			of_node_put(child);
> +		}
> +	}
> +}

This is a lot of of_mdiobus_register_phy(). I think it would be better
to refactor this code a bit, maybe make a helper out of
of_mdiobus_register_phy() for all the shared code.

	  Andrew

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/2] net: phy: tja11xx: add TJA1102 support
  2020-03-09  7:40 ` [PATCH v2 1/2] net: phy: tja11xx: " Oleksij Rempel
  2020-03-09 17:14   ` Andrew Lunn
@ 2020-03-09 19:45   ` Heiner Kallweit
  2020-03-11 13:12     ` Oleksij Rempel
  1 sibling, 1 reply; 8+ messages in thread
From: Heiner Kallweit @ 2020-03-09 19:45 UTC (permalink / raw)
  To: Oleksij Rempel, Andrew Lunn, Florian Fainelli
  Cc: Pengutronix Kernel Team, linux-kernel, David S. Miller, netdev,
	Marek Vasut, David Jander

On 09.03.2020 08:40, Oleksij Rempel wrote:
> TJA1102 is an dual T1 PHY chip. Both PHYs are separately addressable.
> PHY 0 can be identified by PHY ID. PHY 1 has no PHY ID and can be
> configured in device tree by setting compatible = "ethernet-phy-id0180.dc81".
> 
> PHY 1 has less supported registers and functionality. For current driver
> it will affect only the HWMON support.
> 
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
>  drivers/net/phy/nxp-tja11xx.c | 102 ++++++++++++++++++++++++++++++++++
>  1 file changed, 102 insertions(+)
> 
> diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
> index b705d0bd798b..f79c9aa051ed 100644
> --- a/drivers/net/phy/nxp-tja11xx.c
> +++ b/drivers/net/phy/nxp-tja11xx.c
> @@ -15,6 +15,7 @@
>  #define PHY_ID_MASK			0xfffffff0
>  #define PHY_ID_TJA1100			0x0180dc40
>  #define PHY_ID_TJA1101			0x0180dd00
> +#define PHY_ID_TJA1102			0x0180dc80
>  
>  #define MII_ECTRL			17
>  #define MII_ECTRL_LINK_CONTROL		BIT(15)
> @@ -40,6 +41,10 @@
>  #define MII_INTSRC_TEMP_ERR		BIT(1)
>  #define MII_INTSRC_UV_ERR		BIT(3)
>  
> +#define MII_INTEN			22
> +#define MII_INTEN_LINK_FAIL		BIT(10)
> +#define MII_INTEN_LINK_UP		BIT(9)
> +
>  #define MII_COMMSTAT			23
>  #define MII_COMMSTAT_LINK_UP		BIT(15)
>  
> @@ -190,6 +195,7 @@ static int tja11xx_config_init(struct phy_device *phydev)
>  			return ret;
>  		break;
>  	case PHY_ID_TJA1101:
> +	case PHY_ID_TJA1102:
>  		ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
>  		if (ret)
>  			return ret;
> @@ -354,6 +360,66 @@ static int tja11xx_probe(struct phy_device *phydev)
>  	return PTR_ERR_OR_ZERO(priv->hwmon_dev);
>  }
>  
> +static int tja1102_match_phy_device(struct phy_device *phydev, bool port0)
> +{
> +	int ret;
> +
> +	if ((phydev->phy_id & PHY_ID_MASK) != PHY_ID_TJA1102)

For port 1 you rely on DT forcing the appropriate phy_id
(else it would be 0 and port 1 wouldn't be matched).
This is worth a describing comment.

> +		return 0;
> +
> +	ret = phy_read(phydev, MII_PHYSID2);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* TJA1102 Port 1 has phyid 0 and doesn't support temperature
> +	 * and undervoltage alarms.
> +	 */
> +	if (port0)
> +		return ret ? 1 : 0;
> +
> +	return !ret;
> +}
> +
> +static int tja1102_p0_match_phy_device(struct phy_device *phydev)
> +{
> +	return tja1102_match_phy_device(phydev, true);
> +}
> +
> +static int tja1102_p1_match_phy_device(struct phy_device *phydev)
> +{
> +	return tja1102_match_phy_device(phydev, false);
> +}
> +
> +static int tja11xx_ack_interrupt(struct phy_device *phydev)
> +{
> +	int ret;
> +
> +	ret = phy_read(phydev, MII_INTSRC);
> +
> +	return (ret < 0) ? ret : 0;
> +}
> +
> +static int tja11xx_config_intr(struct phy_device *phydev)
> +{
> +	int value;
> +	int ret;
> +
> +	value = phy_read(phydev, MII_INTEN);
> +	if (value < 0)
> +		return value;
> +
> +	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
> +		value |= MII_INTEN_LINK_FAIL;
> +		value |= MII_INTEN_LINK_UP;
> +

This may leave unwanted interrupt sources active. Why not
simply setting a fixed value like in the else clause?

> +		ret = phy_write(phydev, MII_INTEN, value);
> +	}
> +	else

Kernel style:
Closing brace and else belong to one line. And the else clause
needs braces too. checkpatch.pl should complain here.

> +		ret = phy_write(phydev, MII_INTEN, 0);
> +
> +	return ret;
> +}
> +
>  static struct phy_driver tja11xx_driver[] = {
>  	{
>  		PHY_ID_MATCH_MODEL(PHY_ID_TJA1100),
> @@ -385,6 +451,41 @@ static struct phy_driver tja11xx_driver[] = {
>  		.get_sset_count = tja11xx_get_sset_count,
>  		.get_strings	= tja11xx_get_strings,
>  		.get_stats	= tja11xx_get_stats,
> +	}, {
> +		.name		= "NXP TJA1102 Port 0",
> +		.features       = PHY_BASIC_T1_FEATURES,
> +		.probe		= tja11xx_probe,
> +		.soft_reset	= tja11xx_soft_reset,
> +		.config_init	= tja11xx_config_init,
> +		.read_status	= tja11xx_read_status,
> +		.match_phy_device = tja1102_p0_match_phy_device,
> +		.suspend	= genphy_suspend,
> +		.resume		= genphy_resume,
> +		.set_loopback   = genphy_loopback,
> +		/* Statistics */
> +		.get_sset_count = tja11xx_get_sset_count,
> +		.get_strings	= tja11xx_get_strings,
> +		.get_stats	= tja11xx_get_stats,
> +		.ack_interrupt	= tja11xx_ack_interrupt,
> +		.config_intr	= tja11xx_config_intr,
> +
> +	}, {
> +		.name		= "NXP TJA1102 Port 1",
> +		.features       = PHY_BASIC_T1_FEATURES,
> +		/* currently no probe for Port 1 is need */
> +		.soft_reset	= tja11xx_soft_reset,
> +		.config_init	= tja11xx_config_init,
> +		.read_status	= tja11xx_read_status,
> +		.match_phy_device = tja1102_p1_match_phy_device,
> +		.suspend	= genphy_suspend,
> +		.resume		= genphy_resume,
> +		.set_loopback   = genphy_loopback,
> +		/* Statistics */
> +		.get_sset_count = tja11xx_get_sset_count,
> +		.get_strings	= tja11xx_get_strings,
> +		.get_stats	= tja11xx_get_stats,
> +		.ack_interrupt	= tja11xx_ack_interrupt,
> +		.config_intr	= tja11xx_config_intr,
>  	}
>  };
>  
> @@ -393,6 +494,7 @@ module_phy_driver(tja11xx_driver);
>  static struct mdio_device_id __maybe_unused tja11xx_tbl[] = {
>  	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1100) },
>  	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1101) },
> +	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1102) },
>  	{ }
>  };
>  
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/2] net: phy: tja11xx: add TJA1102 support
  2020-03-09 19:45   ` Heiner Kallweit
@ 2020-03-11 13:12     ` Oleksij Rempel
  0 siblings, 0 replies; 8+ messages in thread
From: Oleksij Rempel @ 2020-03-11 13:12 UTC (permalink / raw)
  To: Heiner Kallweit
  Cc: Andrew Lunn, Florian Fainelli, Marek Vasut, netdev, linux-kernel,
	Pengutronix Kernel Team, David Jander, David S. Miller

[-- Attachment #1: Type: text/plain, Size: 6286 bytes --]

On Mon, Mar 09, 2020 at 08:45:50PM +0100, Heiner Kallweit wrote:
> On 09.03.2020 08:40, Oleksij Rempel wrote:
> > TJA1102 is an dual T1 PHY chip. Both PHYs are separately addressable.
> > PHY 0 can be identified by PHY ID. PHY 1 has no PHY ID and can be
> > configured in device tree by setting compatible = "ethernet-phy-id0180.dc81".
> > 
> > PHY 1 has less supported registers and functionality. For current driver
> > it will affect only the HWMON support.
> > 
> > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> > ---
> >  drivers/net/phy/nxp-tja11xx.c | 102 ++++++++++++++++++++++++++++++++++
> >  1 file changed, 102 insertions(+)
> > 
> > diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
> > index b705d0bd798b..f79c9aa051ed 100644
> > --- a/drivers/net/phy/nxp-tja11xx.c
> > +++ b/drivers/net/phy/nxp-tja11xx.c
> > @@ -15,6 +15,7 @@
> >  #define PHY_ID_MASK			0xfffffff0
> >  #define PHY_ID_TJA1100			0x0180dc40
> >  #define PHY_ID_TJA1101			0x0180dd00
> > +#define PHY_ID_TJA1102			0x0180dc80
> >  
> >  #define MII_ECTRL			17
> >  #define MII_ECTRL_LINK_CONTROL		BIT(15)
> > @@ -40,6 +41,10 @@
> >  #define MII_INTSRC_TEMP_ERR		BIT(1)
> >  #define MII_INTSRC_UV_ERR		BIT(3)
> >  
> > +#define MII_INTEN			22
> > +#define MII_INTEN_LINK_FAIL		BIT(10)
> > +#define MII_INTEN_LINK_UP		BIT(9)
> > +
> >  #define MII_COMMSTAT			23
> >  #define MII_COMMSTAT_LINK_UP		BIT(15)
> >  
> > @@ -190,6 +195,7 @@ static int tja11xx_config_init(struct phy_device *phydev)
> >  			return ret;
> >  		break;
> >  	case PHY_ID_TJA1101:
> > +	case PHY_ID_TJA1102:
> >  		ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
> >  		if (ret)
> >  			return ret;
> > @@ -354,6 +360,66 @@ static int tja11xx_probe(struct phy_device *phydev)
> >  	return PTR_ERR_OR_ZERO(priv->hwmon_dev);
> >  }
> >  
> > +static int tja1102_match_phy_device(struct phy_device *phydev, bool port0)
> > +{
> > +	int ret;
> > +
> > +	if ((phydev->phy_id & PHY_ID_MASK) != PHY_ID_TJA1102)
> 
> For port 1 you rely on DT forcing the appropriate phy_id
> (else it would be 0 and port 1 wouldn't be matched).
> This is worth a describing comment.

There is a second patch which will do it automatically, no need to force
the PHY ID in the devicetree.

> > +		return 0;
> > +
> > +	ret = phy_read(phydev, MII_PHYSID2);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	/* TJA1102 Port 1 has phyid 0 and doesn't support temperature
> > +	 * and undervoltage alarms.
> > +	 */
> > +	if (port0)
> > +		return ret ? 1 : 0;
> > +
> > +	return !ret;
> > +}
> > +
> > +static int tja1102_p0_match_phy_device(struct phy_device *phydev)
> > +{
> > +	return tja1102_match_phy_device(phydev, true);
> > +}
> > +
> > +static int tja1102_p1_match_phy_device(struct phy_device *phydev)
> > +{
> > +	return tja1102_match_phy_device(phydev, false);
> > +}
> > +
> > +static int tja11xx_ack_interrupt(struct phy_device *phydev)
> > +{
> > +	int ret;
> > +
> > +	ret = phy_read(phydev, MII_INTSRC);
> > +
> > +	return (ret < 0) ? ret : 0;
> > +}
> > +
> > +static int tja11xx_config_intr(struct phy_device *phydev)
> > +{
> > +	int value;
> > +	int ret;
> > +
> > +	value = phy_read(phydev, MII_INTEN);
> > +	if (value < 0)
> > +		return value;
> > +
> > +	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
> > +		value |= MII_INTEN_LINK_FAIL;
> > +		value |= MII_INTEN_LINK_UP;
> > +
> 
> This may leave unwanted interrupt sources active. Why not
> simply setting a fixed value like in the else clause?

done

> > +		ret = phy_write(phydev, MII_INTEN, value);
> > +	}
> > +	else
> 
> Kernel style:
> Closing brace and else belong to one line. And the else clause
> needs braces too. checkpatch.pl should complain here.

done

> > +		ret = phy_write(phydev, MII_INTEN, 0);
> > +
> > +	return ret;
> > +}
> > +
> >  static struct phy_driver tja11xx_driver[] = {
> >  	{
> >  		PHY_ID_MATCH_MODEL(PHY_ID_TJA1100),
> > @@ -385,6 +451,41 @@ static struct phy_driver tja11xx_driver[] = {
> >  		.get_sset_count = tja11xx_get_sset_count,
> >  		.get_strings	= tja11xx_get_strings,
> >  		.get_stats	= tja11xx_get_stats,
> > +	}, {
> > +		.name		= "NXP TJA1102 Port 0",
> > +		.features       = PHY_BASIC_T1_FEATURES,
> > +		.probe		= tja11xx_probe,
> > +		.soft_reset	= tja11xx_soft_reset,
> > +		.config_init	= tja11xx_config_init,
> > +		.read_status	= tja11xx_read_status,
> > +		.match_phy_device = tja1102_p0_match_phy_device,
> > +		.suspend	= genphy_suspend,
> > +		.resume		= genphy_resume,
> > +		.set_loopback   = genphy_loopback,
> > +		/* Statistics */
> > +		.get_sset_count = tja11xx_get_sset_count,
> > +		.get_strings	= tja11xx_get_strings,
> > +		.get_stats	= tja11xx_get_stats,
> > +		.ack_interrupt	= tja11xx_ack_interrupt,
> > +		.config_intr	= tja11xx_config_intr,
> > +
> > +	}, {
> > +		.name		= "NXP TJA1102 Port 1",
> > +		.features       = PHY_BASIC_T1_FEATURES,
> > +		/* currently no probe for Port 1 is need */
> > +		.soft_reset	= tja11xx_soft_reset,
> > +		.config_init	= tja11xx_config_init,
> > +		.read_status	= tja11xx_read_status,
> > +		.match_phy_device = tja1102_p1_match_phy_device,
> > +		.suspend	= genphy_suspend,
> > +		.resume		= genphy_resume,
> > +		.set_loopback   = genphy_loopback,
> > +		/* Statistics */
> > +		.get_sset_count = tja11xx_get_sset_count,
> > +		.get_strings	= tja11xx_get_strings,
> > +		.get_stats	= tja11xx_get_stats,
> > +		.ack_interrupt	= tja11xx_ack_interrupt,
> > +		.config_intr	= tja11xx_config_intr,
> >  	}
> >  };
> >  
> > @@ -393,6 +494,7 @@ module_phy_driver(tja11xx_driver);
> >  static struct mdio_device_id __maybe_unused tja11xx_tbl[] = {
> >  	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1100) },
> >  	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1101) },
> > +	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1102) },
> >  	{ }
> >  };
> >  
> > 
> 
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2020-03-11 13:12 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-09  7:40 [PATCH v2 0/2] add TJA1102 support Oleksij Rempel
2020-03-09  7:40 ` [PATCH v2 1/2] net: phy: tja11xx: " Oleksij Rempel
2020-03-09 17:14   ` Andrew Lunn
2020-03-09 19:45   ` Heiner Kallweit
2020-03-11 13:12     ` Oleksij Rempel
2020-03-09  7:40 ` [PATCH v2 2/2] net: phy: tja11xx: add delayed registration of TJA1102 PHY1 Oleksij Rempel
2020-03-09 16:58   ` David Miller
2020-03-09 17:28   ` Andrew Lunn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).