32
32
#include <linux/of.h>
33
33
#include <linux/of_device.h>
34
34
#include <linux/of_gpio.h>
35
+ #include <linux/pm.h>
36
+ #include <linux/pm_runtime.h>
35
37
36
38
#include "sdhci.h"
37
39
#include "sdhci-pltfm.h"
38
40
41
+ #define PXAV3_RPM_DELAY_MS 50
42
+
39
43
#define SD_CLOCK_BURST_SIZE_SETUP 0x10A
40
44
#define SDCLK_SEL 0x100
41
45
#define SDCLK_DELAY_SHIFT 9
@@ -296,9 +300,18 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
296
300
297
301
sdhci_get_of_property (pdev );
298
302
303
+ pm_runtime_set_active (& pdev -> dev );
304
+ pm_runtime_enable (& pdev -> dev );
305
+ pm_runtime_set_autosuspend_delay (& pdev -> dev , PXAV3_RPM_DELAY_MS );
306
+ pm_runtime_use_autosuspend (& pdev -> dev );
307
+ pm_suspend_ignore_children (& pdev -> dev , 1 );
308
+ pm_runtime_get_noresume (& pdev -> dev );
309
+
299
310
ret = sdhci_add_host (host );
300
311
if (ret ) {
301
312
dev_err (& pdev -> dev , "failed to add host\n" );
313
+ pm_runtime_forbid (& pdev -> dev );
314
+ pm_runtime_disable (& pdev -> dev );
302
315
goto err_add_host ;
303
316
}
304
317
@@ -311,6 +324,8 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
311
324
device_init_wakeup (& pdev -> dev , 0 );
312
325
}
313
326
327
+ pm_runtime_put_autosuspend (& pdev -> dev );
328
+
314
329
return 0 ;
315
330
316
331
err_add_host :
@@ -329,7 +344,9 @@ static int sdhci_pxav3_remove(struct platform_device *pdev)
329
344
struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
330
345
struct sdhci_pxa * pxa = pltfm_host -> priv ;
331
346
347
+ pm_runtime_get_sync (& pdev -> dev );
332
348
sdhci_remove_host (host , 1 );
349
+ pm_runtime_disable (& pdev -> dev );
333
350
334
351
clk_disable_unprepare (pltfm_host -> clk );
335
352
clk_put (pltfm_host -> clk );
@@ -342,14 +359,91 @@ static int sdhci_pxav3_remove(struct platform_device *pdev)
342
359
return 0 ;
343
360
}
344
361
362
+ #ifdef CONFIG_PM_SLEEP
363
+ static int sdhci_pxav3_suspend (struct device * dev )
364
+ {
365
+ int ret ;
366
+ struct sdhci_host * host = dev_get_drvdata (dev );
367
+
368
+ pm_runtime_get_sync (dev );
369
+ ret = sdhci_suspend_host (host );
370
+ pm_runtime_mark_last_busy (dev );
371
+ pm_runtime_put_autosuspend (dev );
372
+
373
+ return ret ;
374
+ }
375
+
376
+ static int sdhci_pxav3_resume (struct device * dev )
377
+ {
378
+ int ret ;
379
+ struct sdhci_host * host = dev_get_drvdata (dev );
380
+
381
+ pm_runtime_get_sync (dev );
382
+ ret = sdhci_resume_host (host );
383
+ pm_runtime_mark_last_busy (dev );
384
+ pm_runtime_put_autosuspend (dev );
385
+
386
+ return ret ;
387
+ }
388
+ #endif
389
+
390
+ #ifdef CONFIG_PM_RUNTIME
391
+ static int sdhci_pxav3_runtime_suspend (struct device * dev )
392
+ {
393
+ struct sdhci_host * host = dev_get_drvdata (dev );
394
+ struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
395
+ unsigned long flags ;
396
+
397
+ if (pltfm_host -> clk ) {
398
+ spin_lock_irqsave (& host -> lock , flags );
399
+ host -> runtime_suspended = true;
400
+ spin_unlock_irqrestore (& host -> lock , flags );
401
+
402
+ clk_disable_unprepare (pltfm_host -> clk );
403
+ }
404
+
405
+ return 0 ;
406
+ }
407
+
408
+ static int sdhci_pxav3_runtime_resume (struct device * dev )
409
+ {
410
+ struct sdhci_host * host = dev_get_drvdata (dev );
411
+ struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
412
+ unsigned long flags ;
413
+
414
+ if (pltfm_host -> clk ) {
415
+ clk_prepare_enable (pltfm_host -> clk );
416
+
417
+ spin_lock_irqsave (& host -> lock , flags );
418
+ host -> runtime_suspended = false;
419
+ spin_unlock_irqrestore (& host -> lock , flags );
420
+ }
421
+
422
+ return 0 ;
423
+ }
424
+ #endif
425
+
426
+ #ifdef CONFIG_PM
427
+ static const struct dev_pm_ops sdhci_pxav3_pmops = {
428
+ SET_SYSTEM_SLEEP_PM_OPS (sdhci_pxav3_suspend , sdhci_pxav3_resume )
429
+ SET_RUNTIME_PM_OPS (sdhci_pxav3_runtime_suspend ,
430
+ sdhci_pxav3_runtime_resume , NULL )
431
+ };
432
+
433
+ #define SDHCI_PXAV3_PMOPS (&sdhci_pxav3_pmops)
434
+
435
+ #else
436
+ #define SDHCI_PXAV3_PMOPS NULL
437
+ #endif
438
+
345
439
static struct platform_driver sdhci_pxav3_driver = {
346
440
.driver = {
347
441
.name = "sdhci-pxav3" ,
348
442
#ifdef CONFIG_OF
349
443
.of_match_table = sdhci_pxav3_of_match ,
350
444
#endif
351
445
.owner = THIS_MODULE ,
352
- .pm = SDHCI_PLTFM_PMOPS ,
446
+ .pm = SDHCI_PXAV3_PMOPS ,
353
447
},
354
448
.probe = sdhci_pxav3_probe ,
355
449
.remove = sdhci_pxav3_remove ,
0 commit comments