Skip to content

Commit b78ac6e

Browse files
ffainellidavem330
authored andcommitted
net: phy: mdio-bcm-unimac: Allow configuring MDIO clock divider
Allow the configuration of the MDIO clock divider when the Device Tree contains 'clock-frequency' property (similar to I2C and SPI buses). Because the hardware may have lost its state during suspend/resume, re-apply the MDIO clock divider upon resumption. Signed-off-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 94e7c84 commit b78ac6e

File tree

2 files changed

+84
-2
lines changed

2 files changed

+84
-2
lines changed

Documentation/devicetree/bindings/net/brcm,unimac-mdio.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ Optional properties:
1919
- interrupt-names: must be "mdio_done_error" when there is a share interrupt fed
2020
to this hardware block, or must be "mdio_done" for the first interrupt and
2121
"mdio_error" for the second when there are separate interrupts
22+
- clocks: A reference to the clock supplying the MDIO bus controller
23+
- clock-frequency: the MDIO bus clock that must be output by the MDIO bus
24+
hardware, if absent, the default hardware values are used
2225

2326
Child nodes of this MDIO bus controller node are standard Ethernet PHY device
2427
nodes as described in Documentation/devicetree/bindings/net/phy.txt

drivers/net/phy/mdio-bcm-unimac.c

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/module.h>
1717
#include <linux/io.h>
1818
#include <linux/delay.h>
19+
#include <linux/clk.h>
1920

2021
#include <linux/of.h>
2122
#include <linux/of_platform.h>
@@ -45,6 +46,8 @@ struct unimac_mdio_priv {
4546
void __iomem *base;
4647
int (*wait_func) (void *wait_func_data);
4748
void *wait_func_data;
49+
struct clk *clk;
50+
u32 clk_freq;
4851
};
4952

5053
static inline u32 unimac_mdio_readl(struct unimac_mdio_priv *priv, u32 offset)
@@ -189,6 +192,35 @@ static int unimac_mdio_reset(struct mii_bus *bus)
189192
return 0;
190193
}
191194

195+
static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv)
196+
{
197+
unsigned long rate;
198+
u32 reg, div;
199+
200+
/* Keep the hardware default values */
201+
if (!priv->clk_freq)
202+
return;
203+
204+
if (!priv->clk)
205+
rate = 250000000;
206+
else
207+
rate = clk_get_rate(priv->clk);
208+
209+
div = (rate / (2 * priv->clk_freq)) - 1;
210+
if (div & ~MDIO_CLK_DIV_MASK) {
211+
pr_warn("Incorrect MDIO clock frequency, ignoring\n");
212+
return;
213+
}
214+
215+
/* The MDIO clock is the reference clock (typicaly 250Mhz) divided by
216+
* 2 x (MDIO_CLK_DIV + 1)
217+
*/
218+
reg = unimac_mdio_readl(priv, MDIO_CFG);
219+
reg &= ~(MDIO_CLK_DIV_MASK << MDIO_CLK_DIV_SHIFT);
220+
reg |= div << MDIO_CLK_DIV_SHIFT;
221+
unimac_mdio_writel(priv, reg, MDIO_CFG);
222+
}
223+
192224
static int unimac_mdio_probe(struct platform_device *pdev)
193225
{
194226
struct unimac_mdio_pdata *pdata = pdev->dev.platform_data;
@@ -217,9 +249,26 @@ static int unimac_mdio_probe(struct platform_device *pdev)
217249
return -ENOMEM;
218250
}
219251

252+
priv->clk = devm_clk_get(&pdev->dev, NULL);
253+
if (PTR_ERR(priv->clk) == -EPROBE_DEFER)
254+
return PTR_ERR(priv->clk);
255+
else
256+
priv->clk = NULL;
257+
258+
ret = clk_prepare_enable(priv->clk);
259+
if (ret)
260+
return ret;
261+
262+
if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq))
263+
priv->clk_freq = 0;
264+
265+
unimac_mdio_clk_set(priv);
266+
220267
priv->mii_bus = mdiobus_alloc();
221-
if (!priv->mii_bus)
222-
return -ENOMEM;
268+
if (!priv->mii_bus) {
269+
ret = -ENOMEM;
270+
goto out_clk_disable;
271+
}
223272

224273
bus = priv->mii_bus;
225274
bus->priv = priv;
@@ -253,6 +302,8 @@ static int unimac_mdio_probe(struct platform_device *pdev)
253302

254303
out_mdio_free:
255304
mdiobus_free(bus);
305+
out_clk_disable:
306+
clk_disable_unprepare(priv->clk);
256307
return ret;
257308
}
258309

@@ -262,10 +313,37 @@ static int unimac_mdio_remove(struct platform_device *pdev)
262313

263314
mdiobus_unregister(priv->mii_bus);
264315
mdiobus_free(priv->mii_bus);
316+
clk_disable_unprepare(priv->clk);
317+
318+
return 0;
319+
}
320+
321+
static int unimac_mdio_suspend(struct device *d)
322+
{
323+
struct unimac_mdio_priv *priv = dev_get_drvdata(d);
324+
325+
clk_disable_unprepare(priv->clk);
326+
327+
return 0;
328+
}
329+
330+
static int unimac_mdio_resume(struct device *d)
331+
{
332+
struct unimac_mdio_priv *priv = dev_get_drvdata(d);
333+
int ret;
334+
335+
ret = clk_prepare_enable(priv->clk);
336+
if (ret)
337+
return ret;
338+
339+
unimac_mdio_clk_set(priv);
265340

266341
return 0;
267342
}
268343

344+
static SIMPLE_DEV_PM_OPS(unimac_mdio_pm_ops,
345+
unimac_mdio_suspend, unimac_mdio_resume);
346+
269347
static const struct of_device_id unimac_mdio_ids[] = {
270348
{ .compatible = "brcm,genet-mdio-v5", },
271349
{ .compatible = "brcm,genet-mdio-v4", },
@@ -281,6 +359,7 @@ static struct platform_driver unimac_mdio_driver = {
281359
.driver = {
282360
.name = UNIMAC_MDIO_DRV_NAME,
283361
.of_match_table = unimac_mdio_ids,
362+
.pm = &unimac_mdio_pm_ops,
284363
},
285364
.probe = unimac_mdio_probe,
286365
.remove = unimac_mdio_remove,

0 commit comments

Comments
 (0)