2019-05-28 10:10:04 -07:00
// SPDX-License-Identifier: GPL-2.0-only
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
/*
* Copyright ( c ) 2012 , NVIDIA CORPORATION . All rights reserved .
*/
# include <linux/kernel.h>
# include <linux/io.h>
# include <linux/err.h>
# include <linux/slab.h>
# include <linux/clk-provider.h>
# include "clk.h"
# define pll_out_override(p) (BIT((p->shift - 6)))
# define div_mask(d) ((1 << (d->width)) - 1)
# define get_mul(d) (1 << d->frac_width)
# define get_max_div(d) div_mask(d)
# define PERIPH_CLK_UART_DIV_ENB BIT(24)
static int get_div ( struct tegra_clk_frac_div * divider , unsigned long rate ,
unsigned long parent_rate )
{
2018-07-12 14:53:00 +03:00
int div ;
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
2018-07-12 14:53:00 +03:00
div = div_frac_get ( rate , parent_rate , divider - > width ,
divider - > frac_width , divider - > flags ) ;
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
2018-07-12 14:53:00 +03:00
if ( div < 0 )
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
return 0 ;
2018-07-12 14:53:00 +03:00
return div ;
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
}
static unsigned long clk_frac_div_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct tegra_clk_frac_div * divider = to_clk_frac_div ( hw ) ;
u32 reg ;
int div , mul ;
u64 rate = parent_rate ;
2019-12-18 21:44:05 +03:00
reg = readl_relaxed ( divider - > reg ) ;
if ( ( divider - > flags & TEGRA_DIVIDER_UART ) & &
! ( reg & PERIPH_CLK_UART_DIV_ENB ) )
return rate ;
div = ( reg > > divider - > shift ) & div_mask ( divider ) ;
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
mul = get_mul ( divider ) ;
div + = mul ;
rate * = mul ;
rate + = div - 1 ;
do_div ( rate , div ) ;
return rate ;
}
static long clk_frac_div_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
struct tegra_clk_frac_div * divider = to_clk_frac_div ( hw ) ;
int div , mul ;
unsigned long output_rate = * prate ;
if ( ! rate )
return output_rate ;
div = get_div ( divider , rate , output_rate ) ;
if ( div < 0 )
return * prate ;
mul = get_mul ( divider ) ;
return DIV_ROUND_UP ( output_rate * mul , div + mul ) ;
}
static int clk_frac_div_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct tegra_clk_frac_div * divider = to_clk_frac_div ( hw ) ;
int div ;
unsigned long flags = 0 ;
u32 val ;
div = get_div ( divider , rate , parent_rate ) ;
if ( div < 0 )
return div ;
if ( divider - > lock )
spin_lock_irqsave ( divider - > lock , flags ) ;
val = readl_relaxed ( divider - > reg ) ;
val & = ~ ( div_mask ( divider ) < < divider - > shift ) ;
val | = div < < divider - > shift ;
if ( divider - > flags & TEGRA_DIVIDER_UART ) {
if ( div )
val | = PERIPH_CLK_UART_DIV_ENB ;
else
val & = ~ PERIPH_CLK_UART_DIV_ENB ;
}
if ( divider - > flags & TEGRA_DIVIDER_FIXED )
val | = pll_out_override ( divider ) ;
writel_relaxed ( val , divider - > reg ) ;
if ( divider - > lock )
spin_unlock_irqrestore ( divider - > lock , flags ) ;
return 0 ;
}
2019-08-16 12:41:48 -07:00
static void clk_divider_restore_context ( struct clk_hw * hw )
{
struct clk_hw * parent = clk_hw_get_parent ( hw ) ;
unsigned long parent_rate = clk_hw_get_rate ( parent ) ;
unsigned long rate = clk_hw_get_rate ( hw ) ;
if ( clk_frac_div_set_rate ( hw , rate , parent_rate ) < 0 )
WARN_ON ( 1 ) ;
}
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
const struct clk_ops tegra_clk_frac_div_ops = {
. recalc_rate = clk_frac_div_recalc_rate ,
. set_rate = clk_frac_div_set_rate ,
. round_rate = clk_frac_div_round_rate ,
2019-08-16 12:41:48 -07:00
. restore_context = clk_divider_restore_context ,
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
} ;
struct clk * tegra_clk_register_divider ( const char * name ,
const char * parent_name , void __iomem * reg ,
unsigned long flags , u8 clk_divider_flags , u8 shift , u8 width ,
u8 frac_width , spinlock_t * lock )
{
struct tegra_clk_frac_div * divider ;
struct clk * clk ;
struct clk_init_data init ;
divider = kzalloc ( sizeof ( * divider ) , GFP_KERNEL ) ;
if ( ! divider ) {
pr_err ( " %s: could not allocate fractional divider clk \n " ,
__func__ ) ;
return ERR_PTR ( - ENOMEM ) ;
}
init . name = name ;
init . ops = & tegra_clk_frac_div_ops ;
init . flags = flags ;
init . parent_names = parent_name ? & parent_name : NULL ;
init . num_parents = parent_name ? 1 : 0 ;
divider - > reg = reg ;
divider - > shift = shift ;
divider - > width = width ;
divider - > frac_width = frac_width ;
divider - > lock = lock ;
divider - > flags = clk_divider_flags ;
/* Data in .init is copied by clk_register(), so stack variable OK */
divider - > hw . init = & init ;
clk = clk_register ( NULL , & divider - > hw ) ;
if ( IS_ERR ( clk ) )
kfree ( divider ) ;
return clk ;
}
2014-07-29 10:17:53 +02:00
static const struct clk_div_table mc_div_table [ ] = {
{ . val = 0 , . div = 2 } ,
{ . val = 1 , . div = 1 } ,
{ . val = 0 , . div = 0 } ,
} ;
struct clk * tegra_clk_register_mc ( const char * name , const char * parent_name ,
void __iomem * reg , spinlock_t * lock )
{
2018-06-04 01:48:05 +03:00
return clk_register_divider_table ( NULL , name , parent_name ,
2019-04-14 22:23:21 +03:00
CLK_IS_CRITICAL ,
reg , 16 , 1 , CLK_DIVIDER_READ_ONLY ,
2018-06-04 01:48:05 +03:00
mc_div_table , lock ) ;
2014-07-29 10:17:53 +02:00
}