2017-05-05 23:26:09 +08:00
/*
* Copyright ( c ) 2015 Linaro Ltd .
* Author : Pi - Cheng Chen < pi - cheng . chen @ linaro . org >
*
* 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 in the hope that 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 .
*/
# include <linux/clk-provider.h>
# include <linux/mfd/syscon.h>
# include <linux/slab.h>
# include "clk-mtk.h"
# include "clk-cpumux.h"
static inline struct mtk_clk_cpumux * to_mtk_clk_cpumux ( struct clk_hw * _hw )
{
return container_of ( _hw , struct mtk_clk_cpumux , hw ) ;
}
static u8 clk_cpumux_get_parent ( struct clk_hw * hw )
{
struct mtk_clk_cpumux * mux = to_mtk_clk_cpumux ( hw ) ;
unsigned int val ;
regmap_read ( mux - > regmap , mux - > reg , & val ) ;
val > > = mux - > shift ;
val & = mux - > mask ;
return val ;
}
static int clk_cpumux_set_parent ( struct clk_hw * hw , u8 index )
{
struct mtk_clk_cpumux * mux = to_mtk_clk_cpumux ( hw ) ;
u32 mask , val ;
val = index < < mux - > shift ;
mask = mux - > mask < < mux - > shift ;
return regmap_update_bits ( mux - > regmap , mux - > reg , mask , val ) ;
}
static const struct clk_ops clk_cpumux_ops = {
. get_parent = clk_cpumux_get_parent ,
. set_parent = clk_cpumux_set_parent ,
} ;
2018-11-30 00:34:33 -08:00
static struct clk *
2017-05-05 23:26:09 +08:00
mtk_clk_register_cpumux ( const struct mtk_composite * mux ,
struct regmap * regmap )
{
struct mtk_clk_cpumux * cpumux ;
struct clk * clk ;
struct clk_init_data init ;
cpumux = kzalloc ( sizeof ( * cpumux ) , GFP_KERNEL ) ;
if ( ! cpumux )
return ERR_PTR ( - ENOMEM ) ;
init . name = mux - > name ;
init . ops = & clk_cpumux_ops ;
init . parent_names = mux - > parent_names ;
init . num_parents = mux - > num_parents ;
init . flags = mux - > flags ;
cpumux - > reg = mux - > mux_reg ;
cpumux - > shift = mux - > mux_shift ;
cpumux - > mask = BIT ( mux - > mux_width ) - 1 ;
cpumux - > regmap = regmap ;
cpumux - > hw . init = & init ;
clk = clk_register ( NULL , & cpumux - > hw ) ;
if ( IS_ERR ( clk ) )
kfree ( cpumux ) ;
return clk ;
}
2018-11-30 00:34:33 -08:00
int mtk_clk_register_cpumuxes ( struct device_node * node ,
const struct mtk_composite * clks , int num ,
struct clk_onecell_data * clk_data )
2017-05-05 23:26:09 +08:00
{
int i ;
struct clk * clk ;
struct regmap * regmap ;
regmap = syscon_node_to_regmap ( node ) ;
if ( IS_ERR ( regmap ) ) {
2017-07-18 16:42:52 -05:00
pr_err ( " Cannot find regmap for %pOF: %ld \n " , node ,
2017-05-05 23:26:09 +08:00
PTR_ERR ( regmap ) ) ;
return PTR_ERR ( regmap ) ;
}
for ( i = 0 ; i < num ; i + + ) {
const struct mtk_composite * mux = & clks [ i ] ;
clk = mtk_clk_register_cpumux ( mux , regmap ) ;
if ( IS_ERR ( clk ) ) {
pr_err ( " Failed to register clk %s: %ld \n " ,
mux - > name , PTR_ERR ( clk ) ) ;
continue ;
}
clk_data - > clks [ mux - > id ] = clk ;
}
return 0 ;
}