xref: /OK3568_Linux_fs/kernel/drivers/clk/ux500/clk-prcc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * PRCC clock implementation for ux500 platform.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2012 ST-Ericsson SA
6*4882a593Smuzhiyun  * Author: Ulf Hansson <ulf.hansson@linaro.org>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/clk-provider.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/io.h>
12*4882a593Smuzhiyun #include <linux/err.h>
13*4882a593Smuzhiyun #include <linux/types.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "clk.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define PRCC_PCKEN			0x000
18*4882a593Smuzhiyun #define PRCC_PCKDIS			0x004
19*4882a593Smuzhiyun #define PRCC_KCKEN			0x008
20*4882a593Smuzhiyun #define PRCC_KCKDIS			0x00C
21*4882a593Smuzhiyun #define PRCC_PCKSR			0x010
22*4882a593Smuzhiyun #define PRCC_KCKSR			0x014
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define to_clk_prcc(_hw) container_of(_hw, struct clk_prcc, hw)
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun struct clk_prcc {
27*4882a593Smuzhiyun 	struct clk_hw hw;
28*4882a593Smuzhiyun 	void __iomem *base;
29*4882a593Smuzhiyun 	u32 cg_sel;
30*4882a593Smuzhiyun 	int is_enabled;
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /* PRCC clock operations. */
34*4882a593Smuzhiyun 
clk_prcc_pclk_enable(struct clk_hw * hw)35*4882a593Smuzhiyun static int clk_prcc_pclk_enable(struct clk_hw *hw)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	struct clk_prcc *clk = to_clk_prcc(hw);
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	writel(clk->cg_sel, (clk->base + PRCC_PCKEN));
40*4882a593Smuzhiyun 	while (!(readl(clk->base + PRCC_PCKSR) & clk->cg_sel))
41*4882a593Smuzhiyun 		cpu_relax();
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	clk->is_enabled = 1;
44*4882a593Smuzhiyun 	return 0;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun 
clk_prcc_pclk_disable(struct clk_hw * hw)47*4882a593Smuzhiyun static void clk_prcc_pclk_disable(struct clk_hw *hw)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	struct clk_prcc *clk = to_clk_prcc(hw);
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	writel(clk->cg_sel, (clk->base + PRCC_PCKDIS));
52*4882a593Smuzhiyun 	clk->is_enabled = 0;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
clk_prcc_kclk_enable(struct clk_hw * hw)55*4882a593Smuzhiyun static int clk_prcc_kclk_enable(struct clk_hw *hw)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	struct clk_prcc *clk = to_clk_prcc(hw);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	writel(clk->cg_sel, (clk->base + PRCC_KCKEN));
60*4882a593Smuzhiyun 	while (!(readl(clk->base + PRCC_KCKSR) & clk->cg_sel))
61*4882a593Smuzhiyun 		cpu_relax();
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	clk->is_enabled = 1;
64*4882a593Smuzhiyun 	return 0;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun 
clk_prcc_kclk_disable(struct clk_hw * hw)67*4882a593Smuzhiyun static void clk_prcc_kclk_disable(struct clk_hw *hw)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	struct clk_prcc *clk = to_clk_prcc(hw);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	writel(clk->cg_sel, (clk->base + PRCC_KCKDIS));
72*4882a593Smuzhiyun 	clk->is_enabled = 0;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
clk_prcc_is_enabled(struct clk_hw * hw)75*4882a593Smuzhiyun static int clk_prcc_is_enabled(struct clk_hw *hw)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	struct clk_prcc *clk = to_clk_prcc(hw);
78*4882a593Smuzhiyun 	return clk->is_enabled;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static const struct clk_ops clk_prcc_pclk_ops = {
82*4882a593Smuzhiyun 	.enable = clk_prcc_pclk_enable,
83*4882a593Smuzhiyun 	.disable = clk_prcc_pclk_disable,
84*4882a593Smuzhiyun 	.is_enabled = clk_prcc_is_enabled,
85*4882a593Smuzhiyun };
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun static const struct clk_ops clk_prcc_kclk_ops = {
88*4882a593Smuzhiyun 	.enable = clk_prcc_kclk_enable,
89*4882a593Smuzhiyun 	.disable = clk_prcc_kclk_disable,
90*4882a593Smuzhiyun 	.is_enabled = clk_prcc_is_enabled,
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
clk_reg_prcc(const char * name,const char * parent_name,resource_size_t phy_base,u32 cg_sel,unsigned long flags,const struct clk_ops * clk_prcc_ops)93*4882a593Smuzhiyun static struct clk *clk_reg_prcc(const char *name,
94*4882a593Smuzhiyun 				const char *parent_name,
95*4882a593Smuzhiyun 				resource_size_t phy_base,
96*4882a593Smuzhiyun 				u32 cg_sel,
97*4882a593Smuzhiyun 				unsigned long flags,
98*4882a593Smuzhiyun 				const struct clk_ops *clk_prcc_ops)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	struct clk_prcc *clk;
101*4882a593Smuzhiyun 	struct clk_init_data clk_prcc_init;
102*4882a593Smuzhiyun 	struct clk *clk_reg;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	if (!name) {
105*4882a593Smuzhiyun 		pr_err("clk_prcc: %s invalid arguments passed\n", __func__);
106*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	clk = kzalloc(sizeof(*clk), GFP_KERNEL);
110*4882a593Smuzhiyun 	if (!clk)
111*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	clk->base = ioremap(phy_base, SZ_4K);
114*4882a593Smuzhiyun 	if (!clk->base)
115*4882a593Smuzhiyun 		goto free_clk;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	clk->cg_sel = cg_sel;
118*4882a593Smuzhiyun 	clk->is_enabled = 1;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	clk_prcc_init.name = name;
121*4882a593Smuzhiyun 	clk_prcc_init.ops = clk_prcc_ops;
122*4882a593Smuzhiyun 	clk_prcc_init.flags = flags;
123*4882a593Smuzhiyun 	clk_prcc_init.parent_names = (parent_name ? &parent_name : NULL);
124*4882a593Smuzhiyun 	clk_prcc_init.num_parents = (parent_name ? 1 : 0);
125*4882a593Smuzhiyun 	clk->hw.init = &clk_prcc_init;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	clk_reg = clk_register(NULL, &clk->hw);
128*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(clk_reg))
129*4882a593Smuzhiyun 		goto unmap_clk;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	return clk_reg;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun unmap_clk:
134*4882a593Smuzhiyun 	iounmap(clk->base);
135*4882a593Smuzhiyun free_clk:
136*4882a593Smuzhiyun 	kfree(clk);
137*4882a593Smuzhiyun 	pr_err("clk_prcc: %s failed to register clk\n", __func__);
138*4882a593Smuzhiyun 	return ERR_PTR(-ENOMEM);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
clk_reg_prcc_pclk(const char * name,const char * parent_name,resource_size_t phy_base,u32 cg_sel,unsigned long flags)141*4882a593Smuzhiyun struct clk *clk_reg_prcc_pclk(const char *name,
142*4882a593Smuzhiyun 			      const char *parent_name,
143*4882a593Smuzhiyun 			      resource_size_t phy_base,
144*4882a593Smuzhiyun 			      u32 cg_sel,
145*4882a593Smuzhiyun 			      unsigned long flags)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags,
148*4882a593Smuzhiyun 			&clk_prcc_pclk_ops);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
clk_reg_prcc_kclk(const char * name,const char * parent_name,resource_size_t phy_base,u32 cg_sel,unsigned long flags)151*4882a593Smuzhiyun struct clk *clk_reg_prcc_kclk(const char *name,
152*4882a593Smuzhiyun 			      const char *parent_name,
153*4882a593Smuzhiyun 			      resource_size_t phy_base,
154*4882a593Smuzhiyun 			      u32 cg_sel,
155*4882a593Smuzhiyun 			      unsigned long flags)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags,
158*4882a593Smuzhiyun 			&clk_prcc_kclk_ops);
159*4882a593Smuzhiyun }
160