52a6f83500bff86093e2685955301fc1f3e3c18f
[openwrt/staging/neocturne.git] /
1 From 0a4355c2b7f8ecd5e61cc262ecdbd4a2cce1ea7e Mon Sep 17 00:00:00 2001
2 From: Joakim Zhang <qiangqing.zhang@nxp.com>
3 Date: Tue, 8 Jun 2021 11:15:33 +0800
4 Subject: [PATCH] net: phy: realtek: add dt property to disable CLKOUT clock
5
6 CLKOUT is enabled by default after PHY hardware reset, this patch adds
7 "realtek,clkout-disable" property for user to disable CLKOUT clock
8 to save PHY power.
9
10 Per RTL8211F guide, a PHY reset should be issued after setting these
11 bits in PHYCR2 register. After this patch, CLKOUT clock output to be
12 disabled.
13
14 Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
15 Signed-off-by: David S. Miller <davem@davemloft.net>
16 ---
17 drivers/net/phy/realtek.c | 42 ++++++++++++++++++++++++++++++++++++++-
18 1 file changed, 41 insertions(+), 1 deletion(-)
19
20 --- a/drivers/net/phy/realtek.c
21 +++ b/drivers/net/phy/realtek.c
22 @@ -8,6 +8,7 @@
23 * Copyright (c) 2004 Freescale Semiconductor, Inc.
24 */
25 #include <linux/bitops.h>
26 +#include <linux/of.h>
27 #include <linux/phy.h>
28 #include <linux/module.h>
29 #include <linux/delay.h>
30 @@ -27,6 +28,7 @@
31 #define RTL821x_PAGE_SELECT 0x1f
32
33 #define RTL8211F_PHYCR1 0x18
34 +#define RTL8211F_PHYCR2 0x19
35 #define RTL8211F_INSR 0x1d
36
37 #define RTL8211F_TX_DELAY BIT(8)
38 @@ -40,6 +42,8 @@
39 #define RTL8211E_TX_DELAY BIT(12)
40 #define RTL8211E_RX_DELAY BIT(11)
41
42 +#define RTL8211F_CLKOUT_EN BIT(0)
43 +
44 #define RTL8201F_ISR 0x1e
45 #define RTL8201F_IER 0x13
46
47 @@ -62,6 +66,10 @@ MODULE_DESCRIPTION("Realtek PHY driver")
48 MODULE_AUTHOR("Johnson Leung");
49 MODULE_LICENSE("GPL");
50
51 +struct rtl821x_priv {
52 + u16 phycr2;
53 +};
54 +
55 static int rtl821x_read_page(struct phy_device *phydev)
56 {
57 return __phy_read(phydev, RTL821x_PAGE_SELECT);
58 @@ -72,6 +80,28 @@ static int rtl821x_write_page(struct phy
59 return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
60 }
61
62 +static int rtl821x_probe(struct phy_device *phydev)
63 +{
64 + struct device *dev = &phydev->mdio.dev;
65 + struct rtl821x_priv *priv;
66 +
67 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
68 + if (!priv)
69 + return -ENOMEM;
70 +
71 + priv->phycr2 = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2);
72 + if (priv->phycr2 < 0)
73 + return priv->phycr2;
74 +
75 + priv->phycr2 &= RTL8211F_CLKOUT_EN;
76 + if (of_property_read_bool(dev->of_node, "realtek,clkout-disable"))
77 + priv->phycr2 &= ~RTL8211F_CLKOUT_EN;
78 +
79 + phydev->priv = priv;
80 +
81 + return 0;
82 +}
83 +
84 static int rtl8201_ack_interrupt(struct phy_device *phydev)
85 {
86 int err;
87 @@ -180,6 +210,7 @@ static int rtl8211c_config_init(struct p
88
89 static int rtl8211f_config_init(struct phy_device *phydev)
90 {
91 + struct rtl821x_priv *priv = phydev->priv;
92 struct device *dev = &phydev->mdio.dev;
93 u16 val_txdly, val_rxdly;
94 u16 val;
95 @@ -243,7 +274,15 @@ static int rtl8211f_config_init(struct p
96 val_rxdly ? "enabled" : "disabled");
97 }
98
99 - return 0;
100 + ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
101 + RTL8211F_CLKOUT_EN, priv->phycr2);
102 + if (ret < 0) {
103 + dev_err(dev, "clkout configuration failed: %pe\n",
104 + ERR_PTR(ret));
105 + return ret;
106 + }
107 +
108 + return genphy_soft_reset(phydev);
109 }
110
111 static int rtl821x_resume(struct phy_device *phydev)
112 @@ -633,6 +672,7 @@ static struct phy_driver realtek_drvs[]
113 }, {
114 PHY_ID_MATCH_EXACT(0x001cc916),
115 .name = "RTL8211F Gigabit Ethernet",
116 + .probe = rtl821x_probe,
117 .config_init = &rtl8211f_config_init,
118 .ack_interrupt = &rtl8211f_ack_interrupt,
119 .config_intr = &rtl8211f_config_intr,