aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2014-02-03 18:33:10 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-04 23:19:51 -0500
commita13aff0641a92dc0b95136e32526e2ce81ffc4ef (patch)
tree7b99892ca02dd681f538e6de9f99ca7dcf225931
parent445a48cc9df90775d6479ef4c73d3a90184af4ed (diff)
net: ethoc: set up MII management bus clock
MII management bus clock is derived from the MAC clock by dividing it by MIIMODER register CLKDIV field value. This value may need to be set up in case it is undefined or its default value is too high (and communication with PHY is too slow) or too low (and communication with PHY is impossible). The value of CLKDIV is not specified directly, but is derived from the MAC clock for the default MII management bus frequency of 2.5MHz. The MAC clock may be specified in the platform data, or in the 'clocks' device tree attribute. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/ethoc.c32
-rw-r--r--include/net/ethoc.h1
2 files changed, 31 insertions, 2 deletions
diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c
index 0a8533c0c01a..55e0fa03dc90 100644
--- a/drivers/net/ethernet/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -13,6 +13,7 @@
13 13
14#include <linux/dma-mapping.h> 14#include <linux/dma-mapping.h>
15#include <linux/etherdevice.h> 15#include <linux/etherdevice.h>
16#include <linux/clk.h>
16#include <linux/crc32.h> 17#include <linux/crc32.h>
17#include <linux/interrupt.h> 18#include <linux/interrupt.h>
18#include <linux/io.h> 19#include <linux/io.h>
@@ -219,6 +220,7 @@ struct ethoc {
219 220
220 struct phy_device *phy; 221 struct phy_device *phy;
221 struct mii_bus *mdio; 222 struct mii_bus *mdio;
223 struct clk *clk;
222 s8 phy_id; 224 s8 phy_id;
223}; 225};
224 226
@@ -1021,6 +1023,8 @@ static int ethoc_probe(struct platform_device *pdev)
1021 int num_bd; 1023 int num_bd;
1022 int ret = 0; 1024 int ret = 0;
1023 bool random_mac = false; 1025 bool random_mac = false;
1026 struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev);
1027 u32 eth_clkfreq = pdata ? pdata->eth_clkfreq : 0;
1024 1028
1025 /* allocate networking device */ 1029 /* allocate networking device */
1026 netdev = alloc_etherdev(sizeof(struct ethoc)); 1030 netdev = alloc_etherdev(sizeof(struct ethoc));
@@ -1135,8 +1139,7 @@ static int ethoc_probe(struct platform_device *pdev)
1135 } 1139 }
1136 1140
1137 /* Allow the platform setup code to pass in a MAC address. */ 1141 /* Allow the platform setup code to pass in a MAC address. */
1138 if (dev_get_platdata(&pdev->dev)) { 1142 if (pdata) {
1139 struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev);
1140 memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN); 1143 memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN);
1141 priv->phy_id = pdata->phy_id; 1144 priv->phy_id = pdata->phy_id;
1142 } else { 1145 } else {
@@ -1174,6 +1177,27 @@ static int ethoc_probe(struct platform_device *pdev)
1174 if (random_mac) 1177 if (random_mac)
1175 netdev->addr_assign_type = NET_ADDR_RANDOM; 1178 netdev->addr_assign_type = NET_ADDR_RANDOM;
1176 1179
1180 /* Allow the platform setup code to adjust MII management bus clock. */
1181 if (!eth_clkfreq) {
1182 struct clk *clk = devm_clk_get(&pdev->dev, NULL);
1183
1184 if (!IS_ERR(clk)) {
1185 priv->clk = clk;
1186 clk_prepare_enable(clk);
1187 eth_clkfreq = clk_get_rate(clk);
1188 }
1189 }
1190 if (eth_clkfreq) {
1191 u32 clkdiv = MIIMODER_CLKDIV(eth_clkfreq / 2500000 + 1);
1192
1193 if (!clkdiv)
1194 clkdiv = 2;
1195 dev_dbg(&pdev->dev, "setting MII clkdiv to %u\n", clkdiv);
1196 ethoc_write(priv, MIIMODER,
1197 (ethoc_read(priv, MIIMODER) & MIIMODER_NOPRE) |
1198 clkdiv);
1199 }
1200
1177 /* register MII bus */ 1201 /* register MII bus */
1178 priv->mdio = mdiobus_alloc(); 1202 priv->mdio = mdiobus_alloc();
1179 if (!priv->mdio) { 1203 if (!priv->mdio) {
@@ -1239,6 +1263,8 @@ free_mdio:
1239 kfree(priv->mdio->irq); 1263 kfree(priv->mdio->irq);
1240 mdiobus_free(priv->mdio); 1264 mdiobus_free(priv->mdio);
1241free: 1265free:
1266 if (priv->clk)
1267 clk_disable_unprepare(priv->clk);
1242 free_netdev(netdev); 1268 free_netdev(netdev);
1243out: 1269out:
1244 return ret; 1270 return ret;
@@ -1263,6 +1289,8 @@ static int ethoc_remove(struct platform_device *pdev)
1263 kfree(priv->mdio->irq); 1289 kfree(priv->mdio->irq);
1264 mdiobus_free(priv->mdio); 1290 mdiobus_free(priv->mdio);
1265 } 1291 }
1292 if (priv->clk)
1293 clk_disable_unprepare(priv->clk);
1266 unregister_netdev(netdev); 1294 unregister_netdev(netdev);
1267 free_netdev(netdev); 1295 free_netdev(netdev);
1268 } 1296 }
diff --git a/include/net/ethoc.h b/include/net/ethoc.h
index 96f3789b27bc..2a2d6bb34eb8 100644
--- a/include/net/ethoc.h
+++ b/include/net/ethoc.h
@@ -16,6 +16,7 @@
16struct ethoc_platform_data { 16struct ethoc_platform_data {
17 u8 hwaddr[IFHWADDRLEN]; 17 u8 hwaddr[IFHWADDRLEN];
18 s8 phy_id; 18 s8 phy_id;
19 u32 eth_clkfreq;
19}; 20};
20 21
21#endif /* !LINUX_NET_ETHOC_H */ 22#endif /* !LINUX_NET_ETHOC_H */