2011-06-21 10:51:26 -03:00
/*
2012-08-14 17:31:16 -03:00
* linux / drivers / media / platform / s5p - mfc / s5p_mfc_pm . c
2011-06-21 10:51:26 -03:00
*
* Copyright ( c ) 2010 Samsung Electronics Co . , Ltd .
* http : //www.samsung.com/
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/pm_runtime.h>
# include "s5p_mfc_common.h"
# include "s5p_mfc_debug.h"
# include "s5p_mfc_pm.h"
static struct s5p_mfc_pm * pm ;
static struct s5p_mfc_dev * p_dev ;
2012-10-17 07:11:50 -03:00
static atomic_t clk_ref ;
2011-06-21 10:51:26 -03:00
int s5p_mfc_init_pm ( struct s5p_mfc_dev * dev )
{
2016-11-16 07:04:57 -02:00
int i ;
2011-06-21 10:51:26 -03:00
pm = & dev - > pm ;
p_dev = dev ;
2012-02-16 10:51:56 -03:00
2016-11-16 07:04:57 -02:00
pm - > num_clocks = dev - > variant - > num_clocks ;
pm - > clk_names = dev - > variant - > clk_names ;
pm - > device = & dev - > plat_dev - > dev ;
pm - > clock_gate = NULL ;
/* clock control */
for ( i = 0 ; i < pm - > num_clocks ; i + + ) {
pm - > clocks [ i ] = devm_clk_get ( pm - > device , pm - > clk_names [ i ] ) ;
if ( IS_ERR ( pm - > clocks [ i ] ) ) {
mfc_err ( " Failed to get clock: %s \n " ,
pm - > clk_names [ i ] ) ;
return PTR_ERR ( pm - > clocks [ i ] ) ;
2014-07-10 06:00:39 -03:00
}
}
2016-11-16 07:04:57 -02:00
if ( dev - > variant - > use_clock_gating )
pm - > clock_gate = pm - > clocks [ 0 ] ;
2011-06-21 10:51:26 -03:00
pm_runtime_enable ( pm - > device ) ;
atomic_set ( & clk_ref , 0 ) ;
return 0 ;
}
void s5p_mfc_final_pm ( struct s5p_mfc_dev * dev )
{
pm_runtime_disable ( pm - > device ) ;
}
int s5p_mfc_clock_on ( void )
{
atomic_inc ( & clk_ref ) ;
2013-05-28 03:26:16 -03:00
mfc_debug ( 3 , " + %d \n " , atomic_read ( & clk_ref ) ) ;
2016-11-16 07:04:54 -02:00
2016-11-16 07:04:55 -02:00
return clk_enable ( pm - > clock_gate ) ;
2011-06-21 10:51:26 -03:00
}
void s5p_mfc_clock_off ( void )
{
atomic_dec ( & clk_ref ) ;
2013-05-28 03:26:16 -03:00
mfc_debug ( 3 , " - %d \n " , atomic_read ( & clk_ref ) ) ;
2016-11-16 07:04:54 -02:00
2016-11-16 07:04:55 -02:00
clk_disable ( pm - > clock_gate ) ;
2011-06-21 10:51:26 -03:00
}
int s5p_mfc_power_on ( void )
{
2016-11-16 07:04:57 -02:00
int i , ret = 0 ;
2016-11-10 08:31:23 -02:00
ret = pm_runtime_get_sync ( pm - > device ) ;
2016-11-16 07:04:57 -02:00
if ( ret < 0 )
2016-11-10 08:31:23 -02:00
return ret ;
2016-11-16 07:04:54 -02:00
2016-11-16 07:04:57 -02:00
/* clock control */
for ( i = 0 ; i < pm - > num_clocks ; i + + ) {
ret = clk_prepare_enable ( pm - > clocks [ i ] ) ;
if ( ret < 0 ) {
mfc_err ( " clock prepare failed for clock: %s \n " ,
pm - > clk_names [ i ] ) ;
i + + ;
goto err ;
}
2016-11-16 07:04:56 -02:00
}
2016-11-16 07:04:57 -02:00
/* prepare for software clock gating */
clk_disable ( pm - > clock_gate ) ;
2016-11-16 07:04:56 -02:00
2016-11-16 07:04:57 -02:00
return 0 ;
err :
while ( - - i > 0 )
clk_disable_unprepare ( pm - > clocks [ i ] ) ;
pm_runtime_put ( pm - > device ) ;
2016-11-10 08:31:23 -02:00
return ret ;
2011-06-21 10:51:26 -03:00
}
int s5p_mfc_power_off ( void )
{
2016-11-16 07:04:57 -02:00
int i ;
/* finish software clock gating */
clk_enable ( pm - > clock_gate ) ;
2016-11-16 07:04:56 -02:00
2016-11-16 07:04:57 -02:00
for ( i = 0 ; i < pm - > num_clocks ; i + + )
clk_disable_unprepare ( pm - > clocks [ i ] ) ;
2016-11-16 07:04:56 -02:00
2011-06-21 10:51:26 -03:00
return pm_runtime_put_sync ( pm - > device ) ;
}