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