1231ece36SClaudiu Manoil // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2231ece36SClaudiu Manoil /* Copyright 2019 NXP */
3231ece36SClaudiu Manoil #include <linux/of_mdio.h>
4231ece36SClaudiu Manoil #include "enetc_mdio.h"
5231ece36SClaudiu Manoil 
6231ece36SClaudiu Manoil #define ENETC_MDIO_DEV_ID	0xee01
7231ece36SClaudiu Manoil #define ENETC_MDIO_DEV_NAME	"FSL PCIe IE Central MDIO"
8231ece36SClaudiu Manoil #define ENETC_MDIO_BUS_NAME	ENETC_MDIO_DEV_NAME " Bus"
9231ece36SClaudiu Manoil #define ENETC_MDIO_DRV_NAME	ENETC_MDIO_DEV_NAME " driver"
10231ece36SClaudiu Manoil 
11231ece36SClaudiu Manoil static int enetc_pci_mdio_probe(struct pci_dev *pdev,
12231ece36SClaudiu Manoil 				const struct pci_device_id *ent)
13231ece36SClaudiu Manoil {
14231ece36SClaudiu Manoil 	struct enetc_mdio_priv *mdio_priv;
15231ece36SClaudiu Manoil 	struct device *dev = &pdev->dev;
16231ece36SClaudiu Manoil 	struct enetc_hw *hw;
17231ece36SClaudiu Manoil 	struct mii_bus *bus;
18231ece36SClaudiu Manoil 	int err;
19231ece36SClaudiu Manoil 
20231ece36SClaudiu Manoil 	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
21231ece36SClaudiu Manoil 	if (!hw)
22231ece36SClaudiu Manoil 		return -ENOMEM;
23231ece36SClaudiu Manoil 
24231ece36SClaudiu Manoil 	bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
25231ece36SClaudiu Manoil 	if (!bus)
26231ece36SClaudiu Manoil 		return -ENOMEM;
27231ece36SClaudiu Manoil 
28231ece36SClaudiu Manoil 	bus->name = ENETC_MDIO_BUS_NAME;
29231ece36SClaudiu Manoil 	bus->read = enetc_mdio_read;
30231ece36SClaudiu Manoil 	bus->write = enetc_mdio_write;
31231ece36SClaudiu Manoil 	bus->parent = dev;
32231ece36SClaudiu Manoil 	mdio_priv = bus->priv;
33231ece36SClaudiu Manoil 	mdio_priv->hw = hw;
34231ece36SClaudiu Manoil 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
35231ece36SClaudiu Manoil 
36231ece36SClaudiu Manoil 	pcie_flr(pdev);
37231ece36SClaudiu Manoil 	err = pci_enable_device_mem(pdev);
38231ece36SClaudiu Manoil 	if (err) {
39231ece36SClaudiu Manoil 		dev_err(dev, "device enable failed\n");
40231ece36SClaudiu Manoil 		return err;
41231ece36SClaudiu Manoil 	}
42231ece36SClaudiu Manoil 
43231ece36SClaudiu Manoil 	err = pci_request_region(pdev, 0, KBUILD_MODNAME);
44231ece36SClaudiu Manoil 	if (err) {
45231ece36SClaudiu Manoil 		dev_err(dev, "pci_request_region failed\n");
46231ece36SClaudiu Manoil 		goto err_pci_mem_reg;
47231ece36SClaudiu Manoil 	}
48231ece36SClaudiu Manoil 
49231ece36SClaudiu Manoil 	hw->port = pci_iomap(pdev, 0, 0);
50231ece36SClaudiu Manoil 	if (!hw->port) {
51231ece36SClaudiu Manoil 		err = -ENXIO;
52231ece36SClaudiu Manoil 		dev_err(dev, "iomap failed\n");
53231ece36SClaudiu Manoil 		goto err_ioremap;
54231ece36SClaudiu Manoil 	}
55231ece36SClaudiu Manoil 
56231ece36SClaudiu Manoil 	err = of_mdiobus_register(bus, dev->of_node);
57231ece36SClaudiu Manoil 	if (err)
58231ece36SClaudiu Manoil 		goto err_mdiobus_reg;
59231ece36SClaudiu Manoil 
60231ece36SClaudiu Manoil 	pci_set_drvdata(pdev, bus);
61231ece36SClaudiu Manoil 
62231ece36SClaudiu Manoil 	return 0;
63231ece36SClaudiu Manoil 
64231ece36SClaudiu Manoil err_mdiobus_reg:
65231ece36SClaudiu Manoil 	iounmap(mdio_priv->hw->port);
66231ece36SClaudiu Manoil err_ioremap:
67231ece36SClaudiu Manoil 	pci_release_mem_regions(pdev);
68231ece36SClaudiu Manoil err_pci_mem_reg:
69231ece36SClaudiu Manoil 	pci_disable_device(pdev);
70231ece36SClaudiu Manoil 
71231ece36SClaudiu Manoil 	return err;
72231ece36SClaudiu Manoil }
73231ece36SClaudiu Manoil 
74231ece36SClaudiu Manoil static void enetc_pci_mdio_remove(struct pci_dev *pdev)
75231ece36SClaudiu Manoil {
76231ece36SClaudiu Manoil 	struct mii_bus *bus = pci_get_drvdata(pdev);
77231ece36SClaudiu Manoil 	struct enetc_mdio_priv *mdio_priv;
78231ece36SClaudiu Manoil 
79231ece36SClaudiu Manoil 	mdiobus_unregister(bus);
80231ece36SClaudiu Manoil 	mdio_priv = bus->priv;
81231ece36SClaudiu Manoil 	iounmap(mdio_priv->hw->port);
82231ece36SClaudiu Manoil 	pci_release_mem_regions(pdev);
83231ece36SClaudiu Manoil 	pci_disable_device(pdev);
84231ece36SClaudiu Manoil }
85231ece36SClaudiu Manoil 
86231ece36SClaudiu Manoil static const struct pci_device_id enetc_pci_mdio_id_table[] = {
87231ece36SClaudiu Manoil 	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_MDIO_DEV_ID) },
88231ece36SClaudiu Manoil 	{ 0, } /* End of table. */
89231ece36SClaudiu Manoil };
90231ece36SClaudiu Manoil MODULE_DEVICE_TABLE(pci, enetc_pci_mdio_id_table);
91231ece36SClaudiu Manoil 
92231ece36SClaudiu Manoil static struct pci_driver enetc_pci_mdio_driver = {
93231ece36SClaudiu Manoil 	.name = KBUILD_MODNAME,
94231ece36SClaudiu Manoil 	.id_table = enetc_pci_mdio_id_table,
95231ece36SClaudiu Manoil 	.probe = enetc_pci_mdio_probe,
96231ece36SClaudiu Manoil 	.remove = enetc_pci_mdio_remove,
97231ece36SClaudiu Manoil };
98231ece36SClaudiu Manoil module_pci_driver(enetc_pci_mdio_driver);
99231ece36SClaudiu Manoil 
100231ece36SClaudiu Manoil MODULE_DESCRIPTION(ENETC_MDIO_DRV_NAME);
101231ece36SClaudiu Manoil MODULE_LICENSE("Dual BSD/GPL");
102