aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Perier <romain.perier@gmail.com>2014-08-26 09:14:51 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-27 19:40:26 -0400
commit23d2d9a630b98a554cc328c6b69c56fd285e0129 (patch)
tree265d7e4ceba509f54b494db5cdeb8d000f811d97
parent93e91b3dda17be19ecf52de2400a02c6469decfa (diff)
ethernet: arc: Add support for specific SoC layer device tree bindings
Some platforms have special bank registers which might be used to select the correct clock or the right mode for Media Indepent Interface controllers. Sometimes, it is also required to activate vcc regulators in the right order to supply the ethernet controller at the right time. This patch is an architecture refactoring of the arc-emac device driver. It adds a new software design which allows to add specific platform glue layer. Each platform has now its own module which performs custom initialization and remove for the target and then calls to the core driver. Signed-off-by: Romain Perier <romain.perier@gmail.com> Reviewed-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/arc/Kconfig8
-rw-r--r--drivers/net/ethernet/arc/Makefile3
-rw-r--r--drivers/net/ethernet/arc/emac.h4
-rw-r--r--drivers/net/ethernet/arc/emac_arc.c95
-rw-r--r--drivers/net/ethernet/arc/emac_main.c80
5 files changed, 129 insertions, 61 deletions
diff --git a/drivers/net/ethernet/arc/Kconfig b/drivers/net/ethernet/arc/Kconfig
index 514c57fd26f1..89e04fde5f4e 100644
--- a/drivers/net/ethernet/arc/Kconfig
+++ b/drivers/net/ethernet/arc/Kconfig
@@ -17,10 +17,14 @@ config NET_VENDOR_ARC
17 17
18if NET_VENDOR_ARC 18if NET_VENDOR_ARC
19 19
20config ARC_EMAC 20config ARC_EMAC_CORE
21 tristate "ARC EMAC support" 21 tristate
22 select MII 22 select MII
23 select PHYLIB 23 select PHYLIB
24
25config ARC_EMAC
26 tristate "ARC EMAC support"
27 select ARC_EMAC_CORE
24 depends on OF_IRQ 28 depends on OF_IRQ
25 depends on OF_NET 29 depends on OF_NET
26 ---help--- 30 ---help---
diff --git a/drivers/net/ethernet/arc/Makefile b/drivers/net/ethernet/arc/Makefile
index 00c8657637d5..241bb809f351 100644
--- a/drivers/net/ethernet/arc/Makefile
+++ b/drivers/net/ethernet/arc/Makefile
@@ -3,4 +3,5 @@
3# 3#
4 4
5arc_emac-objs := emac_main.o emac_mdio.o 5arc_emac-objs := emac_main.o emac_mdio.o
6obj-$(CONFIG_ARC_EMAC) += arc_emac.o 6obj-$(CONFIG_ARC_EMAC_CORE) += arc_emac.o
7obj-$(CONFIG_ARC_EMAC) += emac_arc.o
diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h
index 8011445adcba..eb2ba67ac711 100644
--- a/drivers/net/ethernet/arc/emac.h
+++ b/drivers/net/ethernet/arc/emac.h
@@ -124,6 +124,8 @@ struct buffer_state {
124 */ 124 */
125struct arc_emac_priv { 125struct arc_emac_priv {
126 /* Devices */ 126 /* Devices */
127 const char *drv_name;
128 const char *drv_version;
127 struct device *dev; 129 struct device *dev;
128 struct phy_device *phy_dev; 130 struct phy_device *phy_dev;
129 struct mii_bus *bus; 131 struct mii_bus *bus;
@@ -206,5 +208,7 @@ static inline void arc_reg_clr(struct arc_emac_priv *priv, int reg, int mask)
206 208
207int arc_mdio_probe(struct arc_emac_priv *priv); 209int arc_mdio_probe(struct arc_emac_priv *priv);
208int arc_mdio_remove(struct arc_emac_priv *priv); 210int arc_mdio_remove(struct arc_emac_priv *priv);
211int arc_emac_probe(struct net_device *ndev, int interface);
212int arc_emac_remove(struct net_device *ndev);
209 213
210#endif /* ARC_EMAC_H */ 214#endif /* ARC_EMAC_H */
diff --git a/drivers/net/ethernet/arc/emac_arc.c b/drivers/net/ethernet/arc/emac_arc.c
new file mode 100644
index 000000000000..f9cb99bfb511
--- /dev/null
+++ b/drivers/net/ethernet/arc/emac_arc.c
@@ -0,0 +1,95 @@
1/**
2 * emac_arc.c - ARC EMAC specific glue layer
3 *
4 * Copyright (C) 2014 Romain Perier
5 *
6 * Romain Perier <romain.perier@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/etherdevice.h>
20#include <linux/module.h>
21#include <linux/of_net.h>
22#include <linux/platform_device.h>
23
24#include "emac.h"
25
26#define DRV_NAME "emac_arc"
27#define DRV_VERSION "1.0"
28
29static int emac_arc_probe(struct platform_device *pdev)
30{
31 struct device *dev = &pdev->dev;
32 struct net_device *ndev;
33 struct arc_emac_priv *priv;
34 int interface, err;
35
36 if (!dev->of_node)
37 return -ENODEV;
38
39 ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
40 if (!ndev)
41 return -ENOMEM;
42 platform_set_drvdata(pdev, ndev);
43 SET_NETDEV_DEV(ndev, dev);
44
45 priv = netdev_priv(ndev);
46 priv->drv_name = DRV_NAME;
47 priv->drv_version = DRV_VERSION;
48
49 interface = of_get_phy_mode(dev->of_node);
50 if (interface < 0)
51 interface = PHY_INTERFACE_MODE_MII;
52
53 priv->clk = devm_clk_get(dev, "hclk");
54 if (IS_ERR(priv->clk)) {
55 dev_err(dev, "failed to retrieve host clock from device tree\n");
56 err = -EINVAL;
57 goto out_netdev;
58 }
59
60 err = arc_emac_probe(ndev, interface);
61out_netdev:
62 if (err)
63 free_netdev(ndev);
64 return err;
65}
66
67static int emac_arc_remove(struct platform_device *pdev)
68{
69 struct net_device *ndev = platform_get_drvdata(pdev);
70 int err;
71
72 err = arc_emac_remove(ndev);
73 free_netdev(ndev);
74 return err;
75}
76
77static const struct of_device_id emac_arc_dt_ids[] = {
78 { .compatible = "snps,arc-emac" },
79 { /* Sentinel */ }
80};
81
82static struct platform_driver emac_arc_driver = {
83 .probe = emac_arc_probe,
84 .remove = emac_arc_remove,
85 .driver = {
86 .name = DRV_NAME,
87 .of_match_table = emac_arc_dt_ids,
88 },
89};
90
91module_platform_driver(emac_arc_driver);
92
93MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
94MODULE_DESCRIPTION("ARC EMAC platform driver");
95MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index bbc3157bed92..b35c69e1b147 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -26,8 +26,6 @@
26 26
27#include "emac.h" 27#include "emac.h"
28 28
29#define DRV_NAME "arc_emac"
30#define DRV_VERSION "1.0"
31 29
32/** 30/**
33 * arc_emac_adjust_link - Adjust the PHY link duplex. 31 * arc_emac_adjust_link - Adjust the PHY link duplex.
@@ -120,8 +118,10 @@ static int arc_emac_set_settings(struct net_device *ndev,
120static void arc_emac_get_drvinfo(struct net_device *ndev, 118static void arc_emac_get_drvinfo(struct net_device *ndev,
121 struct ethtool_drvinfo *info) 119 struct ethtool_drvinfo *info)
122{ 120{
123 strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 121 struct arc_emac_priv *priv = netdev_priv(ndev);
124 strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 122
123 strlcpy(info->driver, priv->drv_name, sizeof(info->driver));
124 strlcpy(info->version, priv->drv_version, sizeof(info->version));
125} 125}
126 126
127static const struct ethtool_ops arc_emac_ethtool_ops = { 127static const struct ethtool_ops arc_emac_ethtool_ops = {
@@ -671,19 +671,16 @@ static const struct net_device_ops arc_emac_netdev_ops = {
671#endif 671#endif
672}; 672};
673 673
674static int arc_emac_probe(struct platform_device *pdev) 674int arc_emac_probe(struct net_device *ndev, int interface)
675{ 675{
676 struct device *dev = &pdev->dev; 676 struct device *dev = ndev->dev.parent;
677 struct resource res_regs; 677 struct resource res_regs;
678 struct device_node *phy_node; 678 struct device_node *phy_node;
679 struct arc_emac_priv *priv; 679 struct arc_emac_priv *priv;
680 struct net_device *ndev;
681 const char *mac_addr; 680 const char *mac_addr;
682 unsigned int id, clock_frequency, irq; 681 unsigned int id, clock_frequency, irq;
683 int err; 682 int err;
684 683
685 if (!dev->of_node)
686 return -ENODEV;
687 684
688 /* Get PHY from device tree */ 685 /* Get PHY from device tree */
689 phy_node = of_parse_phandle(dev->of_node, "phy", 0); 686 phy_node = of_parse_phandle(dev->of_node, "phy", 0);
@@ -706,12 +703,6 @@ static int arc_emac_probe(struct platform_device *pdev)
706 return -ENODEV; 703 return -ENODEV;
707 } 704 }
708 705
709 ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
710 if (!ndev)
711 return -ENOMEM;
712
713 dev_set_drvdata(dev, ndev);
714 SET_NETDEV_DEV(ndev, dev);
715 706
716 ndev->netdev_ops = &arc_emac_netdev_ops; 707 ndev->netdev_ops = &arc_emac_netdev_ops;
717 ndev->ethtool_ops = &arc_emac_ethtool_ops; 708 ndev->ethtool_ops = &arc_emac_ethtool_ops;
@@ -724,28 +715,25 @@ static int arc_emac_probe(struct platform_device *pdev)
724 715
725 priv->regs = devm_ioremap_resource(dev, &res_regs); 716 priv->regs = devm_ioremap_resource(dev, &res_regs);
726 if (IS_ERR(priv->regs)) { 717 if (IS_ERR(priv->regs)) {
727 err = PTR_ERR(priv->regs); 718 return PTR_ERR(priv->regs);
728 goto out_netdev;
729 } 719 }
730 dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs); 720 dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs);
731 721
732 priv->clk = of_clk_get(dev->of_node, 0); 722 if (priv->clk) {
733 if (IS_ERR(priv->clk)) {
734 /* Get CPU clock frequency from device tree */
735 if (of_property_read_u32(dev->of_node, "clock-frequency",
736 &clock_frequency)) {
737 dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
738 err = -EINVAL;
739 goto out_netdev;
740 }
741 } else {
742 err = clk_prepare_enable(priv->clk); 723 err = clk_prepare_enable(priv->clk);
743 if (err) { 724 if (err) {
744 dev_err(dev, "failed to enable clock\n"); 725 dev_err(dev, "failed to enable clock\n");
745 goto out_clkget; 726 return err;
746 } 727 }
747 728
748 clock_frequency = clk_get_rate(priv->clk); 729 clock_frequency = clk_get_rate(priv->clk);
730 } else {
731 /* Get CPU clock frequency from device tree */
732 if (of_property_read_u32(dev->of_node, "clock-frequency",
733 &clock_frequency)) {
734 dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
735 return -EINVAL;
736 }
749 } 737 }
750 738
751 id = arc_reg_get(priv, R_ID); 739 id = arc_reg_get(priv, R_ID);
@@ -806,7 +794,7 @@ static int arc_emac_probe(struct platform_device *pdev)
806 } 794 }
807 795
808 priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0, 796 priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0,
809 PHY_INTERFACE_MODE_MII); 797 interface);
810 if (!priv->phy_dev) { 798 if (!priv->phy_dev) {
811 dev_err(dev, "of_phy_connect() failed\n"); 799 dev_err(dev, "of_phy_connect() failed\n");
812 err = -ENODEV; 800 err = -ENODEV;
@@ -833,20 +821,15 @@ out_netif_api:
833out_mdio: 821out_mdio:
834 arc_mdio_remove(priv); 822 arc_mdio_remove(priv);
835out_clken: 823out_clken:
836 if (!IS_ERR(priv->clk)) 824 if (priv->clk)
837 clk_disable_unprepare(priv->clk); 825 clk_disable_unprepare(priv->clk);
838out_clkget:
839 if (!IS_ERR(priv->clk))
840 clk_put(priv->clk);
841out_netdev:
842 free_netdev(ndev);
843 return err; 826 return err;
844} 827}
828EXPORT_SYMBOL_GPL(arc_emac_probe);
845 829
846static int arc_emac_remove(struct platform_device *pdev) 830int arc_emac_remove(struct net_device *ndev)
847{ 831{
848 struct device *dev = &pdev->dev; 832 struct device *dev = ndev->dev.parent;
849 struct net_device *ndev = dev_get_drvdata(dev);
850 struct arc_emac_priv *priv = netdev_priv(ndev); 833 struct arc_emac_priv *priv = netdev_priv(ndev);
851 834
852 phy_disconnect(priv->phy_dev); 835 phy_disconnect(priv->phy_dev);
@@ -857,31 +840,12 @@ static int arc_emac_remove(struct platform_device *pdev)
857 840
858 if (!IS_ERR(priv->clk)) { 841 if (!IS_ERR(priv->clk)) {
859 clk_disable_unprepare(priv->clk); 842 clk_disable_unprepare(priv->clk);
860 clk_put(priv->clk);
861 } 843 }
862 844
863 free_netdev(ndev);
864 845
865 return 0; 846 return 0;
866} 847}
867 848EXPORT_SYMBOL_GPL(arc_emac_remove);
868static const struct of_device_id arc_emac_dt_ids[] = {
869 { .compatible = "snps,arc-emac" },
870 { /* Sentinel */ }
871};
872MODULE_DEVICE_TABLE(of, arc_emac_dt_ids);
873
874static struct platform_driver arc_emac_driver = {
875 .probe = arc_emac_probe,
876 .remove = arc_emac_remove,
877 .driver = {
878 .name = DRV_NAME,
879 .owner = THIS_MODULE,
880 .of_match_table = arc_emac_dt_ids,
881 },
882};
883
884module_platform_driver(arc_emac_driver);
885 849
886MODULE_AUTHOR("Alexey Brodkin <abrodkin@synopsys.com>"); 850MODULE_AUTHOR("Alexey Brodkin <abrodkin@synopsys.com>");
887MODULE_DESCRIPTION("ARC EMAC driver"); 851MODULE_DESCRIPTION("ARC EMAC driver");