1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2023 Daniel Golle <daniel@makrotopia.org> |
4 | */ |
5 | |
6 | #include <linux/clk-provider.h> |
7 | #include <linux/of.h> |
8 | #include <linux/of_address.h> |
9 | #include <linux/of_device.h> |
10 | #include <linux/platform_device.h> |
11 | #include "clk-mtk.h" |
12 | #include "clk-gate.h" |
13 | #include <dt-bindings/clock/mediatek,mt7988-clk.h> |
14 | |
15 | /* Register to control USXGMII XFI PLL analog */ |
16 | #define XFI_PLL_ANA_GLB8 0x108 |
17 | #define RG_XFI_PLL_ANA_SWWA 0x02283248 |
18 | |
19 | static const struct mtk_gate_regs xfipll_cg_regs = { |
20 | .set_ofs = 0x8, |
21 | .clr_ofs = 0x8, |
22 | .sta_ofs = 0x8, |
23 | }; |
24 | |
25 | #define GATE_XFIPLL(_id, _name, _parent, _shift) \ |
26 | { \ |
27 | .id = _id, \ |
28 | .name = _name, \ |
29 | .parent_name = _parent, \ |
30 | .regs = &xfipll_cg_regs, \ |
31 | .shift = _shift, \ |
32 | .ops = &mtk_clk_gate_ops_no_setclr_inv, \ |
33 | } |
34 | |
35 | static const struct mtk_fixed_factor xfipll_divs[] = { |
36 | FACTOR(CLK_XFIPLL_PLL, "xfipll_pll" , "top_xtal" , 125, 32), |
37 | }; |
38 | |
39 | static const struct mtk_gate xfipll_clks[] = { |
40 | GATE_XFIPLL(CLK_XFIPLL_PLL_EN, "xfipll_pll_en" , "xfipll_pll" , 31), |
41 | }; |
42 | |
43 | static const struct mtk_clk_desc xfipll_desc = { |
44 | .clks = xfipll_clks, |
45 | .num_clks = ARRAY_SIZE(xfipll_clks), |
46 | .factor_clks = xfipll_divs, |
47 | .num_factor_clks = ARRAY_SIZE(xfipll_divs), |
48 | }; |
49 | |
50 | static int clk_mt7988_xfipll_probe(struct platform_device *pdev) |
51 | { |
52 | struct device_node *node = pdev->dev.of_node; |
53 | void __iomem *base = of_iomap(node, index: 0); |
54 | |
55 | if (!base) |
56 | return -ENOMEM; |
57 | |
58 | /* Apply software workaround for USXGMII PLL TCL issue */ |
59 | writel(RG_XFI_PLL_ANA_SWWA, addr: base + XFI_PLL_ANA_GLB8); |
60 | iounmap(addr: base); |
61 | |
62 | return mtk_clk_simple_probe(pdev); |
63 | }; |
64 | |
65 | static const struct of_device_id of_match_clk_mt7988_xfipll[] = { |
66 | { .compatible = "mediatek,mt7988-xfi-pll" , .data = &xfipll_desc }, |
67 | { /* sentinel */ } |
68 | }; |
69 | MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_xfipll); |
70 | |
71 | static struct platform_driver clk_mt7988_xfipll_drv = { |
72 | .driver = { |
73 | .name = "clk-mt7988-xfipll" , |
74 | .of_match_table = of_match_clk_mt7988_xfipll, |
75 | }, |
76 | .probe = clk_mt7988_xfipll_probe, |
77 | .remove_new = mtk_clk_simple_remove, |
78 | }; |
79 | module_platform_driver(clk_mt7988_xfipll_drv); |
80 | |
81 | MODULE_DESCRIPTION("MediaTek MT7988 XFI PLL clock driver" ); |
82 | MODULE_LICENSE("GPL" ); |
83 | |