diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2011-06-24 14:04:35 -0400 |
---|---|---|
committer | Shawn Guo <shawn.guo@linaro.org> | 2011-07-26 21:31:08 -0400 |
commit | ca2cc333920690db87a03c2ee3bd6f43adb3e7fb (patch) | |
tree | d8a01ac861b42adbc160021f0343f4226fd01883 /drivers/net | |
parent | 4157ef1b8779b34581ee8b9dc8f7f95188008eca (diff) |
net/fec: add device tree probe support
It adds device tree probe support for fec driver.
Signed-off-by: Jason Liu <jason.hui@linaro.org>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/fec.c | 103 |
1 files changed, 98 insertions, 5 deletions
diff --git a/drivers/net/fec.c b/drivers/net/fec.c index ed137bbbcf61..e8266ccf818a 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c | |||
@@ -44,6 +44,10 @@ | |||
44 | #include <linux/platform_device.h> | 44 | #include <linux/platform_device.h> |
45 | #include <linux/phy.h> | 45 | #include <linux/phy.h> |
46 | #include <linux/fec.h> | 46 | #include <linux/fec.h> |
47 | #include <linux/of.h> | ||
48 | #include <linux/of_device.h> | ||
49 | #include <linux/of_gpio.h> | ||
50 | #include <linux/of_net.h> | ||
47 | 51 | ||
48 | #include <asm/cacheflush.h> | 52 | #include <asm/cacheflush.h> |
49 | 53 | ||
@@ -89,6 +93,20 @@ static struct platform_device_id fec_devtype[] = { | |||
89 | }; | 93 | }; |
90 | MODULE_DEVICE_TABLE(platform, fec_devtype); | 94 | MODULE_DEVICE_TABLE(platform, fec_devtype); |
91 | 95 | ||
96 | enum imx_fec_type { | ||
97 | IMX25_FEC = 1, /* runs on i.mx25/50/53 */ | ||
98 | IMX27_FEC, /* runs on i.mx27/35/51 */ | ||
99 | IMX28_FEC, | ||
100 | }; | ||
101 | |||
102 | static const struct of_device_id fec_dt_ids[] = { | ||
103 | { .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], }, | ||
104 | { .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], }, | ||
105 | { .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], }, | ||
106 | { /* sentinel */ } | ||
107 | }; | ||
108 | MODULE_DEVICE_TABLE(of, fec_dt_ids); | ||
109 | |||
92 | static unsigned char macaddr[ETH_ALEN]; | 110 | static unsigned char macaddr[ETH_ALEN]; |
93 | module_param_array(macaddr, byte, NULL, 0); | 111 | module_param_array(macaddr, byte, NULL, 0); |
94 | MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); | 112 | MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); |
@@ -748,8 +766,22 @@ static void __inline__ fec_get_mac(struct net_device *ndev) | |||
748 | */ | 766 | */ |
749 | iap = macaddr; | 767 | iap = macaddr; |
750 | 768 | ||
769 | #ifdef CONFIG_OF | ||
770 | /* | ||
771 | * 2) from device tree data | ||
772 | */ | ||
773 | if (!is_valid_ether_addr(iap)) { | ||
774 | struct device_node *np = fep->pdev->dev.of_node; | ||
775 | if (np) { | ||
776 | const char *mac = of_get_mac_address(np); | ||
777 | if (mac) | ||
778 | iap = (unsigned char *) mac; | ||
779 | } | ||
780 | } | ||
781 | #endif | ||
782 | |||
751 | /* | 783 | /* |
752 | * 2) from flash or fuse (via platform data) | 784 | * 3) from flash or fuse (via platform data) |
753 | */ | 785 | */ |
754 | if (!is_valid_ether_addr(iap)) { | 786 | if (!is_valid_ether_addr(iap)) { |
755 | #ifdef CONFIG_M5272 | 787 | #ifdef CONFIG_M5272 |
@@ -762,7 +794,7 @@ static void __inline__ fec_get_mac(struct net_device *ndev) | |||
762 | } | 794 | } |
763 | 795 | ||
764 | /* | 796 | /* |
765 | * 3) FEC mac registers set by bootloader | 797 | * 4) FEC mac registers set by bootloader |
766 | */ | 798 | */ |
767 | if (!is_valid_ether_addr(iap)) { | 799 | if (!is_valid_ether_addr(iap)) { |
768 | *((unsigned long *) &tmpaddr[0]) = | 800 | *((unsigned long *) &tmpaddr[0]) = |
@@ -1368,6 +1400,52 @@ static int fec_enet_init(struct net_device *ndev) | |||
1368 | return 0; | 1400 | return 0; |
1369 | } | 1401 | } |
1370 | 1402 | ||
1403 | #ifdef CONFIG_OF | ||
1404 | static int __devinit fec_get_phy_mode_dt(struct platform_device *pdev) | ||
1405 | { | ||
1406 | struct device_node *np = pdev->dev.of_node; | ||
1407 | |||
1408 | if (np) | ||
1409 | return of_get_phy_mode(np); | ||
1410 | |||
1411 | return -ENODEV; | ||
1412 | } | ||
1413 | |||
1414 | static int __devinit fec_reset_phy(struct platform_device *pdev) | ||
1415 | { | ||
1416 | int err, phy_reset; | ||
1417 | struct device_node *np = pdev->dev.of_node; | ||
1418 | |||
1419 | if (!np) | ||
1420 | return -ENODEV; | ||
1421 | |||
1422 | phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0); | ||
1423 | err = gpio_request_one(phy_reset, GPIOF_OUT_INIT_LOW, "phy-reset"); | ||
1424 | if (err) { | ||
1425 | pr_warn("FEC: failed to get gpio phy-reset: %d\n", err); | ||
1426 | return err; | ||
1427 | } | ||
1428 | msleep(1); | ||
1429 | gpio_set_value(phy_reset, 1); | ||
1430 | |||
1431 | return 0; | ||
1432 | } | ||
1433 | #else /* CONFIG_OF */ | ||
1434 | static inline int fec_get_phy_mode_dt(struct platform_device *pdev) | ||
1435 | { | ||
1436 | return -ENODEV; | ||
1437 | } | ||
1438 | |||
1439 | static inline int fec_reset_phy(struct platform_device *pdev) | ||
1440 | { | ||
1441 | /* | ||
1442 | * In case of platform probe, the reset has been done | ||
1443 | * by machine code. | ||
1444 | */ | ||
1445 | return 0; | ||
1446 | } | ||
1447 | #endif /* CONFIG_OF */ | ||
1448 | |||
1371 | static int __devinit | 1449 | static int __devinit |
1372 | fec_probe(struct platform_device *pdev) | 1450 | fec_probe(struct platform_device *pdev) |
1373 | { | 1451 | { |
@@ -1376,6 +1454,11 @@ fec_probe(struct platform_device *pdev) | |||
1376 | struct net_device *ndev; | 1454 | struct net_device *ndev; |
1377 | int i, irq, ret = 0; | 1455 | int i, irq, ret = 0; |
1378 | struct resource *r; | 1456 | struct resource *r; |
1457 | const struct of_device_id *of_id; | ||
1458 | |||
1459 | of_id = of_match_device(fec_dt_ids, &pdev->dev); | ||
1460 | if (of_id) | ||
1461 | pdev->id_entry = of_id->data; | ||
1379 | 1462 | ||
1380 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1463 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1381 | if (!r) | 1464 | if (!r) |
@@ -1407,9 +1490,18 @@ fec_probe(struct platform_device *pdev) | |||
1407 | 1490 | ||
1408 | platform_set_drvdata(pdev, ndev); | 1491 | platform_set_drvdata(pdev, ndev); |
1409 | 1492 | ||
1410 | pdata = pdev->dev.platform_data; | 1493 | ret = fec_get_phy_mode_dt(pdev); |
1411 | if (pdata) | 1494 | if (ret < 0) { |
1412 | fep->phy_interface = pdata->phy; | 1495 | pdata = pdev->dev.platform_data; |
1496 | if (pdata) | ||
1497 | fep->phy_interface = pdata->phy; | ||
1498 | else | ||
1499 | fep->phy_interface = PHY_INTERFACE_MODE_MII; | ||
1500 | } else { | ||
1501 | fep->phy_interface = ret; | ||
1502 | } | ||
1503 | |||
1504 | fec_reset_phy(pdev); | ||
1413 | 1505 | ||
1414 | /* This device has up to three irqs on some platforms */ | 1506 | /* This device has up to three irqs on some platforms */ |
1415 | for (i = 0; i < 3; i++) { | 1507 | for (i = 0; i < 3; i++) { |
@@ -1544,6 +1636,7 @@ static struct platform_driver fec_driver = { | |||
1544 | #ifdef CONFIG_PM | 1636 | #ifdef CONFIG_PM |
1545 | .pm = &fec_pm_ops, | 1637 | .pm = &fec_pm_ops, |
1546 | #endif | 1638 | #endif |
1639 | .of_match_table = fec_dt_ids, | ||
1547 | }, | 1640 | }, |
1548 | .id_table = fec_devtype, | 1641 | .id_table = fec_devtype, |
1549 | .probe = fec_probe, | 1642 | .probe = fec_probe, |