phylib: Support phy module autoloading
[safe/jmp/linux-2.6] / drivers / net / phy / mdio-octeon.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2009 Cavium Networks
7  */
8
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/phy.h>
13
14 #include <asm/octeon/octeon.h>
15 #include <asm/octeon/cvmx-smix-defs.h>
16
17 #define DRV_VERSION "1.0"
18 #define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver"
19
20 struct octeon_mdiobus {
21         struct mii_bus *mii_bus;
22         int unit;
23         int phy_irq[PHY_MAX_ADDR];
24 };
25
26 static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
27 {
28         struct octeon_mdiobus *p = bus->priv;
29         union cvmx_smix_cmd smi_cmd;
30         union cvmx_smix_rd_dat smi_rd;
31         int timeout = 1000;
32
33         smi_cmd.u64 = 0;
34         smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */
35         smi_cmd.s.phy_adr = phy_id;
36         smi_cmd.s.reg_adr = regnum;
37         cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
38
39         do {
40                 /*
41                  * Wait 1000 clocks so we don't saturate the RSL bus
42                  * doing reads.
43                  */
44                 cvmx_wait(1000);
45                 smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(p->unit));
46         } while (smi_rd.s.pending && --timeout);
47
48         if (smi_rd.s.val)
49                 return smi_rd.s.dat;
50         else
51                 return -EIO;
52 }
53
54 static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
55                                 int regnum, u16 val)
56 {
57         struct octeon_mdiobus *p = bus->priv;
58         union cvmx_smix_cmd smi_cmd;
59         union cvmx_smix_wr_dat smi_wr;
60         int timeout = 1000;
61
62         smi_wr.u64 = 0;
63         smi_wr.s.dat = val;
64         cvmx_write_csr(CVMX_SMIX_WR_DAT(p->unit), smi_wr.u64);
65
66         smi_cmd.u64 = 0;
67         smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */
68         smi_cmd.s.phy_adr = phy_id;
69         smi_cmd.s.reg_adr = regnum;
70         cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
71
72         do {
73                 /*
74                  * Wait 1000 clocks so we don't saturate the RSL bus
75                  * doing reads.
76                  */
77                 cvmx_wait(1000);
78                 smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(p->unit));
79         } while (smi_wr.s.pending && --timeout);
80
81         if (timeout <= 0)
82                 return -EIO;
83
84         return 0;
85 }
86
87 static int __init octeon_mdiobus_probe(struct platform_device *pdev)
88 {
89         struct octeon_mdiobus *bus;
90         int i;
91         int err = -ENOENT;
92
93         bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
94         if (!bus)
95                 return -ENOMEM;
96
97         /* The platform_device id is our unit number.  */
98         bus->unit = pdev->id;
99
100         bus->mii_bus = mdiobus_alloc();
101
102         if (!bus->mii_bus)
103                 goto err;
104
105         /*
106          * Standard Octeon evaluation boards don't support phy
107          * interrupts, we need to poll.
108          */
109         for (i = 0; i < PHY_MAX_ADDR; i++)
110                 bus->phy_irq[i] = PHY_POLL;
111
112         bus->mii_bus->priv = bus;
113         bus->mii_bus->irq = bus->phy_irq;
114         bus->mii_bus->name = "mdio-octeon";
115         snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%x", bus->unit);
116         bus->mii_bus->parent = &pdev->dev;
117
118         bus->mii_bus->read = octeon_mdiobus_read;
119         bus->mii_bus->write = octeon_mdiobus_write;
120
121         dev_set_drvdata(&pdev->dev, bus);
122
123         err = mdiobus_register(bus->mii_bus);
124         if (err)
125                 goto err_register;
126
127         dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
128
129         return 0;
130 err_register:
131         mdiobus_free(bus->mii_bus);
132
133 err:
134         devm_kfree(&pdev->dev, bus);
135         return err;
136 }
137
138 static int __exit octeon_mdiobus_remove(struct platform_device *pdev)
139 {
140         struct octeon_mdiobus *bus;
141
142         bus = dev_get_drvdata(&pdev->dev);
143
144         mdiobus_unregister(bus->mii_bus);
145         mdiobus_free(bus->mii_bus);
146         return 0;
147 }
148
149 static struct platform_driver octeon_mdiobus_driver = {
150         .driver = {
151                 .name           = "mdio-octeon",
152                 .owner          = THIS_MODULE,
153         },
154         .probe          = octeon_mdiobus_probe,
155         .remove         = __exit_p(octeon_mdiobus_remove),
156 };
157
158 void octeon_mdiobus_force_mod_depencency(void)
159 {
160         /* Let ethernet drivers force us to be loaded.  */
161 }
162 EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency);
163
164 static int __init octeon_mdiobus_mod_init(void)
165 {
166         return platform_driver_register(&octeon_mdiobus_driver);
167 }
168
169 static void __exit octeon_mdiobus_mod_exit(void)
170 {
171         platform_driver_unregister(&octeon_mdiobus_driver);
172 }
173
174 module_init(octeon_mdiobus_mod_init);
175 module_exit(octeon_mdiobus_mod_exit);
176
177 MODULE_DESCRIPTION(DRV_DESCRIPTION);
178 MODULE_VERSION(DRV_VERSION);
179 MODULE_AUTHOR("David Daney");
180 MODULE_LICENSE("GPL");