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