6767 */
6868#define SDHCI_CDNS_MAX_TUNING_LOOP 40
6969
70+ struct sdhci_cdns_phy_param {
71+ u8 addr ;
72+ u8 data ;
73+ };
74+
7075struct sdhci_cdns_priv {
7176 void __iomem * hrs_addr ;
7277 bool enhanced_strobe ;
78+ unsigned int nr_phy_params ;
79+ struct sdhci_cdns_phy_param phy_params [0 ];
7380};
7481
7582struct sdhci_cdns_phy_cfg {
@@ -115,9 +122,22 @@ static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv,
115122 return 0 ;
116123}
117124
118- static int sdhci_cdns_phy_init (struct device_node * np ,
119- struct sdhci_cdns_priv * priv )
125+ static unsigned int sdhci_cdns_phy_param_count (struct device_node * np )
120126{
127+ unsigned int count = 0 ;
128+ int i ;
129+
130+ for (i = 0 ; i < ARRAY_SIZE (sdhci_cdns_phy_cfgs ); i ++ )
131+ if (of_property_read_bool (np , sdhci_cdns_phy_cfgs [i ].property ))
132+ count ++ ;
133+
134+ return count ;
135+ }
136+
137+ static void sdhci_cdns_phy_param_parse (struct device_node * np ,
138+ struct sdhci_cdns_priv * priv )
139+ {
140+ struct sdhci_cdns_phy_param * p = priv -> phy_params ;
121141 u32 val ;
122142 int ret , i ;
123143
@@ -127,9 +147,19 @@ static int sdhci_cdns_phy_init(struct device_node *np,
127147 if (ret )
128148 continue ;
129149
130- ret = sdhci_cdns_write_phy_reg (priv ,
131- sdhci_cdns_phy_cfgs [i ].addr ,
132- val );
150+ p -> addr = sdhci_cdns_phy_cfgs [i ].addr ;
151+ p -> data = val ;
152+ p ++ ;
153+ }
154+ }
155+
156+ static int sdhci_cdns_phy_init (struct sdhci_cdns_priv * priv )
157+ {
158+ int ret , i ;
159+
160+ for (i = 0 ; i < priv -> nr_phy_params ; i ++ ) {
161+ ret = sdhci_cdns_write_phy_reg (priv , priv -> phy_params [i ].addr ,
162+ priv -> phy_params [i ].data );
133163 if (ret )
134164 return ret ;
135165 }
@@ -302,6 +332,8 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
302332 struct sdhci_pltfm_host * pltfm_host ;
303333 struct sdhci_cdns_priv * priv ;
304334 struct clk * clk ;
335+ size_t priv_size ;
336+ unsigned int nr_phy_params ;
305337 int ret ;
306338 struct device * dev = & pdev -> dev ;
307339
@@ -313,7 +345,9 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
313345 if (ret )
314346 return ret ;
315347
316- host = sdhci_pltfm_init (pdev , & sdhci_cdns_pltfm_data , sizeof (* priv ));
348+ nr_phy_params = sdhci_cdns_phy_param_count (dev -> of_node );
349+ priv_size = sizeof (* priv ) + sizeof (priv -> phy_params [0 ]) * nr_phy_params ;
350+ host = sdhci_pltfm_init (pdev , & sdhci_cdns_pltfm_data , priv_size );
317351 if (IS_ERR (host )) {
318352 ret = PTR_ERR (host );
319353 goto disable_clk ;
@@ -322,7 +356,8 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
322356 pltfm_host = sdhci_priv (host );
323357 pltfm_host -> clk = clk ;
324358
325- priv = sdhci_cdns_priv (host );
359+ priv = sdhci_pltfm_priv (pltfm_host );
360+ priv -> nr_phy_params = nr_phy_params ;
326361 priv -> hrs_addr = host -> ioaddr ;
327362 priv -> enhanced_strobe = false;
328363 host -> ioaddr += SDHCI_CDNS_SRS_BASE ;
@@ -336,7 +371,9 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
336371 if (ret )
337372 goto free ;
338373
339- ret = sdhci_cdns_phy_init (dev -> of_node , priv );
374+ sdhci_cdns_phy_param_parse (dev -> of_node , priv );
375+
376+ ret = sdhci_cdns_phy_init (priv );
340377 if (ret )
341378 goto free ;
342379
@@ -353,6 +390,57 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
353390 return ret ;
354391}
355392
393+ #ifdef CONFIG_PM_SLEEP
394+ static int sdhci_cdns_suspend (struct device * dev )
395+ {
396+ struct sdhci_host * host = dev_get_drvdata (dev );
397+ struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
398+ int ret ;
399+
400+ if (host -> tuning_mode != SDHCI_TUNING_MODE_3 )
401+ mmc_retune_needed (host -> mmc );
402+
403+ ret = sdhci_suspend_host (host );
404+ if (ret )
405+ return ret ;
406+
407+ clk_disable_unprepare (pltfm_host -> clk );
408+
409+ return 0 ;
410+ }
411+
412+ static int sdhci_cdns_resume (struct device * dev )
413+ {
414+ struct sdhci_host * host = dev_get_drvdata (dev );
415+ struct sdhci_pltfm_host * pltfm_host = sdhci_priv (host );
416+ struct sdhci_cdns_priv * priv = sdhci_pltfm_priv (pltfm_host );
417+ int ret ;
418+
419+ ret = clk_prepare_enable (pltfm_host -> clk );
420+ if (ret )
421+ return ret ;
422+
423+ ret = sdhci_cdns_phy_init (priv );
424+ if (ret )
425+ goto disable_clk ;
426+
427+ ret = sdhci_resume_host (host );
428+ if (ret )
429+ goto disable_clk ;
430+
431+ return 0 ;
432+
433+ disable_clk :
434+ clk_disable_unprepare (pltfm_host -> clk );
435+
436+ return ret ;
437+ }
438+ #endif
439+
440+ static const struct dev_pm_ops sdhci_cdns_pm_ops = {
441+ SET_SYSTEM_SLEEP_PM_OPS (sdhci_cdns_suspend , sdhci_cdns_resume )
442+ };
443+
356444static const struct of_device_id sdhci_cdns_match [] = {
357445 { .compatible = "socionext,uniphier-sd4hc" },
358446 { .compatible = "cdns,sd4hc" },
@@ -363,7 +451,7 @@ MODULE_DEVICE_TABLE(of, sdhci_cdns_match);
363451static struct platform_driver sdhci_cdns_driver = {
364452 .driver = {
365453 .name = "sdhci-cdns" ,
366- .pm = & sdhci_pltfm_pmops ,
454+ .pm = & sdhci_cdns_pm_ops ,
367455 .of_match_table = sdhci_cdns_match ,
368456 },
369457 .probe = sdhci_cdns_probe ,
0 commit comments