2019-05-29 07:17:56 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2017-04-04 17:50:57 +08:00
/*
* Copyright ( c ) 2016 Icenowy Zheng < icenowy @ aosc . xyz >
*/
# include <linux/clk-provider.h>
2021-11-18 21:33:36 -06:00
# include <linux/module.h>
2023-07-18 08:31:43 -06:00
# include <linux/of.h>
2017-04-04 17:50:57 +08:00
# include <linux/platform_device.h>
# include "ccu_common.h"
# include "ccu_reset.h"
# include "ccu_div.h"
# include "ccu_gate.h"
# include "ccu_mp.h"
# include "ccu_nm.h"
# include "ccu-sun8i-r.h"
2019-05-03 11:18:24 +08:00
static const struct clk_parent_data ar100_parents [ ] = {
{ . fw_name = " losc " } ,
{ . fw_name = " hosc " } ,
{ . fw_name = " pll-periph " } ,
{ . fw_name = " iosc " } ,
} ;
2017-05-19 15:06:08 +08:00
static const struct ccu_mux_var_prediv ar100_predivs [ ] = {
{ . index = 2 , . shift = 8 , . width = 5 } ,
} ;
2017-04-04 17:50:57 +08:00
static struct ccu_div ar100_clk = {
. div = _SUNXI_CCU_DIV_FLAGS ( 4 , 2 , CLK_DIVIDER_POWER_OF_TWO ) ,
. mux = {
. shift = 16 ,
. width = 2 ,
2017-05-19 15:06:08 +08:00
. var_predivs = ar100_predivs ,
. n_var_predivs = ARRAY_SIZE ( ar100_predivs ) ,
2017-04-04 17:50:57 +08:00
} ,
. common = {
. reg = 0x00 ,
. features = CCU_FEATURE_VARIABLE_PREDIV ,
2019-05-03 11:18:24 +08:00
. hw . init = CLK_HW_INIT_PARENTS_DATA ( " ar100 " ,
ar100_parents ,
& ccu_div_ops ,
0 ) ,
2017-05-26 16:00:24 +08:00
} ,
} ;
2019-05-03 11:29:42 +08:00
static CLK_FIXED_FACTOR_HW ( ahb0_clk , " ahb0 " , & ar100_clk . common . hw , 1 , 1 , 0 ) ;
2017-04-04 17:50:57 +08:00
2019-12-28 20:59:20 -06:00
static SUNXI_CCU_M ( apb0_clk , " apb0 " , " ahb0 " , 0x0c , 0 , 2 , 0 ) ;
2017-05-26 16:00:24 +08:00
2019-05-03 19:31:04 +08:00
/*
* Define the parent as an array that can be reused to save space
* instead of having compound literals for each gate . Also have it
* non - const so we can change it on the A83T .
*/
static const struct clk_hw * apb0_gate_parent [ ] = { & apb0_clk . common . hw } ;
static SUNXI_CCU_GATE_HWS ( apb0_pio_clk , " apb0-pio " ,
apb0_gate_parent , 0x28 , BIT ( 0 ) , 0 ) ;
static SUNXI_CCU_GATE_HWS ( apb0_ir_clk , " apb0-ir " ,
apb0_gate_parent , 0x28 , BIT ( 1 ) , 0 ) ;
static SUNXI_CCU_GATE_HWS ( apb0_timer_clk , " apb0-timer " ,
apb0_gate_parent , 0x28 , BIT ( 2 ) , 0 ) ;
static SUNXI_CCU_GATE_HWS ( apb0_rsb_clk , " apb0-rsb " ,
apb0_gate_parent , 0x28 , BIT ( 3 ) , 0 ) ;
static SUNXI_CCU_GATE_HWS ( apb0_uart_clk , " apb0-uart " ,
apb0_gate_parent , 0x28 , BIT ( 4 ) , 0 ) ;
static SUNXI_CCU_GATE_HWS ( apb0_i2c_clk , " apb0-i2c " ,
apb0_gate_parent , 0x28 , BIT ( 6 ) , 0 ) ;
static SUNXI_CCU_GATE_HWS ( apb0_twd_clk , " apb0-twd " ,
apb0_gate_parent , 0x28 , BIT ( 7 ) , 0 ) ;
2017-04-04 17:50:57 +08:00
2017-04-08 00:19:03 +08:00
static const char * const r_mod0_default_parents [ ] = { " osc32k " , " osc24M " } ;
2017-04-04 17:50:57 +08:00
static SUNXI_CCU_MP_WITH_MUX_GATE ( ir_clk , " ir " ,
r_mod0_default_parents , 0x54 ,
0 , 4 , /* M */
16 , 2 , /* P */
24 , 2 , /* mux */
BIT ( 31 ) , /* gate */
0 ) ;
2019-05-03 11:18:24 +08:00
static const struct clk_parent_data a83t_r_mod0_parents [ ] = {
{ . fw_name = " iosc " } ,
{ . fw_name = " hosc " } ,
} ;
2017-05-26 16:00:24 +08:00
static const struct ccu_mux_fixed_prediv a83t_ir_predivs [ ] = {
{ . index = 0 , . div = 16 } ,
} ;
static struct ccu_mp a83t_ir_clk = {
. enable = BIT ( 31 ) ,
. m = _SUNXI_CCU_DIV ( 0 , 4 ) ,
. p = _SUNXI_CCU_DIV ( 16 , 2 ) ,
. mux = {
. shift = 24 ,
. width = 2 ,
. fixed_predivs = a83t_ir_predivs ,
. n_predivs = ARRAY_SIZE ( a83t_ir_predivs ) ,
} ,
. common = {
. reg = 0x54 ,
. features = CCU_FEATURE_VARIABLE_PREDIV ,
2019-05-03 11:18:24 +08:00
. hw . init = CLK_HW_INIT_PARENTS_DATA ( " ir " ,
a83t_r_mod0_parents ,
& ccu_mp_ops ,
0 ) ,
2017-05-26 16:00:24 +08:00
} ,
} ;
2022-05-30 23:35:39 -05:00
static struct ccu_common * sun8i_r_ccu_clks [ ] = {
2017-04-04 17:50:57 +08:00
& ar100_clk . common ,
& apb0_clk . common ,
& apb0_pio_clk . common ,
& apb0_ir_clk . common ,
& apb0_timer_clk . common ,
& apb0_rsb_clk . common ,
& apb0_uart_clk . common ,
& apb0_i2c_clk . common ,
& apb0_twd_clk . common ,
& ir_clk . common ,
2022-05-30 23:35:39 -05:00
& a83t_ir_clk . common ,
2017-04-04 17:50:57 +08:00
} ;
2017-05-26 16:00:24 +08:00
static struct clk_hw_onecell_data sun8i_a83t_r_hw_clks = {
. hws = {
2019-05-03 11:18:24 +08:00
[ CLK_AR100 ] = & ar100_clk . common . hw ,
2017-05-26 16:00:24 +08:00
[ CLK_AHB0 ] = & ahb0_clk . hw ,
2019-12-28 20:59:20 -06:00
[ CLK_APB0 ] = & apb0_clk . common . hw ,
2017-05-26 16:00:24 +08:00
[ CLK_APB0_PIO ] = & apb0_pio_clk . common . hw ,
[ CLK_APB0_IR ] = & apb0_ir_clk . common . hw ,
[ CLK_APB0_TIMER ] = & apb0_timer_clk . common . hw ,
[ CLK_APB0_RSB ] = & apb0_rsb_clk . common . hw ,
[ CLK_APB0_UART ] = & apb0_uart_clk . common . hw ,
[ CLK_APB0_I2C ] = & apb0_i2c_clk . common . hw ,
[ CLK_APB0_TWD ] = & apb0_twd_clk . common . hw ,
[ CLK_IR ] = & a83t_ir_clk . common . hw ,
} ,
. num = CLK_NUMBER ,
} ;
2017-04-04 17:50:57 +08:00
static struct clk_hw_onecell_data sun8i_h3_r_hw_clks = {
. hws = {
[ CLK_AR100 ] = & ar100_clk . common . hw ,
[ CLK_AHB0 ] = & ahb0_clk . hw ,
[ CLK_APB0 ] = & apb0_clk . common . hw ,
[ CLK_APB0_PIO ] = & apb0_pio_clk . common . hw ,
[ CLK_APB0_IR ] = & apb0_ir_clk . common . hw ,
[ CLK_APB0_TIMER ] = & apb0_timer_clk . common . hw ,
[ CLK_APB0_UART ] = & apb0_uart_clk . common . hw ,
[ CLK_APB0_I2C ] = & apb0_i2c_clk . common . hw ,
[ CLK_APB0_TWD ] = & apb0_twd_clk . common . hw ,
[ CLK_IR ] = & ir_clk . common . hw ,
} ,
. num = CLK_NUMBER ,
} ;
static struct clk_hw_onecell_data sun50i_a64_r_hw_clks = {
. hws = {
[ CLK_AR100 ] = & ar100_clk . common . hw ,
[ CLK_AHB0 ] = & ahb0_clk . hw ,
[ CLK_APB0 ] = & apb0_clk . common . hw ,
[ CLK_APB0_PIO ] = & apb0_pio_clk . common . hw ,
[ CLK_APB0_IR ] = & apb0_ir_clk . common . hw ,
[ CLK_APB0_TIMER ] = & apb0_timer_clk . common . hw ,
[ CLK_APB0_RSB ] = & apb0_rsb_clk . common . hw ,
[ CLK_APB0_UART ] = & apb0_uart_clk . common . hw ,
[ CLK_APB0_I2C ] = & apb0_i2c_clk . common . hw ,
[ CLK_APB0_TWD ] = & apb0_twd_clk . common . hw ,
[ CLK_IR ] = & ir_clk . common . hw ,
} ,
. num = CLK_NUMBER ,
} ;
2017-05-26 16:00:24 +08:00
static struct ccu_reset_map sun8i_a83t_r_ccu_resets [ ] = {
[ RST_APB0_IR ] = { 0xb0 , BIT ( 1 ) } ,
[ RST_APB0_TIMER ] = { 0xb0 , BIT ( 2 ) } ,
[ RST_APB0_RSB ] = { 0xb0 , BIT ( 3 ) } ,
[ RST_APB0_UART ] = { 0xb0 , BIT ( 4 ) } ,
[ RST_APB0_I2C ] = { 0xb0 , BIT ( 6 ) } ,
} ;
2017-04-04 17:50:57 +08:00
static struct ccu_reset_map sun8i_h3_r_ccu_resets [ ] = {
[ RST_APB0_IR ] = { 0xb0 , BIT ( 1 ) } ,
[ RST_APB0_TIMER ] = { 0xb0 , BIT ( 2 ) } ,
[ RST_APB0_UART ] = { 0xb0 , BIT ( 4 ) } ,
[ RST_APB0_I2C ] = { 0xb0 , BIT ( 6 ) } ,
} ;
static struct ccu_reset_map sun50i_a64_r_ccu_resets [ ] = {
[ RST_APB0_IR ] = { 0xb0 , BIT ( 1 ) } ,
[ RST_APB0_TIMER ] = { 0xb0 , BIT ( 2 ) } ,
[ RST_APB0_RSB ] = { 0xb0 , BIT ( 3 ) } ,
[ RST_APB0_UART ] = { 0xb0 , BIT ( 4 ) } ,
[ RST_APB0_I2C ] = { 0xb0 , BIT ( 6 ) } ,
} ;
2017-05-26 16:00:24 +08:00
static const struct sunxi_ccu_desc sun8i_a83t_r_ccu_desc = {
2022-05-30 23:35:39 -05:00
. ccu_clks = sun8i_r_ccu_clks ,
. num_ccu_clks = ARRAY_SIZE ( sun8i_r_ccu_clks ) ,
2017-05-26 16:00:24 +08:00
. hw_clks = & sun8i_a83t_r_hw_clks ,
. resets = sun8i_a83t_r_ccu_resets ,
. num_resets = ARRAY_SIZE ( sun8i_a83t_r_ccu_resets ) ,
} ;
2017-04-04 17:50:57 +08:00
static const struct sunxi_ccu_desc sun8i_h3_r_ccu_desc = {
2022-05-30 23:35:39 -05:00
. ccu_clks = sun8i_r_ccu_clks ,
. num_ccu_clks = ARRAY_SIZE ( sun8i_r_ccu_clks ) ,
2017-04-04 17:50:57 +08:00
. hw_clks = & sun8i_h3_r_hw_clks ,
. resets = sun8i_h3_r_ccu_resets ,
. num_resets = ARRAY_SIZE ( sun8i_h3_r_ccu_resets ) ,
} ;
static const struct sunxi_ccu_desc sun50i_a64_r_ccu_desc = {
2022-05-30 23:35:39 -05:00
. ccu_clks = sun8i_r_ccu_clks ,
. num_ccu_clks = ARRAY_SIZE ( sun8i_r_ccu_clks ) ,
2017-04-04 17:50:57 +08:00
. hw_clks = & sun50i_a64_r_hw_clks ,
. resets = sun50i_a64_r_ccu_resets ,
. num_resets = ARRAY_SIZE ( sun50i_a64_r_ccu_resets ) ,
} ;
2021-11-18 21:33:36 -06:00
static int sun8i_r_ccu_probe ( struct platform_device * pdev )
2017-04-04 17:50:57 +08:00
{
2021-11-18 21:33:36 -06:00
const struct sunxi_ccu_desc * desc ;
2017-04-04 17:50:57 +08:00
void __iomem * reg ;
2021-11-18 21:33:36 -06:00
desc = of_device_get_match_data ( & pdev - > dev ) ;
if ( ! desc )
return - EINVAL ;
2017-04-04 17:50:57 +08:00
2021-11-18 21:33:36 -06:00
reg = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( reg ) )
return PTR_ERR ( reg ) ;
2017-04-04 17:50:57 +08:00
2021-11-18 21:33:36 -06:00
return devm_sunxi_ccu_probe ( & pdev - > dev , reg , desc ) ;
2017-05-26 16:00:24 +08:00
}
2021-11-18 21:33:36 -06:00
static const struct of_device_id sun8i_r_ccu_ids [ ] = {
{
. compatible = " allwinner,sun8i-a83t-r-ccu " ,
. data = & sun8i_a83t_r_ccu_desc ,
} ,
{
. compatible = " allwinner,sun8i-h3-r-ccu " ,
. data = & sun8i_h3_r_ccu_desc ,
} ,
{
. compatible = " allwinner,sun50i-a64-r-ccu " ,
. data = & sun50i_a64_r_ccu_desc ,
} ,
{ }
} ;
2017-04-04 17:50:57 +08:00
2021-11-18 21:33:36 -06:00
static struct platform_driver sun8i_r_ccu_driver = {
. probe = sun8i_r_ccu_probe ,
. driver = {
. name = " sun8i-r-ccu " ,
. suppress_bind_attrs = true ,
. of_match_table = sun8i_r_ccu_ids ,
} ,
} ;
module_platform_driver ( sun8i_r_ccu_driver ) ;
MODULE_IMPORT_NS ( SUNXI_CCU ) ;
MODULE_LICENSE ( " GPL " ) ;