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