2018-12-01 13:52:13 +03:00
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Copyright 2018 NXP .
*
* This driver supports the SCCG plls found in the imx8m SOCs
*
* Documentation for this SCCG pll can be found at :
* https : //www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834
*/
# include <linux/clk-provider.h>
# include <linux/err.h>
2019-04-19 01:20:22 +03:00
# include <linux/io.h>
2018-12-01 13:52:13 +03:00
# include <linux/iopoll.h>
# include <linux/slab.h>
# include <linux/bitfield.h>
# include "clk.h"
/* PLL CFGs */
# define PLL_CFG0 0x0
# define PLL_CFG1 0x4
# define PLL_CFG2 0x8
# define PLL_DIVF1_MASK GENMASK(18, 13)
# define PLL_DIVF2_MASK GENMASK(12, 7)
# define PLL_DIVR1_MASK GENMASK(27, 25)
# define PLL_DIVR2_MASK GENMASK(24, 19)
2019-02-22 20:07:32 +03:00
# define PLL_DIVQ_MASK GENMASK(6, 1)
2018-12-01 13:52:13 +03:00
# define PLL_REF_MASK GENMASK(2, 0)
# define PLL_LOCK_MASK BIT(31)
# define PLL_PD_MASK BIT(7)
2019-02-22 20:07:32 +03:00
/* These are the specification limits for the SSCG PLL */
# define PLL_REF_MIN_FREQ 25000000UL
# define PLL_REF_MAX_FREQ 235000000UL
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
# define PLL_STAGE1_MIN_FREQ 1600000000UL
# define PLL_STAGE1_MAX_FREQ 2400000000UL
# define PLL_STAGE1_REF_MIN_FREQ 25000000UL
# define PLL_STAGE1_REF_MAX_FREQ 54000000UL
# define PLL_STAGE2_MIN_FREQ 1200000000UL
# define PLL_STAGE2_MAX_FREQ 2400000000UL
# define PLL_STAGE2_REF_MIN_FREQ 54000000UL
# define PLL_STAGE2_REF_MAX_FREQ 75000000UL
# define PLL_OUT_MIN_FREQ 20000000UL
# define PLL_OUT_MAX_FREQ 1200000000UL
# define PLL_DIVR1_MAX 7
# define PLL_DIVR2_MAX 63
# define PLL_DIVF1_MAX 63
# define PLL_DIVF2_MAX 63
# define PLL_DIVQ_MAX 63
# define PLL_BYPASS_NONE 0x0
# define PLL_BYPASS1 0x2
# define PLL_BYPASS2 0x1
# define SSCG_PLL_BYPASS1_MASK BIT(5)
# define SSCG_PLL_BYPASS2_MASK BIT(4)
# define SSCG_PLL_BYPASS_MASK GENMASK(5, 4)
# define PLL_SCCG_LOCK_TIMEOUT 70
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll_setup {
2019-02-22 20:07:32 +03:00
int divr1 , divf1 ;
int divr2 , divf2 ;
int divq ;
int bypass ;
uint64_t vco1 ;
uint64_t vco2 ;
uint64_t fout ;
uint64_t ref ;
uint64_t ref_div1 ;
uint64_t ref_div2 ;
uint64_t fout_request ;
int fout_error ;
} ;
2018-12-01 13:52:13 +03:00
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll {
2018-12-01 13:52:13 +03:00
struct clk_hw hw ;
2019-02-22 20:07:32 +03:00
const struct clk_ops ops ;
void __iomem * base ;
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll_setup setup ;
2019-02-22 20:07:32 +03:00
u8 parent ;
u8 bypass1 ;
u8 bypass2 ;
2018-12-01 13:52:13 +03:00
} ;
2019-12-11 12:25:41 +03:00
# define to_clk_sscg_pll(_hw) container_of(_hw, struct clk_sscg_pll, hw)
2018-12-01 13:52:13 +03:00
2019-12-11 12:25:41 +03:00
static int clk_sscg_pll_wait_lock ( struct clk_sscg_pll * pll )
2018-12-01 13:52:13 +03:00
{
u32 val ;
2019-02-22 20:07:32 +03:00
val = readl_relaxed ( pll - > base + PLL_CFG0 ) ;
/* don't wait for lock if all plls are bypassed */
if ( ! ( val & SSCG_PLL_BYPASS2_MASK ) )
return readl_poll_timeout ( pll - > base , val , val & PLL_LOCK_MASK ,
0 , PLL_SCCG_LOCK_TIMEOUT ) ;
return 0 ;
2018-12-01 13:52:13 +03:00
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_pll2_check_match ( struct clk_sscg_pll_setup * setup ,
struct clk_sscg_pll_setup * temp_setup )
2018-12-01 13:52:13 +03:00
{
2019-02-22 20:07:32 +03:00
int new_diff = temp_setup - > fout - temp_setup - > fout_request ;
int diff = temp_setup - > fout_error ;
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
if ( abs ( diff ) > abs ( new_diff ) ) {
temp_setup - > fout_error = new_diff ;
2019-12-11 12:25:41 +03:00
memcpy ( setup , temp_setup , sizeof ( struct clk_sscg_pll_setup ) ) ;
2019-02-22 20:07:32 +03:00
if ( temp_setup - > fout_request = = temp_setup - > fout )
return 0 ;
}
return - 1 ;
2018-12-01 13:52:13 +03:00
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_divq_lookup ( struct clk_sscg_pll_setup * setup ,
struct clk_sscg_pll_setup * temp_setup )
2018-12-01 13:52:13 +03:00
{
2019-02-22 20:07:32 +03:00
int ret = - EINVAL ;
for ( temp_setup - > divq = 0 ; temp_setup - > divq < = PLL_DIVQ_MAX ;
temp_setup - > divq + + ) {
temp_setup - > vco2 = temp_setup - > vco1 ;
do_div ( temp_setup - > vco2 , temp_setup - > divr2 + 1 ) ;
temp_setup - > vco2 * = 2 ;
temp_setup - > vco2 * = temp_setup - > divf2 + 1 ;
if ( temp_setup - > vco2 > = PLL_STAGE2_MIN_FREQ & &
temp_setup - > vco2 < = PLL_STAGE2_MAX_FREQ ) {
temp_setup - > fout = temp_setup - > vco2 ;
do_div ( temp_setup - > fout , 2 * ( temp_setup - > divq + 1 ) ) ;
2019-12-11 12:25:41 +03:00
ret = clk_sscg_pll2_check_match ( setup , temp_setup ) ;
2019-02-22 20:07:32 +03:00
if ( ! ret ) {
temp_setup - > bypass = PLL_BYPASS1 ;
return ret ;
}
}
}
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
return ret ;
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_divf2_lookup ( struct clk_sscg_pll_setup * setup ,
struct clk_sscg_pll_setup * temp_setup )
2019-02-22 20:07:32 +03:00
{
int ret = - EINVAL ;
for ( temp_setup - > divf2 = 0 ; temp_setup - > divf2 < = PLL_DIVF2_MAX ;
temp_setup - > divf2 + + ) {
2019-12-11 12:25:41 +03:00
ret = clk_sscg_divq_lookup ( setup , temp_setup ) ;
2019-02-22 20:07:32 +03:00
if ( ! ret )
return ret ;
}
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
return ret ;
2018-12-01 13:52:13 +03:00
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_divr2_lookup ( struct clk_sscg_pll_setup * setup ,
struct clk_sscg_pll_setup * temp_setup )
2018-12-01 13:52:13 +03:00
{
2019-02-22 20:07:32 +03:00
int ret = - EINVAL ;
for ( temp_setup - > divr2 = 0 ; temp_setup - > divr2 < = PLL_DIVR2_MAX ;
temp_setup - > divr2 + + ) {
temp_setup - > ref_div2 = temp_setup - > vco1 ;
do_div ( temp_setup - > ref_div2 , temp_setup - > divr2 + 1 ) ;
if ( temp_setup - > ref_div2 > = PLL_STAGE2_REF_MIN_FREQ & &
temp_setup - > ref_div2 < = PLL_STAGE2_REF_MAX_FREQ ) {
2019-12-11 12:25:41 +03:00
ret = clk_sscg_divf2_lookup ( setup , temp_setup ) ;
2019-02-22 20:07:32 +03:00
if ( ! ret )
return ret ;
}
}
return ret ;
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_pll2_find_setup ( struct clk_sscg_pll_setup * setup ,
struct clk_sscg_pll_setup * temp_setup ,
2019-02-22 20:07:32 +03:00
uint64_t ref )
{
2020-02-21 09:59:36 +03:00
int ret ;
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
if ( ref < PLL_STAGE1_MIN_FREQ | | ref > PLL_STAGE1_MAX_FREQ )
2020-02-21 09:59:36 +03:00
return - EINVAL ;
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
temp_setup - > vco1 = ref ;
2018-12-01 13:52:13 +03:00
2019-12-11 12:25:41 +03:00
ret = clk_sscg_divr2_lookup ( setup , temp_setup ) ;
2019-02-22 20:07:32 +03:00
return ret ;
2018-12-01 13:52:13 +03:00
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_divf1_lookup ( struct clk_sscg_pll_setup * setup ,
struct clk_sscg_pll_setup * temp_setup )
2018-12-01 13:52:13 +03:00
{
2019-02-22 20:07:32 +03:00
int ret = - EINVAL ;
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
for ( temp_setup - > divf1 = 0 ; temp_setup - > divf1 < = PLL_DIVF1_MAX ;
temp_setup - > divf1 + + ) {
uint64_t vco1 = temp_setup - > ref ;
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
do_div ( vco1 , temp_setup - > divr1 + 1 ) ;
vco1 * = 2 ;
vco1 * = temp_setup - > divf1 + 1 ;
2018-12-01 13:52:13 +03:00
2019-12-11 12:25:41 +03:00
ret = clk_sscg_pll2_find_setup ( setup , temp_setup , vco1 ) ;
2019-02-22 20:07:32 +03:00
if ( ! ret ) {
temp_setup - > bypass = PLL_BYPASS_NONE ;
return ret ;
}
}
return ret ;
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_divr1_lookup ( struct clk_sscg_pll_setup * setup ,
struct clk_sscg_pll_setup * temp_setup )
2019-02-22 20:07:32 +03:00
{
int ret = - EINVAL ;
for ( temp_setup - > divr1 = 0 ; temp_setup - > divr1 < = PLL_DIVR1_MAX ;
temp_setup - > divr1 + + ) {
temp_setup - > ref_div1 = temp_setup - > ref ;
do_div ( temp_setup - > ref_div1 , temp_setup - > divr1 + 1 ) ;
if ( temp_setup - > ref_div1 > = PLL_STAGE1_REF_MIN_FREQ & &
temp_setup - > ref_div1 < = PLL_STAGE1_REF_MAX_FREQ ) {
2019-12-11 12:25:41 +03:00
ret = clk_sscg_divf1_lookup ( setup , temp_setup ) ;
2019-02-22 20:07:32 +03:00
if ( ! ret )
return ret ;
}
}
return ret ;
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_pll1_find_setup ( struct clk_sscg_pll_setup * setup ,
struct clk_sscg_pll_setup * temp_setup ,
2019-02-22 20:07:32 +03:00
uint64_t ref )
{
2020-02-21 09:59:36 +03:00
int ret ;
2019-02-22 20:07:32 +03:00
if ( ref < PLL_REF_MIN_FREQ | | ref > PLL_REF_MAX_FREQ )
2020-02-21 09:59:36 +03:00
return - EINVAL ;
2019-02-22 20:07:32 +03:00
temp_setup - > ref = ref ;
2019-12-11 12:25:41 +03:00
ret = clk_sscg_divr1_lookup ( setup , temp_setup ) ;
2019-02-22 20:07:32 +03:00
return ret ;
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_pll_find_setup ( struct clk_sscg_pll_setup * setup ,
2019-02-22 20:07:32 +03:00
uint64_t prate ,
uint64_t rate , int try_bypass )
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll_setup temp_setup ;
2019-02-22 20:07:32 +03:00
int ret = - EINVAL ;
2019-12-11 12:25:41 +03:00
memset ( & temp_setup , 0 , sizeof ( struct clk_sscg_pll_setup ) ) ;
memset ( setup , 0 , sizeof ( struct clk_sscg_pll_setup ) ) ;
2019-02-22 20:07:32 +03:00
temp_setup . fout_error = PLL_OUT_MAX_FREQ ;
temp_setup . fout_request = rate ;
switch ( try_bypass ) {
case PLL_BYPASS2 :
if ( prate = = rate ) {
setup - > bypass = PLL_BYPASS2 ;
setup - > fout = rate ;
ret = 0 ;
}
break ;
case PLL_BYPASS1 :
2019-12-11 12:25:41 +03:00
ret = clk_sscg_pll2_find_setup ( setup , & temp_setup , prate ) ;
2019-02-22 20:07:32 +03:00
break ;
case PLL_BYPASS_NONE :
2019-12-11 12:25:41 +03:00
ret = clk_sscg_pll1_find_setup ( setup , & temp_setup , prate ) ;
2019-02-22 20:07:32 +03:00
break ;
}
return ret ;
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_pll_is_prepared ( struct clk_hw * hw )
2019-02-22 20:07:32 +03:00
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll * pll = to_clk_sscg_pll ( hw ) ;
2019-02-22 20:07:32 +03:00
u32 val = readl_relaxed ( pll - > base + PLL_CFG0 ) ;
return ( val & PLL_PD_MASK ) ? 0 : 1 ;
2018-12-01 13:52:13 +03:00
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_pll_prepare ( struct clk_hw * hw )
2018-12-01 13:52:13 +03:00
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll * pll = to_clk_sscg_pll ( hw ) ;
2018-12-01 13:52:13 +03:00
u32 val ;
val = readl_relaxed ( pll - > base + PLL_CFG0 ) ;
val & = ~ PLL_PD_MASK ;
writel_relaxed ( val , pll - > base + PLL_CFG0 ) ;
2019-12-11 12:25:41 +03:00
return clk_sscg_pll_wait_lock ( pll ) ;
2018-12-01 13:52:13 +03:00
}
2019-12-11 12:25:41 +03:00
static void clk_sscg_pll_unprepare ( struct clk_hw * hw )
2018-12-01 13:52:13 +03:00
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll * pll = to_clk_sscg_pll ( hw ) ;
2018-12-01 13:52:13 +03:00
u32 val ;
val = readl_relaxed ( pll - > base + PLL_CFG0 ) ;
val | = PLL_PD_MASK ;
writel_relaxed ( val , pll - > base + PLL_CFG0 ) ;
}
2019-12-11 12:25:41 +03:00
static unsigned long clk_sscg_pll_recalc_rate ( struct clk_hw * hw ,
2018-12-01 13:52:13 +03:00
unsigned long parent_rate )
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll * pll = to_clk_sscg_pll ( hw ) ;
2019-02-22 20:07:32 +03:00
u32 val , divr1 , divf1 , divr2 , divf2 , divq ;
2018-12-01 13:52:13 +03:00
u64 temp64 ;
val = readl_relaxed ( pll - > base + PLL_CFG2 ) ;
divr1 = FIELD_GET ( PLL_DIVR1_MASK , val ) ;
divr2 = FIELD_GET ( PLL_DIVR2_MASK , val ) ;
divf1 = FIELD_GET ( PLL_DIVF1_MASK , val ) ;
divf2 = FIELD_GET ( PLL_DIVF2_MASK , val ) ;
2019-02-22 20:07:32 +03:00
divq = FIELD_GET ( PLL_DIVQ_MASK , val ) ;
temp64 = parent_rate ;
2019-04-18 14:12:11 +03:00
val = readl ( pll - > base + PLL_CFG0 ) ;
2019-02-22 20:07:32 +03:00
if ( val & SSCG_PLL_BYPASS2_MASK ) {
temp64 = parent_rate ;
} else if ( val & SSCG_PLL_BYPASS1_MASK ) {
temp64 * = divf2 ;
do_div ( temp64 , ( divr2 + 1 ) * ( divq + 1 ) ) ;
} else {
temp64 * = 2 ;
temp64 * = ( divf1 + 1 ) * ( divf2 + 1 ) ;
do_div ( temp64 , ( divr1 + 1 ) * ( divr2 + 1 ) * ( divq + 1 ) ) ;
}
2018-12-01 13:52:13 +03:00
return temp64 ;
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_pll_set_rate ( struct clk_hw * hw , unsigned long rate ,
2019-02-22 20:07:32 +03:00
unsigned long parent_rate )
2018-12-01 13:52:13 +03:00
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll * pll = to_clk_sscg_pll ( hw ) ;
struct clk_sscg_pll_setup * setup = & pll - > setup ;
2019-02-22 20:07:32 +03:00
u32 val ;
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
/* set bypass here too since the parent might be the same */
2019-04-18 14:12:11 +03:00
val = readl ( pll - > base + PLL_CFG0 ) ;
2019-02-22 20:07:32 +03:00
val & = ~ SSCG_PLL_BYPASS_MASK ;
val | = FIELD_PREP ( SSCG_PLL_BYPASS_MASK , setup - > bypass ) ;
2019-04-18 14:12:11 +03:00
writel ( val , pll - > base + PLL_CFG0 ) ;
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
val = readl_relaxed ( pll - > base + PLL_CFG2 ) ;
val & = ~ ( PLL_DIVF1_MASK | PLL_DIVF2_MASK ) ;
val & = ~ ( PLL_DIVR1_MASK | PLL_DIVR2_MASK | PLL_DIVQ_MASK ) ;
val | = FIELD_PREP ( PLL_DIVF1_MASK , setup - > divf1 ) ;
val | = FIELD_PREP ( PLL_DIVF2_MASK , setup - > divf2 ) ;
val | = FIELD_PREP ( PLL_DIVR1_MASK , setup - > divr1 ) ;
val | = FIELD_PREP ( PLL_DIVR2_MASK , setup - > divr2 ) ;
val | = FIELD_PREP ( PLL_DIVQ_MASK , setup - > divq ) ;
writel_relaxed ( val , pll - > base + PLL_CFG2 ) ;
2018-12-01 13:52:13 +03:00
2019-12-11 12:25:41 +03:00
return clk_sscg_pll_wait_lock ( pll ) ;
2018-12-01 13:52:13 +03:00
}
2019-12-11 12:25:41 +03:00
static u8 clk_sscg_pll_get_parent ( struct clk_hw * hw )
2018-12-01 13:52:13 +03:00
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll * pll = to_clk_sscg_pll ( hw ) ;
2018-12-01 13:52:13 +03:00
u32 val ;
2019-02-22 20:07:32 +03:00
u8 ret = pll - > parent ;
2019-04-18 14:12:11 +03:00
val = readl ( pll - > base + PLL_CFG0 ) ;
2019-02-22 20:07:32 +03:00
if ( val & SSCG_PLL_BYPASS2_MASK )
ret = pll - > bypass2 ;
else if ( val & SSCG_PLL_BYPASS1_MASK )
ret = pll - > bypass1 ;
return ret ;
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_pll_set_parent ( struct clk_hw * hw , u8 index )
2019-02-22 20:07:32 +03:00
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll * pll = to_clk_sscg_pll ( hw ) ;
2019-02-22 20:07:32 +03:00
u32 val ;
2018-12-01 13:52:13 +03:00
2019-04-18 14:12:11 +03:00
val = readl ( pll - > base + PLL_CFG0 ) ;
2019-02-22 20:07:32 +03:00
val & = ~ SSCG_PLL_BYPASS_MASK ;
val | = FIELD_PREP ( SSCG_PLL_BYPASS_MASK , pll - > setup . bypass ) ;
2019-04-18 14:12:11 +03:00
writel ( val , pll - > base + PLL_CFG0 ) ;
2018-12-01 13:52:13 +03:00
2019-12-11 12:25:41 +03:00
return clk_sscg_pll_wait_lock ( pll ) ;
2019-02-22 20:07:32 +03:00
}
2018-12-01 13:52:13 +03:00
2019-12-11 12:25:41 +03:00
static int __clk_sscg_pll_determine_rate ( struct clk_hw * hw ,
2019-02-22 20:07:32 +03:00
struct clk_rate_request * req ,
uint64_t min ,
uint64_t max ,
uint64_t rate ,
int bypass )
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll * pll = to_clk_sscg_pll ( hw ) ;
struct clk_sscg_pll_setup * setup = & pll - > setup ;
2019-02-22 20:07:32 +03:00
struct clk_hw * parent_hw = NULL ;
int bypass_parent_index ;
2020-02-21 09:59:36 +03:00
int ret ;
2019-02-22 20:07:32 +03:00
req - > max_rate = max ;
req - > min_rate = min ;
switch ( bypass ) {
case PLL_BYPASS2 :
bypass_parent_index = pll - > bypass2 ;
break ;
case PLL_BYPASS1 :
bypass_parent_index = pll - > bypass1 ;
break ;
default :
bypass_parent_index = pll - > parent ;
break ;
}
parent_hw = clk_hw_get_parent_by_index ( hw , bypass_parent_index ) ;
ret = __clk_determine_rate ( parent_hw , req ) ;
if ( ! ret ) {
2019-12-11 12:25:41 +03:00
ret = clk_sscg_pll_find_setup ( setup , req - > rate ,
2019-02-22 20:07:32 +03:00
rate , bypass ) ;
}
req - > best_parent_hw = parent_hw ;
req - > best_parent_rate = req - > rate ;
req - > rate = setup - > fout ;
2018-12-01 13:52:13 +03:00
2019-02-22 20:07:32 +03:00
return ret ;
2018-12-01 13:52:13 +03:00
}
2019-12-11 12:25:41 +03:00
static int clk_sscg_pll_determine_rate ( struct clk_hw * hw ,
2019-02-22 20:07:32 +03:00
struct clk_rate_request * req )
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll * pll = to_clk_sscg_pll ( hw ) ;
struct clk_sscg_pll_setup * setup = & pll - > setup ;
2019-02-22 20:07:32 +03:00
uint64_t rate = req - > rate ;
uint64_t min = req - > min_rate ;
uint64_t max = req - > max_rate ;
2020-02-21 09:59:36 +03:00
int ret ;
2019-02-22 20:07:32 +03:00
if ( rate < PLL_OUT_MIN_FREQ | | rate > PLL_OUT_MAX_FREQ )
2020-02-21 09:59:36 +03:00
return - EINVAL ;
2019-02-22 20:07:32 +03:00
2019-12-11 12:25:41 +03:00
ret = __clk_sscg_pll_determine_rate ( hw , req , req - > rate , req - > rate ,
2019-02-22 20:07:32 +03:00
rate , PLL_BYPASS2 ) ;
if ( ! ret )
return ret ;
2019-12-11 12:25:41 +03:00
ret = __clk_sscg_pll_determine_rate ( hw , req , PLL_STAGE1_REF_MIN_FREQ ,
2019-02-22 20:07:32 +03:00
PLL_STAGE1_REF_MAX_FREQ , rate ,
PLL_BYPASS1 ) ;
if ( ! ret )
return ret ;
2019-12-11 12:25:41 +03:00
ret = __clk_sscg_pll_determine_rate ( hw , req , PLL_REF_MIN_FREQ ,
2019-02-22 20:07:32 +03:00
PLL_REF_MAX_FREQ , rate ,
PLL_BYPASS_NONE ) ;
if ( ! ret )
return ret ;
if ( setup - > fout > = min & & setup - > fout < = max )
ret = 0 ;
return ret ;
}
2018-12-01 13:52:13 +03:00
2019-12-11 12:25:41 +03:00
static const struct clk_ops clk_sscg_pll_ops = {
. prepare = clk_sscg_pll_prepare ,
. unprepare = clk_sscg_pll_unprepare ,
. is_prepared = clk_sscg_pll_is_prepared ,
. recalc_rate = clk_sscg_pll_recalc_rate ,
. set_rate = clk_sscg_pll_set_rate ,
. set_parent = clk_sscg_pll_set_parent ,
. get_parent = clk_sscg_pll_get_parent ,
. determine_rate = clk_sscg_pll_determine_rate ,
2018-12-01 13:52:13 +03:00
} ;
2019-12-11 12:25:46 +03:00
struct clk_hw * imx_clk_hw_sscg_pll ( const char * name ,
2019-02-22 20:07:32 +03:00
const char * const * parent_names ,
u8 num_parents ,
u8 parent , u8 bypass1 , u8 bypass2 ,
2018-12-01 13:52:13 +03:00
void __iomem * base ,
2019-02-22 20:07:32 +03:00
unsigned long flags )
2018-12-01 13:52:13 +03:00
{
2019-12-11 12:25:41 +03:00
struct clk_sscg_pll * pll ;
2018-12-01 13:52:13 +03:00
struct clk_init_data init ;
struct clk_hw * hw ;
int ret ;
pll = kzalloc ( sizeof ( * pll ) , GFP_KERNEL ) ;
if ( ! pll )
return ERR_PTR ( - ENOMEM ) ;
2019-02-22 20:07:32 +03:00
pll - > parent = parent ;
pll - > bypass1 = bypass1 ;
pll - > bypass2 = bypass2 ;
pll - > base = base ;
2018-12-01 13:52:13 +03:00
init . name = name ;
2019-12-11 12:25:41 +03:00
init . ops = & clk_sscg_pll_ops ;
2019-02-22 20:07:32 +03:00
init . flags = flags ;
init . parent_names = parent_names ;
init . num_parents = num_parents ;
2018-12-01 13:52:13 +03:00
pll - > base = base ;
pll - > hw . init = & init ;
hw = & pll - > hw ;
ret = clk_hw_register ( NULL , hw ) ;
if ( ret ) {
kfree ( pll ) ;
return ERR_PTR ( ret ) ;
}
2019-12-11 12:25:46 +03:00
return hw ;
2018-12-01 13:52:13 +03:00
}