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
17static const char * const pll_pre_sels[] = { "sosc", "frosc", };
18static const char * const a35_sels[] = { "frosc", "spll2", "sosc", "lvds", };
19static const char * const nic_sels[] = { "frosc", "spll3_pfd0", "sosc", "lvds", };
20static 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", };
23static const char * const pcc4_periph_bus_sels[] = { "dummy", "dummy", "lposc",
24 "sosc_div2", "frosc_div2", "xbar_divbus",
25 "spll3_vcodiv", "spll3_pfd0_div1", };
26static 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", };
30static const char * const pcc5_periph_bus_sels[] = { "dummy", "dummy", "lposc",
31 "sosc_div2", "frosc_div2", "lpav_bus_clk",
32 "pll4_vcodiv", "pll4_pfd3_div1", };
33static 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", };
37static const char * const hifi_sels[] = { "frosc", "pll4", "pll4_pfd0", "sosc",
38 "lvds", "dummy", "dummy", "dummy", };
39static const char * const ddr_sels[] = { "frosc", "pll4_pfd1", "sosc", "lvds",
40 "pll4", "pll4", "pll4", "pll4", };
41static const char * const lpav_sels[] = { "frosc", "pll4_pfd1", "sosc", "lvds", };
42static const char * const sai45_sels[] = { "spll3_pfd1_div1", "aud_clk1", "aud_clk2", "sosc", };
43static const char * const sai67_sels[] = { "spll1_pfd2_div", "spll3_pfd1_div1", "aud_clk0", "aud_clk1", "aud_clk2", "sosc", "dummy", "dummy", };
44static const char * const aud_clk1_sels[] = { "ext_aud_mclk2", "sai4_rx_bclk", "sai4_tx_bclk", "sai5_rx_bclk", "sai5_tx_bclk", "dummy", "dummy", "dummy", };
45static 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", };
46static const char * const enet_ts_sels[] = { "ext_rmii_clk", "ext_ts_clk", "rosc", "ext_aud_mclk", "sosc", "dummy", "dummy", "dummy"};
47static const char * const xbar_divbus[] = { "xbar_divbus" };
48static const char * const nic_per_divplat[] = { "nic_per_divplat" };
49static const char * const lpav_axi_div[] = { "lpav_axi_div" };
50static const char * const lpav_bus_div[] = { "lpav_bus_div" };
51
52struct 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
63static const u32 pcc3_resets[] = {
64 0xa8, 0xac, 0xc8, 0xcc, 0xd0,
65 0xd4, 0xd8, 0xdc, 0xe0, 0xe4,
66 0xe8, 0xec, 0xf0
67};
68
69static 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
76static const u32 pcc5_resets[] = {
77 0xa0, 0xa4, 0xa8, 0xac, 0xb0,
78 0xb4, 0xbc, 0xc0, 0xc8, 0xcc,
79 0xd0, 0xf0, 0xf4, 0xf8
80};
81
82static 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
100static 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
118static const struct reset_control_ops imx8ulp_pcc_reset_ops = {
119 .assert = imx8ulp_pcc_assert,
120 .deassert = imx8ulp_pcc_deassert,
121};
122
123static 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
145static 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
229static 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
311static 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
394static 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
449static 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
536static 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
548static 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};
556MODULE_DEVICE_TABLE(of, imx8ulp_clk_dt_ids);
557
558static 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};
566module_platform_driver(imx8ulp_clk_driver);
567
568MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
569MODULE_DESCRIPTION("NXP i.MX8ULP clock driver");
570MODULE_LICENSE("GPL v2");
571

source code of linux/drivers/clk/imx/clk-imx8ulp.c