1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Ingenic XBurst SoCs SYSOST clocks driver
4*4882a593Smuzhiyun * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/bitops.h>
8*4882a593Smuzhiyun #include <linux/clk.h>
9*4882a593Smuzhiyun #include <linux/clk-provider.h>
10*4882a593Smuzhiyun #include <linux/clockchips.h>
11*4882a593Smuzhiyun #include <linux/clocksource.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
14*4882a593Smuzhiyun #include <linux/of_address.h>
15*4882a593Smuzhiyun #include <linux/of_irq.h>
16*4882a593Smuzhiyun #include <linux/sched_clock.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/syscore_ops.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <dt-bindings/clock/ingenic,sysost.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /* OST register offsets */
23*4882a593Smuzhiyun #define OST_REG_OSTCCR 0x00
24*4882a593Smuzhiyun #define OST_REG_OSTCR 0x08
25*4882a593Smuzhiyun #define OST_REG_OSTFR 0x0c
26*4882a593Smuzhiyun #define OST_REG_OSTMR 0x10
27*4882a593Smuzhiyun #define OST_REG_OST1DFR 0x14
28*4882a593Smuzhiyun #define OST_REG_OST1CNT 0x18
29*4882a593Smuzhiyun #define OST_REG_OST2CNTL 0x20
30*4882a593Smuzhiyun #define OST_REG_OSTCNT2HBUF 0x24
31*4882a593Smuzhiyun #define OST_REG_OSTESR 0x34
32*4882a593Smuzhiyun #define OST_REG_OSTECR 0x38
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /* bits within the OSTCCR register */
35*4882a593Smuzhiyun #define OSTCCR_PRESCALE1_MASK 0x3
36*4882a593Smuzhiyun #define OSTCCR_PRESCALE2_MASK 0xc
37*4882a593Smuzhiyun #define OSTCCR_PRESCALE1_LSB 0
38*4882a593Smuzhiyun #define OSTCCR_PRESCALE2_LSB 2
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* bits within the OSTCR register */
41*4882a593Smuzhiyun #define OSTCR_OST1CLR BIT(0)
42*4882a593Smuzhiyun #define OSTCR_OST2CLR BIT(1)
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /* bits within the OSTFR register */
45*4882a593Smuzhiyun #define OSTFR_FFLAG BIT(0)
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* bits within the OSTMR register */
48*4882a593Smuzhiyun #define OSTMR_FMASK BIT(0)
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* bits within the OSTESR register */
51*4882a593Smuzhiyun #define OSTESR_OST1ENS BIT(0)
52*4882a593Smuzhiyun #define OSTESR_OST2ENS BIT(1)
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /* bits within the OSTECR register */
55*4882a593Smuzhiyun #define OSTECR_OST1ENC BIT(0)
56*4882a593Smuzhiyun #define OSTECR_OST2ENC BIT(1)
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun struct ingenic_soc_info {
59*4882a593Smuzhiyun unsigned int num_channels;
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun struct ingenic_ost_clk_info {
63*4882a593Smuzhiyun struct clk_init_data init_data;
64*4882a593Smuzhiyun u8 ostccr_reg;
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun struct ingenic_ost_clk {
68*4882a593Smuzhiyun struct clk_hw hw;
69*4882a593Smuzhiyun unsigned int idx;
70*4882a593Smuzhiyun struct ingenic_ost *ost;
71*4882a593Smuzhiyun const struct ingenic_ost_clk_info *info;
72*4882a593Smuzhiyun };
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun struct ingenic_ost {
75*4882a593Smuzhiyun void __iomem *base;
76*4882a593Smuzhiyun const struct ingenic_soc_info *soc_info;
77*4882a593Smuzhiyun struct clk *clk, *percpu_timer_clk, *global_timer_clk;
78*4882a593Smuzhiyun struct clock_event_device cevt;
79*4882a593Smuzhiyun struct clocksource cs;
80*4882a593Smuzhiyun char name[20];
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun struct clk_hw_onecell_data *clocks;
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun static struct ingenic_ost *ingenic_ost;
86*4882a593Smuzhiyun
to_ost_clk(struct clk_hw * hw)87*4882a593Smuzhiyun static inline struct ingenic_ost_clk *to_ost_clk(struct clk_hw *hw)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun return container_of(hw, struct ingenic_ost_clk, hw);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
ingenic_ost_percpu_timer_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)92*4882a593Smuzhiyun static unsigned long ingenic_ost_percpu_timer_recalc_rate(struct clk_hw *hw,
93*4882a593Smuzhiyun unsigned long parent_rate)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
96*4882a593Smuzhiyun const struct ingenic_ost_clk_info *info = ost_clk->info;
97*4882a593Smuzhiyun unsigned int prescale;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun prescale = readl(ost_clk->ost->base + info->ostccr_reg);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun prescale = (prescale & OSTCCR_PRESCALE1_MASK) >> OSTCCR_PRESCALE1_LSB;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun return parent_rate >> (prescale * 2);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
ingenic_ost_global_timer_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)106*4882a593Smuzhiyun static unsigned long ingenic_ost_global_timer_recalc_rate(struct clk_hw *hw,
107*4882a593Smuzhiyun unsigned long parent_rate)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
110*4882a593Smuzhiyun const struct ingenic_ost_clk_info *info = ost_clk->info;
111*4882a593Smuzhiyun unsigned int prescale;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun prescale = readl(ost_clk->ost->base + info->ostccr_reg);
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun prescale = (prescale & OSTCCR_PRESCALE2_MASK) >> OSTCCR_PRESCALE2_LSB;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun return parent_rate >> (prescale * 2);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
ingenic_ost_get_prescale(unsigned long rate,unsigned long req_rate)120*4882a593Smuzhiyun static u8 ingenic_ost_get_prescale(unsigned long rate, unsigned long req_rate)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun u8 prescale;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun for (prescale = 0; prescale < 2; prescale++)
125*4882a593Smuzhiyun if ((rate >> (prescale * 2)) <= req_rate)
126*4882a593Smuzhiyun return prescale;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun return 2; /* /16 divider */
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
ingenic_ost_round_rate(struct clk_hw * hw,unsigned long req_rate,unsigned long * parent_rate)131*4882a593Smuzhiyun static long ingenic_ost_round_rate(struct clk_hw *hw, unsigned long req_rate,
132*4882a593Smuzhiyun unsigned long *parent_rate)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun unsigned long rate = *parent_rate;
135*4882a593Smuzhiyun u8 prescale;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if (req_rate > rate)
138*4882a593Smuzhiyun return rate;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun prescale = ingenic_ost_get_prescale(rate, req_rate);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun return rate >> (prescale * 2);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
ingenic_ost_percpu_timer_set_rate(struct clk_hw * hw,unsigned long req_rate,unsigned long parent_rate)145*4882a593Smuzhiyun static int ingenic_ost_percpu_timer_set_rate(struct clk_hw *hw, unsigned long req_rate,
146*4882a593Smuzhiyun unsigned long parent_rate)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
149*4882a593Smuzhiyun const struct ingenic_ost_clk_info *info = ost_clk->info;
150*4882a593Smuzhiyun u8 prescale = ingenic_ost_get_prescale(parent_rate, req_rate);
151*4882a593Smuzhiyun int val;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun val = readl(ost_clk->ost->base + info->ostccr_reg);
154*4882a593Smuzhiyun val = (val & ~OSTCCR_PRESCALE1_MASK) | (prescale << OSTCCR_PRESCALE1_LSB);
155*4882a593Smuzhiyun writel(val, ost_clk->ost->base + info->ostccr_reg);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun return 0;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
ingenic_ost_global_timer_set_rate(struct clk_hw * hw,unsigned long req_rate,unsigned long parent_rate)160*4882a593Smuzhiyun static int ingenic_ost_global_timer_set_rate(struct clk_hw *hw, unsigned long req_rate,
161*4882a593Smuzhiyun unsigned long parent_rate)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
164*4882a593Smuzhiyun const struct ingenic_ost_clk_info *info = ost_clk->info;
165*4882a593Smuzhiyun u8 prescale = ingenic_ost_get_prescale(parent_rate, req_rate);
166*4882a593Smuzhiyun int val;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun val = readl(ost_clk->ost->base + info->ostccr_reg);
169*4882a593Smuzhiyun val = (val & ~OSTCCR_PRESCALE2_MASK) | (prescale << OSTCCR_PRESCALE2_LSB);
170*4882a593Smuzhiyun writel(val, ost_clk->ost->base + info->ostccr_reg);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun return 0;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun static const struct clk_ops ingenic_ost_percpu_timer_ops = {
176*4882a593Smuzhiyun .recalc_rate = ingenic_ost_percpu_timer_recalc_rate,
177*4882a593Smuzhiyun .round_rate = ingenic_ost_round_rate,
178*4882a593Smuzhiyun .set_rate = ingenic_ost_percpu_timer_set_rate,
179*4882a593Smuzhiyun };
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun static const struct clk_ops ingenic_ost_global_timer_ops = {
182*4882a593Smuzhiyun .recalc_rate = ingenic_ost_global_timer_recalc_rate,
183*4882a593Smuzhiyun .round_rate = ingenic_ost_round_rate,
184*4882a593Smuzhiyun .set_rate = ingenic_ost_global_timer_set_rate,
185*4882a593Smuzhiyun };
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun static const char * const ingenic_ost_clk_parents[] = { "ext" };
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun static const struct ingenic_ost_clk_info ingenic_ost_clk_info[] = {
190*4882a593Smuzhiyun [OST_CLK_PERCPU_TIMER] = {
191*4882a593Smuzhiyun .init_data = {
192*4882a593Smuzhiyun .name = "percpu timer",
193*4882a593Smuzhiyun .parent_names = ingenic_ost_clk_parents,
194*4882a593Smuzhiyun .num_parents = ARRAY_SIZE(ingenic_ost_clk_parents),
195*4882a593Smuzhiyun .ops = &ingenic_ost_percpu_timer_ops,
196*4882a593Smuzhiyun .flags = CLK_SET_RATE_UNGATE,
197*4882a593Smuzhiyun },
198*4882a593Smuzhiyun .ostccr_reg = OST_REG_OSTCCR,
199*4882a593Smuzhiyun },
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun [OST_CLK_GLOBAL_TIMER] = {
202*4882a593Smuzhiyun .init_data = {
203*4882a593Smuzhiyun .name = "global timer",
204*4882a593Smuzhiyun .parent_names = ingenic_ost_clk_parents,
205*4882a593Smuzhiyun .num_parents = ARRAY_SIZE(ingenic_ost_clk_parents),
206*4882a593Smuzhiyun .ops = &ingenic_ost_global_timer_ops,
207*4882a593Smuzhiyun .flags = CLK_SET_RATE_UNGATE,
208*4882a593Smuzhiyun },
209*4882a593Smuzhiyun .ostccr_reg = OST_REG_OSTCCR,
210*4882a593Smuzhiyun },
211*4882a593Smuzhiyun };
212*4882a593Smuzhiyun
ingenic_ost_global_timer_read_cntl(void)213*4882a593Smuzhiyun static u64 notrace ingenic_ost_global_timer_read_cntl(void)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun struct ingenic_ost *ost = ingenic_ost;
216*4882a593Smuzhiyun unsigned int count;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun count = readl(ost->base + OST_REG_OST2CNTL);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun return count;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
ingenic_ost_clocksource_read(struct clocksource * cs)223*4882a593Smuzhiyun static u64 notrace ingenic_ost_clocksource_read(struct clocksource *cs)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun return ingenic_ost_global_timer_read_cntl();
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
to_ingenic_ost(struct clock_event_device * evt)228*4882a593Smuzhiyun static inline struct ingenic_ost *to_ingenic_ost(struct clock_event_device *evt)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun return container_of(evt, struct ingenic_ost, cevt);
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
ingenic_ost_cevt_set_state_shutdown(struct clock_event_device * evt)233*4882a593Smuzhiyun static int ingenic_ost_cevt_set_state_shutdown(struct clock_event_device *evt)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun struct ingenic_ost *ost = to_ingenic_ost(evt);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR);
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun return 0;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
ingenic_ost_cevt_set_next(unsigned long next,struct clock_event_device * evt)242*4882a593Smuzhiyun static int ingenic_ost_cevt_set_next(unsigned long next,
243*4882a593Smuzhiyun struct clock_event_device *evt)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun struct ingenic_ost *ost = to_ingenic_ost(evt);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun writel((u32)~OSTFR_FFLAG, ost->base + OST_REG_OSTFR);
248*4882a593Smuzhiyun writel(next, ost->base + OST_REG_OST1DFR);
249*4882a593Smuzhiyun writel(OSTCR_OST1CLR, ost->base + OST_REG_OSTCR);
250*4882a593Smuzhiyun writel(OSTESR_OST1ENS, ost->base + OST_REG_OSTESR);
251*4882a593Smuzhiyun writel((u32)~OSTMR_FMASK, ost->base + OST_REG_OSTMR);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun return 0;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
ingenic_ost_cevt_cb(int irq,void * dev_id)256*4882a593Smuzhiyun static irqreturn_t ingenic_ost_cevt_cb(int irq, void *dev_id)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun struct clock_event_device *evt = dev_id;
259*4882a593Smuzhiyun struct ingenic_ost *ost = to_ingenic_ost(evt);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun if (evt->event_handler)
264*4882a593Smuzhiyun evt->event_handler(evt);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun return IRQ_HANDLED;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
ingenic_ost_register_clock(struct ingenic_ost * ost,unsigned int idx,const struct ingenic_ost_clk_info * info,struct clk_hw_onecell_data * clocks)269*4882a593Smuzhiyun static int __init ingenic_ost_register_clock(struct ingenic_ost *ost,
270*4882a593Smuzhiyun unsigned int idx, const struct ingenic_ost_clk_info *info,
271*4882a593Smuzhiyun struct clk_hw_onecell_data *clocks)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun struct ingenic_ost_clk *ost_clk;
274*4882a593Smuzhiyun int val, err;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun ost_clk = kzalloc(sizeof(*ost_clk), GFP_KERNEL);
277*4882a593Smuzhiyun if (!ost_clk)
278*4882a593Smuzhiyun return -ENOMEM;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun ost_clk->hw.init = &info->init_data;
281*4882a593Smuzhiyun ost_clk->idx = idx;
282*4882a593Smuzhiyun ost_clk->info = info;
283*4882a593Smuzhiyun ost_clk->ost = ost;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /* Reset clock divider */
286*4882a593Smuzhiyun val = readl(ost->base + info->ostccr_reg);
287*4882a593Smuzhiyun val &= ~(OSTCCR_PRESCALE1_MASK | OSTCCR_PRESCALE2_MASK);
288*4882a593Smuzhiyun writel(val, ost->base + info->ostccr_reg);
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun err = clk_hw_register(NULL, &ost_clk->hw);
291*4882a593Smuzhiyun if (err) {
292*4882a593Smuzhiyun kfree(ost_clk);
293*4882a593Smuzhiyun return err;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun clocks->hws[idx] = &ost_clk->hw;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun return 0;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
ingenic_ost_get_clock(struct device_node * np,int id)301*4882a593Smuzhiyun static struct clk * __init ingenic_ost_get_clock(struct device_node *np, int id)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun struct of_phandle_args args;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun args.np = np;
306*4882a593Smuzhiyun args.args_count = 1;
307*4882a593Smuzhiyun args.args[0] = id;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun return of_clk_get_from_provider(&args);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
ingenic_ost_percpu_timer_init(struct device_node * np,struct ingenic_ost * ost)312*4882a593Smuzhiyun static int __init ingenic_ost_percpu_timer_init(struct device_node *np,
313*4882a593Smuzhiyun struct ingenic_ost *ost)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun unsigned int timer_virq, channel = OST_CLK_PERCPU_TIMER;
316*4882a593Smuzhiyun unsigned long rate;
317*4882a593Smuzhiyun int err;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun ost->percpu_timer_clk = ingenic_ost_get_clock(np, channel);
320*4882a593Smuzhiyun if (IS_ERR(ost->percpu_timer_clk))
321*4882a593Smuzhiyun return PTR_ERR(ost->percpu_timer_clk);
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun err = clk_prepare_enable(ost->percpu_timer_clk);
324*4882a593Smuzhiyun if (err)
325*4882a593Smuzhiyun goto err_clk_put;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun rate = clk_get_rate(ost->percpu_timer_clk);
328*4882a593Smuzhiyun if (!rate) {
329*4882a593Smuzhiyun err = -EINVAL;
330*4882a593Smuzhiyun goto err_clk_disable;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun timer_virq = of_irq_get(np, 0);
334*4882a593Smuzhiyun if (!timer_virq) {
335*4882a593Smuzhiyun err = -EINVAL;
336*4882a593Smuzhiyun goto err_clk_disable;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun snprintf(ost->name, sizeof(ost->name), "OST percpu timer");
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun err = request_irq(timer_virq, ingenic_ost_cevt_cb, IRQF_TIMER,
342*4882a593Smuzhiyun ost->name, &ost->cevt);
343*4882a593Smuzhiyun if (err)
344*4882a593Smuzhiyun goto err_irq_dispose_mapping;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun ost->cevt.cpumask = cpumask_of(smp_processor_id());
347*4882a593Smuzhiyun ost->cevt.features = CLOCK_EVT_FEAT_ONESHOT;
348*4882a593Smuzhiyun ost->cevt.name = ost->name;
349*4882a593Smuzhiyun ost->cevt.rating = 400;
350*4882a593Smuzhiyun ost->cevt.set_state_shutdown = ingenic_ost_cevt_set_state_shutdown;
351*4882a593Smuzhiyun ost->cevt.set_next_event = ingenic_ost_cevt_set_next;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun clockevents_config_and_register(&ost->cevt, rate, 4, 0xffffffff);
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun return 0;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun err_irq_dispose_mapping:
358*4882a593Smuzhiyun irq_dispose_mapping(timer_virq);
359*4882a593Smuzhiyun err_clk_disable:
360*4882a593Smuzhiyun clk_disable_unprepare(ost->percpu_timer_clk);
361*4882a593Smuzhiyun err_clk_put:
362*4882a593Smuzhiyun clk_put(ost->percpu_timer_clk);
363*4882a593Smuzhiyun return err;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
ingenic_ost_global_timer_init(struct device_node * np,struct ingenic_ost * ost)366*4882a593Smuzhiyun static int __init ingenic_ost_global_timer_init(struct device_node *np,
367*4882a593Smuzhiyun struct ingenic_ost *ost)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun unsigned int channel = OST_CLK_GLOBAL_TIMER;
370*4882a593Smuzhiyun struct clocksource *cs = &ost->cs;
371*4882a593Smuzhiyun unsigned long rate;
372*4882a593Smuzhiyun int err;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun ost->global_timer_clk = ingenic_ost_get_clock(np, channel);
375*4882a593Smuzhiyun if (IS_ERR(ost->global_timer_clk))
376*4882a593Smuzhiyun return PTR_ERR(ost->global_timer_clk);
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun err = clk_prepare_enable(ost->global_timer_clk);
379*4882a593Smuzhiyun if (err)
380*4882a593Smuzhiyun goto err_clk_put;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun rate = clk_get_rate(ost->global_timer_clk);
383*4882a593Smuzhiyun if (!rate) {
384*4882a593Smuzhiyun err = -EINVAL;
385*4882a593Smuzhiyun goto err_clk_disable;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun /* Clear counter CNT registers */
389*4882a593Smuzhiyun writel(OSTCR_OST2CLR, ost->base + OST_REG_OSTCR);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun /* Enable OST channel */
392*4882a593Smuzhiyun writel(OSTESR_OST2ENS, ost->base + OST_REG_OSTESR);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun cs->name = "ingenic-ost";
395*4882a593Smuzhiyun cs->rating = 400;
396*4882a593Smuzhiyun cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
397*4882a593Smuzhiyun cs->mask = CLOCKSOURCE_MASK(32);
398*4882a593Smuzhiyun cs->read = ingenic_ost_clocksource_read;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun err = clocksource_register_hz(cs, rate);
401*4882a593Smuzhiyun if (err)
402*4882a593Smuzhiyun goto err_clk_disable;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun return 0;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun err_clk_disable:
407*4882a593Smuzhiyun clk_disable_unprepare(ost->global_timer_clk);
408*4882a593Smuzhiyun err_clk_put:
409*4882a593Smuzhiyun clk_put(ost->global_timer_clk);
410*4882a593Smuzhiyun return err;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun static const struct ingenic_soc_info x1000_soc_info = {
414*4882a593Smuzhiyun .num_channels = 2,
415*4882a593Smuzhiyun };
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun static const struct of_device_id __maybe_unused ingenic_ost_of_match[] __initconst = {
418*4882a593Smuzhiyun { .compatible = "ingenic,x1000-ost", .data = &x1000_soc_info, },
419*4882a593Smuzhiyun { /* sentinel */ }
420*4882a593Smuzhiyun };
421*4882a593Smuzhiyun
ingenic_ost_probe(struct device_node * np)422*4882a593Smuzhiyun static int __init ingenic_ost_probe(struct device_node *np)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun const struct of_device_id *id = of_match_node(ingenic_ost_of_match, np);
425*4882a593Smuzhiyun struct ingenic_ost *ost;
426*4882a593Smuzhiyun unsigned int i;
427*4882a593Smuzhiyun int ret;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun ost = kzalloc(sizeof(*ost), GFP_KERNEL);
430*4882a593Smuzhiyun if (!ost)
431*4882a593Smuzhiyun return -ENOMEM;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun ost->base = of_io_request_and_map(np, 0, of_node_full_name(np));
434*4882a593Smuzhiyun if (IS_ERR(ost->base)) {
435*4882a593Smuzhiyun pr_err("%s: Failed to map OST registers\n", __func__);
436*4882a593Smuzhiyun ret = PTR_ERR(ost->base);
437*4882a593Smuzhiyun goto err_free_ost;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun ost->clk = of_clk_get_by_name(np, "ost");
441*4882a593Smuzhiyun if (IS_ERR(ost->clk)) {
442*4882a593Smuzhiyun ret = PTR_ERR(ost->clk);
443*4882a593Smuzhiyun pr_crit("%s: Cannot get OST clock\n", __func__);
444*4882a593Smuzhiyun goto err_free_ost;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun ret = clk_prepare_enable(ost->clk);
448*4882a593Smuzhiyun if (ret) {
449*4882a593Smuzhiyun pr_crit("%s: Unable to enable OST clock\n", __func__);
450*4882a593Smuzhiyun goto err_put_clk;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun ost->soc_info = id->data;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun ost->clocks = kzalloc(struct_size(ost->clocks, hws, ost->soc_info->num_channels),
456*4882a593Smuzhiyun GFP_KERNEL);
457*4882a593Smuzhiyun if (!ost->clocks) {
458*4882a593Smuzhiyun ret = -ENOMEM;
459*4882a593Smuzhiyun goto err_clk_disable;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun ost->clocks->num = ost->soc_info->num_channels;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun for (i = 0; i < ost->clocks->num; i++) {
465*4882a593Smuzhiyun ret = ingenic_ost_register_clock(ost, i, &ingenic_ost_clk_info[i], ost->clocks);
466*4882a593Smuzhiyun if (ret) {
467*4882a593Smuzhiyun pr_crit("%s: Cannot register clock %d\n", __func__, i);
468*4882a593Smuzhiyun goto err_unregister_ost_clocks;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ost->clocks);
473*4882a593Smuzhiyun if (ret) {
474*4882a593Smuzhiyun pr_crit("%s: Cannot add OF clock provider\n", __func__);
475*4882a593Smuzhiyun goto err_unregister_ost_clocks;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun ingenic_ost = ost;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun return 0;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun err_unregister_ost_clocks:
483*4882a593Smuzhiyun for (i = 0; i < ost->clocks->num; i++)
484*4882a593Smuzhiyun if (ost->clocks->hws[i])
485*4882a593Smuzhiyun clk_hw_unregister(ost->clocks->hws[i]);
486*4882a593Smuzhiyun kfree(ost->clocks);
487*4882a593Smuzhiyun err_clk_disable:
488*4882a593Smuzhiyun clk_disable_unprepare(ost->clk);
489*4882a593Smuzhiyun err_put_clk:
490*4882a593Smuzhiyun clk_put(ost->clk);
491*4882a593Smuzhiyun err_free_ost:
492*4882a593Smuzhiyun kfree(ost);
493*4882a593Smuzhiyun return ret;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
ingenic_ost_init(struct device_node * np)496*4882a593Smuzhiyun static int __init ingenic_ost_init(struct device_node *np)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun struct ingenic_ost *ost;
499*4882a593Smuzhiyun unsigned long rate;
500*4882a593Smuzhiyun int ret;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun ret = ingenic_ost_probe(np);
503*4882a593Smuzhiyun if (ret) {
504*4882a593Smuzhiyun pr_crit("%s: Failed to initialize OST clocks: %d\n", __func__, ret);
505*4882a593Smuzhiyun return ret;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun of_node_clear_flag(np, OF_POPULATED);
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun ost = ingenic_ost;
511*4882a593Smuzhiyun if (IS_ERR(ost))
512*4882a593Smuzhiyun return PTR_ERR(ost);
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun ret = ingenic_ost_global_timer_init(np, ost);
515*4882a593Smuzhiyun if (ret) {
516*4882a593Smuzhiyun pr_crit("%s: Unable to init global timer: %x\n", __func__, ret);
517*4882a593Smuzhiyun goto err_free_ingenic_ost;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun ret = ingenic_ost_percpu_timer_init(np, ost);
521*4882a593Smuzhiyun if (ret)
522*4882a593Smuzhiyun goto err_ost_global_timer_cleanup;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun /* Register the sched_clock at the end as there's no way to undo it */
525*4882a593Smuzhiyun rate = clk_get_rate(ost->global_timer_clk);
526*4882a593Smuzhiyun sched_clock_register(ingenic_ost_global_timer_read_cntl, 32, rate);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun return 0;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun err_ost_global_timer_cleanup:
531*4882a593Smuzhiyun clocksource_unregister(&ost->cs);
532*4882a593Smuzhiyun clk_disable_unprepare(ost->global_timer_clk);
533*4882a593Smuzhiyun clk_put(ost->global_timer_clk);
534*4882a593Smuzhiyun err_free_ingenic_ost:
535*4882a593Smuzhiyun kfree(ost);
536*4882a593Smuzhiyun return ret;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun TIMER_OF_DECLARE(x1000_ost, "ingenic,x1000-ost", ingenic_ost_init);
540