1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Copyright 2021 NXP |
4 | */ |
5 | |
6 | #include <dt-bindings/clock/imx8ulp-clock.h> |
7 | #include <linux/err.h> |
8 | #include <linux/io.h> |
9 | #include <linux/module.h> |
10 | #include <linux/of.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/reset-controller.h> |
13 | #include <linux/slab.h> |
14 | |
15 | #include "clk.h" |
16 | |
17 | static const char * const pll_pre_sels[] = { "sosc" , "frosc" , }; |
18 | static const char * const a35_sels[] = { "frosc" , "spll2" , "sosc" , "lvds" , }; |
19 | static const char * const nic_sels[] = { "frosc" , "spll3_pfd0" , "sosc" , "lvds" , }; |
20 | static const char * const pcc3_periph_bus_sels[] = { "dummy" , "lposc" , "sosc_div2" , |
21 | "frosc_div2" , "xbar_divbus" , "spll3_pfd1_div1" , |
22 | "spll3_pfd0_div2" , "spll3_pfd0_div1" , }; |
23 | static const char * const pcc4_periph_bus_sels[] = { "dummy" , "dummy" , "lposc" , |
24 | "sosc_div2" , "frosc_div2" , "xbar_divbus" , |
25 | "spll3_vcodiv" , "spll3_pfd0_div1" , }; |
26 | static const char * const pcc4_periph_plat_sels[] = { "dummy" , "sosc_div1" , "frosc_div1" , |
27 | "spll3_pfd3_div2" , "spll3_pfd3_div1" , |
28 | "spll3_pfd2_div2" , "spll3_pfd2_div1" , |
29 | "spll3_pfd1_div2" , }; |
30 | static const char * const pcc5_periph_bus_sels[] = { "dummy" , "dummy" , "lposc" , |
31 | "sosc_div2" , "frosc_div2" , "lpav_bus_clk" , |
32 | "pll4_vcodiv" , "pll4_pfd3_div1" , }; |
33 | static const char * const pcc5_periph_plat_sels[] = { "dummy" , "pll4_pfd3_div2" , "pll4_pfd2_div2" , |
34 | "pll4_pfd2_div1" , "pll4_pfd1_div2" , |
35 | "pll4_pfd1_div1" , "pll4_pfd0_div2" , |
36 | "pll4_pfd0_div1" , }; |
37 | static const char * const hifi_sels[] = { "frosc" , "pll4" , "pll4_pfd0" , "sosc" , |
38 | "lvds" , "dummy" , "dummy" , "dummy" , }; |
39 | static const char * const ddr_sels[] = { "frosc" , "pll4_pfd1" , "sosc" , "lvds" , |
40 | "pll4" , "pll4" , "pll4" , "pll4" , }; |
41 | static const char * const lpav_sels[] = { "frosc" , "pll4_pfd1" , "sosc" , "lvds" , }; |
42 | static const char * const sai45_sels[] = { "spll3_pfd1_div1" , "aud_clk1" , "aud_clk2" , "sosc" , }; |
43 | static const char * const sai67_sels[] = { "spll1_pfd2_div" , "spll3_pfd1_div1" , "aud_clk0" , "aud_clk1" , "aud_clk2" , "sosc" , "dummy" , "dummy" , }; |
44 | static const char * const aud_clk1_sels[] = { "ext_aud_mclk2" , "sai4_rx_bclk" , "sai4_tx_bclk" , "sai5_rx_bclk" , "sai5_tx_bclk" , "dummy" , "dummy" , "dummy" , }; |
45 | static const char * const aud_clk2_sels[] = { "ext_aud_mclk3" , "sai6_rx_bclk" , "sai6_tx_bclk" , "sai7_rx_bclk" , "sai7_tx_bclk" , "spdif_rx" , "dummy" , "dummy" , }; |
46 | static const char * const enet_ts_sels[] = { "ext_rmii_clk" , "ext_ts_clk" , "rosc" , "ext_aud_mclk" , "sosc" , "dummy" , "dummy" , "dummy" }; |
47 | static const char * const xbar_divbus[] = { "xbar_divbus" }; |
48 | static const char * const nic_per_divplat[] = { "nic_per_divplat" }; |
49 | static const char * const lpav_axi_div[] = { "lpav_axi_div" }; |
50 | static const char * const lpav_bus_div[] = { "lpav_bus_div" }; |
51 | |
52 | struct pcc_reset_dev { |
53 | void __iomem *base; |
54 | struct reset_controller_dev rcdev; |
55 | const u32 *resets; |
56 | /* Set to imx_ccm_lock to protect register access shared with clock control */ |
57 | spinlock_t *lock; |
58 | }; |
59 | |
60 | #define PCC_SW_RST BIT(28) |
61 | #define to_pcc_reset_dev(_rcdev) container_of(_rcdev, struct pcc_reset_dev, rcdev) |
62 | |
63 | static const u32 pcc3_resets[] = { |
64 | 0xa8, 0xac, 0xc8, 0xcc, 0xd0, |
65 | 0xd4, 0xd8, 0xdc, 0xe0, 0xe4, |
66 | 0xe8, 0xec, 0xf0 |
67 | }; |
68 | |
69 | static const u32 pcc4_resets[] = { |
70 | 0x4, 0x8, 0xc, 0x10, 0x14, |
71 | 0x18, 0x1c, 0x20, 0x24, 0x34, |
72 | 0x38, 0x3c, 0x40, 0x44, 0x48, |
73 | 0x4c, 0x54 |
74 | }; |
75 | |
76 | static const u32 pcc5_resets[] = { |
77 | 0xa0, 0xa4, 0xa8, 0xac, 0xb0, |
78 | 0xb4, 0xbc, 0xc0, 0xc8, 0xcc, |
79 | 0xd0, 0xf0, 0xf4, 0xf8 |
80 | }; |
81 | |
82 | static int imx8ulp_pcc_assert(struct reset_controller_dev *rcdev, unsigned long id) |
83 | { |
84 | struct pcc_reset_dev *pcc_reset = to_pcc_reset_dev(rcdev); |
85 | u32 offset = pcc_reset->resets[id]; |
86 | unsigned long flags; |
87 | u32 val; |
88 | |
89 | spin_lock_irqsave(pcc_reset->lock, flags); |
90 | |
91 | val = readl(addr: pcc_reset->base + offset); |
92 | val &= ~PCC_SW_RST; |
93 | writel(val, addr: pcc_reset->base + offset); |
94 | |
95 | spin_unlock_irqrestore(lock: pcc_reset->lock, flags); |
96 | |
97 | return 0; |
98 | } |
99 | |
100 | static int imx8ulp_pcc_deassert(struct reset_controller_dev *rcdev, unsigned long id) |
101 | { |
102 | struct pcc_reset_dev *pcc_reset = to_pcc_reset_dev(rcdev); |
103 | u32 offset = pcc_reset->resets[id]; |
104 | unsigned long flags; |
105 | u32 val; |
106 | |
107 | spin_lock_irqsave(pcc_reset->lock, flags); |
108 | |
109 | val = readl(addr: pcc_reset->base + offset); |
110 | val |= PCC_SW_RST; |
111 | writel(val, addr: pcc_reset->base + offset); |
112 | |
113 | spin_unlock_irqrestore(lock: pcc_reset->lock, flags); |
114 | |
115 | return 0; |
116 | } |
117 | |
118 | static const struct reset_control_ops imx8ulp_pcc_reset_ops = { |
119 | .assert = imx8ulp_pcc_assert, |
120 | .deassert = imx8ulp_pcc_deassert, |
121 | }; |
122 | |
123 | static int imx8ulp_pcc_reset_init(struct platform_device *pdev, void __iomem *base, |
124 | const u32 *resets, unsigned int nr_resets) |
125 | { |
126 | struct device_node *np = pdev->dev.of_node; |
127 | struct device *dev = &pdev->dev; |
128 | struct pcc_reset_dev *pcc_reset; |
129 | |
130 | pcc_reset = devm_kzalloc(dev, size: sizeof(*pcc_reset), GFP_KERNEL); |
131 | if (!pcc_reset) |
132 | return -ENOMEM; |
133 | |
134 | pcc_reset->base = base; |
135 | pcc_reset->lock = &imx_ccm_lock; |
136 | pcc_reset->resets = resets; |
137 | pcc_reset->rcdev.owner = THIS_MODULE; |
138 | pcc_reset->rcdev.nr_resets = nr_resets; |
139 | pcc_reset->rcdev.ops = &imx8ulp_pcc_reset_ops; |
140 | pcc_reset->rcdev.of_node = np; |
141 | |
142 | return devm_reset_controller_register(dev, rcdev: &pcc_reset->rcdev); |
143 | } |
144 | |
145 | static int imx8ulp_clk_cgc1_init(struct platform_device *pdev) |
146 | { |
147 | struct device *dev = &pdev->dev; |
148 | struct clk_hw_onecell_data *clk_data; |
149 | struct clk_hw **clks; |
150 | void __iomem *base; |
151 | |
152 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_CGC1_END), |
153 | GFP_KERNEL); |
154 | if (!clk_data) |
155 | return -ENOMEM; |
156 | |
157 | clk_data->num = IMX8ULP_CLK_CGC1_END; |
158 | clks = clk_data->hws; |
159 | |
160 | clks[IMX8ULP_CLK_DUMMY] = imx_clk_hw_fixed(name: "dummy" , rate: 0); |
161 | |
162 | /* CGC1 */ |
163 | base = devm_platform_ioremap_resource(pdev, index: 0); |
164 | if (WARN_ON(IS_ERR(base))) |
165 | return PTR_ERR(ptr: base); |
166 | |
167 | clks[IMX8ULP_CLK_SPLL2_PRE_SEL] = imx_clk_hw_mux_flags("spll2_pre_sel" , base + 0x510, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); |
168 | clks[IMX8ULP_CLK_SPLL3_PRE_SEL] = imx_clk_hw_mux_flags("spll3_pre_sel" , base + 0x610, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); |
169 | |
170 | clks[IMX8ULP_CLK_SPLL2] = imx_clk_hw_pllv4(type: IMX_PLLV4_IMX8ULP_1GHZ, name: "spll2" , parent_name: "spll2_pre_sel" , base: base + 0x500); |
171 | clks[IMX8ULP_CLK_SPLL3] = imx_clk_hw_pllv4(type: IMX_PLLV4_IMX8ULP, name: "spll3" , parent_name: "spll3_pre_sel" , base: base + 0x600); |
172 | clks[IMX8ULP_CLK_SPLL3_VCODIV] = imx_clk_hw_divider("spll3_vcodiv" , "spll3" , base + 0x604, 0, 6); |
173 | |
174 | clks[IMX8ULP_CLK_SPLL3_PFD0] = imx_clk_hw_pfdv2(type: IMX_PFDV2_IMX8ULP, name: "spll3_pfd0" , parent_name: "spll3_vcodiv" , reg: base + 0x614, idx: 0); |
175 | clks[IMX8ULP_CLK_SPLL3_PFD1] = imx_clk_hw_pfdv2(type: IMX_PFDV2_IMX8ULP, name: "spll3_pfd1" , parent_name: "spll3_vcodiv" , reg: base + 0x614, idx: 1); |
176 | clks[IMX8ULP_CLK_SPLL3_PFD2] = imx_clk_hw_pfdv2(type: IMX_PFDV2_IMX8ULP, name: "spll3_pfd2" , parent_name: "spll3_vcodiv" , reg: base + 0x614, idx: 2); |
177 | clks[IMX8ULP_CLK_SPLL3_PFD3] = imx_clk_hw_pfdv2(type: IMX_PFDV2_IMX8ULP, name: "spll3_pfd3" , parent_name: "spll3_vcodiv" , reg: base + 0x614, idx: 3); |
178 | |
179 | clks[IMX8ULP_CLK_SPLL3_PFD0_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd0_div1_gate" , "spll3_pfd0" , base + 0x608, 7); |
180 | clks[IMX8ULP_CLK_SPLL3_PFD0_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd0_div2_gate" , "spll3_pfd0" , base + 0x608, 15); |
181 | clks[IMX8ULP_CLK_SPLL3_PFD1_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd1_div1_gate" , "spll3_pfd1" , base + 0x608, 23); |
182 | clks[IMX8ULP_CLK_SPLL3_PFD1_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd1_div2_gate" , "spll3_pfd1" , base + 0x608, 31); |
183 | clks[IMX8ULP_CLK_SPLL3_PFD2_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd2_div1_gate" , "spll3_pfd2" , base + 0x60c, 7); |
184 | clks[IMX8ULP_CLK_SPLL3_PFD2_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd2_div2_gate" , "spll3_pfd2" , base + 0x60c, 15); |
185 | clks[IMX8ULP_CLK_SPLL3_PFD3_DIV1_GATE] = imx_clk_hw_gate_dis("spll3_pfd3_div1_gate" , "spll3_pfd3" , base + 0x60c, 23); |
186 | clks[IMX8ULP_CLK_SPLL3_PFD3_DIV2_GATE] = imx_clk_hw_gate_dis("spll3_pfd3_div2_gate" , "spll3_pfd3" , base + 0x60c, 31); |
187 | clks[IMX8ULP_CLK_SPLL3_PFD0_DIV1] = imx_clk_hw_divider("spll3_pfd0_div1" , "spll3_pfd0_div1_gate" , base + 0x608, 0, 6); |
188 | clks[IMX8ULP_CLK_SPLL3_PFD0_DIV2] = imx_clk_hw_divider("spll3_pfd0_div2" , "spll3_pfd0_div2_gate" , base + 0x608, 8, 6); |
189 | clks[IMX8ULP_CLK_SPLL3_PFD1_DIV1] = imx_clk_hw_divider("spll3_pfd1_div1" , "spll3_pfd1_div1_gate" , base + 0x608, 16, 6); |
190 | clks[IMX8ULP_CLK_SPLL3_PFD1_DIV2] = imx_clk_hw_divider("spll3_pfd1_div2" , "spll3_pfd1_div2_gate" , base + 0x608, 24, 6); |
191 | clks[IMX8ULP_CLK_SPLL3_PFD2_DIV1] = imx_clk_hw_divider("spll3_pfd2_div1" , "spll3_pfd2_div1_gate" , base + 0x60c, 0, 6); |
192 | clks[IMX8ULP_CLK_SPLL3_PFD2_DIV2] = imx_clk_hw_divider("spll3_pfd2_div2" , "spll3_pfd2_div2_gate" , base + 0x60c, 8, 6); |
193 | clks[IMX8ULP_CLK_SPLL3_PFD3_DIV1] = imx_clk_hw_divider("spll3_pfd3_div1" , "spll3_pfd3_div1_gate" , base + 0x60c, 16, 6); |
194 | clks[IMX8ULP_CLK_SPLL3_PFD3_DIV2] = imx_clk_hw_divider("spll3_pfd3_div2" , "spll3_pfd3_div2_gate" , base + 0x60c, 24, 6); |
195 | |
196 | clks[IMX8ULP_CLK_A35_SEL] = imx_clk_hw_mux2("a35_sel" , base + 0x14, 28, 2, a35_sels, ARRAY_SIZE(a35_sels)); |
197 | clks[IMX8ULP_CLK_A35_DIV] = imx_clk_hw_divider_flags("a35_div" , "a35_sel" , base + 0x14, 21, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); |
198 | |
199 | clks[IMX8ULP_CLK_NIC_SEL] = imx_clk_hw_mux2("nic_sel" , base + 0x34, 28, 2, nic_sels, ARRAY_SIZE(nic_sels)); |
200 | clks[IMX8ULP_CLK_NIC_AD_DIVPLAT] = imx_clk_hw_divider_flags("nic_ad_divplat" , "nic_sel" , base + 0x34, 21, 6, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); |
201 | clks[IMX8ULP_CLK_NIC_PER_DIVPLAT] = imx_clk_hw_divider_flags("nic_per_divplat" , "nic_ad_divplat" , base + 0x34, 14, 6, CLK_SET_RATE_PARENT); |
202 | clks[IMX8ULP_CLK_XBAR_AD_DIVPLAT] = imx_clk_hw_divider_flags("xbar_ad_divplat" , "nic_ad_divplat" , base + 0x38, 14, 6, CLK_SET_RATE_PARENT); |
203 | clks[IMX8ULP_CLK_XBAR_DIVBUS] = imx_clk_hw_divider_flags("xbar_divbus" , "xbar_ad_divplat" , base + 0x38, 7, 6, CLK_SET_RATE_PARENT); |
204 | clks[IMX8ULP_CLK_XBAR_AD_SLOW] = imx_clk_hw_divider_flags("xbar_ad_slow" , "xbar_divbus" , base + 0x38, 0, 6, CLK_SET_RATE_PARENT); |
205 | |
206 | clks[IMX8ULP_CLK_SOSC_DIV1_GATE] = imx_clk_hw_gate_dis("sosc_div1_gate" , "sosc" , base + 0x108, 7); |
207 | clks[IMX8ULP_CLK_SOSC_DIV2_GATE] = imx_clk_hw_gate_dis("sosc_div2_gate" , "sosc" , base + 0x108, 15); |
208 | clks[IMX8ULP_CLK_SOSC_DIV3_GATE] = imx_clk_hw_gate_dis("sosc_div3_gate" , "sosc" , base + 0x108, 23); |
209 | clks[IMX8ULP_CLK_SOSC_DIV1] = imx_clk_hw_divider("sosc_div1" , "sosc_div1_gate" , base + 0x108, 0, 6); |
210 | clks[IMX8ULP_CLK_SOSC_DIV2] = imx_clk_hw_divider("sosc_div2" , "sosc_div2_gate" , base + 0x108, 8, 6); |
211 | clks[IMX8ULP_CLK_SOSC_DIV3] = imx_clk_hw_divider("sosc_div3" , "sosc_div3_gate" , base + 0x108, 16, 6); |
212 | |
213 | clks[IMX8ULP_CLK_FROSC_DIV1_GATE] = imx_clk_hw_gate_dis("frosc_div1_gate" , "frosc" , base + 0x208, 7); |
214 | clks[IMX8ULP_CLK_FROSC_DIV2_GATE] = imx_clk_hw_gate_dis("frosc_div2_gate" , "frosc" , base + 0x208, 15); |
215 | clks[IMX8ULP_CLK_FROSC_DIV3_GATE] = imx_clk_hw_gate_dis("frosc_div3_gate" , "frosc" , base + 0x208, 23); |
216 | clks[IMX8ULP_CLK_FROSC_DIV1] = imx_clk_hw_divider("frosc_div1" , "frosc_div1_gate" , base + 0x208, 0, 6); |
217 | clks[IMX8ULP_CLK_FROSC_DIV2] = imx_clk_hw_divider("frosc_div2" , "frosc_div2_gate" , base + 0x208, 8, 6); |
218 | clks[IMX8ULP_CLK_FROSC_DIV3] = imx_clk_hw_divider("frosc_div3" , "frosc_div3_gate" , base + 0x208, 16, 6); |
219 | clks[IMX8ULP_CLK_AUD_CLK1] = imx_clk_hw_mux2("aud_clk1" , base + 0x900, 0, 3, aud_clk1_sels, ARRAY_SIZE(aud_clk1_sels)); |
220 | clks[IMX8ULP_CLK_SAI4_SEL] = imx_clk_hw_mux2("sai4_sel" , base + 0x904, 0, 2, sai45_sels, ARRAY_SIZE(sai45_sels)); |
221 | clks[IMX8ULP_CLK_SAI5_SEL] = imx_clk_hw_mux2("sai5_sel" , base + 0x904, 8, 2, sai45_sels, ARRAY_SIZE(sai45_sels)); |
222 | clks[IMX8ULP_CLK_ENET_TS_SEL] = imx_clk_hw_mux2("enet_ts" , base + 0x700, 24, 3, enet_ts_sels, ARRAY_SIZE(enet_ts_sels)); |
223 | |
224 | imx_check_clk_hws(clks, count: clk_data->num); |
225 | |
226 | return devm_of_clk_add_hw_provider(dev, get: of_clk_hw_onecell_get, data: clk_data); |
227 | } |
228 | |
229 | static int imx8ulp_clk_cgc2_init(struct platform_device *pdev) |
230 | { |
231 | struct device *dev = &pdev->dev; |
232 | struct clk_hw_onecell_data *clk_data; |
233 | struct clk_hw **clks; |
234 | void __iomem *base; |
235 | |
236 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_CGC2_END), |
237 | GFP_KERNEL); |
238 | if (!clk_data) |
239 | return -ENOMEM; |
240 | |
241 | clk_data->num = IMX8ULP_CLK_CGC2_END; |
242 | clks = clk_data->hws; |
243 | |
244 | /* CGC2 */ |
245 | base = devm_platform_ioremap_resource(pdev, index: 0); |
246 | if (WARN_ON(IS_ERR(base))) |
247 | return PTR_ERR(ptr: base); |
248 | |
249 | clks[IMX8ULP_CLK_PLL4_PRE_SEL] = imx_clk_hw_mux_flags("pll4_pre_sel" , base + 0x610, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE); |
250 | |
251 | clks[IMX8ULP_CLK_PLL4] = imx_clk_hw_pllv4(type: IMX_PLLV4_IMX8ULP, name: "pll4" , parent_name: "pll4_pre_sel" , base: base + 0x600); |
252 | clks[IMX8ULP_CLK_PLL4_VCODIV] = imx_clk_hw_divider("pll4_vcodiv" , "pll4" , base + 0x604, 0, 6); |
253 | |
254 | clks[IMX8ULP_CLK_HIFI_SEL] = imx_clk_hw_mux_flags("hifi_sel" , base + 0x14, 28, 3, hifi_sels, ARRAY_SIZE(hifi_sels), CLK_SET_PARENT_GATE); |
255 | clks[IMX8ULP_CLK_HIFI_DIVCORE] = imx_clk_hw_divider("hifi_core_div" , "hifi_sel" , base + 0x14, 21, 6); |
256 | clks[IMX8ULP_CLK_HIFI_DIVPLAT] = imx_clk_hw_divider("hifi_plat_div" , "hifi_core_div" , base + 0x14, 14, 6); |
257 | |
258 | clks[IMX8ULP_CLK_DDR_SEL] = imx_clk_hw_mux_flags("ddr_sel" , base + 0x40, 28, 3, ddr_sels, ARRAY_SIZE(ddr_sels), CLK_GET_RATE_NOCACHE); |
259 | clks[IMX8ULP_CLK_DDR_DIV] = imx_clk_hw_divider_flags("ddr_div" , "ddr_sel" , base + 0x40, 21, 6, CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE); |
260 | clks[IMX8ULP_CLK_LPAV_AXI_SEL] = imx_clk_hw_mux2("lpav_sel" , base + 0x3c, 28, 2, lpav_sels, ARRAY_SIZE(lpav_sels)); |
261 | clks[IMX8ULP_CLK_LPAV_AXI_DIV] = imx_clk_hw_divider_flags("lpav_axi_div" , "lpav_sel" , base + 0x3c, 21, 6, CLK_IS_CRITICAL); |
262 | clks[IMX8ULP_CLK_LPAV_AHB_DIV] = imx_clk_hw_divider_flags("lpav_ahb_div" , "lpav_axi_div" , base + 0x3c, 14, 6, CLK_IS_CRITICAL); |
263 | clks[IMX8ULP_CLK_LPAV_BUS_DIV] = imx_clk_hw_divider_flags("lpav_bus_div" , "lpav_axi_div" , base + 0x3c, 7, 6, CLK_IS_CRITICAL); |
264 | |
265 | clks[IMX8ULP_CLK_PLL4_PFD0] = imx_clk_hw_pfdv2(type: IMX_PFDV2_IMX8ULP, name: "pll4_pfd0" , parent_name: "pll4_vcodiv" , reg: base + 0x614, idx: 0); |
266 | clks[IMX8ULP_CLK_PLL4_PFD1] = imx_clk_hw_pfdv2(type: IMX_PFDV2_IMX8ULP, name: "pll4_pfd1" , parent_name: "pll4_vcodiv" , reg: base + 0x614, idx: 1); |
267 | clks[IMX8ULP_CLK_PLL4_PFD2] = imx_clk_hw_pfdv2(type: IMX_PFDV2_IMX8ULP, name: "pll4_pfd2" , parent_name: "pll4_vcodiv" , reg: base + 0x614, idx: 2); |
268 | clks[IMX8ULP_CLK_PLL4_PFD3] = imx_clk_hw_pfdv2(type: IMX_PFDV2_IMX8ULP, name: "pll4_pfd3" , parent_name: "pll4_vcodiv" , reg: base + 0x614, idx: 3); |
269 | |
270 | clks[IMX8ULP_CLK_PLL4_PFD0_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd0_div1_gate" , "pll4_pfd0" , base + 0x608, 7); |
271 | clks[IMX8ULP_CLK_PLL4_PFD0_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd0_div2_gate" , "pll4_pfd0" , base + 0x608, 15); |
272 | clks[IMX8ULP_CLK_PLL4_PFD1_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd1_div1_gate" , "pll4_pfd1" , base + 0x608, 23); |
273 | clks[IMX8ULP_CLK_PLL4_PFD1_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd1_div2_gate" , "pll4_pfd1" , base + 0x608, 31); |
274 | clks[IMX8ULP_CLK_PLL4_PFD2_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd2_div1_gate" , "pll4_pfd2" , base + 0x60c, 7); |
275 | clks[IMX8ULP_CLK_PLL4_PFD2_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd2_div2_gate" , "pll4_pfd2" , base + 0x60c, 15); |
276 | clks[IMX8ULP_CLK_PLL4_PFD3_DIV1_GATE] = imx_clk_hw_gate_dis("pll4_pfd3_div1_gate" , "pll4_pfd3" , base + 0x60c, 23); |
277 | clks[IMX8ULP_CLK_PLL4_PFD3_DIV2_GATE] = imx_clk_hw_gate_dis("pll4_pfd3_div2_gate" , "pll4_pfd3" , base + 0x60c, 31); |
278 | clks[IMX8ULP_CLK_PLL4_PFD0_DIV1] = imx_clk_hw_divider_closest(name: "pll4_pfd0_div1" , parent: "pll4_pfd0_div1_gate" , reg: base + 0x608, shift: 0, width: 6); |
279 | clks[IMX8ULP_CLK_PLL4_PFD0_DIV2] = imx_clk_hw_divider_closest(name: "pll4_pfd0_div2" , parent: "pll4_pfd0_div2_gate" , reg: base + 0x608, shift: 8, width: 6); |
280 | clks[IMX8ULP_CLK_PLL4_PFD1_DIV1] = imx_clk_hw_divider_closest(name: "pll4_pfd1_div1" , parent: "pll4_pfd1_div1_gate" , reg: base + 0x608, shift: 16, width: 6); |
281 | clks[IMX8ULP_CLK_PLL4_PFD1_DIV2] = imx_clk_hw_divider_closest(name: "pll4_pfd1_div2" , parent: "pll4_pfd1_div2_gate" , reg: base + 0x608, shift: 24, width: 6); |
282 | clks[IMX8ULP_CLK_PLL4_PFD2_DIV1] = imx_clk_hw_divider_closest(name: "pll4_pfd2_div1" , parent: "pll4_pfd2_div1_gate" , reg: base + 0x60c, shift: 0, width: 6); |
283 | clks[IMX8ULP_CLK_PLL4_PFD2_DIV2] = imx_clk_hw_divider_closest(name: "pll4_pfd2_div2" , parent: "pll4_pfd2_div2_gate" , reg: base + 0x60c, shift: 8, width: 6); |
284 | clks[IMX8ULP_CLK_PLL4_PFD3_DIV1] = imx_clk_hw_divider_closest(name: "pll4_pfd3_div1" , parent: "pll4_pfd3_div1_gate" , reg: base + 0x60c, shift: 16, width: 6); |
285 | clks[IMX8ULP_CLK_PLL4_PFD3_DIV2] = imx_clk_hw_divider_closest(name: "pll4_pfd3_div2" , parent: "pll4_pfd3_div2_gate" , reg: base + 0x60c, shift: 24, width: 6); |
286 | |
287 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV1_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div1_gate" , "sosc" , base + 0x108, 7); |
288 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV2_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div2_gate" , "sosc" , base + 0x108, 15); |
289 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV3_GATE] = imx_clk_hw_gate_dis("cgc2_sosc_div3_gate" , "sosc" , base + 0x108, 23); |
290 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV1] = imx_clk_hw_divider("cgc2_sosc_div1" , "cgc2_sosc_div1_gate" , base + 0x108, 0, 6); |
291 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV2] = imx_clk_hw_divider("cgc2_sosc_div2" , "cgc2_sosc_div2_gate" , base + 0x108, 8, 6); |
292 | clks[IMX8ULP_CLK_CGC2_SOSC_DIV3] = imx_clk_hw_divider("cgc2_sosc_div3" , "cgc2_sosc_div3_gate" , base + 0x108, 16, 6); |
293 | |
294 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV1_GATE] = imx_clk_hw_gate_dis("cgc2_frosc_div1_gate" , "frosc" , base + 0x208, 7); |
295 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV2_GATE] = imx_clk_hw_gate_dis("cgc2_frosc_div2_gate" , "frosc" , base + 0x208, 15); |
296 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV3_GATE] = imx_clk_hw_gate_dis("cgc2_frosc_div3_gate" , "frosc" , base + 0x208, 23); |
297 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV1] = imx_clk_hw_divider("cgc2_frosc_div1" , "cgc2_frosc_div1_gate" , base + 0x208, 0, 6); |
298 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV2] = imx_clk_hw_divider("cgc2_frosc_div2" , "cgc2_frosc_div2_gate" , base + 0x208, 8, 6); |
299 | clks[IMX8ULP_CLK_CGC2_FROSC_DIV3] = imx_clk_hw_divider("cgc2_frosc_div3" , "cgc2_frosc_div3_gate" , base + 0x208, 16, 6); |
300 | clks[IMX8ULP_CLK_AUD_CLK2] = imx_clk_hw_mux2("aud_clk2" , base + 0x900, 0, 3, aud_clk2_sels, ARRAY_SIZE(aud_clk2_sels)); |
301 | clks[IMX8ULP_CLK_SAI6_SEL] = imx_clk_hw_mux2("sai6_sel" , base + 0x904, 0, 3, sai67_sels, ARRAY_SIZE(sai67_sels)); |
302 | clks[IMX8ULP_CLK_SAI7_SEL] = imx_clk_hw_mux2("sai7_sel" , base + 0x904, 8, 3, sai67_sels, ARRAY_SIZE(sai67_sels)); |
303 | clks[IMX8ULP_CLK_SPDIF_SEL] = imx_clk_hw_mux2("spdif_sel" , base + 0x910, 0, 3, sai67_sels, ARRAY_SIZE(sai67_sels)); |
304 | clks[IMX8ULP_CLK_DSI_PHY_REF] = imx_clk_hw_fixed(name: "dsi_phy_ref" , rate: 24000000); |
305 | |
306 | imx_check_clk_hws(clks, count: clk_data->num); |
307 | |
308 | return devm_of_clk_add_hw_provider(dev, get: of_clk_hw_onecell_get, data: clk_data); |
309 | } |
310 | |
311 | static int imx8ulp_clk_pcc3_init(struct platform_device *pdev) |
312 | { |
313 | struct device *dev = &pdev->dev; |
314 | struct clk_hw_onecell_data *clk_data; |
315 | struct clk_hw **clks; |
316 | void __iomem *base; |
317 | int ret; |
318 | |
319 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC3_END), |
320 | GFP_KERNEL); |
321 | if (!clk_data) |
322 | return -ENOMEM; |
323 | |
324 | clk_data->num = IMX8ULP_CLK_PCC3_END; |
325 | clks = clk_data->hws; |
326 | |
327 | /* PCC3 */ |
328 | base = devm_platform_ioremap_resource(pdev, index: 0); |
329 | if (WARN_ON(IS_ERR(base))) |
330 | return PTR_ERR(ptr: base); |
331 | |
332 | clks[IMX8ULP_CLK_WDOG3] = imx8ulp_clk_hw_composite(name: "wdog3" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xa8, has_swrst: 1); |
333 | clks[IMX8ULP_CLK_WDOG4] = imx8ulp_clk_hw_composite(name: "wdog4" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xac, has_swrst: 1); |
334 | clks[IMX8ULP_CLK_LPIT1] = imx8ulp_clk_hw_composite(name: "lpit1" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xc8, has_swrst: 1); |
335 | clks[IMX8ULP_CLK_TPM4] = imx8ulp_clk_hw_composite(name: "tpm4" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xcc, has_swrst: 1); |
336 | clks[IMX8ULP_CLK_FLEXIO1] = imx8ulp_clk_hw_composite(name: "flexio1" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xd4, has_swrst: 1); |
337 | clks[IMX8ULP_CLK_I3C2] = imx8ulp_clk_hw_composite(name: "i3c2" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xd8, has_swrst: 1); |
338 | clks[IMX8ULP_CLK_LPI2C4] = imx8ulp_clk_hw_composite(name: "lpi2c4" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xdc, has_swrst: 1); |
339 | clks[IMX8ULP_CLK_LPI2C5] = imx8ulp_clk_hw_composite(name: "lpi2c5" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xe0, has_swrst: 1); |
340 | clks[IMX8ULP_CLK_LPUART4] = imx8ulp_clk_hw_composite(name: "lpuart4" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xe4, has_swrst: 1); |
341 | clks[IMX8ULP_CLK_LPUART5] = imx8ulp_clk_hw_composite(name: "lpuart5" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xe8, has_swrst: 1); |
342 | clks[IMX8ULP_CLK_LPSPI4] = imx8ulp_clk_hw_composite(name: "lpspi4" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xec, has_swrst: 1); |
343 | clks[IMX8ULP_CLK_LPSPI5] = imx8ulp_clk_hw_composite(name: "lpspi5" , parent_names: pcc3_periph_bus_sels, ARRAY_SIZE(pcc3_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xf0, has_swrst: 1); |
344 | |
345 | clks[IMX8ULP_CLK_DMA1_MP] = imx_clk_hw_gate("pcc_dma1_mp" , "xbar_ad_divplat" , base + 0x4, 30); |
346 | clks[IMX8ULP_CLK_DMA1_CH0] = imx_clk_hw_gate("pcc_dma1_ch0" , "xbar_ad_divplat" , base + 0x8, 30); |
347 | clks[IMX8ULP_CLK_DMA1_CH1] = imx_clk_hw_gate("pcc_dma1_ch1" , "xbar_ad_divplat" , base + 0xc, 30); |
348 | clks[IMX8ULP_CLK_DMA1_CH2] = imx_clk_hw_gate("pcc_dma1_ch2" , "xbar_ad_divplat" , base + 0x10, 30); |
349 | clks[IMX8ULP_CLK_DMA1_CH3] = imx_clk_hw_gate("pcc_dma1_ch3" , "xbar_ad_divplat" , base + 0x14, 30); |
350 | clks[IMX8ULP_CLK_DMA1_CH4] = imx_clk_hw_gate("pcc_dma1_ch4" , "xbar_ad_divplat" , base + 0x18, 30); |
351 | clks[IMX8ULP_CLK_DMA1_CH5] = imx_clk_hw_gate("pcc_dma1_ch5" , "xbar_ad_divplat" , base + 0x1c, 30); |
352 | clks[IMX8ULP_CLK_DMA1_CH6] = imx_clk_hw_gate("pcc_dma1_ch6" , "xbar_ad_divplat" , base + 0x20, 30); |
353 | clks[IMX8ULP_CLK_DMA1_CH7] = imx_clk_hw_gate("pcc_dma1_ch7" , "xbar_ad_divplat" , base + 0x24, 30); |
354 | clks[IMX8ULP_CLK_DMA1_CH8] = imx_clk_hw_gate("pcc_dma1_ch8" , "xbar_ad_divplat" , base + 0x28, 30); |
355 | clks[IMX8ULP_CLK_DMA1_CH9] = imx_clk_hw_gate("pcc_dma1_ch9" , "xbar_ad_divplat" , base + 0x2c, 30); |
356 | clks[IMX8ULP_CLK_DMA1_CH10] = imx_clk_hw_gate("pcc_dma1_ch10" , "xbar_ad_divplat" , base + 0x30, 30); |
357 | clks[IMX8ULP_CLK_DMA1_CH11] = imx_clk_hw_gate("pcc_dma1_ch11" , "xbar_ad_divplat" , base + 0x34, 30); |
358 | clks[IMX8ULP_CLK_DMA1_CH12] = imx_clk_hw_gate("pcc_dma1_ch12" , "xbar_ad_divplat" , base + 0x38, 30); |
359 | clks[IMX8ULP_CLK_DMA1_CH13] = imx_clk_hw_gate("pcc_dma1_ch13" , "xbar_ad_divplat" , base + 0x3c, 30); |
360 | clks[IMX8ULP_CLK_DMA1_CH14] = imx_clk_hw_gate("pcc_dma1_ch14" , "xbar_ad_divplat" , base + 0x40, 30); |
361 | clks[IMX8ULP_CLK_DMA1_CH15] = imx_clk_hw_gate("pcc_dma1_ch15" , "xbar_ad_divplat" , base + 0x44, 30); |
362 | clks[IMX8ULP_CLK_DMA1_CH16] = imx_clk_hw_gate("pcc_dma1_ch16" , "xbar_ad_divplat" , base + 0x48, 30); |
363 | clks[IMX8ULP_CLK_DMA1_CH17] = imx_clk_hw_gate("pcc_dma1_ch17" , "xbar_ad_divplat" , base + 0x4c, 30); |
364 | clks[IMX8ULP_CLK_DMA1_CH18] = imx_clk_hw_gate("pcc_dma1_ch18" , "xbar_ad_divplat" , base + 0x50, 30); |
365 | clks[IMX8ULP_CLK_DMA1_CH19] = imx_clk_hw_gate("pcc_dma1_ch19" , "xbar_ad_divplat" , base + 0x54, 30); |
366 | clks[IMX8ULP_CLK_DMA1_CH20] = imx_clk_hw_gate("pcc_dma1_ch20" , "xbar_ad_divplat" , base + 0x58, 30); |
367 | clks[IMX8ULP_CLK_DMA1_CH21] = imx_clk_hw_gate("pcc_dma1_ch21" , "xbar_ad_divplat" , base + 0x5c, 30); |
368 | clks[IMX8ULP_CLK_DMA1_CH22] = imx_clk_hw_gate("pcc_dma1_ch22" , "xbar_ad_divplat" , base + 0x60, 30); |
369 | clks[IMX8ULP_CLK_DMA1_CH23] = imx_clk_hw_gate("pcc_dma1_ch23" , "xbar_ad_divplat" , base + 0x64, 30); |
370 | clks[IMX8ULP_CLK_DMA1_CH24] = imx_clk_hw_gate("pcc_dma1_ch24" , "xbar_ad_divplat" , base + 0x68, 30); |
371 | clks[IMX8ULP_CLK_DMA1_CH25] = imx_clk_hw_gate("pcc_dma1_ch25" , "xbar_ad_divplat" , base + 0x6c, 30); |
372 | clks[IMX8ULP_CLK_DMA1_CH26] = imx_clk_hw_gate("pcc_dma1_ch26" , "xbar_ad_divplat" , base + 0x70, 30); |
373 | clks[IMX8ULP_CLK_DMA1_CH27] = imx_clk_hw_gate("pcc_dma1_ch27" , "xbar_ad_divplat" , base + 0x74, 30); |
374 | clks[IMX8ULP_CLK_DMA1_CH28] = imx_clk_hw_gate("pcc_dma1_ch28" , "xbar_ad_divplat" , base + 0x78, 30); |
375 | clks[IMX8ULP_CLK_DMA1_CH29] = imx_clk_hw_gate("pcc_dma1_ch29" , "xbar_ad_divplat" , base + 0x7c, 30); |
376 | clks[IMX8ULP_CLK_DMA1_CH30] = imx_clk_hw_gate("pcc_dma1_ch30" , "xbar_ad_divplat" , base + 0x80, 30); |
377 | clks[IMX8ULP_CLK_DMA1_CH31] = imx_clk_hw_gate("pcc_dma1_ch31" , "xbar_ad_divplat" , base + 0x84, 30); |
378 | clks[IMX8ULP_CLK_MU0_B] = imx_clk_hw_gate_flags("mu0_b" , "xbar_ad_divplat" , base + 0x88, 30, CLK_IS_CRITICAL); |
379 | clks[IMX8ULP_CLK_MU3_A] = imx_clk_hw_gate("mu3_a" , "xbar_ad_divplat" , base + 0x8c, 30); |
380 | clks[IMX8ULP_CLK_TPM5] = imx_clk_hw_gate_flags("tpm5" , "sosc_div2" , base + 0xd0, 30, CLK_IS_CRITICAL); |
381 | |
382 | imx_check_clk_hws(clks, count: clk_data->num); |
383 | |
384 | ret = devm_of_clk_add_hw_provider(dev, get: of_clk_hw_onecell_get, data: clk_data); |
385 | if (ret) |
386 | return ret; |
387 | |
388 | imx_register_uart_clocks(); |
389 | |
390 | /* register the pcc3 reset controller */ |
391 | return imx8ulp_pcc_reset_init(pdev, base, resets: pcc3_resets, ARRAY_SIZE(pcc3_resets)); |
392 | } |
393 | |
394 | static int imx8ulp_clk_pcc4_init(struct platform_device *pdev) |
395 | { |
396 | struct device *dev = &pdev->dev; |
397 | struct clk_hw_onecell_data *clk_data; |
398 | struct clk_hw **clks; |
399 | void __iomem *base; |
400 | int ret; |
401 | |
402 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC4_END), |
403 | GFP_KERNEL); |
404 | if (!clk_data) |
405 | return -ENOMEM; |
406 | |
407 | clk_data->num = IMX8ULP_CLK_PCC4_END; |
408 | clks = clk_data->hws; |
409 | |
410 | /* PCC4 */ |
411 | base = devm_platform_ioremap_resource(pdev, index: 0); |
412 | if (WARN_ON(IS_ERR(base))) |
413 | return PTR_ERR(ptr: base); |
414 | |
415 | clks[IMX8ULP_CLK_FLEXSPI2] = imx8ulp_clk_hw_composite(name: "flexspi2" , parent_names: pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0x4, has_swrst: 1); |
416 | clks[IMX8ULP_CLK_TPM6] = imx8ulp_clk_hw_composite(name: "tpm6" , parent_names: pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0x8, has_swrst: 1); |
417 | clks[IMX8ULP_CLK_TPM7] = imx8ulp_clk_hw_composite(name: "tpm7" , parent_names: pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xc, has_swrst: 1); |
418 | clks[IMX8ULP_CLK_LPI2C6] = imx8ulp_clk_hw_composite(name: "lpi2c6" , parent_names: pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0x10, has_swrst: 1); |
419 | clks[IMX8ULP_CLK_LPI2C7] = imx8ulp_clk_hw_composite(name: "lpi2c7" , parent_names: pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0x14, has_swrst: 1); |
420 | clks[IMX8ULP_CLK_LPUART6] = imx8ulp_clk_hw_composite(name: "lpuart6" , parent_names: pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0x18, has_swrst: 1); |
421 | clks[IMX8ULP_CLK_LPUART7] = imx8ulp_clk_hw_composite(name: "lpuart7" , parent_names: pcc4_periph_bus_sels, ARRAY_SIZE(pcc4_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0x1c, has_swrst: 1); |
422 | clks[IMX8ULP_CLK_SAI4] = imx8ulp_clk_hw_composite(name: "sai4" , parent_names: xbar_divbus, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0x20, has_swrst: 1); /* sai ipg, NOT from sai sel */ |
423 | clks[IMX8ULP_CLK_SAI5] = imx8ulp_clk_hw_composite(name: "sai5" , parent_names: xbar_divbus, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0x24, has_swrst: 1); /* sai ipg */ |
424 | clks[IMX8ULP_CLK_PCTLE] = imx_clk_hw_gate("pctle" , "xbar_divbus" , base + 0x28, 30); |
425 | clks[IMX8ULP_CLK_PCTLF] = imx_clk_hw_gate("pctlf" , "xbar_divbus" , base + 0x2c, 30); |
426 | clks[IMX8ULP_CLK_USDHC0] = imx8ulp_clk_hw_composite(name: "usdhc0" , parent_names: pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), mux_present: true, rate_present: false, gate_present: true, reg: base + 0x34, has_swrst: 1); |
427 | clks[IMX8ULP_CLK_USDHC1] = imx8ulp_clk_hw_composite(name: "usdhc1" , parent_names: pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), mux_present: true, rate_present: false, gate_present: true, reg: base + 0x38, has_swrst: 1); |
428 | clks[IMX8ULP_CLK_USDHC2] = imx8ulp_clk_hw_composite(name: "usdhc2" , parent_names: pcc4_periph_plat_sels, ARRAY_SIZE(pcc4_periph_plat_sels), mux_present: true, rate_present: false, gate_present: true, reg: base + 0x3c, has_swrst: 1); |
429 | clks[IMX8ULP_CLK_USB0] = imx8ulp_clk_hw_composite(name: "usb0" , parent_names: nic_per_divplat, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0x40, has_swrst: 1); |
430 | clks[IMX8ULP_CLK_USB0_PHY] = imx8ulp_clk_hw_composite(name: "usb0_phy" , parent_names: xbar_divbus, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0x44, has_swrst: 1); |
431 | clks[IMX8ULP_CLK_USB1] = imx8ulp_clk_hw_composite(name: "usb1" , parent_names: nic_per_divplat, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0x48, has_swrst: 1); |
432 | clks[IMX8ULP_CLK_USB1_PHY] = imx8ulp_clk_hw_composite(name: "usb1_phy" , parent_names: xbar_divbus, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0x4c, has_swrst: 1); |
433 | clks[IMX8ULP_CLK_USB_XBAR] = imx_clk_hw_gate("usb_xbar" , "xbar_divbus" , base + 0x50, 30); |
434 | clks[IMX8ULP_CLK_ENET] = imx8ulp_clk_hw_composite(name: "enet" , parent_names: nic_per_divplat, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0x54, has_swrst: 1); |
435 | clks[IMX8ULP_CLK_RGPIOE] = imx_clk_hw_gate("rgpioe" , "nic_per_divplat" , base + 0x78, 30); |
436 | clks[IMX8ULP_CLK_RGPIOF] = imx_clk_hw_gate("rgpiof" , "nic_per_divplat" , base + 0x7c, 30); |
437 | |
438 | imx_check_clk_hws(clks, count: clk_data->num); |
439 | |
440 | ret = devm_of_clk_add_hw_provider(dev, get: of_clk_hw_onecell_get, data: clk_data); |
441 | if (ret) |
442 | return ret; |
443 | |
444 | /* register the pcc4 reset controller */ |
445 | return imx8ulp_pcc_reset_init(pdev, base, resets: pcc4_resets, ARRAY_SIZE(pcc4_resets)); |
446 | |
447 | } |
448 | |
449 | static int imx8ulp_clk_pcc5_init(struct platform_device *pdev) |
450 | { |
451 | struct device *dev = &pdev->dev; |
452 | struct clk_hw_onecell_data *clk_data; |
453 | struct clk_hw **clks; |
454 | void __iomem *base; |
455 | int ret; |
456 | |
457 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, IMX8ULP_CLK_PCC5_END), |
458 | GFP_KERNEL); |
459 | if (!clk_data) |
460 | return -ENOMEM; |
461 | |
462 | clk_data->num = IMX8ULP_CLK_PCC5_END; |
463 | clks = clk_data->hws; |
464 | |
465 | /* PCC5 */ |
466 | base = devm_platform_ioremap_resource(pdev, index: 0); |
467 | if (WARN_ON(IS_ERR(base))) |
468 | return PTR_ERR(ptr: base); |
469 | |
470 | clks[IMX8ULP_CLK_DMA2_MP] = imx_clk_hw_gate("pcc_dma2_mp" , "lpav_axi_div" , base + 0x0, 30); |
471 | clks[IMX8ULP_CLK_DMA2_CH0] = imx_clk_hw_gate("pcc_dma2_ch0" , "lpav_axi_div" , base + 0x4, 30); |
472 | clks[IMX8ULP_CLK_DMA2_CH1] = imx_clk_hw_gate("pcc_dma2_ch1" , "lpav_axi_div" , base + 0x8, 30); |
473 | clks[IMX8ULP_CLK_DMA2_CH2] = imx_clk_hw_gate("pcc_dma2_ch2" , "lpav_axi_div" , base + 0xc, 30); |
474 | clks[IMX8ULP_CLK_DMA2_CH3] = imx_clk_hw_gate("pcc_dma2_ch3" , "lpav_axi_div" , base + 0x10, 30); |
475 | clks[IMX8ULP_CLK_DMA2_CH4] = imx_clk_hw_gate("pcc_dma2_ch4" , "lpav_axi_div" , base + 0x14, 30); |
476 | clks[IMX8ULP_CLK_DMA2_CH5] = imx_clk_hw_gate("pcc_dma2_ch5" , "lpav_axi_div" , base + 0x18, 30); |
477 | clks[IMX8ULP_CLK_DMA2_CH6] = imx_clk_hw_gate("pcc_dma2_ch6" , "lpav_axi_div" , base + 0x1c, 30); |
478 | clks[IMX8ULP_CLK_DMA2_CH7] = imx_clk_hw_gate("pcc_dma2_ch7" , "lpav_axi_div" , base + 0x20, 30); |
479 | clks[IMX8ULP_CLK_DMA2_CH8] = imx_clk_hw_gate("pcc_dma2_ch8" , "lpav_axi_div" , base + 0x24, 30); |
480 | clks[IMX8ULP_CLK_DMA2_CH9] = imx_clk_hw_gate("pcc_dma2_ch9" , "lpav_axi_div" , base + 0x28, 30); |
481 | clks[IMX8ULP_CLK_DMA2_CH10] = imx_clk_hw_gate("pcc_dma2_ch10" , "lpav_axi_div" , base + 0x2c, 30); |
482 | clks[IMX8ULP_CLK_DMA2_CH11] = imx_clk_hw_gate("pcc_dma2_ch11" , "lpav_axi_div" , base + 0x30, 30); |
483 | clks[IMX8ULP_CLK_DMA2_CH12] = imx_clk_hw_gate("pcc_dma2_ch12" , "lpav_axi_div" , base + 0x34, 30); |
484 | clks[IMX8ULP_CLK_DMA2_CH13] = imx_clk_hw_gate("pcc_dma2_ch13" , "lpav_axi_div" , base + 0x38, 30); |
485 | clks[IMX8ULP_CLK_DMA2_CH14] = imx_clk_hw_gate("pcc_dma2_ch14" , "lpav_axi_div" , base + 0x3c, 30); |
486 | clks[IMX8ULP_CLK_DMA2_CH15] = imx_clk_hw_gate("pcc_dma2_ch15" , "lpav_axi_div" , base + 0x40, 30); |
487 | clks[IMX8ULP_CLK_DMA2_CH16] = imx_clk_hw_gate("pcc_dma2_ch16" , "lpav_axi_div" , base + 0x44, 30); |
488 | clks[IMX8ULP_CLK_DMA2_CH17] = imx_clk_hw_gate("pcc_dma2_ch17" , "lpav_axi_div" , base + 0x48, 30); |
489 | clks[IMX8ULP_CLK_DMA2_CH18] = imx_clk_hw_gate("pcc_dma2_ch18" , "lpav_axi_div" , base + 0x4c, 30); |
490 | clks[IMX8ULP_CLK_DMA2_CH19] = imx_clk_hw_gate("pcc_dma2_ch19" , "lpav_axi_div" , base + 0x50, 30); |
491 | clks[IMX8ULP_CLK_DMA2_CH20] = imx_clk_hw_gate("pcc_dma2_ch20" , "lpav_axi_div" , base + 0x54, 30); |
492 | clks[IMX8ULP_CLK_DMA2_CH21] = imx_clk_hw_gate("pcc_dma2_ch21" , "lpav_axi_div" , base + 0x58, 30); |
493 | clks[IMX8ULP_CLK_DMA2_CH22] = imx_clk_hw_gate("pcc_dma2_ch22" , "lpav_axi_div" , base + 0x5c, 30); |
494 | clks[IMX8ULP_CLK_DMA2_CH23] = imx_clk_hw_gate("pcc_dma2_ch23" , "lpav_axi_div" , base + 0x60, 30); |
495 | clks[IMX8ULP_CLK_DMA2_CH24] = imx_clk_hw_gate("pcc_dma2_ch24" , "lpav_axi_div" , base + 0x64, 30); |
496 | clks[IMX8ULP_CLK_DMA2_CH25] = imx_clk_hw_gate("pcc_dma2_ch25" , "lpav_axi_div" , base + 0x68, 30); |
497 | clks[IMX8ULP_CLK_DMA2_CH26] = imx_clk_hw_gate("pcc_dma2_ch26" , "lpav_axi_div" , base + 0x6c, 30); |
498 | clks[IMX8ULP_CLK_DMA2_CH27] = imx_clk_hw_gate("pcc_dma2_ch27" , "lpav_axi_div" , base + 0x70, 30); |
499 | clks[IMX8ULP_CLK_DMA2_CH28] = imx_clk_hw_gate("pcc_dma2_ch28" , "lpav_axi_div" , base + 0x74, 30); |
500 | clks[IMX8ULP_CLK_DMA2_CH29] = imx_clk_hw_gate("pcc_dma2_ch29" , "lpav_axi_div" , base + 0x78, 30); |
501 | clks[IMX8ULP_CLK_DMA2_CH30] = imx_clk_hw_gate("pcc_dma2_ch30" , "lpav_axi_div" , base + 0x7c, 30); |
502 | clks[IMX8ULP_CLK_DMA2_CH31] = imx_clk_hw_gate("pcc_dma2_ch31" , "lpav_axi_div" , base + 0x80, 30); |
503 | |
504 | clks[IMX8ULP_CLK_AVD_SIM] = imx_clk_hw_gate("avd_sim" , "lpav_bus_div" , base + 0x94, 30); |
505 | clks[IMX8ULP_CLK_TPM8] = imx8ulp_clk_hw_composite(name: "tpm8" , parent_names: pcc5_periph_bus_sels, ARRAY_SIZE(pcc5_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xa0, has_swrst: 1); |
506 | clks[IMX8ULP_CLK_MU2_B] = imx_clk_hw_gate("mu2_b" , "lpav_bus_div" , base + 0x84, 30); |
507 | clks[IMX8ULP_CLK_MU3_B] = imx_clk_hw_gate("mu3_b" , "lpav_bus_div" , base + 0x88, 30); |
508 | clks[IMX8ULP_CLK_SAI6] = imx8ulp_clk_hw_composite(name: "sai6" , parent_names: lpav_bus_div, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0xa4, has_swrst: 1); |
509 | clks[IMX8ULP_CLK_SAI7] = imx8ulp_clk_hw_composite(name: "sai7" , parent_names: lpav_bus_div, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0xa8, has_swrst: 1); |
510 | clks[IMX8ULP_CLK_SPDIF] = imx8ulp_clk_hw_composite(name: "spdif" , parent_names: lpav_bus_div, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0xac, has_swrst: 1); |
511 | clks[IMX8ULP_CLK_ISI] = imx8ulp_clk_hw_composite(name: "isi" , parent_names: lpav_axi_div, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0xb0, has_swrst: 1); |
512 | clks[IMX8ULP_CLK_CSI_REGS] = imx8ulp_clk_hw_composite(name: "csi_regs" , parent_names: lpav_bus_div, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0xb4, has_swrst: 1); |
513 | clks[IMX8ULP_CLK_CSI] = imx8ulp_clk_hw_composite(name: "csi" , parent_names: pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xbc, has_swrst: 1); |
514 | clks[IMX8ULP_CLK_DSI] = imx8ulp_clk_hw_composite(name: "dsi" , parent_names: pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xc0, has_swrst: 1); |
515 | clks[IMX8ULP_CLK_WDOG5] = imx8ulp_clk_hw_composite(name: "wdog5" , parent_names: pcc5_periph_bus_sels, ARRAY_SIZE(pcc5_periph_bus_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xc8, has_swrst: 1); |
516 | clks[IMX8ULP_CLK_EPDC] = imx8ulp_clk_hw_composite(name: "epdc" , parent_names: pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xcc, has_swrst: 1); |
517 | clks[IMX8ULP_CLK_PXP] = imx8ulp_clk_hw_composite(name: "pxp" , parent_names: lpav_axi_div, num_parents: 1, mux_present: false, rate_present: false, gate_present: true, reg: base + 0xd0, has_swrst: 1); |
518 | clks[IMX8ULP_CLK_GPU2D] = imx8ulp_clk_hw_composite(name: "gpu2d" , parent_names: pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xf0, has_swrst: 1); |
519 | clks[IMX8ULP_CLK_GPU3D] = imx8ulp_clk_hw_composite(name: "gpu3d" , parent_names: pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xf4, has_swrst: 1); |
520 | clks[IMX8ULP_CLK_DC_NANO] = imx8ulp_clk_hw_composite(name: "dc_nano" , parent_names: pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0xf8, has_swrst: 1); |
521 | clks[IMX8ULP_CLK_CSI_CLK_UI] = imx8ulp_clk_hw_composite(name: "csi_clk_ui" , parent_names: pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0x10c, has_swrst: 1); |
522 | clks[IMX8ULP_CLK_CSI_CLK_ESC] = imx8ulp_clk_hw_composite(name: "csi_clk_esc" , parent_names: pcc5_periph_plat_sels, ARRAY_SIZE(pcc5_periph_plat_sels), mux_present: true, rate_present: true, gate_present: true, reg: base + 0x110, has_swrst: 1); |
523 | clks[IMX8ULP_CLK_RGPIOD] = imx_clk_hw_gate("rgpiod" , "lpav_axi_div" , base + 0x114, 30); |
524 | clks[IMX8ULP_CLK_DSI_TX_ESC] = imx_clk_hw_fixed_factor(name: "mipi_dsi_tx_esc" , parent: "dsi" , mult: 1, div: 4); |
525 | |
526 | imx_check_clk_hws(clks, count: clk_data->num); |
527 | |
528 | ret = devm_of_clk_add_hw_provider(dev, get: of_clk_hw_onecell_get, data: clk_data); |
529 | if (ret) |
530 | return ret; |
531 | |
532 | /* register the pcc5 reset controller */ |
533 | return imx8ulp_pcc_reset_init(pdev, base, resets: pcc5_resets, ARRAY_SIZE(pcc5_resets)); |
534 | } |
535 | |
536 | static int imx8ulp_clk_probe(struct platform_device *pdev) |
537 | { |
538 | int (*probe)(struct platform_device *pdev); |
539 | |
540 | probe = of_device_get_match_data(dev: &pdev->dev); |
541 | |
542 | if (probe) |
543 | return probe(pdev); |
544 | |
545 | return 0; |
546 | } |
547 | |
548 | static const struct of_device_id imx8ulp_clk_dt_ids[] = { |
549 | { .compatible = "fsl,imx8ulp-pcc3" , .data = imx8ulp_clk_pcc3_init }, |
550 | { .compatible = "fsl,imx8ulp-pcc4" , .data = imx8ulp_clk_pcc4_init }, |
551 | { .compatible = "fsl,imx8ulp-pcc5" , .data = imx8ulp_clk_pcc5_init }, |
552 | { .compatible = "fsl,imx8ulp-cgc2" , .data = imx8ulp_clk_cgc2_init }, |
553 | { .compatible = "fsl,imx8ulp-cgc1" , .data = imx8ulp_clk_cgc1_init }, |
554 | { /* sentinel */ }, |
555 | }; |
556 | MODULE_DEVICE_TABLE(of, imx8ulp_clk_dt_ids); |
557 | |
558 | static struct platform_driver imx8ulp_clk_driver = { |
559 | .probe = imx8ulp_clk_probe, |
560 | .driver = { |
561 | .name = KBUILD_MODNAME, |
562 | .suppress_bind_attrs = true, |
563 | .of_match_table = imx8ulp_clk_dt_ids, |
564 | }, |
565 | }; |
566 | module_platform_driver(imx8ulp_clk_driver); |
567 | |
568 | MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>" ); |
569 | MODULE_DESCRIPTION("NXP i.MX8ULP clock driver" ); |
570 | MODULE_LICENSE("GPL v2" ); |
571 | |