1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /** |
3 | * DOC: emac_arc.c - ARC EMAC specific glue layer |
4 | * |
5 | * Copyright (C) 2014 Romain Perier |
6 | * |
7 | * Romain Perier <romain.perier@gmail.com> |
8 | */ |
9 | |
10 | #include <linux/etherdevice.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of_net.h> |
13 | #include <linux/platform_device.h> |
14 | |
15 | #include "emac.h" |
16 | |
17 | #define DRV_NAME "emac_arc" |
18 | |
19 | static int emac_arc_probe(struct platform_device *pdev) |
20 | { |
21 | struct device *dev = &pdev->dev; |
22 | struct arc_emac_priv *priv; |
23 | phy_interface_t interface; |
24 | struct net_device *ndev; |
25 | int err; |
26 | |
27 | if (!dev->of_node) |
28 | return -ENODEV; |
29 | |
30 | ndev = alloc_etherdev(sizeof(struct arc_emac_priv)); |
31 | if (!ndev) |
32 | return -ENOMEM; |
33 | platform_set_drvdata(pdev, data: ndev); |
34 | SET_NETDEV_DEV(ndev, dev); |
35 | |
36 | priv = netdev_priv(dev: ndev); |
37 | priv->drv_name = DRV_NAME; |
38 | |
39 | err = of_get_phy_mode(np: dev->of_node, interface: &interface); |
40 | if (err) { |
41 | if (err == -ENODEV) |
42 | interface = PHY_INTERFACE_MODE_MII; |
43 | else |
44 | goto out_netdev; |
45 | } |
46 | |
47 | priv->clk = devm_clk_get(dev, id: "hclk" ); |
48 | if (IS_ERR(ptr: priv->clk)) { |
49 | dev_err(dev, "failed to retrieve host clock from device tree\n" ); |
50 | err = -EINVAL; |
51 | goto out_netdev; |
52 | } |
53 | |
54 | err = arc_emac_probe(ndev, interface); |
55 | out_netdev: |
56 | if (err) |
57 | free_netdev(dev: ndev); |
58 | return err; |
59 | } |
60 | |
61 | static void emac_arc_remove(struct platform_device *pdev) |
62 | { |
63 | struct net_device *ndev = platform_get_drvdata(pdev); |
64 | |
65 | arc_emac_remove(ndev); |
66 | free_netdev(dev: ndev); |
67 | } |
68 | |
69 | static const struct of_device_id emac_arc_dt_ids[] = { |
70 | { .compatible = "snps,arc-emac" }, |
71 | { /* Sentinel */ } |
72 | }; |
73 | MODULE_DEVICE_TABLE(of, emac_arc_dt_ids); |
74 | |
75 | static struct platform_driver emac_arc_driver = { |
76 | .probe = emac_arc_probe, |
77 | .remove_new = emac_arc_remove, |
78 | .driver = { |
79 | .name = DRV_NAME, |
80 | .of_match_table = emac_arc_dt_ids, |
81 | }, |
82 | }; |
83 | |
84 | module_platform_driver(emac_arc_driver); |
85 | |
86 | MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>" ); |
87 | MODULE_DESCRIPTION("ARC EMAC platform driver" ); |
88 | MODULE_LICENSE("GPL" ); |
89 | |