2019-05-27 08:55:06 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2014-09-16 18:04:01 +08:00
/*
* Copyright 2014 Chen - Yu Tsai
*
* Chen - Yu Tsai < wens @ csie . org >
*/
2015-06-19 15:00:46 -07:00
# include <linux/clk.h>
2014-09-16 18:04:01 +08:00
# include <linux/clk-provider.h>
2019-04-18 15:20:22 -07:00
# include <linux/io.h>
2016-01-25 21:15:47 +08:00
# include <linux/slab.h>
# include <linux/spinlock.h>
2014-09-16 18:04:01 +08:00
# include <linux/of_address.h>
2016-01-25 21:15:47 +08:00
# define SUN8I_MBUS_ENABLE 31
# define SUN8I_MBUS_MUX_SHIFT 24
# define SUN8I_MBUS_MUX_MASK 0x3
# define SUN8I_MBUS_DIV_SHIFT 0
# define SUN8I_MBUS_DIV_WIDTH 3
# define SUN8I_MBUS_MAX_PARENTS 4
2014-09-16 18:04:01 +08:00
2016-01-25 21:15:47 +08:00
static DEFINE_SPINLOCK ( sun8i_a23_mbus_lock ) ;
2014-09-16 18:04:01 +08:00
2016-01-25 21:15:47 +08:00
static void __init sun8i_a23_mbus_setup ( struct device_node * node )
2014-09-16 18:04:01 +08:00
{
2016-01-25 21:15:47 +08:00
int num_parents = of_clk_get_parent_count ( node ) ;
2016-03-04 09:18:41 -08:00
const char * * parents ;
2016-01-25 21:15:47 +08:00
const char * clk_name = node - > name ;
struct resource res ;
struct clk_divider * div ;
struct clk_gate * gate ;
struct clk_mux * mux ;
struct clk * clk ;
void __iomem * reg ;
int err ;
2014-09-16 18:04:01 +08:00
2016-03-04 09:18:41 -08:00
parents = kcalloc ( num_parents , sizeof ( * parents ) , GFP_KERNEL ) ;
if ( ! parents )
return ;
2016-01-25 21:15:47 +08:00
reg = of_io_request_and_map ( node , 0 , of_node_full_name ( node ) ) ;
2016-07-06 12:21:47 +00:00
if ( IS_ERR ( reg ) ) {
2016-01-25 21:15:47 +08:00
pr_err ( " Could not get registers for sun8i-mbus-clk \n " ) ;
2016-03-04 09:18:41 -08:00
goto err_free_parents ;
2016-01-25 21:15:47 +08:00
}
2014-09-16 18:04:01 +08:00
2016-01-25 21:15:47 +08:00
div = kzalloc ( sizeof ( * div ) , GFP_KERNEL ) ;
if ( ! div )
goto err_unmap ;
2014-09-16 18:04:01 +08:00
2016-01-25 21:15:47 +08:00
mux = kzalloc ( sizeof ( * mux ) , GFP_KERNEL ) ;
if ( ! mux )
goto err_free_div ;
2014-09-16 18:04:01 +08:00
2016-01-25 21:15:47 +08:00
gate = kzalloc ( sizeof ( * gate ) , GFP_KERNEL ) ;
if ( ! gate )
goto err_free_mux ;
2014-09-16 18:04:01 +08:00
2016-01-25 21:15:47 +08:00
of_property_read_string ( node , " clock-output-names " , & clk_name ) ;
of_clk_parent_fill ( node , parents , num_parents ) ;
2014-09-16 18:04:01 +08:00
2016-01-25 21:15:47 +08:00
gate - > reg = reg ;
gate - > bit_idx = SUN8I_MBUS_ENABLE ;
gate - > lock = & sun8i_a23_mbus_lock ;
2014-09-16 18:04:01 +08:00
2016-01-25 21:15:47 +08:00
div - > reg = reg ;
div - > shift = SUN8I_MBUS_DIV_SHIFT ;
div - > width = SUN8I_MBUS_DIV_WIDTH ;
div - > lock = & sun8i_a23_mbus_lock ;
2014-09-16 18:04:01 +08:00
2016-01-25 21:15:47 +08:00
mux - > reg = reg ;
mux - > shift = SUN8I_MBUS_MUX_SHIFT ;
mux - > mask = SUN8I_MBUS_MUX_MASK ;
mux - > lock = & sun8i_a23_mbus_lock ;
2014-11-23 14:38:07 +01:00
2018-01-02 16:50:27 -08:00
/* The MBUS clocks needs to be always enabled */
2016-01-25 21:15:47 +08:00
clk = clk_register_composite ( NULL , clk_name , parents , num_parents ,
& mux - > hw , & clk_mux_ops ,
& div - > hw , & clk_divider_ops ,
& gate - > hw , & clk_gate_ops ,
2018-01-02 16:50:27 -08:00
CLK_IS_CRITICAL ) ;
2016-01-25 21:15:47 +08:00
if ( IS_ERR ( clk ) )
goto err_free_gate ;
2014-11-23 14:38:07 +01:00
2016-01-25 21:15:47 +08:00
err = of_clk_add_provider ( node , of_clk_src_simple_get , clk ) ;
if ( err )
goto err_unregister_clk ;
2014-09-16 18:04:01 +08:00
2016-03-04 09:18:41 -08:00
kfree ( parents ) ; /* parents is deep copied */
2016-01-25 21:15:47 +08:00
return ;
err_unregister_clk :
/* TODO: The composite clock stuff will leak a bit here. */
clk_unregister ( clk ) ;
err_free_gate :
kfree ( gate ) ;
err_free_mux :
kfree ( mux ) ;
err_free_div :
kfree ( div ) ;
err_unmap :
iounmap ( reg ) ;
of_address_to_resource ( node , 0 , & res ) ;
release_mem_region ( res . start , resource_size ( & res ) ) ;
2016-03-04 09:18:41 -08:00
err_free_parents :
kfree ( parents ) ;
2014-09-16 18:04:01 +08:00
}
CLK_OF_DECLARE ( sun8i_a23_mbus , " allwinner,sun8i-a23-mbus-clk " , sun8i_a23_mbus_setup ) ;