2019-06-04 05:37:33 -04:00
// SPDX-License-Identifier: GPL-2.0
2016-05-03 07:11:24 -03:00
/*
* Copyright ( c ) 2016 MediaTek Inc .
* Author : Tiffany Lin < tiffany . lin @ mediatek . com >
*/
# include <linux/clk.h>
# include <linux/of_address.h>
# include <linux/of_platform.h>
# include <linux/pm_runtime.h>
# include <soc/mediatek/smi.h>
# include "mtk_vcodec_enc_pm.h"
# include "mtk_vcodec_util.h"
int mtk_vcodec_init_enc_pm ( struct mtk_vcodec_dev * mtkdev )
{
struct device_node * node ;
struct platform_device * pdev ;
struct mtk_vcodec_pm * pm ;
2019-01-17 03:39:20 -02:00
struct mtk_vcodec_clk * enc_clk ;
struct mtk_vcodec_clk_info * clk_info ;
int ret = 0 , i = 0 ;
struct device * dev ;
2016-05-03 07:11:24 -03:00
pdev = mtkdev - > plat_dev ;
pm = & mtkdev - > pm ;
memset ( pm , 0 , sizeof ( struct mtk_vcodec_pm ) ) ;
pm - > mtkdev = mtkdev ;
pm - > dev = & pdev - > dev ;
dev = & pdev - > dev ;
2019-01-17 03:39:20 -02:00
enc_clk = & pm - > venc_clk ;
2016-05-03 07:11:24 -03:00
node = of_parse_phandle ( dev - > of_node , " mediatek,larb " , 0 ) ;
if ( ! node ) {
mtk_v4l2_err ( " no mediatek,larb found " ) ;
2018-10-20 13:50:19 -04:00
return - ENODEV ;
2016-05-03 07:11:24 -03:00
}
pdev = of_find_device_by_node ( node ) ;
2018-10-20 13:50:19 -04:00
of_node_put ( node ) ;
2016-05-03 07:11:24 -03:00
if ( ! pdev ) {
mtk_v4l2_err ( " no mediatek,larb device found " ) ;
2018-10-20 13:50:19 -04:00
return - ENODEV ;
2016-05-03 07:11:24 -03:00
}
pm - > larbvenc = & pdev - > dev ;
node = of_parse_phandle ( dev - > of_node , " mediatek,larb " , 1 ) ;
if ( ! node ) {
mtk_v4l2_err ( " no mediatek,larb found " ) ;
2020-10-09 14:38:03 +02:00
ret = - ENODEV ;
goto put_larbvenc ;
2016-05-03 07:11:24 -03:00
}
pdev = of_find_device_by_node ( node ) ;
2018-10-20 13:50:19 -04:00
of_node_put ( node ) ;
2016-05-03 07:11:24 -03:00
if ( ! pdev ) {
mtk_v4l2_err ( " no mediatek,larb device found " ) ;
2020-10-09 14:38:03 +02:00
ret = - ENODEV ;
goto put_larbvenc ;
2016-05-03 07:11:24 -03:00
}
pm - > larbvenclt = & pdev - > dev ;
pdev = mtkdev - > plat_dev ;
pm - > dev = & pdev - > dev ;
2019-01-17 03:39:20 -02:00
enc_clk - > clk_num = of_property_count_strings ( pdev - > dev . of_node ,
" clock-names " ) ;
if ( enc_clk - > clk_num > 0 ) {
enc_clk - > clk_info = devm_kcalloc ( & pdev - > dev ,
enc_clk - > clk_num , sizeof ( * clk_info ) ,
GFP_KERNEL ) ;
2020-10-09 14:38:03 +02:00
if ( ! enc_clk - > clk_info ) {
ret = - ENOMEM ;
goto put_larbvenclt ;
}
2019-01-17 03:39:20 -02:00
} else {
mtk_v4l2_err ( " Failed to get venc clock count " ) ;
2020-10-09 14:38:03 +02:00
ret = - EINVAL ;
goto put_larbvenclt ;
2016-05-03 07:11:24 -03:00
}
2019-01-17 03:39:20 -02:00
for ( i = 0 ; i < enc_clk - > clk_num ; i + + ) {
clk_info = & enc_clk - > clk_info [ i ] ;
ret = of_property_read_string_index ( pdev - > dev . of_node ,
" clock-names " , i , & clk_info - > clk_name ) ;
if ( ret ) {
mtk_v4l2_err ( " venc failed to get clk name %d " , i ) ;
2020-10-09 14:38:03 +02:00
goto put_larbvenclt ;
2019-01-17 03:39:20 -02:00
}
clk_info - > vcodec_clk = devm_clk_get ( & pdev - > dev ,
clk_info - > clk_name ) ;
if ( IS_ERR ( clk_info - > vcodec_clk ) ) {
mtk_v4l2_err ( " venc devm_clk_get (%d)%s fail " , i ,
clk_info - > clk_name ) ;
2020-10-09 14:38:03 +02:00
ret = PTR_ERR ( clk_info - > vcodec_clk ) ;
goto put_larbvenclt ;
2019-01-17 03:39:20 -02:00
}
2016-05-03 07:11:24 -03:00
}
2020-10-09 14:38:03 +02:00
return 0 ;
put_larbvenclt :
put_device ( pm - > larbvenclt ) ;
put_larbvenc :
put_device ( pm - > larbvenc ) ;
2016-05-03 07:11:24 -03:00
return ret ;
}
void mtk_vcodec_release_enc_pm ( struct mtk_vcodec_dev * mtkdev )
{
2020-10-09 14:38:04 +02:00
put_device ( mtkdev - > pm . larbvenclt ) ;
put_device ( mtkdev - > pm . larbvenc ) ;
2016-05-03 07:11:24 -03:00
}
void mtk_vcodec_enc_clock_on ( struct mtk_vcodec_pm * pm )
{
2019-01-17 03:39:20 -02:00
struct mtk_vcodec_clk * enc_clk = & pm - > venc_clk ;
int ret , i = 0 ;
for ( i = 0 ; i < enc_clk - > clk_num ; i + + ) {
ret = clk_prepare_enable ( enc_clk - > clk_info [ i ] . vcodec_clk ) ;
if ( ret ) {
mtk_v4l2_err ( " venc clk_prepare_enable %d %s fail %d " , i ,
enc_clk - > clk_info [ i ] . clk_name , ret ) ;
goto clkerr ;
}
}
2016-05-03 07:11:24 -03:00
ret = mtk_smi_larb_get ( pm - > larbvenc ) ;
2019-01-17 03:39:20 -02:00
if ( ret ) {
2016-05-03 07:11:24 -03:00
mtk_v4l2_err ( " mtk_smi_larb_get larb3 fail %d " , ret ) ;
2019-01-17 03:39:20 -02:00
goto larbvencerr ;
}
2016-05-03 07:11:24 -03:00
ret = mtk_smi_larb_get ( pm - > larbvenclt ) ;
2019-01-17 03:39:20 -02:00
if ( ret ) {
2016-05-03 07:11:24 -03:00
mtk_v4l2_err ( " mtk_smi_larb_get larb4 fail %d " , ret ) ;
2019-01-17 03:39:20 -02:00
goto larbvenclterr ;
}
return ;
2016-05-03 07:11:24 -03:00
2019-01-17 03:39:20 -02:00
larbvenclterr :
mtk_smi_larb_put ( pm - > larbvenc ) ;
larbvencerr :
clkerr :
for ( i - = 1 ; i > = 0 ; i - - )
clk_disable_unprepare ( enc_clk - > clk_info [ i ] . vcodec_clk ) ;
2016-05-03 07:11:24 -03:00
}
void mtk_vcodec_enc_clock_off ( struct mtk_vcodec_pm * pm )
{
2019-01-17 03:39:20 -02:00
struct mtk_vcodec_clk * enc_clk = & pm - > venc_clk ;
int i = 0 ;
2016-05-03 07:11:24 -03:00
mtk_smi_larb_put ( pm - > larbvenc ) ;
mtk_smi_larb_put ( pm - > larbvenclt ) ;
2019-01-17 03:39:20 -02:00
for ( i = enc_clk - > clk_num - 1 ; i > = 0 ; i - - )
clk_disable_unprepare ( enc_clk - > clk_info [ i ] . vcodec_clk ) ;
2016-05-03 07:11:24 -03:00
}