2 * Atheros AR71xx built-in ethernet mac driver
4 * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
5 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
7 * Based on Atheros' AG7100 driver
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published
11 * by the Free Software Foundation.
14 #include <linux/clk.h>
15 #include <linux/of_mdio.h>
18 #define AG71XX_MDIO_RETRY 1000
19 #define AG71XX_MDIO_DELAY 5
23 static int ag71xx_mdio_wait_busy(struct ag71xx_mdio
*am
)
27 for (i
= 0; i
< AG71XX_MDIO_RETRY
; i
++) {
30 udelay(AG71XX_MDIO_DELAY
);
32 regmap_read(am
->mii_regmap
, AG71XX_REG_MII_IND
, &busy
);
36 udelay(AG71XX_MDIO_DELAY
);
39 pr_err("%s: MDIO operation timed out\n", am
->mii_bus
->name
);
44 static int ag71xx_mdio_mii_read(struct mii_bus
*bus
, int addr
, int reg
)
46 struct ag71xx_mdio
*am
= bus
->priv
;
50 err
= ag71xx_mdio_wait_busy(am
);
54 regmap_write(am
->mii_regmap
, AG71XX_REG_MII_CMD
, MII_CMD_WRITE
);
55 regmap_write(am
->mii_regmap
, AG71XX_REG_MII_ADDR
,
56 ((addr
& 0xff) << MII_ADDR_SHIFT
) | (reg
& 0xff));
57 regmap_write(am
->mii_regmap
, AG71XX_REG_MII_CMD
, MII_CMD_READ
);
59 err
= ag71xx_mdio_wait_busy(am
);
63 regmap_read(am
->mii_regmap
, AG71XX_REG_MII_STATUS
, &ret
);
65 regmap_write(am
->mii_regmap
, AG71XX_REG_MII_CMD
, MII_CMD_WRITE
);
67 DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr
, reg
, ret
);
72 static int ag71xx_mdio_mii_write(struct mii_bus
*bus
, int addr
, int reg
, u16 val
)
74 struct ag71xx_mdio
*am
= bus
->priv
;
76 DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr
, reg
, val
);
78 regmap_write(am
->mii_regmap
, AG71XX_REG_MII_ADDR
,
79 ((addr
& 0xff) << MII_ADDR_SHIFT
) | (reg
& 0xff));
80 regmap_write(am
->mii_regmap
, AG71XX_REG_MII_CTRL
, val
);
82 ag71xx_mdio_wait_busy(am
);
87 static const u32 ar71xx_mdio_div_table
[] = {
88 4, 4, 6, 8, 10, 14, 20, 28,
91 static const u32 ar7240_mdio_div_table
[] = {
92 2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96,
95 static const u32 ar933x_mdio_div_table
[] = {
96 4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98,
99 static int ag71xx_mdio_get_divider(struct device_node
*np
, u32
*div
)
101 struct clk
*ref_clk
= of_clk_get(np
, 0);
102 unsigned long ref_clock
;
110 ref_clock
= clk_get_rate(ref_clk
);
113 if(of_property_read_u32(np
, "qca,mdio-max-frequency", &mdio_clock
)) {
114 if (of_property_read_bool(np
, "builtin-switch"))
115 mdio_clock
= 5000000;
117 mdio_clock
= 2000000;
120 if (of_device_is_compatible(np
, "qca,ar9330-mdio") ||
121 of_device_is_compatible(np
, "qca,ar9340-mdio")) {
122 table
= ar933x_mdio_div_table
;
123 ndivs
= ARRAY_SIZE(ar933x_mdio_div_table
);
124 } else if (of_device_is_compatible(np
, "qca,ar7240-mdio")) {
125 table
= ar7240_mdio_div_table
;
126 ndivs
= ARRAY_SIZE(ar7240_mdio_div_table
);
128 table
= ar71xx_mdio_div_table
;
129 ndivs
= ARRAY_SIZE(ar71xx_mdio_div_table
);
132 for (i
= 0; i
< ndivs
; i
++) {
135 t
= ref_clock
/ table
[i
];
136 if (t
<= mdio_clock
) {
145 static int ag71xx_mdio_reset(struct mii_bus
*bus
)
147 struct device_node
*np
= bus
->dev
.of_node
;
148 struct ag71xx_mdio
*am
= bus
->priv
;
152 builtin_switch
= of_property_read_bool(np
, "builtin-switch");
154 if (ag71xx_mdio_get_divider(np
, &t
)) {
155 if (of_device_is_compatible(np
, "qca,ar9340-mdio"))
156 t
= MII_CFG_CLK_DIV_58
;
157 else if (builtin_switch
)
158 t
= MII_CFG_CLK_DIV_10
;
160 t
= MII_CFG_CLK_DIV_28
;
163 regmap_write(am
->mii_regmap
, AG71XX_REG_MII_CFG
, t
| MII_CFG_RESET
);
166 regmap_write(am
->mii_regmap
, AG71XX_REG_MII_CFG
, t
);
172 static int ag71xx_mdio_probe(struct platform_device
*pdev
)
174 struct device
*amdev
= &pdev
->dev
;
175 struct device_node
*np
= pdev
->dev
.of_node
;
176 struct ag71xx_mdio
*am
;
177 struct mii_bus
*mii_bus
;
181 am
= devm_kzalloc(amdev
, sizeof(*am
), GFP_KERNEL
);
185 am
->mii_regmap
= syscon_regmap_lookup_by_phandle(np
, "regmap");
186 if (IS_ERR(am
->mii_regmap
))
187 return PTR_ERR(am
->mii_regmap
);
189 mii_bus
= devm_mdiobus_alloc(amdev
);
193 am
->mdio_reset
= devm_reset_control_get_exclusive(amdev
, "mdio");
194 builtin_switch
= of_property_read_bool(np
, "builtin-switch");
196 mii_bus
->name
= "ag71xx_mdio";
197 mii_bus
->read
= ag71xx_mdio_mii_read
;
198 mii_bus
->write
= ag71xx_mdio_mii_write
;
199 mii_bus
->reset
= ag71xx_mdio_reset
;
201 mii_bus
->parent
= amdev
;
202 snprintf(mii_bus
->id
, MII_BUS_ID_SIZE
, "%s.%d", np
->name
, bus_count
++);
204 if (!builtin_switch
&&
205 of_property_read_u32(np
, "phy-mask", &mii_bus
->phy_mask
))
206 mii_bus
->phy_mask
= 0;
208 for (i
= 0; i
< PHY_MAX_ADDR
; i
++)
209 mii_bus
->irq
[i
] = PHY_POLL
;
211 if (!IS_ERR(am
->mdio_reset
)) {
212 reset_control_assert(am
->mdio_reset
);
214 reset_control_deassert(am
->mdio_reset
);
218 err
= of_mdiobus_register(mii_bus
, np
);
222 am
->mii_bus
= mii_bus
;
223 platform_set_drvdata(pdev
, am
);
228 static int ag71xx_mdio_remove(struct platform_device
*pdev
)
230 struct ag71xx_mdio
*am
= platform_get_drvdata(pdev
);
232 mdiobus_unregister(am
->mii_bus
);
236 static const struct of_device_id ag71xx_mdio_match
[] = {
237 { .compatible
= "qca,ar7240-mdio" },
238 { .compatible
= "qca,ar9330-mdio" },
239 { .compatible
= "qca,ar9340-mdio" },
240 { .compatible
= "qca,ath79-mdio" },
244 static struct platform_driver ag71xx_mdio_driver
= {
245 .probe
= ag71xx_mdio_probe
,
246 .remove
= ag71xx_mdio_remove
,
248 .name
= "ag71xx-mdio",
249 .of_match_table
= ag71xx_mdio_match
,
253 module_platform_driver(ag71xx_mdio_driver
);
254 MODULE_LICENSE("GPL");