2 * Broadcom UniMAC MDIO bus controller driver
4 * Copyright (C) 2014, Broadcom Corporation
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
12 #include <linux/kernel.h>
13 #include <linux/phy.h>
14 #include <linux/platform_device.h>
15 #include <linux/sched.h>
16 #include <linux/module.h>
18 #include <linux/delay.h>
21 #include <linux/of_platform.h>
22 #include <linux/of_mdio.h>
25 #define MDIO_START_BUSY (1 << 29)
26 #define MDIO_READ_FAIL (1 << 28)
27 #define MDIO_RD (2 << 26)
28 #define MDIO_WR (1 << 26)
29 #define MDIO_PMD_SHIFT 21
30 #define MDIO_PMD_MASK 0x1F
31 #define MDIO_REG_SHIFT 16
32 #define MDIO_REG_MASK 0x1F
35 #define MDIO_C22 (1 << 0)
37 #define MDIO_CLK_DIV_SHIFT 4
38 #define MDIO_CLK_DIV_MASK 0x3F
39 #define MDIO_SUPP_PREAMBLE (1 << 12)
41 struct unimac_mdio_priv
{
42 struct mii_bus
*mii_bus
;
46 static inline void unimac_mdio_start(struct unimac_mdio_priv
*priv
)
50 reg
= __raw_readl(priv
->base
+ MDIO_CMD
);
51 reg
|= MDIO_START_BUSY
;
52 __raw_writel(reg
, priv
->base
+ MDIO_CMD
);
55 static inline unsigned int unimac_mdio_busy(struct unimac_mdio_priv
*priv
)
57 return __raw_readl(priv
->base
+ MDIO_CMD
) & MDIO_START_BUSY
;
60 static int unimac_mdio_read(struct mii_bus
*bus
, int phy_id
, int reg
)
62 struct unimac_mdio_priv
*priv
= bus
->priv
;
63 unsigned int timeout
= 1000;
66 /* Prepare the read operation */
67 cmd
= MDIO_RD
| (phy_id
<< MDIO_PMD_SHIFT
) | (reg
<< MDIO_REG_SHIFT
);
68 __raw_writel(cmd
, priv
->base
+ MDIO_CMD
);
70 /* Start MDIO transaction */
71 unimac_mdio_start(priv
);
74 if (!unimac_mdio_busy(priv
))
77 usleep_range(1000, 2000);
83 cmd
= __raw_readl(priv
->base
+ MDIO_CMD
);
84 if (cmd
& MDIO_READ_FAIL
)
90 static int unimac_mdio_write(struct mii_bus
*bus
, int phy_id
,
93 struct unimac_mdio_priv
*priv
= bus
->priv
;
94 unsigned int timeout
= 1000;
97 /* Prepare the write operation */
98 cmd
= MDIO_WR
| (phy_id
<< MDIO_PMD_SHIFT
) |
99 (reg
<< MDIO_REG_SHIFT
) | (0xffff & val
);
100 __raw_writel(cmd
, priv
->base
+ MDIO_CMD
);
102 unimac_mdio_start(priv
);
105 if (!unimac_mdio_busy(priv
))
108 usleep_range(1000, 2000);
117 static int unimac_mdio_probe(struct platform_device
*pdev
)
119 struct unimac_mdio_priv
*priv
;
120 struct device_node
*np
;
125 np
= pdev
->dev
.of_node
;
127 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
131 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
133 /* Just ioremap, as this MDIO block is usually integrated into an
134 * Ethernet MAC controller register range
136 priv
->base
= devm_ioremap(&pdev
->dev
, r
->start
, resource_size(r
));
138 dev_err(&pdev
->dev
, "failed to remap register\n");
142 priv
->mii_bus
= mdiobus_alloc();
148 bus
->name
= "unimac MII bus";
149 bus
->parent
= &pdev
->dev
;
150 bus
->read
= unimac_mdio_read
;
151 bus
->write
= unimac_mdio_write
;
152 snprintf(bus
->id
, MII_BUS_ID_SIZE
, "%s", pdev
->name
);
154 bus
->irq
= kcalloc(PHY_MAX_ADDR
, sizeof(int), GFP_KERNEL
);
160 ret
= of_mdiobus_register(bus
, np
);
162 dev_err(&pdev
->dev
, "MDIO bus registration failed\n");
166 platform_set_drvdata(pdev
, priv
);
168 dev_info(&pdev
->dev
, "Broadcom UniMAC MDIO bus at 0x%p\n", priv
->base
);
179 static int unimac_mdio_remove(struct platform_device
*pdev
)
181 struct unimac_mdio_priv
*priv
= platform_get_drvdata(pdev
);
183 mdiobus_unregister(priv
->mii_bus
);
184 kfree(priv
->mii_bus
->irq
);
185 mdiobus_free(priv
->mii_bus
);
190 static const struct of_device_id unimac_mdio_ids
[] = {
191 { .compatible
= "brcm,genet-mdio-v4", },
192 { .compatible
= "brcm,genet-mdio-v3", },
193 { .compatible
= "brcm,genet-mdio-v2", },
194 { .compatible
= "brcm,genet-mdio-v1", },
195 { .compatible
= "brcm,unimac-mdio", },
199 static struct platform_driver unimac_mdio_driver
= {
201 .name
= "unimac-mdio",
202 .of_match_table
= unimac_mdio_ids
,
204 .probe
= unimac_mdio_probe
,
205 .remove
= unimac_mdio_remove
,
207 module_platform_driver(unimac_mdio_driver
);
209 MODULE_AUTHOR("Broadcom Corporation");
210 MODULE_DESCRIPTION("Broadcom UniMAC MDIO bus controller");
211 MODULE_LICENSE("GPL");
212 MODULE_ALIAS("platform:unimac-mdio");