xref: /kernel/linux/linux-5.10/drivers/clk/imx/clk.c (revision 8c2ecf20)
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"
12
13#define CCM_CCDR			0x4
14#define CCDR_MMDC_CH0_MASK		BIT(17)
15#define CCDR_MMDC_CH1_MASK		BIT(16)
16
17DEFINE_SPINLOCK(imx_ccm_lock);
18EXPORT_SYMBOL_GPL(imx_ccm_lock);
19
20void imx_unregister_clocks(struct clk *clks[], unsigned int count)
21{
22	unsigned int i;
23
24	for (i = 0; i < count; i++)
25		clk_unregister(clks[i]);
26}
27
28void imx_unregister_hw_clocks(struct clk_hw *hws[], unsigned int count)
29{
30	unsigned int i;
31
32	for (i = 0; i < count; i++)
33		clk_hw_unregister(hws[i]);
34}
35EXPORT_SYMBOL_GPL(imx_unregister_hw_clocks);
36
37void imx_mmdc_mask_handshake(void __iomem *ccm_base,
38				    unsigned int chn)
39{
40	unsigned int reg;
41
42	reg = readl_relaxed(ccm_base + CCM_CCDR);
43	reg |= chn == 0 ? CCDR_MMDC_CH0_MASK : CCDR_MMDC_CH1_MASK;
44	writel_relaxed(reg, ccm_base + CCM_CCDR);
45}
46
47void imx_check_clocks(struct clk *clks[], unsigned int count)
48{
49	unsigned i;
50
51	for (i = 0; i < count; i++)
52		if (IS_ERR(clks[i]))
53			pr_err("i.MX clk %u: register failed with %ld\n",
54			       i, PTR_ERR(clks[i]));
55}
56
57void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
58{
59	unsigned int i;
60
61	for (i = 0; i < count; i++)
62		if (IS_ERR(clks[i]))
63			pr_err("i.MX clk %u: register failed with %ld\n",
64			       i, PTR_ERR(clks[i]));
65}
66EXPORT_SYMBOL_GPL(imx_check_clk_hws);
67
68static struct clk *imx_obtain_fixed_clock_from_dt(const char *name)
69{
70	struct of_phandle_args phandle;
71	struct clk *clk = ERR_PTR(-ENODEV);
72	char *path;
73
74	path = kasprintf(GFP_KERNEL, "/clocks/%s", name);
75	if (!path)
76		return ERR_PTR(-ENOMEM);
77
78	phandle.np = of_find_node_by_path(path);
79	kfree(path);
80
81	if (phandle.np) {
82		clk = of_clk_get_from_provider(&phandle);
83		of_node_put(phandle.np);
84	}
85	return clk;
86}
87
88struct clk *imx_obtain_fixed_clock(
89			const char *name, unsigned long rate)
90{
91	struct clk *clk;
92
93	clk = imx_obtain_fixed_clock_from_dt(name);
94	if (IS_ERR(clk))
95		clk = imx_clk_fixed(name, rate);
96	return clk;
97}
98
99struct clk_hw *imx_obtain_fixed_clock_hw(
100			const char *name, unsigned long rate)
101{
102	struct clk *clk;
103
104	clk = imx_obtain_fixed_clock_from_dt(name);
105	if (IS_ERR(clk))
106		clk = imx_clk_fixed(name, rate);
107	return __clk_get_hw(clk);
108}
109
110struct clk_hw * imx_obtain_fixed_clk_hw(struct device_node *np,
111					const char *name)
112{
113	struct clk *clk;
114
115	clk = of_clk_get_by_name(np, name);
116	if (IS_ERR(clk))
117		return ERR_PTR(-ENOENT);
118
119	return __clk_get_hw(clk);
120}
121EXPORT_SYMBOL_GPL(imx_obtain_fixed_clk_hw);
122
123/*
124 * This fixups the register CCM_CSCMR1 write value.
125 * The write/read/divider values of the aclk_podf field
126 * of that register have the relationship described by
127 * the following table:
128 *
129 * write value       read value        divider
130 * 3b'000            3b'110            7
131 * 3b'001            3b'111            8
132 * 3b'010            3b'100            5
133 * 3b'011            3b'101            6
134 * 3b'100            3b'010            3
135 * 3b'101            3b'011            4
136 * 3b'110            3b'000            1
137 * 3b'111            3b'001            2(default)
138 *
139 * That's why we do the xor operation below.
140 */
141#define CSCMR1_FIXUP	0x00600000
142
143void imx_cscmr1_fixup(u32 *val)
144{
145	*val ^= CSCMR1_FIXUP;
146	return;
147}
148
149#ifndef MODULE
150
151static bool imx_keep_uart_clocks;
152static int imx_enabled_uart_clocks;
153static struct clk **imx_uart_clocks;
154
155static int __init imx_keep_uart_clocks_param(char *str)
156{
157	imx_keep_uart_clocks = 1;
158
159	return 0;
160}
161__setup_param("earlycon", imx_keep_uart_earlycon,
162	      imx_keep_uart_clocks_param, 0);
163__setup_param("earlyprintk", imx_keep_uart_earlyprintk,
164	      imx_keep_uart_clocks_param, 0);
165
166void imx_register_uart_clocks(unsigned int clk_count)
167{
168	imx_enabled_uart_clocks = 0;
169
170/* i.MX boards use device trees now.  For build tests without CONFIG_OF, do nothing */
171#ifdef CONFIG_OF
172	if (imx_keep_uart_clocks) {
173		int i;
174
175		imx_uart_clocks = kcalloc(clk_count, sizeof(struct clk *), GFP_KERNEL);
176
177		if (!of_stdout)
178			return;
179
180		for (i = 0; i < clk_count; i++) {
181			imx_uart_clocks[imx_enabled_uart_clocks] = of_clk_get(of_stdout, i);
182
183			/* Stop if there are no more of_stdout references */
184			if (IS_ERR(imx_uart_clocks[imx_enabled_uart_clocks]))
185				return;
186
187			/* Only enable the clock if it's not NULL */
188			if (imx_uart_clocks[imx_enabled_uart_clocks])
189				clk_prepare_enable(imx_uart_clocks[imx_enabled_uart_clocks++]);
190		}
191	}
192#endif
193}
194
195static int __init imx_clk_disable_uart(void)
196{
197	if (imx_keep_uart_clocks && imx_enabled_uart_clocks) {
198		int i;
199
200		for (i = 0; i < imx_enabled_uart_clocks; i++) {
201			clk_disable_unprepare(imx_uart_clocks[i]);
202			clk_put(imx_uart_clocks[i]);
203		}
204	}
205
206	kfree(imx_uart_clocks);
207
208	return 0;
209}
210late_initcall_sync(imx_clk_disable_uart);
211#endif
212
213MODULE_LICENSE("GPL v2");
214