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
10 #include <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/phy.h>
15 #include <asm/octeon/octeon.h>
16 #include <asm/octeon/cvmx-smix-defs.h>
18 #define DRV_VERSION "1.0"
19 #define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver"
21 struct octeon_mdiobus
{
22 struct mii_bus
*mii_bus
;
24 int phy_irq
[PHY_MAX_ADDR
];
27 static int octeon_mdiobus_read(struct mii_bus
*bus
, int phy_id
, int regnum
)
29 struct octeon_mdiobus
*p
= bus
->priv
;
30 union cvmx_smix_cmd smi_cmd
;
31 union cvmx_smix_rd_dat smi_rd
;
35 smi_cmd
.s
.phy_op
= 1; /* MDIO_CLAUSE_22_READ */
36 smi_cmd
.s
.phy_adr
= phy_id
;
37 smi_cmd
.s
.reg_adr
= regnum
;
38 cvmx_write_csr(CVMX_SMIX_CMD(p
->unit
), smi_cmd
.u64
);
42 * Wait 1000 clocks so we don't saturate the RSL bus
46 smi_rd
.u64
= cvmx_read_csr(CVMX_SMIX_RD_DAT(p
->unit
));
47 } while (smi_rd
.s
.pending
&& --timeout
);
55 static int octeon_mdiobus_write(struct mii_bus
*bus
, int phy_id
,
58 struct octeon_mdiobus
*p
= bus
->priv
;
59 union cvmx_smix_cmd smi_cmd
;
60 union cvmx_smix_wr_dat smi_wr
;
65 cvmx_write_csr(CVMX_SMIX_WR_DAT(p
->unit
), smi_wr
.u64
);
68 smi_cmd
.s
.phy_op
= 0; /* MDIO_CLAUSE_22_WRITE */
69 smi_cmd
.s
.phy_adr
= phy_id
;
70 smi_cmd
.s
.reg_adr
= regnum
;
71 cvmx_write_csr(CVMX_SMIX_CMD(p
->unit
), smi_cmd
.u64
);
75 * Wait 1000 clocks so we don't saturate the RSL bus
79 smi_wr
.u64
= cvmx_read_csr(CVMX_SMIX_WR_DAT(p
->unit
));
80 } while (smi_wr
.s
.pending
&& --timeout
);
88 static int __devinit
octeon_mdiobus_probe(struct platform_device
*pdev
)
90 struct octeon_mdiobus
*bus
;
91 union cvmx_smix_en smi_en
;
95 bus
= devm_kzalloc(&pdev
->dev
, sizeof(*bus
), GFP_KERNEL
);
99 /* The platform_device id is our unit number. */
100 bus
->unit
= pdev
->id
;
102 bus
->mii_bus
= mdiobus_alloc();
109 cvmx_write_csr(CVMX_SMIX_EN(bus
->unit
), smi_en
.u64
);
112 * Standard Octeon evaluation boards don't support phy
113 * interrupts, we need to poll.
115 for (i
= 0; i
< PHY_MAX_ADDR
; i
++)
116 bus
->phy_irq
[i
] = PHY_POLL
;
118 bus
->mii_bus
->priv
= bus
;
119 bus
->mii_bus
->irq
= bus
->phy_irq
;
120 bus
->mii_bus
->name
= "mdio-octeon";
121 snprintf(bus
->mii_bus
->id
, MII_BUS_ID_SIZE
, "%x", bus
->unit
);
122 bus
->mii_bus
->parent
= &pdev
->dev
;
124 bus
->mii_bus
->read
= octeon_mdiobus_read
;
125 bus
->mii_bus
->write
= octeon_mdiobus_write
;
127 dev_set_drvdata(&pdev
->dev
, bus
);
129 err
= mdiobus_register(bus
->mii_bus
);
133 dev_info(&pdev
->dev
, "Version " DRV_VERSION
"\n");
137 mdiobus_free(bus
->mii_bus
);
140 devm_kfree(&pdev
->dev
, bus
);
142 cvmx_write_csr(CVMX_SMIX_EN(bus
->unit
), smi_en
.u64
);
146 static int __devexit
octeon_mdiobus_remove(struct platform_device
*pdev
)
148 struct octeon_mdiobus
*bus
;
149 union cvmx_smix_en smi_en
;
151 bus
= dev_get_drvdata(&pdev
->dev
);
153 mdiobus_unregister(bus
->mii_bus
);
154 mdiobus_free(bus
->mii_bus
);
156 cvmx_write_csr(CVMX_SMIX_EN(bus
->unit
), smi_en
.u64
);
160 static struct platform_driver octeon_mdiobus_driver
= {
162 .name
= "mdio-octeon",
163 .owner
= THIS_MODULE
,
165 .probe
= octeon_mdiobus_probe
,
166 .remove
= __devexit_p(octeon_mdiobus_remove
),
169 void octeon_mdiobus_force_mod_depencency(void)
171 /* Let ethernet drivers force us to be loaded. */
173 EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency
);
175 static int __init
octeon_mdiobus_mod_init(void)
177 return platform_driver_register(&octeon_mdiobus_driver
);
180 static void __exit
octeon_mdiobus_mod_exit(void)
182 platform_driver_unregister(&octeon_mdiobus_driver
);
185 module_init(octeon_mdiobus_mod_init
);
186 module_exit(octeon_mdiobus_mod_exit
);
188 MODULE_DESCRIPTION(DRV_DESCRIPTION
);
189 MODULE_VERSION(DRV_VERSION
);
190 MODULE_AUTHOR("David Daney");
191 MODULE_LICENSE("GPL");