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
6 * Copyright (C) 2009 Cavium Networks
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/phy.h>
14 #include <asm/octeon/octeon.h>
15 #include <asm/octeon/cvmx-smix-defs.h>
17 #define DRV_VERSION "1.0"
18 #define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver"
20 struct octeon_mdiobus
{
21 struct mii_bus
*mii_bus
;
23 int phy_irq
[PHY_MAX_ADDR
];
26 static int octeon_mdiobus_read(struct mii_bus
*bus
, int phy_id
, int regnum
)
28 struct octeon_mdiobus
*p
= bus
->priv
;
29 union cvmx_smix_cmd smi_cmd
;
30 union cvmx_smix_rd_dat smi_rd
;
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
);
41 * Wait 1000 clocks so we don't saturate the RSL bus
45 smi_rd
.u64
= cvmx_read_csr(CVMX_SMIX_RD_DAT(p
->unit
));
46 } while (smi_rd
.s
.pending
&& --timeout
);
54 static int octeon_mdiobus_write(struct mii_bus
*bus
, int phy_id
,
57 struct octeon_mdiobus
*p
= bus
->priv
;
58 union cvmx_smix_cmd smi_cmd
;
59 union cvmx_smix_wr_dat smi_wr
;
64 cvmx_write_csr(CVMX_SMIX_WR_DAT(p
->unit
), smi_wr
.u64
);
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
);
74 * Wait 1000 clocks so we don't saturate the RSL bus
78 smi_wr
.u64
= cvmx_read_csr(CVMX_SMIX_WR_DAT(p
->unit
));
79 } while (smi_wr
.s
.pending
&& --timeout
);
87 static int __init
octeon_mdiobus_probe(struct platform_device
*pdev
)
89 struct octeon_mdiobus
*bus
;
93 bus
= devm_kzalloc(&pdev
->dev
, sizeof(*bus
), GFP_KERNEL
);
97 /* The platform_device id is our unit number. */
100 bus
->mii_bus
= mdiobus_alloc();
106 * Standard Octeon evaluation boards don't support phy
107 * interrupts, we need to poll.
109 for (i
= 0; i
< PHY_MAX_ADDR
; i
++)
110 bus
->phy_irq
[i
] = PHY_POLL
;
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
;
118 bus
->mii_bus
->read
= octeon_mdiobus_read
;
119 bus
->mii_bus
->write
= octeon_mdiobus_write
;
121 dev_set_drvdata(&pdev
->dev
, bus
);
123 err
= mdiobus_register(bus
->mii_bus
);
127 dev_info(&pdev
->dev
, "Version " DRV_VERSION
"\n");
131 mdiobus_free(bus
->mii_bus
);
134 devm_kfree(&pdev
->dev
, bus
);
138 static int __exit
octeon_mdiobus_remove(struct platform_device
*pdev
)
140 struct octeon_mdiobus
*bus
;
142 bus
= dev_get_drvdata(&pdev
->dev
);
144 mdiobus_unregister(bus
->mii_bus
);
145 mdiobus_free(bus
->mii_bus
);
149 static struct platform_driver octeon_mdiobus_driver
= {
151 .name
= "mdio-octeon",
152 .owner
= THIS_MODULE
,
154 .probe
= octeon_mdiobus_probe
,
155 .remove
= __exit_p(octeon_mdiobus_remove
),
158 void octeon_mdiobus_force_mod_depencency(void)
160 /* Let ethernet drivers force us to be loaded. */
162 EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency
);
164 static int __init
octeon_mdiobus_mod_init(void)
166 return platform_driver_register(&octeon_mdiobus_driver
);
169 static void __exit
octeon_mdiobus_mod_exit(void)
171 platform_driver_unregister(&octeon_mdiobus_driver
);
174 module_init(octeon_mdiobus_mod_init
);
175 module_exit(octeon_mdiobus_mod_exit
);
177 MODULE_DESCRIPTION(DRV_DESCRIPTION
);
178 MODULE_VERSION(DRV_VERSION
);
179 MODULE_AUTHOR("David Daney");
180 MODULE_LICENSE("GPL");