1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2009-2015 Cavium, Inc. |
4 | */ |
5 | |
6 | #include <linux/gfp.h> |
7 | #include <linux/io.h> |
8 | #include <linux/module.h> |
9 | #include <linux/of_address.h> |
10 | #include <linux/of_mdio.h> |
11 | #include <linux/phy.h> |
12 | #include <linux/platform_device.h> |
13 | |
14 | #include "mdio-cavium.h" |
15 | |
16 | static int octeon_mdiobus_probe(struct platform_device *pdev) |
17 | { |
18 | struct cavium_mdiobus *bus; |
19 | struct mii_bus *mii_bus; |
20 | struct resource *res_mem; |
21 | resource_size_t mdio_phys; |
22 | resource_size_t regsize; |
23 | union cvmx_smix_en smi_en; |
24 | int err = -ENOENT; |
25 | |
26 | mii_bus = devm_mdiobus_alloc_size(dev: &pdev->dev, sizeof_priv: sizeof(*bus)); |
27 | if (!mii_bus) |
28 | return -ENOMEM; |
29 | |
30 | res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
31 | if (res_mem == NULL) { |
32 | dev_err(&pdev->dev, "found no memory resource\n" ); |
33 | return -ENXIO; |
34 | } |
35 | |
36 | bus = mii_bus->priv; |
37 | bus->mii_bus = mii_bus; |
38 | mdio_phys = res_mem->start; |
39 | regsize = resource_size(res: res_mem); |
40 | |
41 | if (!devm_request_mem_region(&pdev->dev, mdio_phys, regsize, |
42 | res_mem->name)) { |
43 | dev_err(&pdev->dev, "request_mem_region failed\n" ); |
44 | return -ENXIO; |
45 | } |
46 | |
47 | bus->register_base = devm_ioremap(dev: &pdev->dev, offset: mdio_phys, size: regsize); |
48 | if (!bus->register_base) { |
49 | dev_err(&pdev->dev, "dev_ioremap failed\n" ); |
50 | return -ENOMEM; |
51 | } |
52 | |
53 | smi_en.u64 = 0; |
54 | smi_en.s.en = 1; |
55 | oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); |
56 | |
57 | bus->mii_bus->name = KBUILD_MODNAME; |
58 | snprintf(buf: bus->mii_bus->id, MII_BUS_ID_SIZE, fmt: "%px" , bus->register_base); |
59 | bus->mii_bus->parent = &pdev->dev; |
60 | |
61 | bus->mii_bus->read = cavium_mdiobus_read_c22; |
62 | bus->mii_bus->write = cavium_mdiobus_write_c22; |
63 | bus->mii_bus->read_c45 = cavium_mdiobus_read_c45; |
64 | bus->mii_bus->write_c45 = cavium_mdiobus_write_c45; |
65 | |
66 | platform_set_drvdata(pdev, data: bus); |
67 | |
68 | err = of_mdiobus_register(mdio: bus->mii_bus, np: pdev->dev.of_node); |
69 | if (err) |
70 | goto fail_register; |
71 | |
72 | dev_info(&pdev->dev, "Probed\n" ); |
73 | |
74 | return 0; |
75 | fail_register: |
76 | smi_en.u64 = 0; |
77 | oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); |
78 | return err; |
79 | } |
80 | |
81 | static void octeon_mdiobus_remove(struct platform_device *pdev) |
82 | { |
83 | struct cavium_mdiobus *bus; |
84 | union cvmx_smix_en smi_en; |
85 | |
86 | bus = platform_get_drvdata(pdev); |
87 | |
88 | mdiobus_unregister(bus: bus->mii_bus); |
89 | smi_en.u64 = 0; |
90 | oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); |
91 | } |
92 | |
93 | static const struct of_device_id octeon_mdiobus_match[] = { |
94 | { |
95 | .compatible = "cavium,octeon-3860-mdio" , |
96 | }, |
97 | {}, |
98 | }; |
99 | MODULE_DEVICE_TABLE(of, octeon_mdiobus_match); |
100 | |
101 | static struct platform_driver octeon_mdiobus_driver = { |
102 | .driver = { |
103 | .name = KBUILD_MODNAME, |
104 | .of_match_table = octeon_mdiobus_match, |
105 | }, |
106 | .probe = octeon_mdiobus_probe, |
107 | .remove_new = octeon_mdiobus_remove, |
108 | }; |
109 | |
110 | module_platform_driver(octeon_mdiobus_driver); |
111 | |
112 | MODULE_DESCRIPTION("Cavium OCTEON MDIO bus driver" ); |
113 | MODULE_AUTHOR("David Daney" ); |
114 | MODULE_LICENSE("GPL v2" ); |
115 | |