net: fec: Support phys probed from devicetree and fixed-link
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Mon, 11 Aug 2014 15:35:33 +0000 (17:35 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 11 Aug 2014 21:41:06 +0000 (14:41 -0700)
This adds support for specifying the phy to be used with the fec in the
devicetree using the standard phy-handle property and also supports
fixed-link.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/devicetree/bindings/net/fsl-fec.txt
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c

index 6bc84adb10c0ca6f278cc30d40e0b802c12adfd8..8a2c7b55ec165b69ce1b6084fea32466f68ff483 100644 (file)
@@ -12,7 +12,14 @@ Optional properties:
   only if property "phy-reset-gpios" is available.  Missing the property
   will have the duration be 1 millisecond.  Numbers greater than 1000 are
   invalid and 1 millisecond will be used instead.
-- phy-supply: regulator that powers the Ethernet PHY.
+- phy-supply : regulator that powers the Ethernet PHY.
+- phy-handle : phandle to the PHY device connected to this device.
+- fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
+  Use instead of phy-handle.
+
+Optional subnodes:
+- mdio : specifies the mdio bus in the FEC, used as a container for phy nodes
+  according to phy.txt in the same directory
 
 Example:
 
@@ -25,3 +32,23 @@ ethernet@83fec000 {
        local-mac-address = [00 04 9F 01 1B B9];
        phy-supply = <&reg_fec_supply>;
 };
+
+Example with phy specified:
+
+ethernet@83fec000 {
+       compatible = "fsl,imx51-fec", "fsl,imx27-fec";
+       reg = <0x83fec000 0x4000>;
+       interrupts = <87>;
+       phy-mode = "mii";
+       phy-reset-gpios = <&gpio2 14 0>; /* GPIO2_14 */
+       local-mac-address = [00 04 9F 01 1B B9];
+       phy-supply = <&reg_fec_supply>;
+       phy-handle = <&ethphy>;
+       mdio {
+               ethphy: ethernet-phy@6 {
+                       compatible = "ethernet-phy-ieee802.3-c22";
+                       reg = <6>;
+                       max-speed = <100>;
+               };
+       };
+};
index bd53caf1c1eb6b735be414aecd11a4e3ff732747..9f7fa644a397a57c21bfa317b9154f1bc5b8e2ee 100644 (file)
@@ -310,6 +310,7 @@ struct fec_enet_private {
        int     mii_timeout;
        uint    phy_speed;
        phy_interface_t phy_interface;
+       struct device_node *phy_node;
        int     link;
        int     full_duplex;
        int     speed;
index 66fe1f6724996b57eba5e30b4e8b2bbc908ca38e..4f87dffcb9b26688ba7ef51145138c88b8d6ad8a 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
+#include <linux/of_mdio.h>
 #include <linux/of_net.h>
 #include <linux/regulator/consumer.h>
 #include <linux/if_vlan.h>
@@ -1648,29 +1649,37 @@ static int fec_enet_mii_probe(struct net_device *ndev)
 
        fep->phy_dev = NULL;
 
-       /* check for attached phy */
-       for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) {
-               if ((fep->mii_bus->phy_mask & (1 << phy_id)))
-                       continue;
-               if (fep->mii_bus->phy_map[phy_id] == NULL)
-                       continue;
-               if (fep->mii_bus->phy_map[phy_id]->phy_id == 0)
-                       continue;
-               if (dev_id--)
-                       continue;
-               strncpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE);
-               break;
-       }
+       if (fep->phy_node) {
+               phy_dev = of_phy_connect(ndev, fep->phy_node,
+                                        &fec_enet_adjust_link, 0,
+                                        fep->phy_interface);
+       } else {
+               /* check for attached phy */
+               for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) {
+                       if ((fep->mii_bus->phy_mask & (1 << phy_id)))
+                               continue;
+                       if (fep->mii_bus->phy_map[phy_id] == NULL)
+                               continue;
+                       if (fep->mii_bus->phy_map[phy_id]->phy_id == 0)
+                               continue;
+                       if (dev_id--)
+                               continue;
+                       strncpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE);
+                       break;
+               }
 
-       if (phy_id >= PHY_MAX_ADDR) {
-               netdev_info(ndev, "no PHY, assuming direct connection to switch\n");
-               strncpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE);
-               phy_id = 0;
+               if (phy_id >= PHY_MAX_ADDR) {
+                       netdev_info(ndev, "no PHY, assuming direct connection to switch\n");
+                       strncpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE);
+                       phy_id = 0;
+               }
+
+               snprintf(phy_name, sizeof(phy_name),
+                        PHY_ID_FMT, mdio_bus_id, phy_id);
+               phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link,
+                                     fep->phy_interface);
        }
 
-       snprintf(phy_name, sizeof(phy_name), PHY_ID_FMT, mdio_bus_id, phy_id);
-       phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link,
-                             fep->phy_interface);
        if (IS_ERR(phy_dev)) {
                netdev_err(ndev, "could not attach to PHY\n");
                return PTR_ERR(phy_dev);
@@ -1707,6 +1716,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        const struct platform_device_id *id_entry =
                                platform_get_device_id(fep->pdev);
+       struct device_node *node;
        int err = -ENXIO, i;
 
        /*
@@ -1774,7 +1784,15 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        for (i = 0; i < PHY_MAX_ADDR; i++)
                fep->mii_bus->irq[i] = PHY_POLL;
 
-       if (mdiobus_register(fep->mii_bus))
+       node = of_get_child_by_name(pdev->dev.of_node, "mdio");
+       if (node) {
+               err = of_mdiobus_register(fep->mii_bus, node);
+               of_node_put(node);
+       } else {
+               err = mdiobus_register(fep->mii_bus);
+       }
+
+       if (err)
                goto err_out_free_mdio_irq;
 
        mii_cnt++;
@@ -2527,6 +2545,7 @@ fec_probe(struct platform_device *pdev)
        struct resource *r;
        const struct of_device_id *of_id;
        static int dev_id;
+       struct device_node *np = pdev->dev.of_node, *phy_node;
 
        of_id = of_match_device(fec_dt_ids, &pdev->dev);
        if (of_id)
@@ -2566,6 +2585,18 @@ fec_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ndev);
 
+       phy_node = of_parse_phandle(np, "phy-handle", 0);
+       if (!phy_node && of_phy_is_fixed_link(np)) {
+               ret = of_phy_register_fixed_link(np);
+               if (ret < 0) {
+                       dev_err(&pdev->dev,
+                               "broken fixed-link specification\n");
+                       goto failed_phy;
+               }
+               phy_node = of_node_get(np);
+       }
+       fep->phy_node = phy_node;
+
        ret = of_get_phy_mode(pdev->dev.of_node);
        if (ret < 0) {
                pdata = dev_get_platdata(&pdev->dev);
@@ -2670,6 +2701,8 @@ failed_init:
 failed_regulator:
        fec_enet_clk_enable(ndev, false);
 failed_clk:
+failed_phy:
+       of_node_put(phy_node);
 failed_ioremap:
        free_netdev(ndev);
 
@@ -2691,6 +2724,7 @@ fec_drv_remove(struct platform_device *pdev)
        if (fep->ptp_clock)
                ptp_clock_unregister(fep->ptp_clock);
        fec_enet_clk_enable(ndev, false);
+       of_node_put(fep->phy_node);
        free_netdev(ndev);
 
        return 0;