Commit fa2bc962 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'add-interface-mode-select-and-rmii'

Wei Fang says:

====================
add interface mode select and RMII

From: Wei Fang <wei.fang@nxp.com>

The patches add the below feature support for both TJA1100 and
TJA1101 PHYs cards:
- Add MII and RMII mode support.
- Add REF_CLK input/output support for RMII mode.
====================

Link: https://lore.kernel.org/r/20220822015949.1569969-1-wei.fang@nxp.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 3de1484b 60ddc78d
Loading
Loading
Loading
Loading
+17 −0
Original line number Original line Diff line number Diff line
@@ -31,6 +31,22 @@ patternProperties:
        description:
        description:
          The ID number for the child PHY. Should be +1 of parent PHY.
          The ID number for the child PHY. Should be +1 of parent PHY.


      nxp,rmii-refclk-in:
        type: boolean
        description: |
          The REF_CLK is provided for both transmitted and received data
          in RMII mode. This clock signal is provided by the PHY and is
          typically derived from an external 25MHz crystal. Alternatively,
          a 50MHz clock signal generated by an external oscillator can be
          connected to pin REF_CLK. A third option is to connect a 25MHz
          clock to pin CLK_IN_OUT. So, the REF_CLK should be configured
          as input or output according to the actual circuit connection.
          If present, indicates that the REF_CLK will be configured as
          interface reference clock input when RMII mode enabled.
          If not present, the REF_CLK will be configured as interface
          reference clock output when RMII mode enabled.
          Only supported on TJA1100 and TJA1101.

    required:
    required:
      - reg
      - reg


@@ -44,6 +60,7 @@ examples:


        tja1101_phy0: ethernet-phy@4 {
        tja1101_phy0: ethernet-phy@4 {
            reg = <0x4>;
            reg = <0x4>;
            nxp,rmii-refclk-in;
        };
        };
    };
    };
  - |
  - |
+78 −5
Original line number Original line Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/mdio.h>
#include <linux/mdio.h>
#include <linux/mii.h>
#include <linux/mii.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/phy.h>
#include <linux/hwmon.h>
#include <linux/hwmon.h>
#include <linux/bitfield.h>
#include <linux/bitfield.h>
@@ -34,6 +35,11 @@
#define MII_CFG1			18
#define MII_CFG1			18
#define MII_CFG1_MASTER_SLAVE		BIT(15)
#define MII_CFG1_MASTER_SLAVE		BIT(15)
#define MII_CFG1_AUTO_OP		BIT(14)
#define MII_CFG1_AUTO_OP		BIT(14)
#define MII_CFG1_INTERFACE_MODE_MASK	GENMASK(9, 8)
#define MII_CFG1_MII_MODE				(0x0 << 8)
#define MII_CFG1_RMII_MODE_REFCLK_IN	BIT(8)
#define MII_CFG1_RMII_MODE_REFCLK_OUT	BIT(9)
#define MII_CFG1_REVMII_MODE			GENMASK(9, 8)
#define MII_CFG1_SLEEP_CONFIRM		BIT(6)
#define MII_CFG1_SLEEP_CONFIRM		BIT(6)
#define MII_CFG1_LED_MODE_MASK		GENMASK(5, 4)
#define MII_CFG1_LED_MODE_MASK		GENMASK(5, 4)
#define MII_CFG1_LED_MODE_LINKUP	0
#define MII_CFG1_LED_MODE_LINKUP	0
@@ -72,11 +78,15 @@
#define MII_COMMCFG			27
#define MII_COMMCFG			27
#define MII_COMMCFG_AUTO_OP		BIT(15)
#define MII_COMMCFG_AUTO_OP		BIT(15)


/* Configure REF_CLK as input in RMII mode */
#define TJA110X_RMII_MODE_REFCLK_IN       BIT(0)

struct tja11xx_priv {
struct tja11xx_priv {
	char		*hwmon_name;
	char		*hwmon_name;
	struct device	*hwmon_dev;
	struct device	*hwmon_dev;
	struct phy_device *phydev;
	struct phy_device *phydev;
	struct work_struct phy_register_work;
	struct work_struct phy_register_work;
	u32 flags;
};
};


struct tja11xx_phy_stats {
struct tja11xx_phy_stats {
@@ -251,8 +261,34 @@ static int tja11xx_config_aneg(struct phy_device *phydev)
	return __genphy_config_aneg(phydev, changed);
	return __genphy_config_aneg(phydev, changed);
}
}


