1 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) |
2 | /* Copyright 2019 NXP */ |
3 | #include <linux/fsl/enetc_mdio.h> |
4 | #include <linux/of_mdio.h> |
5 | #include "enetc_pf.h" |
6 | |
7 | #define ENETC_MDIO_DEV_ID 0xee01 |
8 | #define ENETC_MDIO_DEV_NAME "FSL PCIe IE Central MDIO" |
9 | #define ENETC_MDIO_BUS_NAME ENETC_MDIO_DEV_NAME " Bus" |
10 | #define ENETC_MDIO_DRV_NAME ENETC_MDIO_DEV_NAME " driver" |
11 | |
12 | static int enetc_pci_mdio_probe(struct pci_dev *pdev, |
13 | const struct pci_device_id *ent) |
14 | { |
15 | struct enetc_mdio_priv *mdio_priv; |
16 | struct device *dev = &pdev->dev; |
17 | void __iomem *port_regs; |
18 | struct enetc_hw *hw; |
19 | struct mii_bus *bus; |
20 | int err; |
21 | |
22 | port_regs = pci_iomap(dev: pdev, bar: 0, max: 0); |
23 | if (!port_regs) { |
24 | dev_err(dev, "iomap failed\n" ); |
25 | err = -ENXIO; |
26 | goto err_ioremap; |
27 | } |
28 | |
29 | hw = enetc_hw_alloc(dev, port_regs); |
30 | if (IS_ERR(ptr: hw)) { |
31 | err = PTR_ERR(ptr: hw); |
32 | goto err_hw_alloc; |
33 | } |
34 | |
35 | bus = devm_mdiobus_alloc_size(dev, sizeof_priv: sizeof(*mdio_priv)); |
36 | if (!bus) { |
37 | err = -ENOMEM; |
38 | goto err_mdiobus_alloc; |
39 | } |
40 | |
41 | bus->name = ENETC_MDIO_BUS_NAME; |
42 | bus->read = enetc_mdio_read_c22; |
43 | bus->write = enetc_mdio_write_c22; |
44 | bus->read_c45 = enetc_mdio_read_c45; |
45 | bus->write_c45 = enetc_mdio_write_c45; |
46 | bus->parent = dev; |
47 | mdio_priv = bus->priv; |
48 | mdio_priv->hw = hw; |
49 | mdio_priv->mdio_base = ENETC_EMDIO_BASE; |
50 | snprintf(buf: bus->id, MII_BUS_ID_SIZE, fmt: "%s" , dev_name(dev)); |
51 | |
52 | pcie_flr(dev: pdev); |
53 | err = pci_enable_device_mem(dev: pdev); |
54 | if (err) { |
55 | dev_err(dev, "device enable failed\n" ); |
56 | goto err_pci_enable; |
57 | } |
58 | |
59 | err = pci_request_region(pdev, 0, KBUILD_MODNAME); |
60 | if (err) { |
61 | dev_err(dev, "pci_request_region failed\n" ); |
62 | goto err_pci_mem_reg; |
63 | } |
64 | |
65 | err = of_mdiobus_register(mdio: bus, np: dev->of_node); |
66 | if (err) |
67 | goto err_mdiobus_reg; |
68 | |
69 | pci_set_drvdata(pdev, data: bus); |
70 | |
71 | return 0; |
72 | |
73 | err_mdiobus_reg: |
74 | pci_release_region(pdev, 0); |
75 | err_pci_mem_reg: |
76 | pci_disable_device(dev: pdev); |
77 | err_pci_enable: |
78 | err_mdiobus_alloc: |
79 | err_hw_alloc: |
80 | iounmap(addr: port_regs); |
81 | err_ioremap: |
82 | return err; |
83 | } |
84 | |
85 | static void enetc_pci_mdio_remove(struct pci_dev *pdev) |
86 | { |
87 | struct mii_bus *bus = pci_get_drvdata(pdev); |
88 | struct enetc_mdio_priv *mdio_priv; |
89 | |
90 | mdiobus_unregister(bus); |
91 | mdio_priv = bus->priv; |
92 | iounmap(addr: mdio_priv->hw->port); |
93 | pci_release_region(pdev, 0); |
94 | pci_disable_device(dev: pdev); |
95 | } |
96 | |
97 | static const struct pci_device_id enetc_pci_mdio_id_table[] = { |
98 | { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_MDIO_DEV_ID) }, |
99 | { 0, } /* End of table. */ |
100 | }; |
101 | MODULE_DEVICE_TABLE(pci, enetc_pci_mdio_id_table); |
102 | |
103 | static struct pci_driver enetc_pci_mdio_driver = { |
104 | .name = KBUILD_MODNAME, |
105 | .id_table = enetc_pci_mdio_id_table, |
106 | .probe = enetc_pci_mdio_probe, |
107 | .remove = enetc_pci_mdio_remove, |
108 | }; |
109 | module_pci_driver(enetc_pci_mdio_driver); |
110 | |
111 | MODULE_DESCRIPTION(ENETC_MDIO_DRV_NAME); |
112 | MODULE_LICENSE("Dual BSD/GPL" ); |
113 | |