2014-07-04 13:38:27 +05:30
/*
* Copyright ( C ) 2014 Texas Instruments Ltd
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*
* You should have received a copy of the GNU General Public License along with
* this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <linux/sched.h>
# include <video/omapdss.h>
# include "dss.h"
# include "dss_features.h"
struct dss_video_pll {
struct dss_pll pll ;
struct device * dev ;
void __iomem * clkctrl_base ;
} ;
# define REG_MOD(reg, val, start, end) \
writel_relaxed ( FLD_MOD ( readl_relaxed ( reg ) , val , start , end ) , reg )
static void dss_dpll_enable_scp_clk ( struct dss_video_pll * vpll )
{
REG_MOD ( vpll - > clkctrl_base , 1 , 14 , 14 ) ; /* CIO_CLK_ICG */
}
static void dss_dpll_disable_scp_clk ( struct dss_video_pll * vpll )
{
REG_MOD ( vpll - > clkctrl_base , 0 , 14 , 14 ) ; /* CIO_CLK_ICG */
}
static void dss_dpll_power_enable ( struct dss_video_pll * vpll )
{
REG_MOD ( vpll - > clkctrl_base , 2 , 31 , 30 ) ; /* PLL_POWER_ON_ALL */
/*
* DRA7x PLL CTRL ' s PLL_PWR_STATUS seems to always return 0 ,
* so we have to use fixed delay here .
*/
msleep ( 1 ) ;
}
static void dss_dpll_power_disable ( struct dss_video_pll * vpll )
{
REG_MOD ( vpll - > clkctrl_base , 0 , 31 , 30 ) ; /* PLL_POWER_OFF */
}
static int dss_video_pll_enable ( struct dss_pll * pll )
{
struct dss_video_pll * vpll = container_of ( pll , struct dss_video_pll , pll ) ;
int r ;
r = dss_runtime_get ( ) ;
if ( r )
return r ;
dss_ctrl_pll_enable ( pll - > id , true ) ;
dss_dpll_enable_scp_clk ( vpll ) ;
r = dss_pll_wait_reset_done ( pll ) ;
if ( r )
goto err_reset ;
dss_dpll_power_enable ( vpll ) ;
return 0 ;
err_reset :
dss_dpll_disable_scp_clk ( vpll ) ;
dss_ctrl_pll_enable ( pll - > id , false ) ;
dss_runtime_put ( ) ;
return r ;
}
static void dss_video_pll_disable ( struct dss_pll * pll )
{
struct dss_video_pll * vpll = container_of ( pll , struct dss_video_pll , pll ) ;
dss_dpll_power_disable ( vpll ) ;
dss_dpll_disable_scp_clk ( vpll ) ;
dss_ctrl_pll_enable ( pll - > id , false ) ;
dss_runtime_put ( ) ;
}
static const struct dss_pll_ops dss_pll_ops = {
. enable = dss_video_pll_enable ,
. disable = dss_video_pll_disable ,
. set_config = dss_pll_write_config_type_a ,
} ;
static const struct dss_pll_hw dss_dra7_video_pll_hw = {
. n_max = ( 1 < < 8 ) - 1 ,
. m_max = ( 1 < < 12 ) - 1 ,
. mX_max = ( 1 < < 5 ) - 1 ,
. fint_min = 500000 ,
. fint_max = 2500000 ,
. clkdco_max = 1800000000 ,
. n_msb = 8 ,
. n_lsb = 1 ,
. m_msb = 20 ,
. m_lsb = 9 ,
. mX_msb [ 0 ] = 25 ,
. mX_lsb [ 0 ] = 21 ,
. mX_msb [ 1 ] = 30 ,
. mX_lsb [ 1 ] = 26 ,
2016-05-17 16:31:41 +03:00
. mX_msb [ 2 ] = 4 ,
. mX_lsb [ 2 ] = 0 ,
. mX_msb [ 3 ] = 9 ,
. mX_lsb [ 3 ] = 5 ,
2014-07-04 13:38:27 +05:30
. has_refsel = true ,
} ;
struct dss_pll * dss_video_pll_init ( struct platform_device * pdev , int id ,
struct regulator * regulator )
{
const char * const reg_name [ ] = { " pll1 " , " pll2 " } ;
const char * const clkctrl_name [ ] = { " pll1_clkctrl " , " pll2_clkctrl " } ;
const char * const clkin_name [ ] = { " video1_clk " , " video2_clk " } ;
struct resource * res ;
struct dss_video_pll * vpll ;
void __iomem * pll_base , * clkctrl_base ;
struct clk * clk ;
struct dss_pll * pll ;
int r ;
/* PLL CONTROL */
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM , reg_name [ id ] ) ;
if ( ! res ) {
dev_err ( & pdev - > dev ,
" missing platform resource data for pll%d \n " , id ) ;
return ERR_PTR ( - ENODEV ) ;
}
pll_base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( pll_base ) ) {
dev_err ( & pdev - > dev , " failed to ioremap pll%d reg_name \n " , id ) ;
return ERR_CAST ( pll_base ) ;
}
/* CLOCK CONTROL */
res = platform_get_resource_byname ( pdev , IORESOURCE_MEM ,
clkctrl_name [ id ] ) ;
if ( ! res ) {
dev_err ( & pdev - > dev ,
" missing platform resource data for pll%d \n " , id ) ;
return ERR_PTR ( - ENODEV ) ;
}
clkctrl_base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( clkctrl_base ) ) {
dev_err ( & pdev - > dev , " failed to ioremap pll%d clkctrl \n " , id ) ;
return ERR_CAST ( clkctrl_base ) ;
}
/* CLKIN */
clk = devm_clk_get ( & pdev - > dev , clkin_name [ id ] ) ;
if ( IS_ERR ( clk ) ) {
DSSERR ( " can't get video pll clkin \n " ) ;
return ERR_CAST ( clk ) ;
}
vpll = devm_kzalloc ( & pdev - > dev , sizeof ( * vpll ) , GFP_KERNEL ) ;
if ( ! vpll )
return ERR_PTR ( - ENOMEM ) ;
vpll - > dev = & pdev - > dev ;
vpll - > clkctrl_base = clkctrl_base ;
pll = & vpll - > pll ;
pll - > name = id = = 0 ? " video0 " : " video1 " ;
pll - > id = id = = 0 ? DSS_PLL_VIDEO1 : DSS_PLL_VIDEO2 ;
pll - > clkin = clk ;
pll - > regulator = regulator ;
pll - > base = pll_base ;
pll - > hw = & dss_dra7_video_pll_hw ;
pll - > ops = & dss_pll_ops ;
r = dss_pll_register ( pll ) ;
if ( r )
return ERR_PTR ( r ) ;
return pll ;
}
void dss_video_pll_uninit ( struct dss_pll * pll )
{
dss_pll_unregister ( pll ) ;
}