2017-12-07 15:57:05 +03:00
// SPDX-License-Identifier: GPL-2.0
//
// Spreadtrum clock infrastructure
//
// Copyright (C) 2017 Spreadtrum, Inc.
// Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
# include <linux/mfd/syscon.h>
# include <linux/module.h>
# include <linux/of_address.h>
# include <linux/of_platform.h>
# include <linux/regmap.h>
# include "common.h"
static const struct regmap_config sprdclk_regmap_config = {
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
. max_register = 0xffff ,
. fast_io = true ,
} ;
static void sprd_clk_set_regmap ( const struct sprd_clk_desc * desc ,
struct regmap * regmap )
{
int i ;
struct sprd_clk_common * cclk ;
for ( i = 0 ; i < desc - > num_clk_clks ; i + + ) {
cclk = desc - > clk_clks [ i ] ;
if ( ! cclk )
continue ;
cclk - > regmap = regmap ;
}
}
int sprd_clk_regmap_init ( struct platform_device * pdev ,
const struct sprd_clk_desc * desc )
{
void __iomem * base ;
2020-03-04 10:27:29 +03:00
struct device * dev = & pdev - > dev ;
2022-07-04 03:47:29 +03:00
struct device_node * node = dev - > of_node , * np ;
2017-12-07 15:57:05 +03:00
struct regmap * regmap ;
if ( of_find_property ( node , " sprd,syscon " , NULL ) ) {
regmap = syscon_regmap_lookup_by_phandle ( node , " sprd,syscon " ) ;
2019-10-08 10:41:38 +03:00
if ( IS_ERR ( regmap ) ) {
2017-12-07 15:57:05 +03:00
pr_err ( " %s: failed to get syscon regmap \n " , __func__ ) ;
return PTR_ERR ( regmap ) ;
}
2022-07-04 03:47:29 +03:00
} else if ( of_device_is_compatible ( np = of_get_parent ( node ) , " syscon " ) | |
( of_node_put ( np ) , 0 ) ) {
regmap = device_node_to_regmap ( np ) ;
of_node_put ( np ) ;
2020-03-04 10:27:29 +03:00
if ( IS_ERR ( regmap ) ) {
dev_err ( dev , " failed to get regmap from its parent. \n " ) ;
return PTR_ERR ( regmap ) ;
}
2017-12-07 15:57:05 +03:00
} else {
2019-10-08 10:41:39 +03:00
base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2019-05-22 04:15:01 +03:00
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2017-12-07 15:57:05 +03:00
regmap = devm_regmap_init_mmio ( & pdev - > dev , base ,
& sprdclk_regmap_config ) ;
2019-05-22 04:15:02 +03:00
if ( IS_ERR ( regmap ) ) {
2017-12-07 15:57:05 +03:00
pr_err ( " failed to init regmap \n " ) ;
return PTR_ERR ( regmap ) ;
}
}
sprd_clk_set_regmap ( desc , regmap ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( sprd_clk_regmap_init ) ;
int sprd_clk_probe ( struct device * dev , struct clk_hw_onecell_data * clkhw )
{
int i , ret ;
struct clk_hw * hw ;
for ( i = 0 ; i < clkhw - > num ; i + + ) {
2019-07-31 22:35:15 +03:00
const char * name ;
2017-12-07 15:57:05 +03:00
hw = clkhw - > hws [ i ] ;
if ( ! hw )
continue ;
2019-07-31 22:35:15 +03:00
name = hw - > init - > name ;
2017-12-07 15:57:05 +03:00
ret = devm_clk_hw_register ( dev , hw ) ;
if ( ret ) {
dev_err ( dev , " Couldn't register clock %d - %s \n " ,
2019-07-31 22:35:15 +03:00
i , name ) ;
2017-12-07 15:57:05 +03:00
return ret ;
}
}
ret = devm_of_clk_add_hw_provider ( dev , of_clk_hw_onecell_get , clkhw ) ;
if ( ret )
dev_err ( dev , " Failed to add clock provider \n " ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( sprd_clk_probe ) ;
MODULE_LICENSE ( " GPL v2 " ) ;