| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * Copyright (c) 2025 MediaTek Inc. |
| * Guangjie Song <guangjie.song@mediatek.com> |
| * Copyright (c) 2025 Collabora Ltd. |
| * Laura Nao <laura.nao@collabora.com> |
| */ |
| #include <dt-bindings/clock/mediatek,mt8196-clock.h> |
| |
| #include <linux/clk.h> |
| #include <linux/module.h> |
| #include <linux/of.h> |
| #include <linux/of_address.h> |
| #include <linux/of_device.h> |
| #include <linux/platform_device.h> |
| #include <linux/regmap.h> |
| |
| #include "clk-mtk.h" |
| #include "clk-mux.h" |
| #include "clk-pll.h" |
| |
| /* MUX SEL REG */ |
| #define VLP_CLK_CFG_UPDATE 0x0004 |
| #define VLP_CLK_CFG_UPDATE1 0x0008 |
| #define VLP_CLK_CFG_0 0x0010 |
| #define VLP_CLK_CFG_0_SET 0x0014 |
| #define VLP_CLK_CFG_0_CLR 0x0018 |
| #define VLP_CLK_CFG_1 0x0020 |
| #define VLP_CLK_CFG_1_SET 0x0024 |
| #define VLP_CLK_CFG_1_CLR 0x0028 |
| #define VLP_CLK_CFG_2 0x0030 |
| #define VLP_CLK_CFG_2_SET 0x0034 |
| #define VLP_CLK_CFG_2_CLR 0x0038 |
| #define VLP_CLK_CFG_3 0x0040 |
| #define VLP_CLK_CFG_3_SET 0x0044 |
| #define VLP_CLK_CFG_3_CLR 0x0048 |
| #define VLP_CLK_CFG_4 0x0050 |
| #define VLP_CLK_CFG_4_SET 0x0054 |
| #define VLP_CLK_CFG_4_CLR 0x0058 |
| #define VLP_CLK_CFG_5 0x0060 |
| #define VLP_CLK_CFG_5_SET 0x0064 |
| #define VLP_CLK_CFG_5_CLR 0x0068 |
| #define VLP_CLK_CFG_6 0x0070 |
| #define VLP_CLK_CFG_6_SET 0x0074 |
| #define VLP_CLK_CFG_6_CLR 0x0078 |
| #define VLP_CLK_CFG_7 0x0080 |
| #define VLP_CLK_CFG_7_SET 0x0084 |
| #define VLP_CLK_CFG_7_CLR 0x0088 |
| #define VLP_CLK_CFG_8 0x0090 |
| #define VLP_CLK_CFG_8_SET 0x0094 |
| #define VLP_CLK_CFG_8_CLR 0x0098 |
| #define VLP_CLK_CFG_9 0x00a0 |
| #define VLP_CLK_CFG_9_SET 0x00a4 |
| #define VLP_CLK_CFG_9_CLR 0x00a8 |
| #define VLP_CLK_CFG_10 0x00b0 |
| #define VLP_CLK_CFG_10_SET 0x00b4 |
| #define VLP_CLK_CFG_10_CLR 0x00b8 |
| #define VLP_OCIC_FENC_STATUS_MON_0 0x039c |
| #define VLP_OCIC_FENC_STATUS_MON_1 0x03a0 |
| |
| /* MUX SHIFT */ |
| #define TOP_MUX_SCP_SHIFT 0 |
| #define TOP_MUX_SCP_SPI_SHIFT 1 |
| #define TOP_MUX_SCP_IIC_SHIFT 2 |
| #define TOP_MUX_SCP_IIC_HS_SHIFT 3 |
| #define TOP_MUX_PWRAP_ULPOSC_SHIFT 4 |
| #define TOP_MUX_SPMI_M_TIA_32K_SHIFT 5 |
| #define TOP_MUX_APXGPT_26M_B_SHIFT 6 |
| #define TOP_MUX_DPSW_SHIFT 7 |
| #define TOP_MUX_DPSW_CENTRAL_SHIFT 8 |
| #define TOP_MUX_SPMI_M_MST_SHIFT 9 |
| #define TOP_MUX_DVFSRC_SHIFT 10 |
| #define TOP_MUX_PWM_VLP_SHIFT 11 |
| #define TOP_MUX_AXI_VLP_SHIFT 12 |
| #define TOP_MUX_SYSTIMER_26M_SHIFT 13 |
| #define TOP_MUX_SSPM_SHIFT 14 |
| #define TOP_MUX_SRCK_SHIFT 15 |
| #define TOP_MUX_CAMTG0_SHIFT 16 |
| #define TOP_MUX_CAMTG1_SHIFT 17 |
| #define TOP_MUX_CAMTG2_SHIFT 18 |
| #define TOP_MUX_CAMTG3_SHIFT 19 |
| #define TOP_MUX_CAMTG4_SHIFT 20 |
| #define TOP_MUX_CAMTG5_SHIFT 21 |
| #define TOP_MUX_CAMTG6_SHIFT 22 |
| #define TOP_MUX_CAMTG7_SHIFT 23 |
| #define TOP_MUX_SSPM_26M_SHIFT 25 |
| #define TOP_MUX_ULPOSC_SSPM_SHIFT 26 |
| #define TOP_MUX_VLP_PBUS_26M_SHIFT 27 |
| #define TOP_MUX_DEBUG_ERR_FLAG_VLP_26M_SHIFT 28 |
| #define TOP_MUX_DPMSRDMA_SHIFT 29 |
| #define TOP_MUX_VLP_PBUS_156M_SHIFT 30 |
| #define TOP_MUX_SPM_SHIFT 0 |
| #define TOP_MUX_MMINFRA_VLP_SHIFT 1 |
| #define TOP_MUX_USB_TOP_SHIFT 2 |
| #define TOP_MUX_SSUSB_XHCI_SHIFT 3 |
| #define TOP_MUX_NOC_VLP_SHIFT 4 |
| #define TOP_MUX_AUDIO_H_SHIFT 5 |
| #define TOP_MUX_AUD_ENGEN1_SHIFT 6 |
| #define TOP_MUX_AUD_ENGEN2_SHIFT 7 |
| #define TOP_MUX_AUD_INTBUS_SHIFT 8 |
| #define TOP_MUX_SPU_VLP_26M_SHIFT 9 |
| #define TOP_MUX_SPU0_VLP_SHIFT 10 |
| #define TOP_MUX_SPU1_VLP_SHIFT 11 |
| |
| /* CKSTA REG */ |
| #define VLP_CKSTA_REG0 0x0250 |
| #define VLP_CKSTA_REG1 0x0254 |
| |
| /* HW Voter REG */ |
| #define HWV_CG_9_SET 0x0048 |
| #define HWV_CG_9_CLR 0x004c |
| #define HWV_CG_9_DONE 0x2c24 |
| #define HWV_CG_10_SET 0x0050 |
| #define HWV_CG_10_CLR 0x0054 |
| #define HWV_CG_10_DONE 0x2c28 |
| |
| /* PLL REG */ |
| #define VLP_AP_PLL_CON3 0x264 |
| #define VLP_APLL1_TUNER_CON0 0x2a4 |
| #define VLP_APLL2_TUNER_CON0 0x2a8 |
| #define VLP_APLL1_CON0 0x274 |
| #define VLP_APLL1_CON1 0x278 |
| #define VLP_APLL1_CON2 0x27c |
| #define VLP_APLL1_CON3 0x280 |
| #define VLP_APLL2_CON0 0x28c |
| #define VLP_APLL2_CON1 0x290 |
| #define VLP_APLL2_CON2 0x294 |
| #define VLP_APLL2_CON3 0x298 |
| |
| /* vlp apll1 tuner default value*/ |
| #define VLP_APLL1_TUNER_CON0_VALUE 0x6f28bd4d |
| /* vlp apll2 tuner default value + 1*/ |
| #define VLP_APLL2_TUNER_CON0_VALUE 0x78fd5265 |
| |
| #define VLP_PLLEN_ALL 0x080 |
| #define VLP_PLLEN_ALL_SET 0x084 |
| #define VLP_PLLEN_ALL_CLR 0x088 |
| |
| #define MT8196_PLL_FMAX (3800UL * MHZ) |
| #define MT8196_PLL_FMIN (1500UL * MHZ) |
| #define MT8196_INTEGER_BITS 8 |
| |
| #define PLL_FENC(_id, _name, _reg, _fenc_sta_ofs, _fenc_sta_bit,\ |
| _flags, _pd_reg, _pd_shift, \ |
| _pcw_reg, _pcw_shift, _pcwbits, \ |
| _pll_en_bit) { \ |
| .id = _id, \ |
| .name = _name, \ |
| .reg = _reg, \ |
| .fenc_sta_ofs = _fenc_sta_ofs, \ |
| .fenc_sta_bit = _fenc_sta_bit, \ |
| .flags = _flags, \ |
| .fmax = MT8196_PLL_FMAX, \ |
| .fmin = MT8196_PLL_FMIN, \ |
| .pd_reg = _pd_reg, \ |
| .pd_shift = _pd_shift, \ |
| .pcw_reg = _pcw_reg, \ |
| .pcw_shift = _pcw_shift, \ |
| .pcwbits = _pcwbits, \ |
| .pcwibits = MT8196_INTEGER_BITS, \ |
| .en_reg = VLP_PLLEN_ALL, \ |
| .en_set_reg = VLP_PLLEN_ALL_SET, \ |
| .en_clr_reg = VLP_PLLEN_ALL_CLR, \ |
| .pll_en_bit = _pll_en_bit, \ |
| .ops = &mtk_pll_fenc_clr_set_ops, \ |
| } |
| |
| static DEFINE_SPINLOCK(mt8196_clk_vlp_lock); |
| |
| static const struct mtk_fixed_factor vlp_divs[] = { |
| FACTOR(CLK_VLP_CLK26M, "vlp_clk26m", "clk26m", 1, 1), |
| FACTOR(CLK_VLP_APLL1_D4, "apll1_d4", "vlp_apll1", 1, 4), |
| FACTOR(CLK_VLP_APLL1_D8, "apll1_d8", "vlp_apll1", 1, 8), |
| FACTOR(CLK_VLP_APLL2_D4, "apll2_d4", "vlp_apll2", 1, 4), |
| FACTOR(CLK_VLP_APLL2_D8, "apll2_d8", "vlp_apll2", 1, 8), |
| }; |
| |
| static const char * const vlp_scp_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "mainpll_d6", |
| "mainpll_d4", |
| "mainpll_d3", |
| "vlp_apll1" |
| }; |
| |
| static const char * const vlp_scp_spi_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "mainpll_d7_d2", |
| "mainpll_d5_d2" |
| }; |
| |
| static const char * const vlp_scp_iic_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "mainpll_d5_d4", |
| "mainpll_d7_d2" |
| }; |
| |
| static const char * const vlp_scp_iic_hs_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "mainpll_d5_d4", |
| "mainpll_d7_d2", |
| "mainpll_d7" |
| }; |
| |
| static const char * const vlp_pwrap_ulposc_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "osc_d14", |
| "osc_d10" |
| }; |
| |
| static const char * const vlp_spmi_32k_parents[] = { |
| "clk26m", |
| "clk32k", |
| "osc_d20", |
| "osc_d14", |
| "osc_d10" |
| }; |
| |
| static const char * const vlp_apxgpt_26m_b_parents[] = { |
| "clk26m", |
| "osc_d20" |
| }; |
| |
| static const char * const vlp_dpsw_parents[] = { |
| "clk26m", |
| "osc_d10", |
| "osc_d7", |
| "mainpll_d7_d4" |
| }; |
| |
| static const char * const vlp_dpsw_central_parents[] = { |
| "clk26m", |
| "osc_d10", |
| "osc_d7", |
| "mainpll_d7_d4" |
| }; |
| |
| static const char * const vlp_spmi_m_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "osc_d14", |
| "osc_d10" |
| }; |
| |
| static const char * const vlp_dvfsrc_parents[] = { |
| "clk26m", |
| "osc_d20" |
| }; |
| |
| static const char * const vlp_pwm_vlp_parents[] = { |
| "clk26m", |
| "clk32k", |
| "osc_d20", |
| "osc_d8", |
| "mainpll_d4_d8" |
| }; |
| |
| static const char * const vlp_axi_vlp_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "mainpll_d7_d4", |
| "osc_d4", |
| "mainpll_d7_d2" |
| }; |
| |
| static const char * const vlp_systimer_26m_parents[] = { |
| "clk26m", |
| "osc_d20" |
| }; |
| |
| static const char * const vlp_sspm_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "mainpll_d5_d2", |
| "osc_d2", |
| "mainpll_d6" |
| }; |
| |
| static const char * const vlp_srck_parents[] = { |
| "clk26m", |
| "osc_d20" |
| }; |
| |
| static const char * const vlp_camtg0_1_parents[] = { |
| "clk26m", |
| "univpll_192m_d32", |
| "univpll_192m_d16", |
| "clk13m", |
| "osc_d40", |
| "osc_d32", |
| "univpll_192m_d10", |
| "univpll_192m_d8", |
| "univpll_d6_d16", |
| "ulposc3", |
| "osc_d20", |
| "ck2_tvdpll1_d16", |
| "univpll_d6_d8" |
| }; |
| |
| static const char * const vlp_camtg2_7_parents[] = { |
| "clk26m", |
| "univpll_192m_d32", |
| "univpll_192m_d16", |
| "clk13m", |
| "osc_d40", |
| "osc_d32", |
| "univpll_192m_d10", |
| "univpll_192m_d8", |
| "univpll_d6_d16", |
| "osc_d20", |
| "ck2_tvdpll1_d16", |
| "univpll_d6_d8" |
| }; |
| |
| static const char * const vlp_sspm_26m_parents[] = { |
| "clk26m", |
| "osc_d20" |
| }; |
| |
| static const char * const vlp_ulposc_sspm_parents[] = { |
| "clk26m", |
| "osc_d2", |
| "mainpll_d4_d2" |
| }; |
| |
| static const char * const vlp_vlp_pbus_26m_parents[] = { |
| "clk26m", |
| "osc_d20" |
| }; |
| |
| static const char * const vlp_debug_err_flag_parents[] = { |
| "clk26m", |
| "osc_d20" |
| }; |
| |
| static const char * const vlp_dpmsrdma_parents[] = { |
| "clk26m", |
| "mainpll_d7_d2" |
| }; |
| |
| static const char * const vlp_vlp_pbus_156m_parents[] = { |
| "clk26m", |
| "osc_d2", |
| "mainpll_d7_d2", |
| "mainpll_d7" |
| }; |
| |
| static const char * const vlp_spm_parents[] = { |
| "clk26m", |
| "mainpll_d7_d4" |
| }; |
| |
| static const char * const vlp_mminfra_parents[] = { |
| "clk26m", |
| "osc_d4", |
| "mainpll_d3" |
| }; |
| |
| static const char * const vlp_usb_parents[] = { |
| "clk26m", |
| "mainpll_d9" |
| }; |
| |
| static const char * const vlp_noc_vlp_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "mainpll_d9" |
| }; |
| |
| static const char * const vlp_audio_h_parents[] = { |
| "vlp_clk26m", |
| "vlp_apll1", |
| "vlp_apll2" |
| }; |
| |
| static const char * const vlp_aud_engen1_parents[] = { |
| "vlp_clk26m", |
| "apll1_d8", |
| "apll1_d4" |
| }; |
| |
| static const char * const vlp_aud_engen2_parents[] = { |
| "vlp_clk26m", |
| "apll2_d8", |
| "apll2_d4" |
| }; |
| |
| static const char * const vlp_aud_intbus_parents[] = { |
| "vlp_clk26m", |
| "mainpll_d7_d4", |
| "mainpll_d4_d4" |
| }; |
| |
| static const u8 vlp_aud_parent_index[] = { 1, 2, 3 }; |
| |
| static const char * const vlp_spvlp_26m_parents[] = { |
| "clk26m", |
| "osc_d20" |
| }; |
| |
| static const char * const vlp_spu0_vlp_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "mainpll_d4_d4", |
| "mainpll_d4_d2", |
| "mainpll_d7", |
| "mainpll_d6", |
| "mainpll_d5" |
| }; |
| |
| static const char * const vlp_spu1_vlp_parents[] = { |
| "clk26m", |
| "osc_d20", |
| "mainpll_d4_d4", |
| "mainpll_d4_d2", |
| "mainpll_d7", |
| "mainpll_d6", |
| "mainpll_d5" |
| }; |
| |
| static const struct mtk_mux vlp_muxes[] = { |
| /* VLP_CLK_CFG_0 */ |
| MUX_GATE_FENC_CLR_SET_UPD(CLK_VLP_SCP, "vlp_scp", vlp_scp_parents, |
| VLP_CLK_CFG_0, VLP_CLK_CFG_0_SET, VLP_CLK_CFG_0_CLR, |
| 0, 3, 7, VLP_CLK_CFG_UPDATE, TOP_MUX_SCP_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_0, 31), |
| MUX_CLR_SET_UPD(CLK_VLP_SCP_SPI, "vlp_scp_spi", |
| vlp_scp_spi_parents, VLP_CLK_CFG_0, VLP_CLK_CFG_0_SET, |
| VLP_CLK_CFG_0_CLR, 8, 2, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_SCP_SPI_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_SCP_IIC, "vlp_scp_iic", |
| vlp_scp_iic_parents, VLP_CLK_CFG_0, VLP_CLK_CFG_0_SET, |
| VLP_CLK_CFG_0_CLR, 16, 2, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_SCP_IIC_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_SCP_IIC_HS, "vlp_scp_iic_hs", |
| vlp_scp_iic_hs_parents, VLP_CLK_CFG_0, VLP_CLK_CFG_0_SET, |
| VLP_CLK_CFG_0_CLR, 24, 3, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_SCP_IIC_HS_SHIFT), |
| /* VLP_CLK_CFG_1 */ |
| MUX_CLR_SET_UPD(CLK_VLP_PWRAP_ULPOSC, "vlp_pwrap_ulposc", |
| vlp_pwrap_ulposc_parents, VLP_CLK_CFG_1, VLP_CLK_CFG_1_SET, |
| VLP_CLK_CFG_1_CLR, 0, 2, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_PWRAP_ULPOSC_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_SPMI_M_TIA_32K, "vlp_spmi_32k", |
| vlp_spmi_32k_parents, VLP_CLK_CFG_1, VLP_CLK_CFG_1_SET, |
| VLP_CLK_CFG_1_CLR, 8, 3, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_SPMI_M_TIA_32K_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_APXGPT_26M_B, "vlp_apxgpt_26m_b", |
| vlp_apxgpt_26m_b_parents, VLP_CLK_CFG_1, VLP_CLK_CFG_1_SET, |
| VLP_CLK_CFG_1_CLR, 16, 1, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_APXGPT_26M_B_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_DPSW, "vlp_dpsw", |
| vlp_dpsw_parents, VLP_CLK_CFG_1, VLP_CLK_CFG_1_SET, |
| VLP_CLK_CFG_1_CLR, 24, 2, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_DPSW_SHIFT), |
| /* VLP_CLK_CFG_2 */ |
| MUX_CLR_SET_UPD(CLK_VLP_DPSW_CENTRAL, "vlp_dpsw_central", |
| vlp_dpsw_central_parents, VLP_CLK_CFG_2, VLP_CLK_CFG_2_SET, |
| VLP_CLK_CFG_2_CLR, 0, 2, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_DPSW_CENTRAL_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_SPMI_M_MST, "vlp_spmi_m", |
| vlp_spmi_m_parents, VLP_CLK_CFG_2, VLP_CLK_CFG_2_SET, |
| VLP_CLK_CFG_2_CLR, 8, 2, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_SPMI_M_MST_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_DVFSRC, "vlp_dvfsrc", |
| vlp_dvfsrc_parents, VLP_CLK_CFG_2, VLP_CLK_CFG_2_SET, |
| VLP_CLK_CFG_2_CLR, 16, 1, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_DVFSRC_SHIFT), |
| MUX_GATE_FENC_CLR_SET_UPD(CLK_VLP_PWM_VLP, "vlp_pwm_vlp", vlp_pwm_vlp_parents, |
| VLP_CLK_CFG_2, VLP_CLK_CFG_2_SET, VLP_CLK_CFG_2_CLR, |
| 24, 3, 31, VLP_CLK_CFG_UPDATE, TOP_MUX_PWM_VLP_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_0, 20), |
| /* VLP_CLK_CFG_3 */ |
| MUX_CLR_SET_UPD(CLK_VLP_AXI_VLP, "vlp_axi_vlp", |
| vlp_axi_vlp_parents, VLP_CLK_CFG_3, VLP_CLK_CFG_3_SET, |
| VLP_CLK_CFG_3_CLR, 0, 3, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_AXI_VLP_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_SYSTIMER_26M, "vlp_systimer_26m", |
| vlp_systimer_26m_parents, VLP_CLK_CFG_3, VLP_CLK_CFG_3_SET, |
| VLP_CLK_CFG_3_CLR, 8, 1, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_SYSTIMER_26M_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_SSPM, "vlp_sspm", |
| vlp_sspm_parents, VLP_CLK_CFG_3, VLP_CLK_CFG_3_SET, |
| VLP_CLK_CFG_3_CLR, 16, 3, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_SSPM_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_SRCK, "vlp_srck", |
| vlp_srck_parents, VLP_CLK_CFG_3, VLP_CLK_CFG_3_SET, |
| VLP_CLK_CFG_3_CLR, 24, 1, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_SRCK_SHIFT), |
| /* VLP_CLK_CFG_4 */ |
| MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG0, "vlp_camtg0", vlp_camtg0_1_parents, |
| VLP_CLK_CFG_4, VLP_CLK_CFG_4_SET, VLP_CLK_CFG_4_CLR, |
| HWV_CG_9_DONE, HWV_CG_9_SET, HWV_CG_9_CLR, |
| 0, 4, 7, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG0_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_0, 15), |
| MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG1, "vlp_camtg1", vlp_camtg0_1_parents, |
| VLP_CLK_CFG_4, VLP_CLK_CFG_4_SET, VLP_CLK_CFG_4_CLR, |
| HWV_CG_9_DONE, HWV_CG_9_SET, HWV_CG_9_CLR, |
| 8, 4, 15, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG1_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_0, 14), |
| MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG2, "vlp_camtg2", vlp_camtg2_7_parents, |
| VLP_CLK_CFG_4, VLP_CLK_CFG_4_SET, VLP_CLK_CFG_4_CLR, |
| HWV_CG_9_DONE, HWV_CG_9_SET, HWV_CG_9_CLR, |
| 16, 4, 23, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG2_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_0, 13), |
| MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG3, "vlp_camtg3", vlp_camtg2_7_parents, |
| VLP_CLK_CFG_4, VLP_CLK_CFG_4_SET, VLP_CLK_CFG_4_CLR, |
| HWV_CG_9_DONE, HWV_CG_9_SET, HWV_CG_9_CLR, |
| 24, 4, 31, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG3_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_0, 12), |
| /* VLP_CLK_CFG_5 */ |
| MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG4, "vlp_camtg4", vlp_camtg2_7_parents, |
| VLP_CLK_CFG_5, VLP_CLK_CFG_5_SET, VLP_CLK_CFG_5_CLR, |
| HWV_CG_10_DONE, HWV_CG_10_SET, HWV_CG_10_CLR, |
| 0, 4, 7, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG4_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_0, 11), |
| MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG5, "vlp_camtg5", vlp_camtg2_7_parents, |
| VLP_CLK_CFG_5, VLP_CLK_CFG_5_SET, VLP_CLK_CFG_5_CLR, |
| HWV_CG_10_DONE, HWV_CG_10_SET, HWV_CG_10_CLR, |
| 8, 4, 15, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG5_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_0, 10), |
| MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG6, "vlp_camtg6", vlp_camtg2_7_parents, |
| VLP_CLK_CFG_5, VLP_CLK_CFG_5_SET, VLP_CLK_CFG_5_CLR, |
| HWV_CG_10_DONE, HWV_CG_10_SET, HWV_CG_10_CLR, |
| 16, 4, 23, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG6_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_0, 9), |
| MUX_GATE_HWV_FENC_CLR_SET_UPD(CLK_VLP_CAMTG7, "vlp_camtg7", vlp_camtg2_7_parents, |
| VLP_CLK_CFG_5, VLP_CLK_CFG_5_SET, VLP_CLK_CFG_5_CLR, |
| HWV_CG_10_DONE, HWV_CG_10_SET, HWV_CG_10_CLR, |
| 24, 4, 31, VLP_CLK_CFG_UPDATE, TOP_MUX_CAMTG7_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_0, 8), |
| /* VLP_CLK_CFG_6 */ |
| MUX_CLR_SET_UPD(CLK_VLP_SSPM_26M, "vlp_sspm_26m", |
| vlp_sspm_26m_parents, VLP_CLK_CFG_6, VLP_CLK_CFG_6_SET, |
| VLP_CLK_CFG_6_CLR, 8, 1, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_SSPM_26M_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_ULPOSC_SSPM, "vlp_ulposc_sspm", |
| vlp_ulposc_sspm_parents, VLP_CLK_CFG_6, VLP_CLK_CFG_6_SET, |
| VLP_CLK_CFG_6_CLR, 16, 2, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_ULPOSC_SSPM_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_VLP_PBUS_26M, "vlp_vlp_pbus_26m", |
| vlp_vlp_pbus_26m_parents, VLP_CLK_CFG_6, VLP_CLK_CFG_6_SET, |
| VLP_CLK_CFG_6_CLR, 24, 1, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_VLP_PBUS_26M_SHIFT), |
| /* VLP_CLK_CFG_7 */ |
| MUX_CLR_SET_UPD(CLK_VLP_DEBUG_ERR_FLAG, "vlp_debug_err_flag", |
| vlp_debug_err_flag_parents, VLP_CLK_CFG_7, VLP_CLK_CFG_7_SET, |
| VLP_CLK_CFG_7_CLR, 0, 1, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_DEBUG_ERR_FLAG_VLP_26M_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_DPMSRDMA, "vlp_dpmsrdma", |
| vlp_dpmsrdma_parents, VLP_CLK_CFG_7, VLP_CLK_CFG_7_SET, |
| VLP_CLK_CFG_7_CLR, 8, 1, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_DPMSRDMA_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_VLP_PBUS_156M, "vlp_vlp_pbus_156m", |
| vlp_vlp_pbus_156m_parents, VLP_CLK_CFG_7, VLP_CLK_CFG_7_SET, |
| VLP_CLK_CFG_7_CLR, 16, 2, |
| VLP_CLK_CFG_UPDATE, TOP_MUX_VLP_PBUS_156M_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_SPM, "vlp_spm", |
| vlp_spm_parents, VLP_CLK_CFG_7, VLP_CLK_CFG_7_SET, |
| VLP_CLK_CFG_7_CLR, 24, 1, |
| VLP_CLK_CFG_UPDATE1, TOP_MUX_SPM_SHIFT), |
| /* VLP_CLK_CFG_8 */ |
| MUX_GATE_FENC_CLR_SET_UPD(CLK_VLP_MMINFRA, "vlp_mminfra", vlp_mminfra_parents, |
| VLP_CLK_CFG_8, VLP_CLK_CFG_8_SET, VLP_CLK_CFG_8_CLR, |
| 0, 2, 7, VLP_CLK_CFG_UPDATE1, TOP_MUX_MMINFRA_VLP_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_1, 31), |
| MUX_GATE_FENC_CLR_SET_UPD(CLK_VLP_USB_TOP, "vlp_usb", vlp_usb_parents, |
| VLP_CLK_CFG_8, VLP_CLK_CFG_8_SET, VLP_CLK_CFG_8_CLR, |
| 8, 1, 15, VLP_CLK_CFG_UPDATE1, TOP_MUX_USB_TOP_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_1, 30), |
| MUX_GATE_FENC_CLR_SET_UPD(CLK_VLP_USB_XHCI, "vlp_usb_xhci", vlp_usb_parents, |
| VLP_CLK_CFG_8, VLP_CLK_CFG_8_SET, VLP_CLK_CFG_8_CLR, |
| 16, 1, 23, VLP_CLK_CFG_UPDATE1, TOP_MUX_SSUSB_XHCI_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_1, 29), |
| MUX_CLR_SET_UPD(CLK_VLP_NOC_VLP, "vlp_noc_vlp", |
| vlp_noc_vlp_parents, VLP_CLK_CFG_8, VLP_CLK_CFG_8_SET, |
| VLP_CLK_CFG_8_CLR, 24, 2, |
| VLP_CLK_CFG_UPDATE1, TOP_MUX_NOC_VLP_SHIFT), |
| /* VLP_CLK_CFG_9 */ |
| MUX_GATE_FENC_CLR_SET_UPD_INDEXED(CLK_VLP_AUDIO_H, "vlp_audio_h", |
| vlp_audio_h_parents, vlp_aud_parent_index, |
| VLP_CLK_CFG_9, VLP_CLK_CFG_9_SET, VLP_CLK_CFG_9_CLR, |
| 0, 2, 7, VLP_CLK_CFG_UPDATE1, TOP_MUX_AUDIO_H_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_1, 27), |
| MUX_GATE_FENC_CLR_SET_UPD_INDEXED(CLK_VLP_AUD_ENGEN1, "vlp_aud_engen1", |
| vlp_aud_engen1_parents, vlp_aud_parent_index, |
| VLP_CLK_CFG_9, VLP_CLK_CFG_9_SET, VLP_CLK_CFG_9_CLR, |
| 8, 2, 15, VLP_CLK_CFG_UPDATE1, TOP_MUX_AUD_ENGEN1_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_1, 26), |
| MUX_GATE_FENC_CLR_SET_UPD_INDEXED(CLK_VLP_AUD_ENGEN2, "vlp_aud_engen2", |
| vlp_aud_engen2_parents, vlp_aud_parent_index, |
| VLP_CLK_CFG_9, VLP_CLK_CFG_9_SET, VLP_CLK_CFG_9_CLR, |
| 16, 2, 23, VLP_CLK_CFG_UPDATE1, TOP_MUX_AUD_ENGEN2_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_1, 25), |
| MUX_GATE_FENC_CLR_SET_UPD_INDEXED(CLK_VLP_AUD_INTBUS, "vlp_aud_intbus", |
| vlp_aud_intbus_parents, vlp_aud_parent_index, |
| VLP_CLK_CFG_9, VLP_CLK_CFG_9_SET, VLP_CLK_CFG_9_CLR, |
| 24, 2, 31, VLP_CLK_CFG_UPDATE1, TOP_MUX_AUD_INTBUS_SHIFT, |
| VLP_OCIC_FENC_STATUS_MON_1, 24), |
| /* VLP_CLK_CFG_10 */ |
| MUX_CLR_SET_UPD(CLK_VLP_SPVLP_26M, "vlp_spvlp_26m", |
| vlp_spvlp_26m_parents, VLP_CLK_CFG_10, VLP_CLK_CFG_10_SET, |
| VLP_CLK_CFG_10_CLR, 0, 1, |
| VLP_CLK_CFG_UPDATE1, TOP_MUX_SPU_VLP_26M_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_SPU0_VLP, "vlp_spu0_vlp", |
| vlp_spu0_vlp_parents, VLP_CLK_CFG_10, VLP_CLK_CFG_10_SET, |
| VLP_CLK_CFG_10_CLR, 8, 3, |
| VLP_CLK_CFG_UPDATE1, TOP_MUX_SPU0_VLP_SHIFT), |
| MUX_CLR_SET_UPD(CLK_VLP_SPU1_VLP, "vlp_spu1_vlp", |
| vlp_spu1_vlp_parents, VLP_CLK_CFG_10, VLP_CLK_CFG_10_SET, |
| VLP_CLK_CFG_10_CLR, 16, 3, |
| VLP_CLK_CFG_UPDATE1, TOP_MUX_SPU1_VLP_SHIFT), |
| }; |
| |
| static const struct mtk_pll_data vlp_plls[] = { |
| PLL_FENC(CLK_VLP_APLL1, "vlp_apll1", VLP_APLL1_CON0, 0x0358, 1, 0, |
| VLP_APLL1_CON1, 24, VLP_APLL1_CON2, 0, 32, 0), |
| PLL_FENC(CLK_VLP_APLL2, "vlp_apll2", VLP_APLL2_CON0, 0x0358, 0, 0, |
| VLP_APLL2_CON1, 24, VLP_APLL2_CON2, 0, 32, 1), |
| }; |
| |
| static const struct regmap_config vlpckgen_regmap_config = { |
| .reg_bits = 32, |
| .val_bits = 32, |
| .reg_stride = 4, |
| .max_register = 0x1000, |
| .fast_io = true, |
| }; |
| |
| static int clk_mt8196_vlp_probe(struct platform_device *pdev) |
| { |
| static void __iomem *base; |
| struct clk_hw_onecell_data *clk_data; |
| int r; |
| struct device_node *node = pdev->dev.of_node; |
| struct device *dev = &pdev->dev; |
| struct regmap *regmap; |
| |
| clk_data = mtk_alloc_clk_data(ARRAY_SIZE(vlp_muxes) + |
| ARRAY_SIZE(vlp_plls) + |
| ARRAY_SIZE(vlp_divs)); |
| if (!clk_data) |
| return -ENOMEM; |
| |
| base = devm_platform_ioremap_resource(pdev, 0); |
| if (IS_ERR(base)) |
| return PTR_ERR(base); |
| |
| regmap = devm_regmap_init_mmio(dev, base, &vlpckgen_regmap_config); |
| if (IS_ERR(regmap)) |
| return PTR_ERR(regmap); |
| |
| r = mtk_clk_register_factors(vlp_divs, ARRAY_SIZE(vlp_divs), clk_data); |
| if (r) |
| goto free_clk_data; |
| |
| r = mtk_clk_register_muxes(&pdev->dev, vlp_muxes, ARRAY_SIZE(vlp_muxes), |
| node, &mt8196_clk_vlp_lock, clk_data); |
| if (r) |
| goto unregister_factors; |
| |
| r = mtk_clk_register_plls(dev, vlp_plls, ARRAY_SIZE(vlp_plls), |
| clk_data); |
| if (r) |
| goto unregister_muxes; |
| |
| r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); |
| if (r) |
| goto unregister_plls; |
| |
| platform_set_drvdata(pdev, clk_data); |
| |
| /* Initialize APLL tuner registers */ |
| regmap_write(regmap, VLP_APLL1_TUNER_CON0, VLP_APLL1_TUNER_CON0_VALUE); |
| regmap_write(regmap, VLP_APLL2_TUNER_CON0, VLP_APLL2_TUNER_CON0_VALUE); |
| |
| return r; |
| |
| unregister_plls: |
| mtk_clk_unregister_plls(vlp_plls, ARRAY_SIZE(vlp_plls), clk_data); |
| unregister_muxes: |
| mtk_clk_unregister_muxes(vlp_muxes, ARRAY_SIZE(vlp_muxes), clk_data); |
| unregister_factors: |
| mtk_clk_unregister_factors(vlp_divs, ARRAY_SIZE(vlp_divs), clk_data); |
| free_clk_data: |
| mtk_free_clk_data(clk_data); |
| |
| return r; |
| } |
| |
| static void clk_mt8196_vlp_remove(struct platform_device *pdev) |
| { |
| struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); |
| struct device_node *node = pdev->dev.of_node; |
| |
| of_clk_del_provider(node); |
| mtk_clk_unregister_plls(vlp_plls, ARRAY_SIZE(vlp_plls), clk_data); |
| mtk_clk_unregister_muxes(vlp_muxes, ARRAY_SIZE(vlp_muxes), clk_data); |
| mtk_clk_unregister_factors(vlp_divs, ARRAY_SIZE(vlp_divs), clk_data); |
| mtk_free_clk_data(clk_data); |
| } |
| |
| static const struct of_device_id of_match_clk_mt8196_vlp_ck[] = { |
| { .compatible = "mediatek,mt8196-vlpckgen" }, |
| { /* sentinel */ } |
| }; |
| MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_vlp_ck); |
| |
| static struct platform_driver clk_mt8196_vlp_drv = { |
| .probe = clk_mt8196_vlp_probe, |
| .remove = clk_mt8196_vlp_remove, |
| .driver = { |
| .name = "clk-mt8196-vlpck", |
| .of_match_table = of_match_clk_mt8196_vlp_ck, |
| }, |
| }; |
| |
| MODULE_DESCRIPTION("MediaTek MT8196 VLP clock generator driver"); |
| module_platform_driver(clk_mt8196_vlp_drv); |
| MODULE_LICENSE("GPL"); |