2013-07-18 11:52:33 +03:00
/*
* TI clock support
*
* Copyright ( C ) 2013 Texas Instruments , Inc .
*
* Tero Kristo < t - kristo @ ti . com >
*
* 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 .
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
2015-06-19 15:00:46 -07:00
# include <linux/clk.h>
2013-07-18 11:52:33 +03:00
# include <linux/clk-provider.h>
# include <linux/clkdev.h>
# include <linux/clk/ti.h>
# include <linux/of.h>
2013-10-22 11:39:36 +03:00
# include <linux/of_address.h>
# include <linux/list.h>
2015-04-27 22:23:06 +03:00
# include <linux/regmap.h>
# include <linux/bootmem.h>
2016-09-29 12:00:57 +03:00
# include <linux/device.h>
2013-07-18 11:52:33 +03:00
2014-12-16 18:20:46 +02:00
# include "clock.h"
2013-07-18 11:52:33 +03:00
# undef pr_fmt
# define pr_fmt(fmt) "%s: " fmt, __func__
2013-10-22 11:39:36 +03:00
struct ti_clk_ll_ops * ti_clk_ll_ops ;
2014-09-12 15:01:57 +03:00
static struct device_node * clocks_node_ptr [ CLK_MAX_MEMMAPS ] ;
2013-10-22 11:39:36 +03:00
2015-07-15 12:03:52 -07:00
static struct ti_clk_features ti_clk_features ;
2015-04-27 21:55:42 +03:00
2015-04-27 22:23:06 +03:00
struct clk_iomap {
struct regmap * regmap ;
void __iomem * mem ;
} ;
static struct clk_iomap * clk_memmaps [ CLK_MAX_MEMMAPS ] ;
2017-02-09 11:24:37 +02:00
static void clk_memmap_writel ( u32 val , const struct clk_omap_reg * reg )
2015-04-27 22:23:06 +03:00
{
2017-02-09 11:24:37 +02:00
struct clk_iomap * io = clk_memmaps [ reg - > index ] ;
2015-04-27 22:23:06 +03:00
2017-02-09 11:24:37 +02:00
if ( reg - > ptr )
writel_relaxed ( val , reg - > ptr ) ;
else if ( io - > regmap )
regmap_write ( io - > regmap , reg - > offset , val ) ;
2015-04-27 22:23:06 +03:00
else
2017-02-09 11:24:37 +02:00
writel_relaxed ( val , io - > mem + reg - > offset ) ;
2015-04-27 22:23:06 +03:00
}
2017-07-26 16:47:27 +03:00
static void _clk_rmw ( u32 val , u32 mask , void __iomem * ptr )
{
u32 v ;
v = readl_relaxed ( ptr ) ;
v & = ~ mask ;
v | = val ;
writel_relaxed ( v , ptr ) ;
}
static void clk_memmap_rmw ( u32 val , u32 mask , const struct clk_omap_reg * reg )
{
struct clk_iomap * io = clk_memmaps [ reg - > index ] ;
if ( reg - > ptr ) {
_clk_rmw ( val , mask , reg - > ptr ) ;
} else if ( io - > regmap ) {
regmap_update_bits ( io - > regmap , reg - > offset , mask , val ) ;
} else {
_clk_rmw ( val , mask , io - > mem + reg - > offset ) ;
}
}
2017-02-09 11:24:37 +02:00
static u32 clk_memmap_readl ( const struct clk_omap_reg * reg )
2015-04-27 22:23:06 +03:00
{
u32 val ;
2017-02-09 11:24:37 +02:00
struct clk_iomap * io = clk_memmaps [ reg - > index ] ;
2015-04-27 22:23:06 +03:00
2017-02-09 11:24:37 +02:00
if ( reg - > ptr )
val = readl_relaxed ( reg - > ptr ) ;
else if ( io - > regmap )
regmap_read ( io - > regmap , reg - > offset , & val ) ;
2015-04-27 22:23:06 +03:00
else
2017-02-09 11:24:37 +02:00
val = readl_relaxed ( io - > mem + reg - > offset ) ;
2015-04-27 22:23:06 +03:00
return val ;
}
2015-04-27 21:55:42 +03:00
/**
* ti_clk_setup_ll_ops - setup low level clock operations
* @ ops : low level clock ops descriptor
*
* Sets up low level clock operations for TI clock driver . This is used
* to provide various callbacks for the clock driver towards platform
* specific code . Returns 0 on success , - EBUSY if ll_ops have been
* registered already .
*/
int ti_clk_setup_ll_ops ( struct ti_clk_ll_ops * ops )
{
if ( ti_clk_ll_ops ) {
pr_err ( " Attempt to register ll_ops multiple times. \n " ) ;
return - EBUSY ;
}
ti_clk_ll_ops = ops ;
2015-04-27 22:23:06 +03:00
ops - > clk_readl = clk_memmap_readl ;
ops - > clk_writel = clk_memmap_writel ;
2017-07-26 16:47:27 +03:00
ops - > clk_rmw = clk_memmap_rmw ;
2015-04-27 21:55:42 +03:00
return 0 ;
}
2015-02-27 17:54:14 +02:00
2013-07-18 11:52:33 +03:00
/**
* ti_dt_clocks_register - register DT alias clocks during boot
* @ oclks : list of clocks to register
*
* Register alias or non - standard DT clock entries during boot . By
* default , DT clocks are found based on their node name . If any
* additional con - id / dev - id - > clock mapping is required , use this
* function to list these .
*/
void __init ti_dt_clocks_register ( struct ti_dt_clk oclks [ ] )
{
struct ti_dt_clk * c ;
2018-08-22 11:03:19 +02:00
struct device_node * node , * parent ;
2013-07-18 11:52:33 +03:00
struct clk * clk ;
struct of_phandle_args clkspec ;
2017-09-26 15:34:27 +03:00
char buf [ 64 ] ;
char * ptr ;
char * tags [ 2 ] ;
int i ;
int num_args ;
int ret ;
static bool clkctrl_nodes_missing ;
static bool has_clkctrl_data ;
2013-07-18 11:52:33 +03:00
for ( c = oclks ; c - > node_name ! = NULL ; c + + ) {
2017-09-26 15:34:27 +03:00
strcpy ( buf , c - > node_name ) ;
ptr = buf ;
for ( i = 0 ; i < 2 ; i + + )
tags [ i ] = NULL ;
num_args = 0 ;
while ( * ptr ) {
if ( * ptr = = ' : ' ) {
if ( num_args > = 2 ) {
pr_warn ( " Bad number of tags on %s \n " ,
c - > node_name ) ;
return ;
}
tags [ num_args + + ] = ptr + 1 ;
* ptr = 0 ;
}
ptr + + ;
}
if ( num_args & & clkctrl_nodes_missing )
continue ;
node = of_find_node_by_name ( NULL , buf ) ;
2018-08-22 11:03:19 +02:00
if ( num_args ) {
parent = node ;
node = of_get_child_by_name ( parent , " clk " ) ;
of_node_put ( parent ) ;
}
2013-07-18 11:52:33 +03:00
clkspec . np = node ;
2017-09-26 15:34:27 +03:00
clkspec . args_count = num_args ;
for ( i = 0 ; i < num_args ; i + + ) {
ret = kstrtoint ( tags [ i ] , i ? 10 : 16 , clkspec . args + i ) ;
if ( ret ) {
pr_warn ( " Bad tag in %s at %d: %s \n " ,
c - > node_name , i , tags [ i ] ) ;
2018-08-22 11:03:19 +02:00
of_node_put ( node ) ;
2017-09-26 15:34:27 +03:00
return ;
}
}
2013-07-18 11:52:33 +03:00
clk = of_clk_get_from_provider ( & clkspec ) ;
2018-08-22 11:03:19 +02:00
of_node_put ( node ) ;
2013-07-18 11:52:33 +03:00
if ( ! IS_ERR ( clk ) ) {
c - > lk . clk = clk ;
clkdev_add ( & c - > lk ) ;
} else {
2017-09-26 15:34:27 +03:00
if ( num_args & & ! has_clkctrl_data ) {
if ( of_find_compatible_node ( NULL , NULL ,
" ti,clkctrl " ) ) {
has_clkctrl_data = true ;
} else {
clkctrl_nodes_missing = true ;
pr_warn ( " missing clkctrl nodes, please update your dts. \n " ) ;
continue ;
}
}
pr_warn ( " failed to lookup clock node %s, ret=%ld \n " ,
c - > node_name , PTR_ERR ( clk ) ) ;
2013-07-18 11:52:33 +03:00
}
}
}
2013-10-22 11:39:36 +03:00
struct clk_init_item {
struct device_node * node ;
2017-11-06 09:43:16 +02:00
void * user ;
2013-10-22 11:39:36 +03:00
ti_of_clk_init_cb_t func ;
struct list_head link ;
} ;
static LIST_HEAD ( retry_list ) ;
/**
* ti_clk_retry_init - retries a failed clock init at later phase
* @ node : device not for the clock
2017-11-06 09:43:16 +02:00
* @ user : user data pointer
2013-10-22 11:39:36 +03:00
* @ func : init function to be called for the clock
*
* Adds a failed clock init to the retry list . The retry list is parsed
* once all the other clocks have been initialized .
*/
2017-11-06 09:43:16 +02:00
int __init ti_clk_retry_init ( struct device_node * node , void * user ,
ti_of_clk_init_cb_t func )
2013-10-22 11:39:36 +03:00
{
struct clk_init_item * retry ;
pr_debug ( " %s: adding to retry list... \n " , node - > name ) ;
retry = kzalloc ( sizeof ( * retry ) , GFP_KERNEL ) ;
if ( ! retry )
return - ENOMEM ;
retry - > node = node ;
retry - > func = func ;
2017-11-06 09:43:16 +02:00
retry - > user = user ;
2013-10-22 11:39:36 +03:00
list_add ( & retry - > link , & retry_list ) ;
return 0 ;
}
/**
* ti_clk_get_reg_addr - get register address for a clock register
* @ node : device node for the clock
* @ index : register index from the clock node
2017-02-09 11:24:37 +02:00
* @ reg : pointer to target register struct
2013-10-22 11:39:36 +03:00
*
2017-02-09 11:24:37 +02:00
* Builds clock register address from device tree information , and returns
* the data via the provided output pointer @ reg . Returns 0 on success ,
* negative error value on failure .
2013-10-22 11:39:36 +03:00
*/
2017-02-09 11:24:37 +02:00
int ti_clk_get_reg_addr ( struct device_node * node , int index ,
struct clk_omap_reg * reg )
2013-10-22 11:39:36 +03:00
{
u32 val ;
2014-09-12 15:01:57 +03:00
int i ;
2013-10-22 11:39:36 +03:00
2014-09-12 15:01:57 +03:00
for ( i = 0 ; i < CLK_MAX_MEMMAPS ; i + + ) {
if ( clocks_node_ptr [ i ] = = node - > parent )
break ;
}
if ( i = = CLK_MAX_MEMMAPS ) {
pr_err ( " clk-provider not found for %s! \n " , node - > name ) ;
2017-02-09 11:24:37 +02:00
return - ENOENT ;
2014-09-12 15:01:57 +03:00
}
reg - > index = i ;
2013-10-22 11:39:36 +03:00
if ( of_property_read_u32_index ( node , " reg " , index , & val ) ) {
pr_err ( " %s must have reg[%d]! \n " , node - > name , index ) ;
2017-02-09 11:24:37 +02:00
return - EINVAL ;
2013-10-22 11:39:36 +03:00
}
reg - > offset = val ;
2017-02-09 11:24:37 +02:00
reg - > ptr = NULL ;
2013-10-22 11:39:36 +03:00
2017-02-09 11:24:37 +02:00
return 0 ;
2013-10-22 11:39:36 +03:00
}
2017-07-26 16:47:28 +03:00
void ti_clk_latch ( struct clk_omap_reg * reg , s8 shift )
{
u32 latch ;
if ( shift < 0 )
return ;
latch = 1 < < shift ;
ti_clk_ll_ops - > clk_rmw ( latch , latch , reg ) ;
ti_clk_ll_ops - > clk_rmw ( 0 , latch , reg ) ;
ti_clk_ll_ops - > clk_readl ( reg ) ; /* OCP barrier */
}
2013-10-22 11:39:36 +03:00
/**
2015-04-27 22:23:06 +03:00
* omap2_clk_provider_init - init master clock provider
2013-10-22 11:39:36 +03:00
* @ parent : master node
* @ index : internal index for clk_reg_ops
2015-04-27 22:23:06 +03:00
* @ syscon : syscon regmap pointer for accessing clock registers
* @ mem : iomem pointer for the clock provider memory area , only used if
* syscon is not provided
2013-10-22 11:39:36 +03:00
*
2014-09-12 15:01:57 +03:00
* Initializes a master clock IP block . This basically sets up the
* mapping from clocks node to the memory map index . All the clocks
* are then initialized through the common of_clk_init call , and the
* clocks will access their memory maps based on the node layout .
2015-04-27 22:23:06 +03:00
* Returns 0 in success .
2013-10-22 11:39:36 +03:00
*/
2015-04-27 22:23:06 +03:00
int __init omap2_clk_provider_init ( struct device_node * parent , int index ,
struct regmap * syscon , void __iomem * mem )
2013-10-22 11:39:36 +03:00
{
struct device_node * clocks ;
2015-04-27 22:23:06 +03:00
struct clk_iomap * io ;
2013-10-22 11:39:36 +03:00
/* get clocks for this parent */
clocks = of_get_child_by_name ( parent , " clocks " ) ;
if ( ! clocks ) {
pr_err ( " %s missing 'clocks' child node. \n " , parent - > name ) ;
2015-04-27 22:23:06 +03:00
return - EINVAL ;
2013-10-22 11:39:36 +03:00
}
2014-09-12 15:01:57 +03:00
/* add clocks node info */
clocks_node_ptr [ index ] = clocks ;
2015-04-27 22:23:06 +03:00
io = kzalloc ( sizeof ( * io ) , GFP_KERNEL ) ;
2015-07-15 11:55:42 -07:00
if ( ! io )
return - ENOMEM ;
2015-04-27 22:23:06 +03:00
io - > regmap = syscon ;
io - > mem = mem ;
clk_memmaps [ index ] = io ;
return 0 ;
}
/**
* omap2_clk_legacy_provider_init - initialize a legacy clock provider
* @ index : index for the clock provider
* @ mem : iomem pointer for the clock provider memory area
*
* Initializes a legacy clock provider memory mapping .
*/
void __init omap2_clk_legacy_provider_init ( int index , void __iomem * mem )
{
struct clk_iomap * io ;
io = memblock_virt_alloc ( sizeof ( * io ) , 0 ) ;
io - > mem = mem ;
clk_memmaps [ index ] = io ;
2014-09-12 15:01:57 +03:00
}
2013-10-22 11:39:36 +03:00
2014-09-12 15:01:57 +03:00
/**
* ti_dt_clk_init_retry_clks - init clocks from the retry list
*
* Initializes any clocks that have failed to initialize before ,
* reasons being missing parent node ( s ) during earlier init . This
* typically happens only for DPLLs which need to have both of their
* parent clocks ready during init .
*/
void ti_dt_clk_init_retry_clks ( void )
{
struct clk_init_item * retry ;
struct clk_init_item * tmp ;
int retries = 5 ;
while ( ! list_empty ( & retry_list ) & & retries ) {
list_for_each_entry_safe ( retry , tmp , & retry_list , link ) {
pr_debug ( " retry-init: %s \n " , retry - > node - > name ) ;
2017-11-06 09:43:16 +02:00
retry - > func ( retry - > user , retry - > node ) ;
2014-09-12 15:01:57 +03:00
list_del ( & retry - > link ) ;
kfree ( retry ) ;
}
retries - - ;
2013-10-22 11:39:36 +03:00
}
}
2014-12-16 18:20:46 +02:00
2017-04-19 19:44:56 +02:00
static const struct of_device_id simple_clk_match_table [ ] __initconst = {
{ . compatible = " fixed-clock " } ,
{ . compatible = " fixed-factor-clock " } ,
{ }
} ;
2016-09-29 12:05:00 +03:00
/**
* ti_clk_add_aliases - setup clock aliases
*
* Sets up any missing clock aliases . No return value .
*/
void __init ti_clk_add_aliases ( void )
{
struct device_node * np ;
struct clk * clk ;
for_each_matching_node ( np , simple_clk_match_table ) {
struct of_phandle_args clkspec ;
clkspec . np = np ;
clk = of_clk_get_from_provider ( & clkspec ) ;
ti_clk_add_alias ( NULL , clk , np - > name ) ;
}
}
2015-02-27 17:54:14 +02:00
/**
* ti_clk_setup_features - setup clock features flags
* @ features : features definition to use
*
* Initializes the clock driver features flags based on platform
* provided data . No return value .
*/
void __init ti_clk_setup_features ( struct ti_clk_features * features )
{
memcpy ( & ti_clk_features , features , sizeof ( * features ) ) ;
}
/**
* ti_clk_get_features - get clock driver features flags
*
* Get TI clock driver features description . Returns a pointer
* to the current feature setup .
*/
const struct ti_clk_features * ti_clk_get_features ( void )
{
return & ti_clk_features ;
}
2015-03-03 10:51:01 +02:00
/**
* omap2_clk_enable_init_clocks - prepare & enable a list of clocks
* @ clk_names : ptr to an array of strings of clock names to enable
* @ num_clocks : number of clock names in @ clk_names
*
* Prepare and enable a list of clocks , named by @ clk_names . No
* return value . XXX Deprecated ; only needed until these clocks are
* properly claimed and enabled by the drivers or core code that uses
* them . XXX What code disables & calls clk_put on these clocks ?
*/
void omap2_clk_enable_init_clocks ( const char * * clk_names , u8 num_clocks )
{
struct clk * init_clk ;
int i ;
for ( i = 0 ; i < num_clocks ; i + + ) {
init_clk = clk_get ( NULL , clk_names [ i ] ) ;
if ( WARN ( IS_ERR ( init_clk ) , " could not find init clock %s \n " ,
clk_names [ i ] ) )
continue ;
clk_prepare_enable ( init_clk ) ;
}
}
2016-09-29 12:00:57 +03:00
/**
* ti_clk_add_alias - add a clock alias for a TI clock
* @ dev : device alias for this clock
* @ clk : clock handle to create alias for
* @ con : connection ID for this clock
*
* Creates a clock alias for a TI clock . Allocates the clock lookup entry
* and assigns the data to it . Returns 0 if successful , negative error
* value otherwise .
*/
int ti_clk_add_alias ( struct device * dev , struct clk * clk , const char * con )
{
struct clk_lookup * cl ;
if ( ! clk )
return 0 ;
if ( IS_ERR ( clk ) )
return PTR_ERR ( clk ) ;
cl = kzalloc ( sizeof ( * cl ) , GFP_KERNEL ) ;
if ( ! cl )
return - ENOMEM ;
if ( dev )
cl - > dev_id = dev_name ( dev ) ;
cl - > con_id = con ;
cl - > clk = clk ;
clkdev_add ( cl ) ;
return 0 ;
}
/**
* ti_clk_register - register a TI clock to the common clock framework
* @ dev : device for this clock
* @ hw : hardware clock handle
* @ con : connection ID for this clock
*
* Registers a TI clock to the common clock framework , and adds a clock
* alias for it . Returns a handle to the registered clock if successful ,
* ERR_PTR value in failure .
*/
struct clk * ti_clk_register ( struct device * dev , struct clk_hw * hw ,
const char * con )
{
struct clk * clk ;
int ret ;
clk = clk_register ( dev , hw ) ;
if ( IS_ERR ( clk ) )
return clk ;
ret = ti_clk_add_alias ( dev , clk , con ) ;
if ( ret ) {
clk_unregister ( clk ) ;
return ERR_PTR ( ret ) ;
}
return clk ;
}