1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright (c) 2021 MediaTek Inc. 4 // Author: Chun-Jie Chen <chun-jie.chen@mediatek.com> 5 6 #include "clk-mtk.h" 7 #include "clk-pll.h" 8 9 #include <dt-bindings/clock/mt8195-clk.h> 10 #include <linux/clk-provider.h> 11 #include <linux/platform_device.h> 12 13 #define MT8195_PLL_FMAX (3800UL * MHZ) 14 #define MT8195_PLL_FMIN (1500UL * MHZ) 15 #define MT8195_INTEGER_BITS (8) 16 #define MT8195_PCW_BITS (22) 17 #define MT8195_POSDIV_SHIFT (24) 18 #define MT8195_PLL_EN_BIT (0) 19 #define MT8195_PCW_SHIFT (0) 20 21 /* 22 * The "en_reg" and "pcw_chg_reg" fields are standard offset register compared 23 * with "reg" field, so set zero to imply it. 24 * No tuner control in apu pll, so set "tuner_XXX" as zero to imply it. 25 * No rst or post divider enable in apu pll, so set "rst_bar_mask" and "en_mask" 26 * as zero to imply it. 27 */ 28 #define PLL(_id, _name, _reg, _pwr_reg, _pd_reg, _pcw_reg) { \ 29 .id = _id, \ 30 .name = _name, \ 31 .reg = _reg, \ 32 .pwr_reg = _pwr_reg, \ 33 .en_mask = 0, \ 34 .flags = 0, \ 35 .rst_bar_mask = 0, \ 36 .fmax = MT8195_PLL_FMAX, \ 37 .fmin = MT8195_PLL_FMIN, \ 38 .pcwbits = MT8195_PCW_BITS, \ 39 .pcwibits = MT8195_INTEGER_BITS, \ 40 .pd_reg = _pd_reg, \ 41 .pd_shift = MT8195_POSDIV_SHIFT, \ 42 .tuner_reg = 0, \ 43 .tuner_en_reg = 0, \ 44 .tuner_en_bit = 0, \ 45 .pcw_reg = _pcw_reg, \ 46 .pcw_shift = MT8195_PCW_SHIFT, \ 47 .pcw_chg_reg = 0, \ 48 .en_reg = 0, \ 49 .pll_en_bit = MT8195_PLL_EN_BIT, \ 50 } 51 52 static const struct mtk_pll_data apusys_plls[] = { 53 PLL(CLK_APUSYS_PLL_APUPLL, "apusys_pll_apupll", 0x008, 0x014, 0x00c, 0x00c), 54 PLL(CLK_APUSYS_PLL_NPUPLL, "apusys_pll_npupll", 0x018, 0x024, 0x01c, 0x01c), 55 PLL(CLK_APUSYS_PLL_APUPLL1, "apusys_pll_apupll1", 0x028, 0x034, 0x02c, 0x02c), 56 PLL(CLK_APUSYS_PLL_APUPLL2, "apusys_pll_apupll2", 0x038, 0x044, 0x03c, 0x03c), 57 }; 58 59 static int clk_mt8195_apusys_pll_probe(struct platform_device *pdev) 60 { 61 struct clk_onecell_data *clk_data; 62 struct device_node *node = pdev->dev.of_node; 63 int r; 64 65 clk_data = mtk_alloc_clk_data(CLK_APUSYS_PLL_NR_CLK); 66 if (!clk_data) 67 return -ENOMEM; 68 69 r = mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data); 70 if (r) 71 goto free_apusys_pll_data; 72 73 r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); 74 if (r) 75 goto unregister_plls; 76 77 platform_set_drvdata(pdev, clk_data); 78 79 return r; 80 81 unregister_plls: 82 mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data); 83 free_apusys_pll_data: 84 mtk_free_clk_data(clk_data); 85 return r; 86 } 87 88 static int clk_mt8195_apusys_pll_remove(struct platform_device *pdev) 89 { 90 struct clk_onecell_data *clk_data = platform_get_drvdata(pdev); 91 struct device_node *node = pdev->dev.of_node; 92 93 of_clk_del_provider(node); 94 mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data); 95 mtk_free_clk_data(clk_data); 96 97 return 0; 98 } 99 100 static const struct of_device_id of_match_clk_mt8195_apusys_pll[] = { 101 { .compatible = "mediatek,mt8195-apusys_pll", }, 102 {} 103 }; 104 105 static struct platform_driver clk_mt8195_apusys_pll_drv = { 106 .probe = clk_mt8195_apusys_pll_probe, 107 .remove = clk_mt8195_apusys_pll_remove, 108 .driver = { 109 .name = "clk-mt8195-apusys_pll", 110 .of_match_table = of_match_clk_mt8195_apusys_pll, 111 }, 112 }; 113 builtin_platform_driver(clk_mt8195_apusys_pll_drv); 114