Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / clk / imx / clk.c
blobdf83bd939492ebac5bce703942c2fcb79e6aea94
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/bits.h>
3 #include <linux/clk.h>
4 #include <linux/clk-provider.h>
5 #include <linux/err.h>
6 #include <linux/io.h>
7 #include <linux/module.h>
8 #include <linux/of.h>
9 #include <linux/slab.h>
10 #include <linux/spinlock.h>
11 #include "clk.h"
13 #define CCM_CCDR 0x4
14 #define CCDR_MMDC_CH0_MASK BIT(17)
15 #define CCDR_MMDC_CH1_MASK BIT(16)
17 DEFINE_SPINLOCK(imx_ccm_lock);
18 EXPORT_SYMBOL_GPL(imx_ccm_lock);
20 bool mcore_booted;
21 EXPORT_SYMBOL_GPL(mcore_booted);
23 void imx_unregister_hw_clocks(struct clk_hw *hws[], unsigned int count)
25 unsigned int i;
27 for (i = 0; i < count; i++)
28 clk_hw_unregister(hws[i]);
30 EXPORT_SYMBOL_GPL(imx_unregister_hw_clocks);
32 void imx_mmdc_mask_handshake(void __iomem *ccm_base,
33 unsigned int chn)
35 unsigned int reg;
37 reg = readl_relaxed(ccm_base + CCM_CCDR);
38 reg |= chn == 0 ? CCDR_MMDC_CH0_MASK : CCDR_MMDC_CH1_MASK;
39 writel_relaxed(reg, ccm_base + CCM_CCDR);
42 void imx_check_clocks(struct clk *clks[], unsigned int count)
44 unsigned i;
46 for (i = 0; i < count; i++)
47 if (IS_ERR(clks[i]))
48 pr_err("i.MX clk %u: register failed with %ld\n",
49 i, PTR_ERR(clks[i]));
52 void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
54 unsigned int i;
56 for (i = 0; i < count; i++)
57 if (IS_ERR(clks[i]))
58 pr_err("i.MX clk %u: register failed with %ld\n",
59 i, PTR_ERR(clks[i]));
61 EXPORT_SYMBOL_GPL(imx_check_clk_hws);
63 static struct clk *imx_obtain_fixed_clock_from_dt(const char *name)
65 struct of_phandle_args phandle;
66 struct clk *clk = ERR_PTR(-ENODEV);
67 char *path;
69 path = kasprintf(GFP_KERNEL, "/clocks/%s", name);
70 if (!path)
71 return ERR_PTR(-ENOMEM);
73 phandle.np = of_find_node_by_path(path);
74 kfree(path);
76 if (phandle.np) {
77 clk = of_clk_get_from_provider(&phandle);
78 of_node_put(phandle.np);
80 return clk;
83 struct clk *imx_obtain_fixed_clock(
84 const char *name, unsigned long rate)
86 struct clk *clk;
88 clk = imx_obtain_fixed_clock_from_dt(name);
89 if (IS_ERR(clk))
90 clk = imx_clk_fixed(name, rate);
91 return clk;
94 struct clk_hw *imx_obtain_fixed_clock_hw(
95 const char *name, unsigned long rate)
97 struct clk *clk;
99 clk = imx_obtain_fixed_clock_from_dt(name);
100 if (IS_ERR(clk))
101 clk = imx_clk_fixed(name, rate);
102 return __clk_get_hw(clk);
105 struct clk_hw *imx_obtain_fixed_of_clock(struct device_node *np,
106 const char *name, unsigned long rate)
108 struct clk *clk = of_clk_get_by_name(np, name);
109 struct clk_hw *hw;
111 if (IS_ERR(clk))
112 hw = imx_obtain_fixed_clock_hw(name, rate);
113 else
114 hw = __clk_get_hw(clk);
116 return hw;
119 struct clk_hw *imx_get_clk_hw_by_name(struct device_node *np, const char *name)
121 struct clk *clk;
123 clk = of_clk_get_by_name(np, name);
124 if (IS_ERR(clk))
125 return ERR_PTR(-ENOENT);
127 return __clk_get_hw(clk);
129 EXPORT_SYMBOL_GPL(imx_get_clk_hw_by_name);
132 * This fixups the register CCM_CSCMR1 write value.
133 * The write/read/divider values of the aclk_podf field
134 * of that register have the relationship described by
135 * the following table:
137 * write value read value divider
138 * 3b'000 3b'110 7
139 * 3b'001 3b'111 8
140 * 3b'010 3b'100 5
141 * 3b'011 3b'101 6
142 * 3b'100 3b'010 3
143 * 3b'101 3b'011 4
144 * 3b'110 3b'000 1
145 * 3b'111 3b'001 2(default)
147 * That's why we do the xor operation below.
149 #define CSCMR1_FIXUP 0x00600000
151 void imx_cscmr1_fixup(u32 *val)
153 *val ^= CSCMR1_FIXUP;
154 return;
157 #ifndef MODULE
159 static bool imx_keep_uart_clocks;
160 static int imx_enabled_uart_clocks;
161 static struct clk **imx_uart_clocks;
163 static int __init imx_keep_uart_clocks_param(char *str)
165 imx_keep_uart_clocks = 1;
167 return 0;
169 __setup_param("earlycon", imx_keep_uart_earlycon,
170 imx_keep_uart_clocks_param, 0);
171 __setup_param("earlyprintk", imx_keep_uart_earlyprintk,
172 imx_keep_uart_clocks_param, 0);
174 void imx_register_uart_clocks(void)
176 unsigned int num __maybe_unused;
178 imx_enabled_uart_clocks = 0;
180 /* i.MX boards use device trees now. For build tests without CONFIG_OF, do nothing */
181 #ifdef CONFIG_OF
182 if (imx_keep_uart_clocks) {
183 int i;
185 num = of_clk_get_parent_count(of_stdout);
186 if (!num)
187 return;
189 if (!of_stdout)
190 return;
192 imx_uart_clocks = kcalloc(num, sizeof(struct clk *), GFP_KERNEL);
193 if (!imx_uart_clocks)
194 return;
196 for (i = 0; i < num; i++) {
197 imx_uart_clocks[imx_enabled_uart_clocks] = of_clk_get(of_stdout, i);
199 /* Stop if there are no more of_stdout references */
200 if (IS_ERR(imx_uart_clocks[imx_enabled_uart_clocks]))
201 return;
203 /* Only enable the clock if it's not NULL */
204 if (imx_uart_clocks[imx_enabled_uart_clocks])
205 clk_prepare_enable(imx_uart_clocks[imx_enabled_uart_clocks++]);
208 #endif
211 static int __init imx_clk_disable_uart(void)
213 if (imx_keep_uart_clocks && imx_enabled_uart_clocks) {
214 int i;
216 for (i = 0; i < imx_enabled_uart_clocks; i++) {
217 clk_disable_unprepare(imx_uart_clocks[i]);
218 clk_put(imx_uart_clocks[i]);
222 kfree(imx_uart_clocks);
224 return 0;
226 late_initcall_sync(imx_clk_disable_uart);
227 #endif
229 MODULE_DESCRIPTION("Common clock support for NXP i.MX SoC family");
230 MODULE_LICENSE("GPL v2");