1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2025 MediaTek Inc. 4 * Guangjie Song <guangjie.song@mediatek.com> 5 * Copyright (c) 2025 Collabora Ltd. 6 * Laura Nao <laura.nao@collabora.com> 7 */ 8 #include <dt-bindings/clock/mediatek,mt8196-clock.h> 9 10 #include <linux/clk.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 #include <linux/of_address.h> 14 #include <linux/of_device.h> 15 #include <linux/platform_device.h> 16 17 #include "clk-mtk.h" 18 #include "clk-pll.h" 19 20 #define ARMPLL_LL_CON0 0x008 21 #define ARMPLL_LL_CON1 0x00c 22 #define ARMPLL_LL_CON2 0x010 23 #define ARMPLL_LL_CON3 0x014 24 #define ARMPLL_BL_CON0 0x008 25 #define ARMPLL_BL_CON1 0x00c 26 #define ARMPLL_BL_CON2 0x010 27 #define ARMPLL_BL_CON3 0x014 28 #define ARMPLL_B_CON0 0x008 29 #define ARMPLL_B_CON1 0x00c 30 #define ARMPLL_B_CON2 0x010 31 #define ARMPLL_B_CON3 0x014 32 #define CCIPLL_CON0 0x008 33 #define CCIPLL_CON1 0x00c 34 #define CCIPLL_CON2 0x010 35 #define CCIPLL_CON3 0x014 36 #define PTPPLL_CON0 0x008 37 #define PTPPLL_CON1 0x00c 38 #define PTPPLL_CON2 0x010 39 #define PTPPLL_CON3 0x014 40 41 #define MT8196_PLL_FMAX (3800UL * MHZ) 42 #define MT8196_PLL_FMIN (1500UL * MHZ) 43 #define MT8196_INTEGER_BITS 8 44 45 #define PLL(_id, _name, _reg, _en_reg, _en_mask, _pll_en_bit, \ 46 _flags, _rst_bar_mask, \ 47 _pd_reg, _pd_shift, _tuner_reg, \ 48 _tuner_en_reg, _tuner_en_bit, \ 49 _pcw_reg, _pcw_shift, _pcwbits) { \ 50 .id = _id, \ 51 .name = _name, \ 52 .reg = _reg, \ 53 .en_reg = _en_reg, \ 54 .en_mask = _en_mask, \ 55 .pll_en_bit = _pll_en_bit, \ 56 .flags = _flags, \ 57 .rst_bar_mask = _rst_bar_mask, \ 58 .fmax = MT8196_PLL_FMAX, \ 59 .fmin = MT8196_PLL_FMIN, \ 60 .pd_reg = _pd_reg, \ 61 .pd_shift = _pd_shift, \ 62 .tuner_reg = _tuner_reg, \ 63 .tuner_en_reg = _tuner_en_reg, \ 64 .tuner_en_bit = _tuner_en_bit, \ 65 .pcw_reg = _pcw_reg, \ 66 .pcw_shift = _pcw_shift, \ 67 .pcwbits = _pcwbits, \ 68 .pcwibits = MT8196_INTEGER_BITS, \ 69 } 70 71 static const struct mtk_pll_data cpu_bl_plls[] = { 72 PLL(CLK_CPBL_ARMPLL_BL, "armpll-bl", ARMPLL_BL_CON0, ARMPLL_BL_CON0, 0, 73 0, PLL_AO, BIT(0), ARMPLL_BL_CON1, 24, 0, 0, 0, ARMPLL_BL_CON1, 0, 22), 74 }; 75 76 static const struct mtk_pll_data cpu_b_plls[] = { 77 PLL(CLK_CPB_ARMPLL_B, "armpll-b", ARMPLL_B_CON0, ARMPLL_B_CON0, 0, 0, 78 PLL_AO, BIT(0), ARMPLL_B_CON1, 24, 0, 0, 0, ARMPLL_B_CON1, 0, 22), 79 }; 80 81 static const struct mtk_pll_data cpu_ll_plls[] = { 82 PLL(CLK_CPLL_ARMPLL_LL, "armpll-ll", ARMPLL_LL_CON0, ARMPLL_LL_CON0, 0, 83 0, PLL_AO, BIT(0), ARMPLL_LL_CON1, 24, 0, 0, 0, ARMPLL_LL_CON1, 0, 22), 84 }; 85 86 static const struct mtk_pll_data cci_plls[] = { 87 PLL(CLK_CCIPLL, "ccipll", CCIPLL_CON0, CCIPLL_CON0, 0, 0, PLL_AO, 88 BIT(0), CCIPLL_CON1, 24, 0, 0, 0, CCIPLL_CON1, 0, 22), 89 }; 90 91 static const struct mtk_pll_data ptp_plls[] = { 92 PLL(CLK_PTPPLL, "ptppll", PTPPLL_CON0, PTPPLL_CON0, 0, 0, PLL_AO, 93 BIT(0), PTPPLL_CON1, 24, 0, 0, 0, PTPPLL_CON1, 0, 22), 94 }; 95 96 static const struct of_device_id of_match_clk_mt8196_mcu[] = { 97 { .compatible = "mediatek,mt8196-armpll-bl-pll-ctrl", 98 .data = &cpu_bl_plls }, 99 { .compatible = "mediatek,mt8196-armpll-b-pll-ctrl", 100 .data = &cpu_b_plls }, 101 { .compatible = "mediatek,mt8196-armpll-ll-pll-ctrl", 102 .data = &cpu_ll_plls }, 103 { .compatible = "mediatek,mt8196-ccipll-pll-ctrl", .data = &cci_plls }, 104 { .compatible = "mediatek,mt8196-ptppll-pll-ctrl", .data = &ptp_plls }, 105 { /* sentinel */ } 106 }; 107 MODULE_DEVICE_TABLE(of, of_match_clk_mt8196_mcu); 108 109 static int clk_mt8196_mcu_probe(struct platform_device *pdev) 110 { 111 const struct mtk_pll_data *plls; 112 struct clk_hw_onecell_data *clk_data; 113 struct device_node *node = pdev->dev.of_node; 114 const int num_plls = 1; 115 int r; 116 117 plls = of_device_get_match_data(&pdev->dev); 118 if (!plls) 119 return -EINVAL; 120 121 clk_data = mtk_alloc_clk_data(num_plls); 122 if (!clk_data) 123 return -ENOMEM; 124 125 r = mtk_clk_register_plls(node, plls, num_plls, clk_data); 126 if (r) 127 goto free_clk_data; 128 129 r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); 130 if (r) 131 goto unregister_plls; 132 133 platform_set_drvdata(pdev, clk_data); 134 135 return r; 136 137 unregister_plls: 138 mtk_clk_unregister_plls(plls, num_plls, clk_data); 139 free_clk_data: 140 mtk_free_clk_data(clk_data); 141 142 return r; 143 } 144 145 static void clk_mt8196_mcu_remove(struct platform_device *pdev) 146 { 147 const struct mtk_pll_data *plls = of_device_get_match_data(&pdev->dev); 148 struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); 149 struct device_node *node = pdev->dev.of_node; 150 151 of_clk_del_provider(node); 152 mtk_clk_unregister_plls(plls, 1, clk_data); 153 mtk_free_clk_data(clk_data); 154 } 155 156 static struct platform_driver clk_mt8196_mcu_drv = { 157 .probe = clk_mt8196_mcu_probe, 158 .remove = clk_mt8196_mcu_remove, 159 .driver = { 160 .name = "clk-mt8196-mcu", 161 .of_match_table = of_match_clk_mt8196_mcu, 162 }, 163 }; 164 module_platform_driver(clk_mt8196_mcu_drv); 165 166 MODULE_DESCRIPTION("MediaTek MT8196 mcusys clocks driver"); 167 MODULE_LICENSE("GPL"); 168