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
5053static 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+
192224static 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
254303out_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+
269347static 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