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
*
* License Terms : GNU General Public License v2
*
* 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>
# include <linux/module.h>
# 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 ) ) ;
}
CLK_OF_DECLARE ( sun8i_a23_apb0 , " allwinner,sun8i-a23-apb0-clk " ,
sun8i_a23_apb0_setup ) ;
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 ;
struct resource * r ;
void __iomem * reg ;
struct clk * clk ;
r = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
reg = devm_ioremap_resource ( & pdev - > dev , r ) ;
if ( IS_ERR ( reg ) )
return PTR_ERR ( reg ) ;
2015-12-03 15:05:30 +08:00
clk = sun8i_a23_apb0_register ( np , reg ) ;
2014-07-03 22:55:41 +08:00
if ( IS_ERR ( clk ) )
return PTR_ERR ( clk ) ;
2015-12-03 15:05:30 +08:00
return 0 ;
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 */ }
} ;
2015-08-28 14:44:14 +02:00
MODULE_DEVICE_TABLE ( of , sun8i_a23_apb0_clk_dt_ids ) ;
2014-07-03 22:55:41 +08:00
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 ,
} ;
module_platform_driver ( sun8i_a23_apb0_clk_driver ) ;
MODULE_AUTHOR ( " Chen-Yu Tsai <wens@csie.org> " ) ;
MODULE_DESCRIPTION ( " Allwinner A23 APB0 clock Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;