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 11:46:20 +04:00
/*
* Copyright ( c ) 2012 , NVIDIA CORPORATION . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2015-06-20 01:00:46 +03:00
# include <linux/clkdev.h>
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 11:46:20 +04:00
# include <linux/clk.h>
# include <linux/clk-provider.h>
2013-01-11 11:46:26 +04:00
# include <linux/of.h>
# include <linux/clk/tegra.h>
2013-11-06 04:33:17 +04:00
# include <linux/reset-controller.h>
2014-07-17 15:17:24 +04:00
# include <soc/tegra/fuse.h>
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 11:46:20 +04:00
# include "clk.h"
2013-08-22 19:44:06 +04:00
# define CLK_OUT_ENB_L 0x010
# define CLK_OUT_ENB_H 0x014
# define CLK_OUT_ENB_U 0x018
# define CLK_OUT_ENB_V 0x360
# define CLK_OUT_ENB_W 0x364
# define CLK_OUT_ENB_X 0x280
2015-03-23 12:52:45 +03:00
# define CLK_OUT_ENB_Y 0x298
2013-08-22 19:44:06 +04:00
# define CLK_OUT_ENB_SET_L 0x320
# define CLK_OUT_ENB_CLR_L 0x324
# define CLK_OUT_ENB_SET_H 0x328
# define CLK_OUT_ENB_CLR_H 0x32c
# define CLK_OUT_ENB_SET_U 0x330
# define CLK_OUT_ENB_CLR_U 0x334
# define CLK_OUT_ENB_SET_V 0x440
# define CLK_OUT_ENB_CLR_V 0x444
# define CLK_OUT_ENB_SET_W 0x448
# define CLK_OUT_ENB_CLR_W 0x44c
# define CLK_OUT_ENB_SET_X 0x284
# define CLK_OUT_ENB_CLR_X 0x288
2015-03-23 12:52:45 +03:00
# define CLK_OUT_ENB_SET_Y 0x29c
# define CLK_OUT_ENB_CLR_Y 0x2a0
2013-08-22 19:44:06 +04:00
# define RST_DEVICES_L 0x004
# define RST_DEVICES_H 0x008
# define RST_DEVICES_U 0x00C
# define RST_DEVICES_V 0x358
# define RST_DEVICES_W 0x35C
# define RST_DEVICES_X 0x28C
2015-03-23 12:52:45 +03:00
# define RST_DEVICES_Y 0x2a4
2013-08-22 19:44:06 +04:00
# define RST_DEVICES_SET_L 0x300
# define RST_DEVICES_CLR_L 0x304
# define RST_DEVICES_SET_H 0x308
# define RST_DEVICES_CLR_H 0x30c
# define RST_DEVICES_SET_U 0x310
# define RST_DEVICES_CLR_U 0x314
# define RST_DEVICES_SET_V 0x430
# define RST_DEVICES_CLR_V 0x434
# define RST_DEVICES_SET_W 0x438
# define RST_DEVICES_CLR_W 0x43c
2013-09-11 18:57:37 +04:00
# define RST_DEVICES_SET_X 0x290
# define RST_DEVICES_CLR_X 0x294
2015-03-23 12:52:45 +03:00
# define RST_DEVICES_SET_Y 0x2a8
# define RST_DEVICES_CLR_Y 0x2ac
2013-08-22 19:44:06 +04:00
2013-01-11 11:46:26 +04:00
/* Global data of Tegra CPU CAR ops */
2013-04-03 18:40:35 +04:00
static struct tegra_cpu_car_ops dummy_car_ops ;
struct tegra_cpu_car_ops * tegra_cpu_car_ops = & dummy_car_ops ;
2013-01-11 11:46:26 +04:00
2013-09-02 16:22:02 +04:00
int * periph_clk_enb_refcnt ;
2013-08-22 19:44:06 +04:00
static int periph_banks ;
2013-09-02 16:22:02 +04:00
static struct clk * * clks ;
static int clk_num ;
static struct clk_onecell_data clk_data ;
2013-08-22 19:44:06 +04:00
2015-05-20 09:27:05 +03:00
/* Handlers for SoC-specific reset lines */
static int ( * special_reset_assert ) ( unsigned long ) ;
static int ( * special_reset_deassert ) ( unsigned long ) ;
static unsigned int num_special_reset ;
2015-04-20 15:38:39 +03:00
static const struct tegra_clk_periph_regs periph_regs [ ] = {
2013-08-22 19:44:06 +04:00
[ 0 ] = {
. enb_reg = CLK_OUT_ENB_L ,
. enb_set_reg = CLK_OUT_ENB_SET_L ,
. enb_clr_reg = CLK_OUT_ENB_CLR_L ,
. rst_reg = RST_DEVICES_L ,
. rst_set_reg = RST_DEVICES_SET_L ,
. rst_clr_reg = RST_DEVICES_CLR_L ,
} ,
[ 1 ] = {
. enb_reg = CLK_OUT_ENB_H ,
. enb_set_reg = CLK_OUT_ENB_SET_H ,
. enb_clr_reg = CLK_OUT_ENB_CLR_H ,
. rst_reg = RST_DEVICES_H ,
. rst_set_reg = RST_DEVICES_SET_H ,
. rst_clr_reg = RST_DEVICES_CLR_H ,
} ,
[ 2 ] = {
. enb_reg = CLK_OUT_ENB_U ,
. enb_set_reg = CLK_OUT_ENB_SET_U ,
. enb_clr_reg = CLK_OUT_ENB_CLR_U ,
. rst_reg = RST_DEVICES_U ,
. rst_set_reg = RST_DEVICES_SET_U ,
. rst_clr_reg = RST_DEVICES_CLR_U ,
} ,
[ 3 ] = {
. enb_reg = CLK_OUT_ENB_V ,
. enb_set_reg = CLK_OUT_ENB_SET_V ,
. enb_clr_reg = CLK_OUT_ENB_CLR_V ,
. rst_reg = RST_DEVICES_V ,
. rst_set_reg = RST_DEVICES_SET_V ,
. rst_clr_reg = RST_DEVICES_CLR_V ,
} ,
[ 4 ] = {
. enb_reg = CLK_OUT_ENB_W ,
. enb_set_reg = CLK_OUT_ENB_SET_W ,
. enb_clr_reg = CLK_OUT_ENB_CLR_W ,
. rst_reg = RST_DEVICES_W ,
. rst_set_reg = RST_DEVICES_SET_W ,
. rst_clr_reg = RST_DEVICES_CLR_W ,
} ,
2013-09-11 18:57:37 +04:00
[ 5 ] = {
. enb_reg = CLK_OUT_ENB_X ,
. enb_set_reg = CLK_OUT_ENB_SET_X ,
. enb_clr_reg = CLK_OUT_ENB_CLR_X ,
. rst_reg = RST_DEVICES_X ,
. rst_set_reg = RST_DEVICES_SET_X ,
. rst_clr_reg = RST_DEVICES_CLR_X ,
} ,
2015-03-23 12:52:45 +03:00
[ 6 ] = {
. enb_reg = CLK_OUT_ENB_Y ,
. enb_set_reg = CLK_OUT_ENB_SET_Y ,
. enb_clr_reg = CLK_OUT_ENB_CLR_Y ,
. rst_reg = RST_DEVICES_Y ,
. rst_set_reg = RST_DEVICES_SET_Y ,
. rst_clr_reg = RST_DEVICES_CLR_Y ,
} ,
2013-08-22 19:44:06 +04:00
} ;
2013-11-06 04:33:17 +04:00
static void __iomem * clk_base ;
static int tegra_clk_rst_assert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
/*
* If peripheral is on the APB bus then we must read the APB bus to
* flush the write operation in apb bus . This will avoid peripheral
* access after disabling clock . Since the reset driver has no
* knowledge of which reset IDs represent which devices , simply do
* this all the time .
*/
tegra_read_chipid ( ) ;
2015-05-20 09:27:05 +03:00
if ( id < periph_banks * 32 ) {
writel_relaxed ( BIT ( id % 32 ) ,
clk_base + periph_regs [ id / 32 ] . rst_set_reg ) ;
return 0 ;
} else if ( id < periph_banks * 32 + num_special_reset ) {
return special_reset_assert ( id ) ;
}
2013-11-06 04:33:17 +04:00
2015-05-20 09:27:05 +03:00
return - EINVAL ;
2013-11-06 04:33:17 +04:00
}
static int tegra_clk_rst_deassert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
2015-05-20 09:27:05 +03:00
if ( id < periph_banks * 32 ) {
writel_relaxed ( BIT ( id % 32 ) ,
clk_base + periph_regs [ id / 32 ] . rst_clr_reg ) ;
return 0 ;
} else if ( id < periph_banks * 32 + num_special_reset ) {
return special_reset_deassert ( id ) ;
}
2013-11-06 04:33:17 +04:00
2015-05-20 09:27:05 +03:00
return - EINVAL ;
2013-11-06 04:33:17 +04:00
}
2015-04-20 15:38:39 +03:00
const struct tegra_clk_periph_regs * get_reg_bank ( int clkid )
2013-08-22 19:44:06 +04:00
{
int reg_bank = clkid / 32 ;
if ( reg_bank < periph_banks )
return & periph_regs [ reg_bank ] ;
else {
WARN_ON ( 1 ) ;
return NULL ;
}
}
2013-11-06 04:33:17 +04:00
struct clk * * __init tegra_clk_init ( void __iomem * regs , int num , int banks )
2013-08-22 19:44:06 +04:00
{
2013-11-06 04:33:17 +04:00
clk_base = regs ;
2013-09-02 16:22:02 +04:00
if ( WARN_ON ( banks > ARRAY_SIZE ( periph_regs ) ) )
return NULL ;
periph_clk_enb_refcnt = kzalloc ( 32 * banks *
sizeof ( * periph_clk_enb_refcnt ) , GFP_KERNEL ) ;
if ( ! periph_clk_enb_refcnt )
return NULL ;
2013-08-22 19:44:06 +04:00
2013-09-02 16:22:02 +04:00
periph_banks = banks ;
2013-08-22 19:44:06 +04:00
2013-09-02 16:22:02 +04:00
clks = kzalloc ( num * sizeof ( struct clk * ) , GFP_KERNEL ) ;
if ( ! clks )
kfree ( periph_clk_enb_refcnt ) ;
clk_num = num ;
return clks ;
2013-08-22 19:44:06 +04:00
}
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 11:46:20 +04:00
void __init tegra_init_dup_clks ( struct tegra_clk_duplicate * dup_list ,
struct clk * clks [ ] , int clk_max )
{
struct clk * clk ;
for ( ; dup_list - > clk_id < clk_max ; dup_list + + ) {
clk = clks [ dup_list - > clk_id ] ;
dup_list - > lookup . clk = clk ;
clkdev_add ( & dup_list - > lookup ) ;
}
}
void __init tegra_init_from_table ( struct tegra_clk_init_table * tbl ,
struct clk * clks [ ] , int clk_max )
{
struct clk * clk ;
for ( ; tbl - > clk_id < clk_max ; tbl + + ) {
clk = clks [ tbl - > clk_id ] ;
2014-09-17 13:34:17 +04:00
if ( IS_ERR_OR_NULL ( clk ) ) {
pr_err ( " %s: invalid entry %ld in clks array for id %d \n " ,
__func__ , PTR_ERR ( clk ) , tbl - > clk_id ) ;
WARN_ON ( 1 ) ;
continue ;
}
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 11:46:20 +04:00
if ( tbl - > parent_id < clk_max ) {
struct clk * parent = clks [ tbl - > parent_id ] ;
if ( clk_set_parent ( clk , parent ) ) {
pr_err ( " %s: Failed to set parent %s of %s \n " ,
__func__ , __clk_get_name ( parent ) ,
__clk_get_name ( clk ) ) ;
WARN_ON ( 1 ) ;
}
}
if ( tbl - > rate )
if ( clk_set_rate ( clk , tbl - > rate ) ) {
pr_err ( " %s: Failed to set rate %lu of %s \n " ,
__func__ , tbl - > rate ,
__clk_get_name ( clk ) ) ;
WARN_ON ( 1 ) ;
}
if ( tbl - > state )
if ( clk_prepare_enable ( clk ) ) {
pr_err ( " %s: Failed to enable %s \n " , __func__ ,
__clk_get_name ( clk ) ) ;
WARN_ON ( 1 ) ;
}
}
}
2013-01-11 11:46:26 +04:00
2016-02-25 12:45:11 +03:00
static const struct reset_control_ops rst_ops = {
2013-11-06 04:33:17 +04:00
. assert = tegra_clk_rst_assert ,
. deassert = tegra_clk_rst_deassert ,
} ;
static struct reset_controller_dev rst_ctlr = {
. ops = & rst_ops ,
. owner = THIS_MODULE ,
. of_reset_n_cells = 1 ,
} ;
2013-09-02 16:22:02 +04:00
void __init tegra_add_of_provider ( struct device_node * np )
{
int i ;
for ( i = 0 ; i < clk_num ; i + + ) {
if ( IS_ERR ( clks [ i ] ) ) {
pr_err
( " Tegra clk %d: register failed with %ld \n " ,
i , PTR_ERR ( clks [ i ] ) ) ;
}
if ( ! clks [ i ] )
clks [ i ] = ERR_PTR ( - EINVAL ) ;
}
clk_data . clks = clks ;
clk_data . clk_num = clk_num ;
of_clk_add_provider ( np , of_clk_src_onecell_get , & clk_data ) ;
2013-11-06 04:33:17 +04:00
rst_ctlr . of_node = np ;
2015-05-20 09:27:05 +03:00
rst_ctlr . nr_resets = periph_banks * 32 + num_special_reset ;
2013-11-06 04:33:17 +04:00
reset_controller_register ( & rst_ctlr ) ;
2013-09-02 16:22:02 +04:00
}
2015-05-20 09:27:05 +03:00
void __init tegra_init_special_resets ( unsigned int num ,
int ( * assert ) ( unsigned long ) ,
int ( * deassert ) ( unsigned long ) )
{
num_special_reset = num ;
special_reset_assert = assert ;
special_reset_deassert = deassert ;
}
2013-10-09 15:47:57 +04:00
void __init tegra_register_devclks ( struct tegra_devclk * dev_clks , int num )
{
int i ;
for ( i = 0 ; i < num ; i + + , dev_clks + + )
clk_register_clkdev ( clks [ dev_clks - > dt_id ] , dev_clks - > con_id ,
dev_clks - > dev_id ) ;
2014-06-26 19:36:13 +04:00
for ( i = 0 ; i < clk_num ; i + + ) {
if ( ! IS_ERR_OR_NULL ( clks [ i ] ) )
clk_register_clkdev ( clks [ i ] , __clk_get_name ( clks [ i ] ) ,
" tegra-clk-debug " ) ;
}
2013-10-09 15:47:57 +04:00
}
2013-10-14 17:47:37 +04:00
struct clk * * __init tegra_lookup_dt_id ( int clk_id ,
struct tegra_clk * tegra_clk )
{
if ( tegra_clk [ clk_id ] . present )
return & clks [ tegra_clk [ clk_id ] . dt_id ] ;
else
return NULL ;
}
2013-03-25 23:22:24 +04:00
tegra_clk_apply_init_table_func tegra_clk_apply_init_table ;
2014-12-16 23:38:27 +03:00
static int __init tegra_clocks_apply_init_table ( void )
2013-03-25 23:22:24 +04:00
{
if ( ! tegra_clk_apply_init_table )
2014-12-16 23:38:27 +03:00
return 0 ;
2013-03-25 23:22:24 +04:00
tegra_clk_apply_init_table ( ) ;
2014-12-16 23:38:27 +03:00
return 0 ;
2013-03-25 23:22:24 +04:00
}
2014-12-16 23:38:27 +03:00
arch_initcall ( tegra_clocks_apply_init_table ) ;