static int tja11xx_get_interface_mode(struct phy_device *phydev)
{
	struct tja11xx_priv *priv = phydev->priv;
	int mii_mode;

	switch (phydev->interface) {
	case PHY_INTERFACE_MODE_MII:
		mii_mode = MII_CFG1_MII_MODE;
		break;
	case PHY_INTERFACE_MODE_REVMII:
		mii_mode = MII_CFG1_REVMII_MODE;
		break;
	case PHY_INTERFACE_MODE_RMII:
		if (priv->flags & TJA110X_RMII_MODE_REFCLK_IN)
			mii_mode = MII_CFG1_RMII_MODE_REFCLK_IN;
		else
			mii_mode = MII_CFG1_RMII_MODE_REFCLK_OUT;
		break;
	default:
		return -EINVAL;
	}

	return mii_mode;
}

static int tja11xx_config_init(struct phy_device *phydev)
static int tja11xx_config_init(struct phy_device *phydev)
{
{
	u16 reg_mask, reg_val;
	int ret;
	int ret;


	ret = tja11xx_enable_reg_write(phydev);
	ret = tja11xx_enable_reg_write(phydev);
@@ -265,15 +301,32 @@ static int tja11xx_config_init(struct phy_device *phydev)


	switch (phydev->phy_id & PHY_ID_MASK) {
	switch (phydev->phy_id & PHY_ID_MASK) {
	case PHY_ID_TJA1100:
	case PHY_ID_TJA1100:
		ret = phy_modify(phydev, MII_CFG1,
		reg_mask = MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_MASK |
				 MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_MASK |
			   MII_CFG1_LED_ENABLE;
				 MII_CFG1_LED_ENABLE,
		reg_val = MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_LINKUP |
				 MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_LINKUP |
			  MII_CFG1_LED_ENABLE;
				 MII_CFG1_LED_ENABLE);

		reg_mask |= MII_CFG1_INTERFACE_MODE_MASK;
		ret = tja11xx_get_interface_mode(phydev);
		if (ret < 0)
			return ret;

		reg_val |= (ret & 0xffff);
		ret = phy_modify(phydev, MII_CFG1, reg_mask, reg_val);
		if (ret)
		if (ret)
			return ret;
			return ret;
		break;
		break;
	case PHY_ID_TJA1101:
	case PHY_ID_TJA1101:
		reg_mask = MII_CFG1_INTERFACE_MODE_MASK;
		ret = tja11xx_get_interface_mode(phydev);
		if (ret < 0)
			return ret;

		reg_val = ret & 0xffff;
		ret = phy_modify(phydev, MII_CFG1, reg_mask, reg_val);
		if (ret)
			return ret;
		fallthrough;
	case PHY_ID_TJA1102:
	case PHY_ID_TJA1102:
		ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
		ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
		if (ret)
		if (ret)
@@ -458,16 +511,36 @@ static int tja11xx_hwmon_register(struct phy_device *phydev,
	return PTR_ERR_OR_ZERO(priv->hwmon_dev);
	return PTR_ERR_OR_ZERO(priv->hwmon_dev);
}
}


static int tja11xx_parse_dt(struct phy_device *phydev)
{
	struct device_node *node = phydev->mdio.dev.of_node;
	struct tja11xx_priv *priv = phydev->priv;

	if (!IS_ENABLED(CONFIG_OF_MDIO))
		return 0;

	if (of_property_read_bool(node, "nxp,rmii-refclk-in"))
		priv->flags |= TJA110X_RMII_MODE_REFCLK_IN;

	return 0;
}

static int tja11xx_probe(struct phy_device *phydev)
static int tja11xx_probe(struct phy_device *phydev)
{
{
	struct device *dev = &phydev->mdio.dev;
	struct device *dev = &phydev->mdio.dev;
	struct tja11xx_priv *priv;
	struct tja11xx_priv *priv;
	int ret;


	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
	if (!priv)
		return -ENOMEM;
		return -ENOMEM;


	priv->phydev = phydev;
	priv->phydev = phydev;
	phydev->priv = priv;

	ret = tja11xx_parse_dt(phydev);
	if (ret)
		return ret;


	return tja11xx_hwmon_register(phydev, priv);
	return tja11xx_hwmon_register(phydev, priv);
}
}