2014-11-28 14:38:36 +01:00
/*
* Copyright ( C ) 2014 Linaro Ltd
*
* Author : Ulf Hansson < ulf . hansson @ linaro . org >
*
* License terms : GNU General Public License ( GPL ) version 2
*
* MMC power sequence management
*/
2014-12-05 14:36:58 +01:00
# include <linux/kernel.h>
# include <linux/err.h>
2016-04-14 14:02:16 +01:00
# include <linux/module.h>
2014-12-05 14:36:58 +01:00
# include <linux/of.h>
2014-11-28 14:38:36 +01:00
# include <linux/mmc/host.h>
# include "pwrseq.h"
2016-04-14 14:02:16 +01:00
static DEFINE_MUTEX ( pwrseq_list_mutex ) ;
static LIST_HEAD ( pwrseq_list ) ;
2014-11-28 14:38:36 +01:00
int mmc_pwrseq_alloc ( struct mmc_host * host )
{
2014-12-05 14:36:58 +01:00
struct device_node * np ;
2016-04-14 14:02:16 +01:00
struct mmc_pwrseq * p ;
2014-12-05 14:36:58 +01:00
np = of_parse_phandle ( host - > parent - > of_node , " mmc-pwrseq " , 0 ) ;
if ( ! np )
return 0 ;
2016-04-14 14:02:16 +01:00
mutex_lock ( & pwrseq_list_mutex ) ;
list_for_each_entry ( p , & pwrseq_list , pwrseq_node ) {
if ( p - > dev - > of_node = = np ) {
if ( ! try_module_get ( p - > owner ) )
dev_err ( host - > parent ,
" increasing module refcount failed \n " ) ;
else
host - > pwrseq = p ;
2014-12-05 14:36:58 +01:00
2016-04-14 14:02:16 +01:00
break ;
}
2014-12-05 14:36:58 +01:00
}
2016-04-14 14:02:16 +01:00
of_node_put ( np ) ;
mutex_unlock ( & pwrseq_list_mutex ) ;
if ( ! host - > pwrseq )
return - EPROBE_DEFER ;
2015-02-12 13:36:11 +09:00
dev_info ( host - > parent , " allocated mmc-pwrseq \n " ) ;
2014-12-05 14:36:58 +01:00
2016-04-14 14:02:16 +01:00
return 0 ;
2014-11-28 14:38:36 +01:00
}
void mmc_pwrseq_pre_power_on ( struct mmc_host * host )
{
struct mmc_pwrseq * pwrseq = host - > pwrseq ;
2016-04-14 14:02:16 +01:00
if ( pwrseq & & pwrseq - > ops - > pre_power_on )
2014-11-28 14:38:36 +01:00
pwrseq - > ops - > pre_power_on ( host ) ;
}
void mmc_pwrseq_post_power_on ( struct mmc_host * host )
{
struct mmc_pwrseq * pwrseq = host - > pwrseq ;
2016-04-14 14:02:16 +01:00
if ( pwrseq & & pwrseq - > ops - > post_power_on )
2014-11-28 14:38:36 +01:00
pwrseq - > ops - > post_power_on ( host ) ;
}
void mmc_pwrseq_power_off ( struct mmc_host * host )
{
struct mmc_pwrseq * pwrseq = host - > pwrseq ;
2016-04-14 14:02:16 +01:00
if ( pwrseq & & pwrseq - > ops - > power_off )
2014-11-28 14:38:36 +01:00
pwrseq - > ops - > power_off ( host ) ;
}
2017-05-08 23:49:12 +02:00
void mmc_pwrseq_reset ( struct mmc_host * host )
{
struct mmc_pwrseq * pwrseq = host - > pwrseq ;
if ( pwrseq & & pwrseq - > ops - > reset )
pwrseq - > ops - > reset ( host ) ;
}
2014-11-28 14:38:36 +01:00
void mmc_pwrseq_free ( struct mmc_host * host )
{
struct mmc_pwrseq * pwrseq = host - > pwrseq ;
2016-04-14 14:02:16 +01:00
if ( pwrseq ) {
module_put ( pwrseq - > owner ) ;
host - > pwrseq = NULL ;
}
}
int mmc_pwrseq_register ( struct mmc_pwrseq * pwrseq )
{
if ( ! pwrseq | | ! pwrseq - > ops | | ! pwrseq - > dev )
return - EINVAL ;
2015-02-12 13:36:11 +09:00
2016-04-14 14:02:16 +01:00
mutex_lock ( & pwrseq_list_mutex ) ;
list_add ( & pwrseq - > pwrseq_node , & pwrseq_list ) ;
mutex_unlock ( & pwrseq_list_mutex ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( mmc_pwrseq_register ) ;
void mmc_pwrseq_unregister ( struct mmc_pwrseq * pwrseq )
{
if ( pwrseq ) {
mutex_lock ( & pwrseq_list_mutex ) ;
list_del ( & pwrseq - > pwrseq_node ) ;
mutex_unlock ( & pwrseq_list_mutex ) ;
}
2014-11-28 14:38:36 +01:00
}
2016-04-14 14:02:16 +01:00
EXPORT_SYMBOL_GPL ( mmc_pwrseq_unregister ) ;