diff options
author | Heiko Stübner <heiko@sntech.de> | 2014-04-25 04:06:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-04-27 19:46:17 -0400 |
commit | 88154c96ee2dab84ae78ad41562b4a3a23d83788 (patch) | |
tree | 8b5892907536e3d31a325ce0587e3e1a6e416535 | |
parent | 796bec1efbbd3be98d84cd68279c6ec03a4782f9 (diff) |
arc_emac: add clock handling
This adds ability for the arc_emac to really handle its supplying clock.
To get the needed clock-frequency either a real clock or the previous
clock-frequency property must be provided.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Max Schwarz <max.schwarz@online.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/devicetree/bindings/net/arc_emac.txt | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/arc/emac.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/arc/emac_main.c | 46 |
3 files changed, 47 insertions, 13 deletions
diff --git a/Documentation/devicetree/bindings/net/arc_emac.txt b/Documentation/devicetree/bindings/net/arc_emac.txt index 7fbb027218a1..a1d71eb43b20 100644 --- a/Documentation/devicetree/bindings/net/arc_emac.txt +++ b/Documentation/devicetree/bindings/net/arc_emac.txt | |||
@@ -4,11 +4,15 @@ Required properties: | |||
4 | - compatible: Should be "snps,arc-emac" | 4 | - compatible: Should be "snps,arc-emac" |
5 | - reg: Address and length of the register set for the device | 5 | - reg: Address and length of the register set for the device |
6 | - interrupts: Should contain the EMAC interrupts | 6 | - interrupts: Should contain the EMAC interrupts |
7 | - clock-frequency: CPU frequency. It is needed to calculate and set polling | ||
8 | period of EMAC. | ||
9 | - max-speed: see ethernet.txt file in the same directory. | 7 | - max-speed: see ethernet.txt file in the same directory. |
10 | - phy: see ethernet.txt file in the same directory. | 8 | - phy: see ethernet.txt file in the same directory. |
11 | 9 | ||
10 | Clock handling: | ||
11 | The clock frequency is needed to calculate and set polling period of EMAC. | ||
12 | It must be provided by one of: | ||
13 | - clock-frequency: CPU frequency. | ||
14 | - clocks: reference to the clock supplying the EMAC. | ||
15 | |||
12 | Child nodes of the driver are the individual PHY devices connected to the | 16 | Child nodes of the driver are the individual PHY devices connected to the |
13 | MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus. | 17 | MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus. |
14 | 18 | ||
@@ -19,7 +23,11 @@ Examples: | |||
19 | reg = <0xc0fc2000 0x3c>; | 23 | reg = <0xc0fc2000 0x3c>; |
20 | interrupts = <6>; | 24 | interrupts = <6>; |
21 | mac-address = [ 00 11 22 33 44 55 ]; | 25 | mac-address = [ 00 11 22 33 44 55 ]; |
26 | |||
22 | clock-frequency = <80000000>; | 27 | clock-frequency = <80000000>; |
28 | /* or */ | ||
29 | clocks = <&emac_clock>; | ||
30 | |||
23 | max-speed = <100>; | 31 | max-speed = <100>; |
24 | phy = <&phy0>; | 32 | phy = <&phy0>; |
25 | 33 | ||
diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h index 928fac6dd10a..53f85bf71526 100644 --- a/drivers/net/ethernet/arc/emac.h +++ b/drivers/net/ethernet/arc/emac.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/dma-mapping.h> | 11 | #include <linux/dma-mapping.h> |
12 | #include <linux/netdevice.h> | 12 | #include <linux/netdevice.h> |
13 | #include <linux/phy.h> | 13 | #include <linux/phy.h> |
14 | #include <linux/clk.h> | ||
14 | 15 | ||
15 | /* STATUS and ENABLE Register bit masks */ | 16 | /* STATUS and ENABLE Register bit masks */ |
16 | #define TXINT_MASK (1<<0) /* Transmit interrupt */ | 17 | #define TXINT_MASK (1<<0) /* Transmit interrupt */ |
@@ -131,6 +132,7 @@ struct arc_emac_priv { | |||
131 | struct mii_bus *bus; | 132 | struct mii_bus *bus; |
132 | 133 | ||
133 | void __iomem *regs; | 134 | void __iomem *regs; |
135 | struct clk *clk; | ||
134 | 136 | ||
135 | struct napi_struct napi; | 137 | struct napi_struct napi; |
136 | struct net_device_stats stats; | 138 | struct net_device_stats stats; |
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index 9747ddaf6ad2..d647a7d115ac 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c | |||
@@ -649,13 +649,6 @@ static int arc_emac_probe(struct platform_device *pdev) | |||
649 | return -ENODEV; | 649 | return -ENODEV; |
650 | } | 650 | } |
651 | 651 | ||
652 | /* Get CPU clock frequency from device tree */ | ||
653 | if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", | ||
654 | &clock_frequency)) { | ||
655 | dev_err(&pdev->dev, "failed to retrieve <clock-frequency> from device tree\n"); | ||
656 | return -EINVAL; | ||
657 | } | ||
658 | |||
659 | /* Get IRQ from device tree */ | 652 | /* Get IRQ from device tree */ |
660 | irq = irq_of_parse_and_map(pdev->dev.of_node, 0); | 653 | irq = irq_of_parse_and_map(pdev->dev.of_node, 0); |
661 | if (!irq) { | 654 | if (!irq) { |
@@ -687,13 +680,32 @@ static int arc_emac_probe(struct platform_device *pdev) | |||
687 | } | 680 | } |
688 | dev_dbg(&pdev->dev, "Registers base address is 0x%p\n", priv->regs); | 681 | dev_dbg(&pdev->dev, "Registers base address is 0x%p\n", priv->regs); |
689 | 682 | ||
683 | priv->clk = of_clk_get(pdev->dev.of_node, 0); | ||
684 | if (IS_ERR(priv->clk)) { | ||
685 | /* Get CPU clock frequency from device tree */ | ||
686 | if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", | ||
687 | &clock_frequency)) { | ||
688 | dev_err(&pdev->dev, "failed to retrieve <clock-frequency> from device tree\n"); | ||
689 | err = -EINVAL; | ||
690 | goto out_netdev; | ||
691 | } | ||
692 | } else { | ||
693 | err = clk_prepare_enable(priv->clk); | ||
694 | if (err) { | ||
695 | dev_err(&pdev->dev, "failed to enable clock\n"); | ||
696 | goto out_clkget; | ||
697 | } | ||
698 | |||
699 | clock_frequency = clk_get_rate(priv->clk); | ||
700 | } | ||
701 | |||
690 | id = arc_reg_get(priv, R_ID); | 702 | id = arc_reg_get(priv, R_ID); |
691 | 703 | ||
692 | /* Check for EMAC revision 5 or 7, magic number */ | 704 | /* Check for EMAC revision 5 or 7, magic number */ |
693 | if (!(id == 0x0005fd02 || id == 0x0007fd02)) { | 705 | if (!(id == 0x0005fd02 || id == 0x0007fd02)) { |
694 | dev_err(&pdev->dev, "ARC EMAC not detected, id=0x%x\n", id); | 706 | dev_err(&pdev->dev, "ARC EMAC not detected, id=0x%x\n", id); |
695 | err = -ENODEV; | 707 | err = -ENODEV; |
696 | goto out_netdev; | 708 | goto out_clken; |
697 | } | 709 | } |
698 | dev_info(&pdev->dev, "ARC EMAC detected with id: 0x%x\n", id); | 710 | dev_info(&pdev->dev, "ARC EMAC detected with id: 0x%x\n", id); |
699 | 711 | ||
@@ -708,7 +720,7 @@ static int arc_emac_probe(struct platform_device *pdev) | |||
708 | ndev->name, ndev); | 720 | ndev->name, ndev); |
709 | if (err) { | 721 | if (err) { |
710 | dev_err(&pdev->dev, "could not allocate IRQ\n"); | 722 | dev_err(&pdev->dev, "could not allocate IRQ\n"); |
711 | goto out_netdev; | 723 | goto out_clken; |
712 | } | 724 | } |
713 | 725 | ||
714 | /* Get MAC address from device tree */ | 726 | /* Get MAC address from device tree */ |
@@ -729,7 +741,7 @@ static int arc_emac_probe(struct platform_device *pdev) | |||
729 | if (!priv->rxbd) { | 741 | if (!priv->rxbd) { |
730 | dev_err(&pdev->dev, "failed to allocate data buffers\n"); | 742 | dev_err(&pdev->dev, "failed to allocate data buffers\n"); |
731 | err = -ENOMEM; | 743 | err = -ENOMEM; |
732 | goto out_netdev; | 744 | goto out_clken; |
733 | } | 745 | } |
734 | 746 | ||
735 | priv->txbd = priv->rxbd + RX_BD_NUM; | 747 | priv->txbd = priv->rxbd + RX_BD_NUM; |
@@ -741,7 +753,7 @@ static int arc_emac_probe(struct platform_device *pdev) | |||
741 | err = arc_mdio_probe(pdev, priv); | 753 | err = arc_mdio_probe(pdev, priv); |
742 | if (err) { | 754 | if (err) { |
743 | dev_err(&pdev->dev, "failed to probe MII bus\n"); | 755 | dev_err(&pdev->dev, "failed to probe MII bus\n"); |
744 | goto out_netdev; | 756 | goto out_clken; |
745 | } | 757 | } |
746 | 758 | ||
747 | priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0, | 759 | priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0, |
@@ -771,6 +783,12 @@ out_netif_api: | |||
771 | priv->phy_dev = NULL; | 783 | priv->phy_dev = NULL; |
772 | out_mdio: | 784 | out_mdio: |
773 | arc_mdio_remove(priv); | 785 | arc_mdio_remove(priv); |
786 | out_clken: | ||
787 | if (!IS_ERR(priv->clk)) | ||
788 | clk_disable_unprepare(priv->clk); | ||
789 | out_clkget: | ||
790 | if (!IS_ERR(priv->clk)) | ||
791 | clk_put(priv->clk); | ||
774 | out_netdev: | 792 | out_netdev: |
775 | free_netdev(ndev); | 793 | free_netdev(ndev); |
776 | return err; | 794 | return err; |
@@ -786,6 +804,12 @@ static int arc_emac_remove(struct platform_device *pdev) | |||
786 | arc_mdio_remove(priv); | 804 | arc_mdio_remove(priv); |
787 | unregister_netdev(ndev); | 805 | unregister_netdev(ndev); |
788 | netif_napi_del(&priv->napi); | 806 | netif_napi_del(&priv->napi); |
807 | |||
808 | if (!IS_ERR(priv->clk)) { | ||
809 | clk_disable_unprepare(priv->clk); | ||
810 | clk_put(priv->clk); | ||
811 | } | ||
812 | |||
789 | free_netdev(ndev); | 813 | free_netdev(ndev); |
790 | 814 | ||
791 | return 0; | 815 | return 0; |