16
16
#include <linux/module.h>
17
17
#include <linux/io.h>
18
18
#include <linux/delay.h>
19
+ #include <linux/clk.h>
19
20
20
21
#include <linux/of.h>
21
22
#include <linux/of_platform.h>
@@ -45,6 +46,8 @@ struct unimac_mdio_priv {
45
46
void __iomem * base ;
46
47
int (* wait_func ) (void * wait_func_data );
47
48
void * wait_func_data ;
49
+ struct clk * clk ;
50
+ u32 clk_freq ;
48
51
};
49
52
50
53
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)
189
192
return 0 ;
190
193
}
191
194
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
+
192
224
static int unimac_mdio_probe (struct platform_device * pdev )
193
225
{
194
226
struct unimac_mdio_pdata * pdata = pdev -> dev .platform_data ;
@@ -217,9 +249,26 @@ static int unimac_mdio_probe(struct platform_device *pdev)
217
249
return - ENOMEM ;
218
250
}
219
251
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
+
220
267
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
+ }
223
272
224
273
bus = priv -> mii_bus ;
225
274
bus -> priv = priv ;
@@ -253,6 +302,8 @@ static int unimac_mdio_probe(struct platform_device *pdev)
253
302
254
303
out_mdio_free :
255
304
mdiobus_free (bus );
305
+ out_clk_disable :
306
+ clk_disable_unprepare (priv -> clk );
256
307
return ret ;
257
308
}
258
309
@@ -262,10 +313,37 @@ static int unimac_mdio_remove(struct platform_device *pdev)
262
313
263
314
mdiobus_unregister (priv -> mii_bus );
264
315
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 );
265
340
266
341
return 0 ;
267
342
}
268
343
344
+ static SIMPLE_DEV_PM_OPS (unimac_mdio_pm_ops ,
345
+ unimac_mdio_suspend , unimac_mdio_resume ) ;
346
+
269
347
static const struct of_device_id unimac_mdio_ids [] = {
270
348
{ .compatible = "brcm,genet-mdio-v5" , },
271
349
{ .compatible = "brcm,genet-mdio-v4" , },
@@ -281,6 +359,7 @@ static struct platform_driver unimac_mdio_driver = {
281
359
.driver = {
282
360
.name = UNIMAC_MDIO_DRV_NAME ,
283
361
.of_match_table = unimac_mdio_ids ,
362
+ .pm = & unimac_mdio_pm_ops ,
284
363
},
285
364
.probe = unimac_mdio_probe ,
286
365
.remove = unimac_mdio_remove ,
0 commit comments