1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2012 ST Microelectronics
4 * Viresh Kumar <vireshk@kernel.org>
5 *
6 * General Purpose Timer Synthesizer clock implementation
7 */
8
9 #define pr_fmt(fmt) "clk-gpt-synth: " fmt
10
11 #include <linux/clk-provider.h>
12 #include <linux/slab.h>
13 #include <linux/io.h>
14 #include <linux/err.h>
15 #include "clk.h"
16
17 #define GPT_MSCALE_MASK 0xFFF
18 #define GPT_NSCALE_SHIFT 12
19 #define GPT_NSCALE_MASK 0xF
20
21 /*
22 * DOC: General Purpose Timer Synthesizer clock
23 *
24 * Calculates gpt synth clk rate for different values of mscale and nscale
25 *
26 * Fout= Fin/((2 ^ (N+1)) * (M+1))
27 */
28
29 #define to_clk_gpt(_hw) container_of(_hw, struct clk_gpt, hw)
30
gpt_calc_rate(struct clk_hw * hw,unsigned long prate,int index)31 static unsigned long gpt_calc_rate(struct clk_hw *hw, unsigned long prate,
32 int index)
33 {
34 struct clk_gpt *gpt = to_clk_gpt(hw);
35 struct gpt_rate_tbl *rtbl = gpt->rtbl;
36
37 prate /= ((1 << (rtbl[index].nscale + 1)) * (rtbl[index].mscale + 1));
38
39 return prate;
40 }
41
clk_gpt_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)42 static int clk_gpt_determine_rate(struct clk_hw *hw,
43 struct clk_rate_request *req)
44 {
45 struct clk_gpt *gpt = to_clk_gpt(hw);
46 int unused;
47
48 req->rate = clk_round_rate_index(hw, req->rate, req->best_parent_rate,
49 gpt_calc_rate, gpt->rtbl_cnt, &unused);
50
51 return 0;
52 }
53
clk_gpt_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)54 static unsigned long clk_gpt_recalc_rate(struct clk_hw *hw,
55 unsigned long parent_rate)
56 {
57 struct clk_gpt *gpt = to_clk_gpt(hw);
58 unsigned long flags = 0;
59 unsigned int div = 1, val;
60
61 if (gpt->lock)
62 spin_lock_irqsave(gpt->lock, flags);
63
64 val = readl_relaxed(gpt->reg);
65
66 if (gpt->lock)
67 spin_unlock_irqrestore(gpt->lock, flags);
68
69 div += val & GPT_MSCALE_MASK;
70 div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1);
71
72 if (!div)
73 return 0;
74
75 return parent_rate / div;
76 }
77
78 /* Configures new clock rate of gpt */
clk_gpt_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate)79 static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate,
80 unsigned long prate)
81 {
82 struct clk_gpt *gpt = to_clk_gpt(hw);
83 struct gpt_rate_tbl *rtbl = gpt->rtbl;
84 unsigned long flags = 0, val;
85 int i;
86
87 clk_round_rate_index(hw, drate, prate, gpt_calc_rate, gpt->rtbl_cnt,
88 &i);
89
90 if (gpt->lock)
91 spin_lock_irqsave(gpt->lock, flags);
92
93 val = readl(gpt->reg) & ~GPT_MSCALE_MASK;
94 val &= ~(GPT_NSCALE_MASK << GPT_NSCALE_SHIFT);
95
96 val |= rtbl[i].mscale & GPT_MSCALE_MASK;
97 val |= (rtbl[i].nscale & GPT_NSCALE_MASK) << GPT_NSCALE_SHIFT;
98
99 writel_relaxed(val, gpt->reg);
100
101 if (gpt->lock)
102 spin_unlock_irqrestore(gpt->lock, flags);
103
104 return 0;
105 }
106
107 static const struct clk_ops clk_gpt_ops = {
108 .recalc_rate = clk_gpt_recalc_rate,
109 .determine_rate = clk_gpt_determine_rate,
110 .set_rate = clk_gpt_set_rate,
111 };
112
clk_register_gpt(const char * name,const char * parent_name,unsigned long flags,void __iomem * reg,struct gpt_rate_tbl * rtbl,u8 rtbl_cnt,spinlock_t * lock)113 struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned
114 long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8
115 rtbl_cnt, spinlock_t *lock)
116 {
117 struct clk_init_data init;
118 struct clk_gpt *gpt;
119 struct clk *clk;
120
121 if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) {
122 pr_err("Invalid arguments passed\n");
123 return ERR_PTR(-EINVAL);
124 }
125
126 gpt = kzalloc(sizeof(*gpt), GFP_KERNEL);
127 if (!gpt)
128 return ERR_PTR(-ENOMEM);
129
130 /* struct clk_gpt assignments */
131 gpt->reg = reg;
132 gpt->rtbl = rtbl;
133 gpt->rtbl_cnt = rtbl_cnt;
134 gpt->lock = lock;
135 gpt->hw.init = &init;
136
137 init.name = name;
138 init.ops = &clk_gpt_ops;
139 init.flags = flags;
140 init.parent_names = &parent_name;
141 init.num_parents = 1;
142
143 clk = clk_register(NULL, &gpt->hw);
144 if (!IS_ERR_OR_NULL(clk))
145 return clk;
146
147 pr_err("clk register failed\n");
148 kfree(gpt);
149
150 return NULL;
151 }
152