2019-05-28 09:57:24 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2014-07-03 22:55:41 +08:00
/*
* Copyright ( C ) 2014 Chen - Yu Tsai
* Author : Chen - Yu Tsai < wens @ csie . org >
*
* Allwinner A23 APB0 clock driver
*
* Based on clk - sun6i - apb0 . c
* Allwinner A31 APB0 clock driver
*
* Copyright ( C ) 2014 Free Electrons
* Author : Boris BREZILLON < boris . brezillon @ free - electrons . com >
*/
# include <linux/clk-provider.h>
2016-07-04 17:12:18 -04:00
# include <linux/init.h>
2019-04-18 15:20:22 -07:00
# include <linux/io.h>
2014-07-03 22:55:41 +08:00
# include <linux/of.h>
2015-12-03 15:05:30 +08:00
# include <linux/of_address.h>
2014-07-03 22:55:41 +08:00
# include <linux/platform_device.h>
2015-12-03 15:05:30 +08:00
static struct clk * sun8i_a23_apb0_register ( struct device_node * node ,
void __iomem * reg )
{
const char * clk_name = node - > name ;
const char * clk_parent ;
struct clk * clk ;
int ret ;
clk_parent = of_clk_get_parent_name ( node , 0 ) ;
if ( ! clk_parent )
return ERR_PTR ( - EINVAL ) ;
of_property_read_string ( node , " clock-output-names " , & clk_name ) ;
/* The A23 APB0 clock is a standard 2 bit wide divider clock */
clk = clk_register_divider ( NULL , clk_name , clk_parent , 0 , reg ,
2016-02-15 17:40:19 +08:00
0 , 2 , 0 , NULL ) ;
2015-12-03 15:05:30 +08:00
if ( IS_ERR ( clk ) )
return clk ;
ret = of_clk_add_provider ( node , of_clk_src_simple_get , clk ) ;
if ( ret )
goto err_unregister ;
return clk ;
err_unregister :
clk_unregister_divider ( clk ) ;
return ERR_PTR ( ret ) ;
}
static void sun8i_a23_apb0_setup ( struct device_node * node )
{
void __iomem * reg ;
struct resource res ;
struct clk * clk ;
reg = of_io_request_and_map ( node , 0 , of_node_full_name ( node ) ) ;
if ( IS_ERR ( reg ) ) {
/*
* This happens with clk nodes instantiated through mfd ,
* as those do not have their resources assigned in the
* device tree . Do not print an error in this case .
*/
if ( PTR_ERR ( reg ) ! = - EINVAL )
pr_err ( " Could not get registers for a23-apb0-clk \n " ) ;
return ;
}
clk = sun8i_a23_apb0_register ( node , reg ) ;
if ( IS_ERR ( clk ) )
goto err_unmap ;
return ;
err_unmap :
iounmap ( reg ) ;
of_address_to_resource ( node , 0 , & res ) ;
release_mem_region ( res . start , resource_size ( & res ) ) ;
}
2016-07-05 18:23:30 +02:00
CLK_OF_DECLARE_DRIVER ( sun8i_a23_apb0 , " allwinner,sun8i-a23-apb0-clk " ,
sun8i_a23_apb0_setup ) ;
2015-12-03 15:05:30 +08:00
2014-07-03 22:55:41 +08:00
static int sun8i_a23_apb0_clk_probe ( struct platform_device * pdev )
{
struct device_node * np = pdev - > dev . of_node ;
void __iomem * reg ;
struct clk * clk ;
2021-09-07 16:53:19 +08:00
reg = devm_platform_ioremap_resource ( pdev , 0 ) ;
2014-07-03 22:55:41 +08:00
if ( IS_ERR ( reg ) )
return PTR_ERR ( reg ) ;
2015-12-03 15:05:30 +08:00
clk = sun8i_a23_apb0_register ( np , reg ) ;
2017-11-29 17:15:43 +01:00
return PTR_ERR_OR_ZERO ( clk ) ;
2014-07-03 22:55:41 +08:00
}
2014-07-28 00:49:43 -03:00
static const struct of_device_id sun8i_a23_apb0_clk_dt_ids [ ] = {
2014-07-03 22:55:41 +08:00
{ . compatible = " allwinner,sun8i-a23-apb0-clk " } ,
{ /* sentinel */ }
} ;
static struct platform_driver sun8i_a23_apb0_clk_driver = {
. driver = {
. name = " sun8i-a23-apb0-clk " ,
. of_match_table = sun8i_a23_apb0_clk_dt_ids ,
} ,
. probe = sun8i_a23_apb0_clk_probe ,
} ;
2016-07-04 17:12:18 -04:00
builtin_platform_driver ( sun8i_a23_apb0_clk_driver ) ;