2018-05-03 16:26:23 +03:00
// SPDX-License-Identifier: GPL-2.0+
/*
* Amlogic Meson - AXG Clock Controller Driver
*
* Copyright ( c ) 2016 Baylibre SAS .
* Author : Michael Turquette < mturquette @ baylibre . com >
*
* Copyright ( c ) 2018 Amlogic , inc .
* Author : Qiufang Dai < qiufang . dai @ amlogic . com >
*/
# include <linux/clk-provider.h>
# include <linux/platform_device.h>
# include <linux/reset-controller.h>
# include <linux/mfd/syscon.h>
2020-11-18 22:14:05 +03:00
# include <linux/module.h>
2018-05-03 16:26:23 +03:00
# include "meson-aoclk.h"
# include "axg-aoclk.h"
clk: meson: rework and clean drivers dependencies
Initially, the meson clock directory only hosted 2 controllers drivers,
for meson8 and gxbb. At the time, both used the same set of clock drivers
so managing the dependencies was not a big concern.
Since this ancient time, entropy did its job, controllers with different
requirement and specific clock drivers have been added. Unfortunately, we
did not do a great job at managing the dependencies between the
controllers and the different clock drivers. Some drivers, such as
clk-phase or vid-pll-div, are compiled even if they are useless on the
target (meson8). As we are adding new controllers, we need to be able to
pick a driver w/o pulling the whole thing.
The patch aims to clean things up by:
* providing a dedicated CONFIG_ for each clock drivers
* allowing clock drivers to be compiled as a modules, if possible
* stating explicitly which drivers are required by each controller.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Link: https://lkml.kernel.org/r/20190201125841.26785-5-jbrunet@baylibre.com
2019-02-01 15:58:41 +03:00
# include "clk-regmap.h"
# include "clk-dualdiv.h"
2018-12-21 19:02:39 +03:00
/*
* AO Configuration Clock registers offsets
* Register offsets from the data sheet must be multiplied by 4.
*/
# define AO_RTI_PWR_CNTL_REG1 0x0C
# define AO_RTI_PWR_CNTL_REG0 0x10
# define AO_RTI_GEN_CNTL_REG0 0x40
# define AO_OSCIN_CNTL 0x58
# define AO_CRT_CLK_CNTL1 0x68
# define AO_SAR_CLK 0x90
# define AO_RTC_ALT_CLK_CNTL0 0x94
# define AO_RTC_ALT_CLK_CNTL1 0x98
2018-05-03 16:26:23 +03:00
# define AXG_AO_GATE(_name, _bit) \
static struct clk_regmap axg_aoclk_ # # _name = { \
. data = & ( struct clk_regmap_gate_data ) { \
. offset = ( AO_RTI_GEN_CNTL_REG0 ) , \
. bit_idx = ( _bit ) , \
} , \
. hw . init = & ( struct clk_init_data ) { \
. name = " axg_ao_ " # _name , \
. ops = & clk_regmap_gate_ops , \
2019-07-25 19:41:25 +03:00
. parent_data = & ( const struct clk_parent_data ) { \
. fw_name = " mpeg-clk " , \
} , \
2018-05-03 16:26:23 +03:00
. num_parents = 1 , \
. flags = CLK_IGNORE_UNUSED , \
} , \
}
AXG_AO_GATE ( remote , 0 ) ;
AXG_AO_GATE ( i2c_master , 1 ) ;
AXG_AO_GATE ( i2c_slave , 2 ) ;
AXG_AO_GATE ( uart1 , 3 ) ;
AXG_AO_GATE ( uart2 , 5 ) ;
AXG_AO_GATE ( ir_blaster , 6 ) ;
AXG_AO_GATE ( saradc , 7 ) ;
2018-12-21 19:02:39 +03:00
static struct clk_regmap axg_aoclk_cts_oscin = {
. data = & ( struct clk_regmap_gate_data ) {
. offset = AO_RTI_PWR_CNTL_REG0 ,
. bit_idx = 14 ,
} ,
. hw . init = & ( struct clk_init_data ) {
. name = " cts_oscin " ,
. ops = & clk_regmap_gate_ro_ops ,
2019-07-25 19:41:25 +03:00
. parent_data = & ( const struct clk_parent_data ) {
. fw_name = " xtal " ,
} ,
2018-12-21 19:02:39 +03:00
. num_parents = 1 ,
} ,
} ;
static struct clk_regmap axg_aoclk_32k_pre = {
. data = & ( struct clk_regmap_gate_data ) {
. offset = AO_RTC_ALT_CLK_CNTL0 ,
. bit_idx = 31 ,
} ,
. hw . init = & ( struct clk_init_data ) {
. name = " axg_ao_32k_pre " ,
. ops = & clk_regmap_gate_ops ,
2019-07-25 19:41:25 +03:00
. parent_hws = ( const struct clk_hw * [ ] ) {
& axg_aoclk_cts_oscin . hw
} ,
2018-12-21 19:02:39 +03:00
. num_parents = 1 ,
} ,
} ;
static const struct meson_clk_dualdiv_param axg_32k_div_table [ ] = {
{
. dual = 1 ,
. n1 = 733 ,
. m1 = 8 ,
. n2 = 732 ,
. m2 = 11 ,
} , { }
} ;
static struct clk_regmap axg_aoclk_32k_div = {
. data = & ( struct meson_clk_dualdiv_data ) {
. n1 = {
. reg_off = AO_RTC_ALT_CLK_CNTL0 ,
. shift = 0 ,
. width = 12 ,
} ,
. n2 = {
. reg_off = AO_RTC_ALT_CLK_CNTL0 ,
. shift = 12 ,
. width = 12 ,
} ,
. m1 = {
. reg_off = AO_RTC_ALT_CLK_CNTL1 ,
. shift = 0 ,
. width = 12 ,
} ,
. m2 = {
. reg_off = AO_RTC_ALT_CLK_CNTL1 ,
. shift = 12 ,
. width = 12 ,
} ,
. dual = {
. reg_off = AO_RTC_ALT_CLK_CNTL0 ,
. shift = 28 ,
. width = 1 ,
} ,
. table = axg_32k_div_table ,
} ,
. hw . init = & ( struct clk_init_data ) {
. name = " axg_ao_32k_div " ,
. ops = & meson_clk_dualdiv_ops ,
2019-07-25 19:41:25 +03:00
. parent_hws = ( const struct clk_hw * [ ] ) {
& axg_aoclk_32k_pre . hw
} ,
2018-12-21 19:02:39 +03:00
. num_parents = 1 ,
} ,
} ;
static struct clk_regmap axg_aoclk_32k_sel = {
. data = & ( struct clk_regmap_mux_data ) {
. offset = AO_RTC_ALT_CLK_CNTL1 ,
. mask = 0x1 ,
. shift = 24 ,
. flags = CLK_MUX_ROUND_CLOSEST ,
} ,
. hw . init = & ( struct clk_init_data ) {
. name = " axg_ao_32k_sel " ,
. ops = & clk_regmap_mux_ops ,
2019-07-25 19:41:25 +03:00
. parent_hws = ( const struct clk_hw * [ ] ) {
& axg_aoclk_32k_div . hw ,
& axg_aoclk_32k_pre . hw ,
} ,
2018-12-21 19:02:39 +03:00
. num_parents = 2 ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ;
static struct clk_regmap axg_aoclk_32k = {
. data = & ( struct clk_regmap_gate_data ) {
. offset = AO_RTC_ALT_CLK_CNTL0 ,
. bit_idx = 30 ,
} ,
. hw . init = & ( struct clk_init_data ) {
. name = " axg_ao_32k " ,
. ops = & clk_regmap_gate_ops ,
2019-07-25 19:41:25 +03:00
. parent_hws = ( const struct clk_hw * [ ] ) {
& axg_aoclk_32k_sel . hw
} ,
2018-12-21 19:02:39 +03:00
. num_parents = 1 ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ;
static struct clk_regmap axg_aoclk_cts_rtc_oscin = {
. data = & ( struct clk_regmap_mux_data ) {
. offset = AO_RTI_PWR_CNTL_REG0 ,
. mask = 0x1 ,
. shift = 10 ,
. flags = CLK_MUX_ROUND_CLOSEST ,
} ,
. hw . init = & ( struct clk_init_data ) {
. name = " axg_ao_cts_rtc_oscin " ,
. ops = & clk_regmap_mux_ops ,
2019-07-25 19:41:25 +03:00
. parent_data = ( const struct clk_parent_data [ ] ) {
{ . hw = & axg_aoclk_32k . hw } ,
{ . fw_name = " ext_32k-0 " , } ,
} ,
2018-12-21 19:02:39 +03:00
. num_parents = 2 ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ;
2018-05-03 16:26:23 +03:00
static struct clk_regmap axg_aoclk_clk81 = {
. data = & ( struct clk_regmap_mux_data ) {
. offset = AO_RTI_PWR_CNTL_REG0 ,
. mask = 0x1 ,
. shift = 8 ,
2018-12-21 19:02:39 +03:00
. flags = CLK_MUX_ROUND_CLOSEST ,
2018-05-03 16:26:23 +03:00
} ,
. hw . init = & ( struct clk_init_data ) {
. name = " axg_ao_clk81 " ,
. ops = & clk_regmap_mux_ro_ops ,
2019-07-25 19:41:25 +03:00
. parent_data = ( const struct clk_parent_data [ ] ) {
{ . fw_name = " mpeg-clk " , } ,
{ . hw = & axg_aoclk_cts_rtc_oscin . hw } ,
} ,
2018-05-03 16:26:23 +03:00
. num_parents = 2 ,
2018-12-21 19:02:39 +03:00
. flags = CLK_SET_RATE_PARENT ,
2018-05-03 16:26:23 +03:00
} ,
} ;
static struct clk_regmap axg_aoclk_saradc_mux = {
. data = & ( struct clk_regmap_mux_data ) {
. offset = AO_SAR_CLK ,
. mask = 0x3 ,
. shift = 9 ,
} ,
. hw . init = & ( struct clk_init_data ) {
. name = " axg_ao_saradc_mux " ,
. ops = & clk_regmap_mux_ops ,
2019-07-25 19:41:25 +03:00
. parent_data = ( const struct clk_parent_data [ ] ) {
{ . fw_name = " xtal " , } ,
{ . hw = & axg_aoclk_clk81 . hw } ,
} ,
2018-05-03 16:26:23 +03:00
. num_parents = 2 ,
} ,
} ;
static struct clk_regmap axg_aoclk_saradc_div = {
. data = & ( struct clk_regmap_div_data ) {
. offset = AO_SAR_CLK ,
. shift = 0 ,
. width = 8 ,
} ,
. hw . init = & ( struct clk_init_data ) {
. name = " axg_ao_saradc_div " ,
. ops = & clk_regmap_divider_ops ,
2019-07-25 19:41:25 +03:00
. parent_hws = ( const struct clk_hw * [ ] ) {
& axg_aoclk_saradc_mux . hw
} ,
2018-05-03 16:26:23 +03:00
. num_parents = 1 ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ;
static struct clk_regmap axg_aoclk_saradc_gate = {
. data = & ( struct clk_regmap_gate_data ) {
. offset = AO_SAR_CLK ,
. bit_idx = 8 ,
} ,
. hw . init = & ( struct clk_init_data ) {
. name = " axg_ao_saradc_gate " ,
. ops = & clk_regmap_gate_ops ,
2019-07-25 19:41:25 +03:00
. parent_hws = ( const struct clk_hw * [ ] ) {
& axg_aoclk_saradc_div . hw
} ,
2018-05-03 16:26:23 +03:00
. num_parents = 1 ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ;
static const unsigned int axg_aoclk_reset [ ] = {
[ RESET_AO_REMOTE ] = 16 ,
[ RESET_AO_I2C_MASTER ] = 18 ,
[ RESET_AO_I2C_SLAVE ] = 19 ,
[ RESET_AO_UART1 ] = 17 ,
[ RESET_AO_UART2 ] = 22 ,
[ RESET_AO_IR_BLASTER ] = 23 ,
} ;
static struct clk_regmap * axg_aoclk_regmap [ ] = {
2018-12-21 19:02:39 +03:00
& axg_aoclk_remote ,
& axg_aoclk_i2c_master ,
& axg_aoclk_i2c_slave ,
& axg_aoclk_uart1 ,
& axg_aoclk_uart2 ,
& axg_aoclk_ir_blaster ,
& axg_aoclk_saradc ,
& axg_aoclk_cts_oscin ,
& axg_aoclk_32k_pre ,
& axg_aoclk_32k_div ,
& axg_aoclk_32k_sel ,
& axg_aoclk_32k ,
& axg_aoclk_cts_rtc_oscin ,
& axg_aoclk_clk81 ,
& axg_aoclk_saradc_mux ,
& axg_aoclk_saradc_div ,
& axg_aoclk_saradc_gate ,
2018-05-03 16:26:23 +03:00
} ;
static const struct clk_hw_onecell_data axg_aoclk_onecell_data = {
. hws = {
[ CLKID_AO_REMOTE ] = & axg_aoclk_remote . hw ,
[ CLKID_AO_I2C_MASTER ] = & axg_aoclk_i2c_master . hw ,
[ CLKID_AO_I2C_SLAVE ] = & axg_aoclk_i2c_slave . hw ,
[ CLKID_AO_UART1 ] = & axg_aoclk_uart1 . hw ,
[ CLKID_AO_UART2 ] = & axg_aoclk_uart2 . hw ,
[ CLKID_AO_IR_BLASTER ] = & axg_aoclk_ir_blaster . hw ,
[ CLKID_AO_SAR_ADC ] = & axg_aoclk_saradc . hw ,
[ CLKID_AO_CLK81 ] = & axg_aoclk_clk81 . hw ,
[ CLKID_AO_SAR_ADC_SEL ] = & axg_aoclk_saradc_mux . hw ,
[ CLKID_AO_SAR_ADC_DIV ] = & axg_aoclk_saradc_div . hw ,
[ CLKID_AO_SAR_ADC_CLK ] = & axg_aoclk_saradc_gate . hw ,
2018-12-21 19:02:39 +03:00
[ CLKID_AO_CTS_OSCIN ] = & axg_aoclk_cts_oscin . hw ,
[ CLKID_AO_32K_PRE ] = & axg_aoclk_32k_pre . hw ,
[ CLKID_AO_32K_DIV ] = & axg_aoclk_32k_div . hw ,
[ CLKID_AO_32K_SEL ] = & axg_aoclk_32k_sel . hw ,
[ CLKID_AO_32K ] = & axg_aoclk_32k . hw ,
[ CLKID_AO_CTS_RTC_OSCIN ] = & axg_aoclk_cts_rtc_oscin . hw ,
2018-05-03 16:26:23 +03:00
} ,
. num = NR_CLKS ,
} ;
static const struct meson_aoclk_data axg_aoclkc_data = {
. reset_reg = AO_RTI_GEN_CNTL_REG0 ,
. num_reset = ARRAY_SIZE ( axg_aoclk_reset ) ,
. reset = axg_aoclk_reset ,
. num_clks = ARRAY_SIZE ( axg_aoclk_regmap ) ,
. clks = axg_aoclk_regmap ,
. hw_data = & axg_aoclk_onecell_data ,
} ;
static const struct of_device_id axg_aoclkc_match_table [ ] = {
{
. compatible = " amlogic,meson-axg-aoclkc " ,
. data = & axg_aoclkc_data ,
} ,
{ }
} ;
2020-11-18 22:14:05 +03:00
MODULE_DEVICE_TABLE ( of , axg_aoclkc_match_table ) ;
2018-05-03 16:26:23 +03:00
static struct platform_driver axg_aoclkc_driver = {
. probe = meson_aoclkc_probe ,
. driver = {
. name = " axg-aoclkc " ,
. of_match_table = axg_aoclkc_match_table ,
} ,
} ;
2020-11-18 22:14:05 +03:00
module_platform_driver ( axg_aoclkc_driver ) ;
MODULE_LICENSE ( " GPL v2 " ) ;