Commit 0a4355c2 authored by Joakim Zhang's avatar Joakim Zhang Committed by David S. Miller
Browse files

net: phy: realtek: add dt property to disable CLKOUT clock



CLKOUT is enabled by default after PHY hardware reset, this patch adds
"realtek,clkout-disable" property for user to disable CLKOUT clock
to save PHY power.

Per RTL8211F guide, a PHY reset should be issued after setting these
bits in PHYCR2 register. After this patch, CLKOUT clock output to be
disabled.

Signed-off-by: default avatarJoakim Zhang <qiangqing.zhang@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a9f15dc2
Loading
Loading
Loading
Loading
+41 −1
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 * Copyright (c) 2004 Freescale Semiconductor, Inc.
 */
#include <linux/bitops.h>
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/module.h>
#include <linux/delay.h>
@@ -27,6 +28,7 @@
#define RTL821x_PAGE_SELECT			0x1f

#define RTL8211F_PHYCR1				0x18
#define RTL8211F_PHYCR2				0x19
#define RTL8211F_INSR				0x1d

#define RTL8211F_TX_DELAY			BIT(8)
@@ -40,6 +42,8 @@
#define RTL8211E_TX_DELAY			BIT(12)
#define RTL8211E_RX_DELAY			BIT(11)

#define RTL8211F_CLKOUT_EN			BIT(0)

#define RTL8201F_ISR				0x1e
#define RTL8201F_ISR_ANERR			BIT(15)
#define RTL8201F_ISR_DUPLEX			BIT(13)
@@ -71,6 +75,10 @@ MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
MODULE_LICENSE("GPL");

struct rtl821x_priv {
	u16 phycr2;
};

static int rtl821x_read_page(struct phy_device *phydev)
{
	return __phy_read(phydev, RTL821x_PAGE_SELECT);
@@ -81,6 +89,28 @@ static int rtl821x_write_page(struct phy_device *phydev, int page)
	return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
}

static int rtl821x_probe(struct phy_device *phydev)
{
	struct device *dev = &phydev->mdio.dev;
	struct rtl821x_priv *priv;

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

	priv->phycr2 = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2);
	if (priv->phycr2 < 0)
		return priv->phycr2;

	priv->phycr2 &= RTL8211F_CLKOUT_EN;
	if (of_property_read_bool(dev->of_node, "realtek,clkout-disable"))
		priv->phycr2 &= ~RTL8211F_CLKOUT_EN;

	phydev->priv = priv;

	return 0;
}

static int rtl8201_ack_interrupt(struct phy_device *phydev)
{
	int err;
@@ -291,6 +321,7 @@ static int rtl8211c_config_init(struct phy_device *phydev)

static int rtl8211f_config_init(struct phy_device *phydev)
{
	struct rtl821x_priv *priv = phydev->priv;
	struct device *dev = &phydev->mdio.dev;
	u16 val_txdly, val_rxdly;
	u16 val;
@@ -354,7 +385,15 @@ static int rtl8211f_config_init(struct phy_device *phydev)
			val_rxdly ? "enabled" : "disabled");
	}

	return 0;
	ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
			       RTL8211F_CLKOUT_EN, priv->phycr2);
	if (ret < 0) {
		dev_err(dev, "clkout configuration failed: %pe\n",
			ERR_PTR(ret));
		return ret;
	}

	return genphy_soft_reset(phydev);
}

static int rtl8211e_config_init(struct phy_device *phydev)
@@ -847,6 +886,7 @@ static struct phy_driver realtek_drvs[] = {
	}, {
		PHY_ID_MATCH_EXACT(0x001cc916),
		.name		= "RTL8211F Gigabit Ethernet",
		.probe		= rtl821x_probe,
		.config_init	= &rtl8211f_config_init,
		.read_status	= rtlgen_read_status,
		.config_intr	= &rtl8211f_config_intr,