1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018 MediaTek Inc.
4 * Weiyi Lu <weiyi.lu@mediatek.com>
5 * Copyright (c) 2023 Collabora, Ltd.
6 * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
9 #include <dt-bindings/clock/mt8183-clk.h>
10 #include <linux/clk.h>
12 #include <linux/platform_device.h>
18 static const struct mtk_gate_regs apmixed_cg_regs
= {
24 #define GATE_APMIXED_FLAGS(_id, _name, _parent, _shift, _flags) \
25 GATE_MTK_FLAGS(_id, _name, _parent, &apmixed_cg_regs, \
26 _shift, &mtk_clk_gate_ops_no_setclr_inv, _flags)
28 #define GATE_APMIXED(_id, _name, _parent, _shift) \
29 GATE_APMIXED_FLAGS(_id, _name, _parent, _shift, 0)
33 * apmixed_appll26m is the toppest clock gate of all PLLs.
35 static const struct mtk_gate apmixed_clks
[] = {
37 GATE_APMIXED(CLK_APMIXED_SSUSB_26M
, "apmixed_ssusb26m", "f_f26m_ck", 4),
38 GATE_APMIXED_FLAGS(CLK_APMIXED_APPLL_26M
, "apmixed_appll26m",
39 "f_f26m_ck", 5, CLK_IS_CRITICAL
),
40 GATE_APMIXED(CLK_APMIXED_MIPIC0_26M
, "apmixed_mipic026m", "f_f26m_ck", 6),
41 GATE_APMIXED(CLK_APMIXED_MDPLLGP_26M
, "apmixed_mdpll26m", "f_f26m_ck", 7),
42 GATE_APMIXED(CLK_APMIXED_MMSYS_26M
, "apmixed_mmsys26m", "f_f26m_ck", 8),
43 GATE_APMIXED(CLK_APMIXED_UFS_26M
, "apmixed_ufs26m", "f_f26m_ck", 9),
44 GATE_APMIXED(CLK_APMIXED_MIPIC1_26M
, "apmixed_mipic126m", "f_f26m_ck", 11),
45 GATE_APMIXED(CLK_APMIXED_MEMPLL_26M
, "apmixed_mempll26m", "f_f26m_ck", 13),
46 GATE_APMIXED(CLK_APMIXED_CLKSQ_LVPLL_26M
, "apmixed_lvpll26m", "f_f26m_ck", 14),
47 GATE_APMIXED(CLK_APMIXED_MIPID0_26M
, "apmixed_mipid026m", "f_f26m_ck", 16),
48 GATE_APMIXED(CLK_APMIXED_MIPID1_26M
, "apmixed_mipid126m", "f_f26m_ck", 17),
51 #define MT8183_PLL_FMAX (3800UL * MHZ)
52 #define MT8183_PLL_FMIN (1500UL * MHZ)
54 #define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \
55 _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \
56 _pd_shift, _tuner_reg, _tuner_en_reg, \
57 _tuner_en_bit, _pcw_reg, _pcw_shift, \
58 _pcw_chg_reg, _div_table) { \
62 .pwr_reg = _pwr_reg, \
63 .en_mask = _en_mask, \
65 .rst_bar_mask = _rst_bar_mask, \
66 .fmax = MT8183_PLL_FMAX, \
67 .fmin = MT8183_PLL_FMIN, \
68 .pcwbits = _pcwbits, \
69 .pcwibits = _pcwibits, \
71 .pd_shift = _pd_shift, \
72 .tuner_reg = _tuner_reg, \
73 .tuner_en_reg = _tuner_en_reg, \
74 .tuner_en_bit = _tuner_en_bit, \
75 .pcw_reg = _pcw_reg, \
76 .pcw_shift = _pcw_shift, \
77 .pcw_chg_reg = _pcw_chg_reg, \
78 .div_table = _div_table, \
81 #define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \
82 _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \
83 _pd_shift, _tuner_reg, _tuner_en_reg, \
84 _tuner_en_bit, _pcw_reg, _pcw_shift, \
86 PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \
87 _rst_bar_mask, _pcwbits, _pcwibits, _pd_reg, \
88 _pd_shift, _tuner_reg, _tuner_en_reg, \
89 _tuner_en_bit, _pcw_reg, _pcw_shift, \
92 static const struct mtk_pll_div_table armpll_div_table
[] = {
93 { .div
= 0, .freq
= MT8183_PLL_FMAX
},
94 { .div
= 1, .freq
= 1500 * MHZ
},
95 { .div
= 2, .freq
= 750 * MHZ
},
96 { .div
= 3, .freq
= 375 * MHZ
},
97 { .div
= 4, .freq
= 187500000 },
101 static const struct mtk_pll_div_table mfgpll_div_table
[] = {
102 { .div
= 0, .freq
= MT8183_PLL_FMAX
},
103 { .div
= 1, .freq
= 1600 * MHZ
},
104 { .div
= 2, .freq
= 800 * MHZ
},
105 { .div
= 3, .freq
= 400 * MHZ
},
106 { .div
= 4, .freq
= 200 * MHZ
},
110 static const struct mtk_pll_data plls
[] = {
111 PLL_B(CLK_APMIXED_ARMPLL_LL
, "armpll_ll", 0x0200, 0x020C, 0,
112 HAVE_RST_BAR
| PLL_AO
, BIT(24), 22, 8, 0x0204, 24, 0x0, 0x0, 0,
113 0x0204, 0, 0, armpll_div_table
),
114 PLL_B(CLK_APMIXED_ARMPLL_L
, "armpll_l", 0x0210, 0x021C, 0,
115 HAVE_RST_BAR
| PLL_AO
, BIT(24), 22, 8, 0x0214, 24, 0x0, 0x0, 0,
116 0x0214, 0, 0, armpll_div_table
),
117 PLL(CLK_APMIXED_CCIPLL
, "ccipll", 0x0290, 0x029C, 0,
118 HAVE_RST_BAR
| PLL_AO
, BIT(24), 22, 8, 0x0294, 24, 0x0, 0x0, 0,
120 PLL(CLK_APMIXED_MAINPLL
, "mainpll", 0x0220, 0x022C, 0,
121 HAVE_RST_BAR
, BIT(24), 22, 8, 0x0224, 24, 0x0, 0x0, 0,
123 PLL(CLK_APMIXED_UNIV2PLL
, "univ2pll", 0x0230, 0x023C, 0,
124 HAVE_RST_BAR
, BIT(24), 22, 8, 0x0234, 24, 0x0, 0x0, 0,
126 PLL_B(CLK_APMIXED_MFGPLL
, "mfgpll", 0x0240, 0x024C, 0,
127 0, 0, 22, 8, 0x0244, 24, 0x0, 0x0, 0, 0x0244, 0, 0,
129 PLL(CLK_APMIXED_MSDCPLL
, "msdcpll", 0x0250, 0x025C, 0,
130 0, 0, 22, 8, 0x0254, 24, 0x0, 0x0, 0, 0x0254, 0, 0),
131 PLL(CLK_APMIXED_TVDPLL
, "tvdpll", 0x0260, 0x026C, 0,
132 0, 0, 22, 8, 0x0264, 24, 0x0, 0x0, 0, 0x0264, 0, 0),
133 PLL(CLK_APMIXED_MMPLL
, "mmpll", 0x0270, 0x027C, 0,
134 HAVE_RST_BAR
, BIT(23), 22, 8, 0x0274, 24, 0x0, 0x0, 0,
136 PLL(CLK_APMIXED_APLL1
, "apll1", 0x02A0, 0x02B0, 0,
137 0, 0, 32, 8, 0x02A0, 1, 0x02A8, 0x0014, 0, 0x02A4, 0, 0x02A0),
138 PLL(CLK_APMIXED_APLL2
, "apll2", 0x02b4, 0x02c4, 0,
139 0, 0, 32, 8, 0x02B4, 1, 0x02BC, 0x0014, 1, 0x02B8, 0, 0x02B4),
142 static int clk_mt8183_apmixed_probe(struct platform_device
*pdev
)
145 struct clk_hw_onecell_data
*clk_data
;
146 struct device_node
*node
= pdev
->dev
.of_node
;
147 struct device
*dev
= &pdev
->dev
;
150 base
= devm_platform_ioremap_resource(pdev
, 0);
152 return PTR_ERR(base
);
154 clk_data
= mtk_devm_alloc_clk_data(dev
, CLK_APMIXED_NR_CLK
);
158 ret
= mtk_clk_register_plls(node
, plls
, ARRAY_SIZE(plls
), clk_data
);
162 ret
= mtk_clk_register_gates(&pdev
->dev
, node
, apmixed_clks
,
163 ARRAY_SIZE(apmixed_clks
), clk_data
);
165 goto unregister_plls
;
167 ret
= of_clk_add_hw_provider(node
, of_clk_hw_onecell_get
, clk_data
);
169 goto unregister_gates
;
174 mtk_clk_unregister_gates(apmixed_clks
, ARRAY_SIZE(apmixed_clks
), clk_data
);
176 mtk_clk_unregister_plls(plls
, ARRAY_SIZE(plls
), clk_data
);
181 static const struct of_device_id of_match_clk_mt8183_apmixed
[] = {
182 { .compatible
= "mediatek,mt8183-apmixedsys" },
185 MODULE_DEVICE_TABLE(of
, of_match_clk_mt8183_apmixed
);
187 static struct platform_driver clk_mt8183_apmixed_drv
= {
188 .probe
= clk_mt8183_apmixed_probe
,
190 .name
= "clk-mt8183-apmixed",
191 .of_match_table
= of_match_clk_mt8183_apmixed
,
194 builtin_platform_driver(clk_mt8183_apmixed_drv
)
196 MODULE_DESCRIPTION("MediaTek MT8183 apmixedsys clocks driver");
197 MODULE_LICENSE("GPL");