Skip to content

Commit

Permalink
net: ethoc: set up MII management bus clock
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Max Filippov authored and David S. Miller committed Feb 5, 2014
1 parent 445a48c commit a13aff0
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
32 changes: 30 additions & 2 deletions drivers/net/ethernet/ethoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
#include <linux/clk.h>
#include <linux/crc32.h>
#include <linux/interrupt.h>
#include <linux/io.h>
Expand Down Expand Up @@ -219,6 +220,7 @@ struct ethoc {

struct phy_device *phy;
struct mii_bus *mdio;
struct clk *clk;
s8 phy_id;
};

Expand Down Expand Up @@ -1021,6 +1023,8 @@ static int ethoc_probe(struct platform_device *pdev)
int num_bd;
int ret = 0;
bool random_mac = false;
struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev);
u32 eth_clkfreq = pdata ? pdata->eth_clkfreq : 0;

/* allocate networking device */
netdev = alloc_etherdev(sizeof(struct ethoc));
Expand Down Expand Up @@ -1135,8 +1139,7 @@ static int ethoc_probe(struct platform_device *pdev)
}

/* Allow the platform setup code to pass in a MAC address. */
if (dev_get_platdata(&pdev->dev)) {
struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev);
if (pdata) {
memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN);
priv->phy_id = pdata->phy_id;
} else {
Expand Down Expand Up @@ -1174,6 +1177,27 @@ static int ethoc_probe(struct platform_device *pdev)
if (random_mac)
netdev->addr_assign_type = NET_ADDR_RANDOM;

/* Allow the platform setup code to adjust MII management bus clock. */
if (!eth_clkfreq) {
struct clk *clk = devm_clk_get(&pdev->dev, NULL);

if (!IS_ERR(clk)) {
priv->clk = clk;
clk_prepare_enable(clk);
eth_clkfreq = clk_get_rate(clk);
}
}
if (eth_clkfreq) {
u32 clkdiv = MIIMODER_CLKDIV(eth_clkfreq / 2500000 + 1);

if (!clkdiv)
clkdiv = 2;
dev_dbg(&pdev->dev, "setting MII clkdiv to %u\n", clkdiv);
ethoc_write(priv, MIIMODER,
(ethoc_read(priv, MIIMODER) & MIIMODER_NOPRE) |
clkdiv);
}

/* register MII bus */
priv->mdio = mdiobus_alloc();
if (!priv->mdio) {
Expand Down Expand Up @@ -1239,6 +1263,8 @@ static int ethoc_probe(struct platform_device *pdev)
kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
free:
if (priv->clk)
clk_disable_unprepare(priv->clk);
free_netdev(netdev);
out:
return ret;
Expand All @@ -1263,6 +1289,8 @@ static int ethoc_remove(struct platform_device *pdev)
kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
}
if (priv->clk)
clk_disable_unprepare(priv->clk);
unregister_netdev(netdev);
free_netdev(netdev);
}
Expand Down
1 change: 1 addition & 0 deletions include/net/ethoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
struct ethoc_platform_data {
u8 hwaddr[IFHWADDRLEN];
s8 phy_id;
u32 eth_clkfreq;
};

#endif /* !LINUX_NET_ETHOC_H */
Expand Down

0 comments on commit a13aff0

Please sign in to comment.