xref: /openbmc/linux/drivers/clocksource/ingenic-sysost.c (revision 870a6e1539829356baf70b57c933d0b309cfac21)
15ecafc12S周琰杰 (Zhou Yanjie) // SPDX-License-Identifier: GPL-2.0
25ecafc12S周琰杰 (Zhou Yanjie) /*
35ecafc12S周琰杰 (Zhou Yanjie)  * Ingenic XBurst SoCs SYSOST clocks driver
45ecafc12S周琰杰 (Zhou Yanjie)  * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
55ecafc12S周琰杰 (Zhou Yanjie)  */
65ecafc12S周琰杰 (Zhou Yanjie) 
75ecafc12S周琰杰 (Zhou Yanjie) #include <linux/bitops.h>
85ecafc12S周琰杰 (Zhou Yanjie) #include <linux/clk.h>
95ecafc12S周琰杰 (Zhou Yanjie) #include <linux/clk-provider.h>
105ecafc12S周琰杰 (Zhou Yanjie) #include <linux/clockchips.h>
115ecafc12S周琰杰 (Zhou Yanjie) #include <linux/clocksource.h>
125ecafc12S周琰杰 (Zhou Yanjie) #include <linux/interrupt.h>
135ecafc12S周琰杰 (Zhou Yanjie) #include <linux/mfd/syscon.h>
145ecafc12S周琰杰 (Zhou Yanjie) #include <linux/of_address.h>
155ecafc12S周琰杰 (Zhou Yanjie) #include <linux/of_irq.h>
165ecafc12S周琰杰 (Zhou Yanjie) #include <linux/sched_clock.h>
175ecafc12S周琰杰 (Zhou Yanjie) #include <linux/slab.h>
185ecafc12S周琰杰 (Zhou Yanjie) #include <linux/syscore_ops.h>
195ecafc12S周琰杰 (Zhou Yanjie) 
205ecafc12S周琰杰 (Zhou Yanjie) #include <dt-bindings/clock/ingenic,sysost.h>
215ecafc12S周琰杰 (Zhou Yanjie) 
225ecafc12S周琰杰 (Zhou Yanjie) /* OST register offsets */
235ecafc12S周琰杰 (Zhou Yanjie) #define OST_REG_OSTCCR			0x00
245ecafc12S周琰杰 (Zhou Yanjie) #define OST_REG_OSTCR			0x08
255ecafc12S周琰杰 (Zhou Yanjie) #define OST_REG_OSTFR			0x0c
265ecafc12S周琰杰 (Zhou Yanjie) #define OST_REG_OSTMR			0x10
275ecafc12S周琰杰 (Zhou Yanjie) #define OST_REG_OST1DFR			0x14
285ecafc12S周琰杰 (Zhou Yanjie) #define OST_REG_OST1CNT			0x18
295ecafc12S周琰杰 (Zhou Yanjie) #define OST_REG_OST2CNTL		0x20
305ecafc12S周琰杰 (Zhou Yanjie) #define OST_REG_OSTCNT2HBUF		0x24
315ecafc12S周琰杰 (Zhou Yanjie) #define OST_REG_OSTESR			0x34
325ecafc12S周琰杰 (Zhou Yanjie) #define OST_REG_OSTECR			0x38
335ecafc12S周琰杰 (Zhou Yanjie) 
345ecafc12S周琰杰 (Zhou Yanjie) /* bits within the OSTCCR register */
355ecafc12S周琰杰 (Zhou Yanjie) #define OSTCCR_PRESCALE1_MASK	0x3
365ecafc12S周琰杰 (Zhou Yanjie) #define OSTCCR_PRESCALE2_MASK	0xc
375ecafc12S周琰杰 (Zhou Yanjie) #define OSTCCR_PRESCALE1_LSB	0
385ecafc12S周琰杰 (Zhou Yanjie) #define OSTCCR_PRESCALE2_LSB	2
395ecafc12S周琰杰 (Zhou Yanjie) 
405ecafc12S周琰杰 (Zhou Yanjie) /* bits within the OSTCR register */
415ecafc12S周琰杰 (Zhou Yanjie) #define OSTCR_OST1CLR			BIT(0)
425ecafc12S周琰杰 (Zhou Yanjie) #define OSTCR_OST2CLR			BIT(1)
435ecafc12S周琰杰 (Zhou Yanjie) 
445ecafc12S周琰杰 (Zhou Yanjie) /* bits within the OSTFR register */
455ecafc12S周琰杰 (Zhou Yanjie) #define OSTFR_FFLAG				BIT(0)
465ecafc12S周琰杰 (Zhou Yanjie) 
475ecafc12S周琰杰 (Zhou Yanjie) /* bits within the OSTMR register */
485ecafc12S周琰杰 (Zhou Yanjie) #define OSTMR_FMASK				BIT(0)
495ecafc12S周琰杰 (Zhou Yanjie) 
505ecafc12S周琰杰 (Zhou Yanjie) /* bits within the OSTESR register */
515ecafc12S周琰杰 (Zhou Yanjie) #define OSTESR_OST1ENS			BIT(0)
525ecafc12S周琰杰 (Zhou Yanjie) #define OSTESR_OST2ENS			BIT(1)
535ecafc12S周琰杰 (Zhou Yanjie) 
545ecafc12S周琰杰 (Zhou Yanjie) /* bits within the OSTECR register */
555ecafc12S周琰杰 (Zhou Yanjie) #define OSTECR_OST1ENC			BIT(0)
565ecafc12S周琰杰 (Zhou Yanjie) #define OSTECR_OST2ENC			BIT(1)
575ecafc12S周琰杰 (Zhou Yanjie) 
585ecafc12S周琰杰 (Zhou Yanjie) struct ingenic_soc_info {
595ecafc12S周琰杰 (Zhou Yanjie) 	unsigned int num_channels;
605ecafc12S周琰杰 (Zhou Yanjie) };
615ecafc12S周琰杰 (Zhou Yanjie) 
625ecafc12S周琰杰 (Zhou Yanjie) struct ingenic_ost_clk_info {
635ecafc12S周琰杰 (Zhou Yanjie) 	struct clk_init_data init_data;
645ecafc12S周琰杰 (Zhou Yanjie) 	u8 ostccr_reg;
655ecafc12S周琰杰 (Zhou Yanjie) };
665ecafc12S周琰杰 (Zhou Yanjie) 
675ecafc12S周琰杰 (Zhou Yanjie) struct ingenic_ost_clk {
685ecafc12S周琰杰 (Zhou Yanjie) 	struct clk_hw hw;
695ecafc12S周琰杰 (Zhou Yanjie) 	unsigned int idx;
705ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost *ost;
715ecafc12S周琰杰 (Zhou Yanjie) 	const struct ingenic_ost_clk_info *info;
725ecafc12S周琰杰 (Zhou Yanjie) };
735ecafc12S周琰杰 (Zhou Yanjie) 
745ecafc12S周琰杰 (Zhou Yanjie) struct ingenic_ost {
755ecafc12S周琰杰 (Zhou Yanjie) 	void __iomem *base;
765ecafc12S周琰杰 (Zhou Yanjie) 	const struct ingenic_soc_info *soc_info;
775ecafc12S周琰杰 (Zhou Yanjie) 	struct clk *clk, *percpu_timer_clk, *global_timer_clk;
785ecafc12S周琰杰 (Zhou Yanjie) 	struct clock_event_device cevt;
795ecafc12S周琰杰 (Zhou Yanjie) 	struct clocksource cs;
805ecafc12S周琰杰 (Zhou Yanjie) 	char name[20];
815ecafc12S周琰杰 (Zhou Yanjie) 
825ecafc12S周琰杰 (Zhou Yanjie) 	struct clk_hw_onecell_data *clocks;
835ecafc12S周琰杰 (Zhou Yanjie) };
845ecafc12S周琰杰 (Zhou Yanjie) 
855ecafc12S周琰杰 (Zhou Yanjie) static struct ingenic_ost *ingenic_ost;
865ecafc12S周琰杰 (Zhou Yanjie) 
875ecafc12S周琰杰 (Zhou Yanjie) static inline struct ingenic_ost_clk *to_ost_clk(struct clk_hw *hw)
885ecafc12S周琰杰 (Zhou Yanjie) {
895ecafc12S周琰杰 (Zhou Yanjie) 	return container_of(hw, struct ingenic_ost_clk, hw);
905ecafc12S周琰杰 (Zhou Yanjie) }
915ecafc12S周琰杰 (Zhou Yanjie) 
925ecafc12S周琰杰 (Zhou Yanjie) static unsigned long ingenic_ost_percpu_timer_recalc_rate(struct clk_hw *hw,
935ecafc12S周琰杰 (Zhou Yanjie) 		unsigned long parent_rate)
945ecafc12S周琰杰 (Zhou Yanjie) {
955ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
965ecafc12S周琰杰 (Zhou Yanjie) 	const struct ingenic_ost_clk_info *info = ost_clk->info;
975ecafc12S周琰杰 (Zhou Yanjie) 	unsigned int prescale;
985ecafc12S周琰杰 (Zhou Yanjie) 
995ecafc12S周琰杰 (Zhou Yanjie) 	prescale = readl(ost_clk->ost->base + info->ostccr_reg);
1005ecafc12S周琰杰 (Zhou Yanjie) 
1015ecafc12S周琰杰 (Zhou Yanjie) 	prescale = (prescale & OSTCCR_PRESCALE1_MASK) >> OSTCCR_PRESCALE1_LSB;
1025ecafc12S周琰杰 (Zhou Yanjie) 
1035ecafc12S周琰杰 (Zhou Yanjie) 	return parent_rate >> (prescale * 2);
1045ecafc12S周琰杰 (Zhou Yanjie) }
1055ecafc12S周琰杰 (Zhou Yanjie) 
1065ecafc12S周琰杰 (Zhou Yanjie) static unsigned long ingenic_ost_global_timer_recalc_rate(struct clk_hw *hw,
1075ecafc12S周琰杰 (Zhou Yanjie) 		unsigned long parent_rate)
1085ecafc12S周琰杰 (Zhou Yanjie) {
1095ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
1105ecafc12S周琰杰 (Zhou Yanjie) 	const struct ingenic_ost_clk_info *info = ost_clk->info;
1115ecafc12S周琰杰 (Zhou Yanjie) 	unsigned int prescale;
1125ecafc12S周琰杰 (Zhou Yanjie) 
1135ecafc12S周琰杰 (Zhou Yanjie) 	prescale = readl(ost_clk->ost->base + info->ostccr_reg);
1145ecafc12S周琰杰 (Zhou Yanjie) 
1155ecafc12S周琰杰 (Zhou Yanjie) 	prescale = (prescale & OSTCCR_PRESCALE2_MASK) >> OSTCCR_PRESCALE2_LSB;
1165ecafc12S周琰杰 (Zhou Yanjie) 
1175ecafc12S周琰杰 (Zhou Yanjie) 	return parent_rate >> (prescale * 2);
1185ecafc12S周琰杰 (Zhou Yanjie) }
1195ecafc12S周琰杰 (Zhou Yanjie) 
1205ecafc12S周琰杰 (Zhou Yanjie) static u8 ingenic_ost_get_prescale(unsigned long rate, unsigned long req_rate)
1215ecafc12S周琰杰 (Zhou Yanjie) {
1225ecafc12S周琰杰 (Zhou Yanjie) 	u8 prescale;
1235ecafc12S周琰杰 (Zhou Yanjie) 
1245ecafc12S周琰杰 (Zhou Yanjie) 	for (prescale = 0; prescale < 2; prescale++)
1255ecafc12S周琰杰 (Zhou Yanjie) 		if ((rate >> (prescale * 2)) <= req_rate)
1265ecafc12S周琰杰 (Zhou Yanjie) 			return prescale;
1275ecafc12S周琰杰 (Zhou Yanjie) 
1285ecafc12S周琰杰 (Zhou Yanjie) 	return 2; /* /16 divider */
1295ecafc12S周琰杰 (Zhou Yanjie) }
1305ecafc12S周琰杰 (Zhou Yanjie) 
1315ecafc12S周琰杰 (Zhou Yanjie) static long ingenic_ost_round_rate(struct clk_hw *hw, unsigned long req_rate,
1325ecafc12S周琰杰 (Zhou Yanjie) 		unsigned long *parent_rate)
1335ecafc12S周琰杰 (Zhou Yanjie) {
1345ecafc12S周琰杰 (Zhou Yanjie) 	unsigned long rate = *parent_rate;
1355ecafc12S周琰杰 (Zhou Yanjie) 	u8 prescale;
1365ecafc12S周琰杰 (Zhou Yanjie) 
1375ecafc12S周琰杰 (Zhou Yanjie) 	if (req_rate > rate)
1385ecafc12S周琰杰 (Zhou Yanjie) 		return rate;
1395ecafc12S周琰杰 (Zhou Yanjie) 
1405ecafc12S周琰杰 (Zhou Yanjie) 	prescale = ingenic_ost_get_prescale(rate, req_rate);
1415ecafc12S周琰杰 (Zhou Yanjie) 
1425ecafc12S周琰杰 (Zhou Yanjie) 	return rate >> (prescale * 2);
1435ecafc12S周琰杰 (Zhou Yanjie) }
1445ecafc12S周琰杰 (Zhou Yanjie) 
1455ecafc12S周琰杰 (Zhou Yanjie) static int ingenic_ost_percpu_timer_set_rate(struct clk_hw *hw, unsigned long req_rate,
1465ecafc12S周琰杰 (Zhou Yanjie) 		unsigned long parent_rate)
1475ecafc12S周琰杰 (Zhou Yanjie) {
1485ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
1495ecafc12S周琰杰 (Zhou Yanjie) 	const struct ingenic_ost_clk_info *info = ost_clk->info;
1505ecafc12S周琰杰 (Zhou Yanjie) 	u8 prescale = ingenic_ost_get_prescale(parent_rate, req_rate);
1515ecafc12S周琰杰 (Zhou Yanjie) 	int val;
1525ecafc12S周琰杰 (Zhou Yanjie) 
1535ecafc12S周琰杰 (Zhou Yanjie) 	val = readl(ost_clk->ost->base + info->ostccr_reg);
1545ecafc12S周琰杰 (Zhou Yanjie) 	val = (val & ~OSTCCR_PRESCALE1_MASK) | (prescale << OSTCCR_PRESCALE1_LSB);
1555ecafc12S周琰杰 (Zhou Yanjie) 	writel(val, ost_clk->ost->base + info->ostccr_reg);
1565ecafc12S周琰杰 (Zhou Yanjie) 
1575ecafc12S周琰杰 (Zhou Yanjie) 	return 0;
1585ecafc12S周琰杰 (Zhou Yanjie) }
1595ecafc12S周琰杰 (Zhou Yanjie) 
1605ecafc12S周琰杰 (Zhou Yanjie) static int ingenic_ost_global_timer_set_rate(struct clk_hw *hw, unsigned long req_rate,
1615ecafc12S周琰杰 (Zhou Yanjie) 		unsigned long parent_rate)
1625ecafc12S周琰杰 (Zhou Yanjie) {
1635ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
1645ecafc12S周琰杰 (Zhou Yanjie) 	const struct ingenic_ost_clk_info *info = ost_clk->info;
1655ecafc12S周琰杰 (Zhou Yanjie) 	u8 prescale = ingenic_ost_get_prescale(parent_rate, req_rate);
1665ecafc12S周琰杰 (Zhou Yanjie) 	int val;
1675ecafc12S周琰杰 (Zhou Yanjie) 
1685ecafc12S周琰杰 (Zhou Yanjie) 	val = readl(ost_clk->ost->base + info->ostccr_reg);
1695ecafc12S周琰杰 (Zhou Yanjie) 	val = (val & ~OSTCCR_PRESCALE2_MASK) | (prescale << OSTCCR_PRESCALE2_LSB);
1705ecafc12S周琰杰 (Zhou Yanjie) 	writel(val, ost_clk->ost->base + info->ostccr_reg);
1715ecafc12S周琰杰 (Zhou Yanjie) 
1725ecafc12S周琰杰 (Zhou Yanjie) 	return 0;
1735ecafc12S周琰杰 (Zhou Yanjie) }
1745ecafc12S周琰杰 (Zhou Yanjie) 
1755ecafc12S周琰杰 (Zhou Yanjie) static const struct clk_ops ingenic_ost_percpu_timer_ops = {
1765ecafc12S周琰杰 (Zhou Yanjie) 	.recalc_rate	= ingenic_ost_percpu_timer_recalc_rate,
1775ecafc12S周琰杰 (Zhou Yanjie) 	.round_rate		= ingenic_ost_round_rate,
1785ecafc12S周琰杰 (Zhou Yanjie) 	.set_rate		= ingenic_ost_percpu_timer_set_rate,
1795ecafc12S周琰杰 (Zhou Yanjie) };
1805ecafc12S周琰杰 (Zhou Yanjie) 
1815ecafc12S周琰杰 (Zhou Yanjie) static const struct clk_ops ingenic_ost_global_timer_ops = {
1825ecafc12S周琰杰 (Zhou Yanjie) 	.recalc_rate	= ingenic_ost_global_timer_recalc_rate,
1835ecafc12S周琰杰 (Zhou Yanjie) 	.round_rate		= ingenic_ost_round_rate,
1845ecafc12S周琰杰 (Zhou Yanjie) 	.set_rate		= ingenic_ost_global_timer_set_rate,
1855ecafc12S周琰杰 (Zhou Yanjie) };
1865ecafc12S周琰杰 (Zhou Yanjie) 
1875ecafc12S周琰杰 (Zhou Yanjie) static const char * const ingenic_ost_clk_parents[] = { "ext" };
1885ecafc12S周琰杰 (Zhou Yanjie) 
189*870a6e15S周琰杰 (Zhou Yanjie) static const struct ingenic_ost_clk_info x1000_ost_clk_info[] = {
1905ecafc12S周琰杰 (Zhou Yanjie) 	[OST_CLK_PERCPU_TIMER] = {
1915ecafc12S周琰杰 (Zhou Yanjie) 		.init_data = {
1925ecafc12S周琰杰 (Zhou Yanjie) 			.name = "percpu timer",
1935ecafc12S周琰杰 (Zhou Yanjie) 			.parent_names = ingenic_ost_clk_parents,
1945ecafc12S周琰杰 (Zhou Yanjie) 			.num_parents = ARRAY_SIZE(ingenic_ost_clk_parents),
1955ecafc12S周琰杰 (Zhou Yanjie) 			.ops = &ingenic_ost_percpu_timer_ops,
1965ecafc12S周琰杰 (Zhou Yanjie) 			.flags = CLK_SET_RATE_UNGATE,
1975ecafc12S周琰杰 (Zhou Yanjie) 		},
1985ecafc12S周琰杰 (Zhou Yanjie) 		.ostccr_reg = OST_REG_OSTCCR,
1995ecafc12S周琰杰 (Zhou Yanjie) 	},
2005ecafc12S周琰杰 (Zhou Yanjie) 
2015ecafc12S周琰杰 (Zhou Yanjie) 	[OST_CLK_GLOBAL_TIMER] = {
2025ecafc12S周琰杰 (Zhou Yanjie) 		.init_data = {
2035ecafc12S周琰杰 (Zhou Yanjie) 			.name = "global timer",
2045ecafc12S周琰杰 (Zhou Yanjie) 			.parent_names = ingenic_ost_clk_parents,
2055ecafc12S周琰杰 (Zhou Yanjie) 			.num_parents = ARRAY_SIZE(ingenic_ost_clk_parents),
2065ecafc12S周琰杰 (Zhou Yanjie) 			.ops = &ingenic_ost_global_timer_ops,
2075ecafc12S周琰杰 (Zhou Yanjie) 			.flags = CLK_SET_RATE_UNGATE,
2085ecafc12S周琰杰 (Zhou Yanjie) 		},
2095ecafc12S周琰杰 (Zhou Yanjie) 		.ostccr_reg = OST_REG_OSTCCR,
2105ecafc12S周琰杰 (Zhou Yanjie) 	},
2115ecafc12S周琰杰 (Zhou Yanjie) };
2125ecafc12S周琰杰 (Zhou Yanjie) 
2135ecafc12S周琰杰 (Zhou Yanjie) static u64 notrace ingenic_ost_global_timer_read_cntl(void)
2145ecafc12S周琰杰 (Zhou Yanjie) {
2155ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost *ost = ingenic_ost;
2165ecafc12S周琰杰 (Zhou Yanjie) 	unsigned int count;
2175ecafc12S周琰杰 (Zhou Yanjie) 
2185ecafc12S周琰杰 (Zhou Yanjie) 	count = readl(ost->base + OST_REG_OST2CNTL);
2195ecafc12S周琰杰 (Zhou Yanjie) 
2205ecafc12S周琰杰 (Zhou Yanjie) 	return count;
2215ecafc12S周琰杰 (Zhou Yanjie) }
2225ecafc12S周琰杰 (Zhou Yanjie) 
2235ecafc12S周琰杰 (Zhou Yanjie) static u64 notrace ingenic_ost_clocksource_read(struct clocksource *cs)
2245ecafc12S周琰杰 (Zhou Yanjie) {
2255ecafc12S周琰杰 (Zhou Yanjie) 	return ingenic_ost_global_timer_read_cntl();
2265ecafc12S周琰杰 (Zhou Yanjie) }
2275ecafc12S周琰杰 (Zhou Yanjie) 
2285ecafc12S周琰杰 (Zhou Yanjie) static inline struct ingenic_ost *to_ingenic_ost(struct clock_event_device *evt)
2295ecafc12S周琰杰 (Zhou Yanjie) {
2305ecafc12S周琰杰 (Zhou Yanjie) 	return container_of(evt, struct ingenic_ost, cevt);
2315ecafc12S周琰杰 (Zhou Yanjie) }
2325ecafc12S周琰杰 (Zhou Yanjie) 
2335ecafc12S周琰杰 (Zhou Yanjie) static int ingenic_ost_cevt_set_state_shutdown(struct clock_event_device *evt)
2345ecafc12S周琰杰 (Zhou Yanjie) {
2355ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost *ost = to_ingenic_ost(evt);
2365ecafc12S周琰杰 (Zhou Yanjie) 
2375ecafc12S周琰杰 (Zhou Yanjie) 	writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR);
2385ecafc12S周琰杰 (Zhou Yanjie) 
2395ecafc12S周琰杰 (Zhou Yanjie) 	return 0;
2405ecafc12S周琰杰 (Zhou Yanjie) }
2415ecafc12S周琰杰 (Zhou Yanjie) 
2425ecafc12S周琰杰 (Zhou Yanjie) static int ingenic_ost_cevt_set_next(unsigned long next,
2435ecafc12S周琰杰 (Zhou Yanjie) 				     struct clock_event_device *evt)
2445ecafc12S周琰杰 (Zhou Yanjie) {
2455ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost *ost = to_ingenic_ost(evt);
2465ecafc12S周琰杰 (Zhou Yanjie) 
2475ecafc12S周琰杰 (Zhou Yanjie) 	writel((u32)~OSTFR_FFLAG, ost->base + OST_REG_OSTFR);
2485ecafc12S周琰杰 (Zhou Yanjie) 	writel(next, ost->base + OST_REG_OST1DFR);
2495ecafc12S周琰杰 (Zhou Yanjie) 	writel(OSTCR_OST1CLR, ost->base + OST_REG_OSTCR);
2505ecafc12S周琰杰 (Zhou Yanjie) 	writel(OSTESR_OST1ENS, ost->base + OST_REG_OSTESR);
2515ecafc12S周琰杰 (Zhou Yanjie) 	writel((u32)~OSTMR_FMASK, ost->base + OST_REG_OSTMR);
2525ecafc12S周琰杰 (Zhou Yanjie) 
2535ecafc12S周琰杰 (Zhou Yanjie) 	return 0;
2545ecafc12S周琰杰 (Zhou Yanjie) }
2555ecafc12S周琰杰 (Zhou Yanjie) 
2565ecafc12S周琰杰 (Zhou Yanjie) static irqreturn_t ingenic_ost_cevt_cb(int irq, void *dev_id)
2575ecafc12S周琰杰 (Zhou Yanjie) {
2585ecafc12S周琰杰 (Zhou Yanjie) 	struct clock_event_device *evt = dev_id;
2595ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost *ost = to_ingenic_ost(evt);
2605ecafc12S周琰杰 (Zhou Yanjie) 
2615ecafc12S周琰杰 (Zhou Yanjie) 	writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR);
2625ecafc12S周琰杰 (Zhou Yanjie) 
2635ecafc12S周琰杰 (Zhou Yanjie) 	if (evt->event_handler)
2645ecafc12S周琰杰 (Zhou Yanjie) 		evt->event_handler(evt);
2655ecafc12S周琰杰 (Zhou Yanjie) 
2665ecafc12S周琰杰 (Zhou Yanjie) 	return IRQ_HANDLED;
2675ecafc12S周琰杰 (Zhou Yanjie) }
2685ecafc12S周琰杰 (Zhou Yanjie) 
2695ecafc12S周琰杰 (Zhou Yanjie) static int __init ingenic_ost_register_clock(struct ingenic_ost *ost,
2705ecafc12S周琰杰 (Zhou Yanjie) 			unsigned int idx, const struct ingenic_ost_clk_info *info,
2715ecafc12S周琰杰 (Zhou Yanjie) 			struct clk_hw_onecell_data *clocks)
2725ecafc12S周琰杰 (Zhou Yanjie) {
2735ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost_clk *ost_clk;
2745ecafc12S周琰杰 (Zhou Yanjie) 	int val, err;
2755ecafc12S周琰杰 (Zhou Yanjie) 
2765ecafc12S周琰杰 (Zhou Yanjie) 	ost_clk = kzalloc(sizeof(*ost_clk), GFP_KERNEL);
2775ecafc12S周琰杰 (Zhou Yanjie) 	if (!ost_clk)
2785ecafc12S周琰杰 (Zhou Yanjie) 		return -ENOMEM;
2795ecafc12S周琰杰 (Zhou Yanjie) 
2805ecafc12S周琰杰 (Zhou Yanjie) 	ost_clk->hw.init = &info->init_data;
2815ecafc12S周琰杰 (Zhou Yanjie) 	ost_clk->idx = idx;
2825ecafc12S周琰杰 (Zhou Yanjie) 	ost_clk->info = info;
2835ecafc12S周琰杰 (Zhou Yanjie) 	ost_clk->ost = ost;
2845ecafc12S周琰杰 (Zhou Yanjie) 
2855ecafc12S周琰杰 (Zhou Yanjie) 	/* Reset clock divider */
2865ecafc12S周琰杰 (Zhou Yanjie) 	val = readl(ost->base + info->ostccr_reg);
2875ecafc12S周琰杰 (Zhou Yanjie) 	val &= ~(OSTCCR_PRESCALE1_MASK | OSTCCR_PRESCALE2_MASK);
2885ecafc12S周琰杰 (Zhou Yanjie) 	writel(val, ost->base + info->ostccr_reg);
2895ecafc12S周琰杰 (Zhou Yanjie) 
2905ecafc12S周琰杰 (Zhou Yanjie) 	err = clk_hw_register(NULL, &ost_clk->hw);
2915ecafc12S周琰杰 (Zhou Yanjie) 	if (err) {
2925ecafc12S周琰杰 (Zhou Yanjie) 		kfree(ost_clk);
2935ecafc12S周琰杰 (Zhou Yanjie) 		return err;
2945ecafc12S周琰杰 (Zhou Yanjie) 	}
2955ecafc12S周琰杰 (Zhou Yanjie) 
2965ecafc12S周琰杰 (Zhou Yanjie) 	clocks->hws[idx] = &ost_clk->hw;
2975ecafc12S周琰杰 (Zhou Yanjie) 
2985ecafc12S周琰杰 (Zhou Yanjie) 	return 0;
2995ecafc12S周琰杰 (Zhou Yanjie) }
3005ecafc12S周琰杰 (Zhou Yanjie) 
3015ecafc12S周琰杰 (Zhou Yanjie) static struct clk * __init ingenic_ost_get_clock(struct device_node *np, int id)
3025ecafc12S周琰杰 (Zhou Yanjie) {
3035ecafc12S周琰杰 (Zhou Yanjie) 	struct of_phandle_args args;
3045ecafc12S周琰杰 (Zhou Yanjie) 
3055ecafc12S周琰杰 (Zhou Yanjie) 	args.np = np;
3065ecafc12S周琰杰 (Zhou Yanjie) 	args.args_count = 1;
3075ecafc12S周琰杰 (Zhou Yanjie) 	args.args[0] = id;
3085ecafc12S周琰杰 (Zhou Yanjie) 
3095ecafc12S周琰杰 (Zhou Yanjie) 	return of_clk_get_from_provider(&args);
3105ecafc12S周琰杰 (Zhou Yanjie) }
3115ecafc12S周琰杰 (Zhou Yanjie) 
3125ecafc12S周琰杰 (Zhou Yanjie) static int __init ingenic_ost_percpu_timer_init(struct device_node *np,
3135ecafc12S周琰杰 (Zhou Yanjie) 					 struct ingenic_ost *ost)
3145ecafc12S周琰杰 (Zhou Yanjie) {
3155ecafc12S周琰杰 (Zhou Yanjie) 	unsigned int timer_virq, channel = OST_CLK_PERCPU_TIMER;
3165ecafc12S周琰杰 (Zhou Yanjie) 	unsigned long rate;
3175ecafc12S周琰杰 (Zhou Yanjie) 	int err;
3185ecafc12S周琰杰 (Zhou Yanjie) 
3195ecafc12S周琰杰 (Zhou Yanjie) 	ost->percpu_timer_clk = ingenic_ost_get_clock(np, channel);
3205ecafc12S周琰杰 (Zhou Yanjie) 	if (IS_ERR(ost->percpu_timer_clk))
3215ecafc12S周琰杰 (Zhou Yanjie) 		return PTR_ERR(ost->percpu_timer_clk);
3225ecafc12S周琰杰 (Zhou Yanjie) 
3235ecafc12S周琰杰 (Zhou Yanjie) 	err = clk_prepare_enable(ost->percpu_timer_clk);
3245ecafc12S周琰杰 (Zhou Yanjie) 	if (err)
3255ecafc12S周琰杰 (Zhou Yanjie) 		goto err_clk_put;
3265ecafc12S周琰杰 (Zhou Yanjie) 
3275ecafc12S周琰杰 (Zhou Yanjie) 	rate = clk_get_rate(ost->percpu_timer_clk);
3285ecafc12S周琰杰 (Zhou Yanjie) 	if (!rate) {
3295ecafc12S周琰杰 (Zhou Yanjie) 		err = -EINVAL;
3305ecafc12S周琰杰 (Zhou Yanjie) 		goto err_clk_disable;
3315ecafc12S周琰杰 (Zhou Yanjie) 	}
3325ecafc12S周琰杰 (Zhou Yanjie) 
3335ecafc12S周琰杰 (Zhou Yanjie) 	timer_virq = of_irq_get(np, 0);
3345ecafc12S周琰杰 (Zhou Yanjie) 	if (!timer_virq) {
3355ecafc12S周琰杰 (Zhou Yanjie) 		err = -EINVAL;
3365ecafc12S周琰杰 (Zhou Yanjie) 		goto err_clk_disable;
3375ecafc12S周琰杰 (Zhou Yanjie) 	}
3385ecafc12S周琰杰 (Zhou Yanjie) 
3395ecafc12S周琰杰 (Zhou Yanjie) 	snprintf(ost->name, sizeof(ost->name), "OST percpu timer");
3405ecafc12S周琰杰 (Zhou Yanjie) 
3415ecafc12S周琰杰 (Zhou Yanjie) 	err = request_irq(timer_virq, ingenic_ost_cevt_cb, IRQF_TIMER,
3425ecafc12S周琰杰 (Zhou Yanjie) 			  ost->name, &ost->cevt);
3435ecafc12S周琰杰 (Zhou Yanjie) 	if (err)
3445ecafc12S周琰杰 (Zhou Yanjie) 		goto err_irq_dispose_mapping;
3455ecafc12S周琰杰 (Zhou Yanjie) 
3465ecafc12S周琰杰 (Zhou Yanjie) 	ost->cevt.cpumask = cpumask_of(smp_processor_id());
3475ecafc12S周琰杰 (Zhou Yanjie) 	ost->cevt.features = CLOCK_EVT_FEAT_ONESHOT;
3485ecafc12S周琰杰 (Zhou Yanjie) 	ost->cevt.name = ost->name;
3495ecafc12S周琰杰 (Zhou Yanjie) 	ost->cevt.rating = 400;
3505ecafc12S周琰杰 (Zhou Yanjie) 	ost->cevt.set_state_shutdown = ingenic_ost_cevt_set_state_shutdown;
3515ecafc12S周琰杰 (Zhou Yanjie) 	ost->cevt.set_next_event = ingenic_ost_cevt_set_next;
3525ecafc12S周琰杰 (Zhou Yanjie) 
3535ecafc12S周琰杰 (Zhou Yanjie) 	clockevents_config_and_register(&ost->cevt, rate, 4, 0xffffffff);
3545ecafc12S周琰杰 (Zhou Yanjie) 
3555ecafc12S周琰杰 (Zhou Yanjie) 	return 0;
3565ecafc12S周琰杰 (Zhou Yanjie) 
3575ecafc12S周琰杰 (Zhou Yanjie) err_irq_dispose_mapping:
3585ecafc12S周琰杰 (Zhou Yanjie) 	irq_dispose_mapping(timer_virq);
3595ecafc12S周琰杰 (Zhou Yanjie) err_clk_disable:
3605ecafc12S周琰杰 (Zhou Yanjie) 	clk_disable_unprepare(ost->percpu_timer_clk);
3615ecafc12S周琰杰 (Zhou Yanjie) err_clk_put:
3625ecafc12S周琰杰 (Zhou Yanjie) 	clk_put(ost->percpu_timer_clk);
3635ecafc12S周琰杰 (Zhou Yanjie) 	return err;
3645ecafc12S周琰杰 (Zhou Yanjie) }
3655ecafc12S周琰杰 (Zhou Yanjie) 
3665ecafc12S周琰杰 (Zhou Yanjie) static int __init ingenic_ost_global_timer_init(struct device_node *np,
3675ecafc12S周琰杰 (Zhou Yanjie) 					       struct ingenic_ost *ost)
3685ecafc12S周琰杰 (Zhou Yanjie) {
3695ecafc12S周琰杰 (Zhou Yanjie) 	unsigned int channel = OST_CLK_GLOBAL_TIMER;
3705ecafc12S周琰杰 (Zhou Yanjie) 	struct clocksource *cs = &ost->cs;
3715ecafc12S周琰杰 (Zhou Yanjie) 	unsigned long rate;
3725ecafc12S周琰杰 (Zhou Yanjie) 	int err;
3735ecafc12S周琰杰 (Zhou Yanjie) 
3745ecafc12S周琰杰 (Zhou Yanjie) 	ost->global_timer_clk = ingenic_ost_get_clock(np, channel);
3755ecafc12S周琰杰 (Zhou Yanjie) 	if (IS_ERR(ost->global_timer_clk))
3765ecafc12S周琰杰 (Zhou Yanjie) 		return PTR_ERR(ost->global_timer_clk);
3775ecafc12S周琰杰 (Zhou Yanjie) 
3785ecafc12S周琰杰 (Zhou Yanjie) 	err = clk_prepare_enable(ost->global_timer_clk);
3795ecafc12S周琰杰 (Zhou Yanjie) 	if (err)
3805ecafc12S周琰杰 (Zhou Yanjie) 		goto err_clk_put;
3815ecafc12S周琰杰 (Zhou Yanjie) 
3825ecafc12S周琰杰 (Zhou Yanjie) 	rate = clk_get_rate(ost->global_timer_clk);
3835ecafc12S周琰杰 (Zhou Yanjie) 	if (!rate) {
3845ecafc12S周琰杰 (Zhou Yanjie) 		err = -EINVAL;
3855ecafc12S周琰杰 (Zhou Yanjie) 		goto err_clk_disable;
3865ecafc12S周琰杰 (Zhou Yanjie) 	}
3875ecafc12S周琰杰 (Zhou Yanjie) 
3885ecafc12S周琰杰 (Zhou Yanjie) 	/* Clear counter CNT registers */
3895ecafc12S周琰杰 (Zhou Yanjie) 	writel(OSTCR_OST2CLR, ost->base + OST_REG_OSTCR);
3905ecafc12S周琰杰 (Zhou Yanjie) 
3915ecafc12S周琰杰 (Zhou Yanjie) 	/* Enable OST channel */
3925ecafc12S周琰杰 (Zhou Yanjie) 	writel(OSTESR_OST2ENS, ost->base + OST_REG_OSTESR);
3935ecafc12S周琰杰 (Zhou Yanjie) 
3945ecafc12S周琰杰 (Zhou Yanjie) 	cs->name = "ingenic-ost";
3955ecafc12S周琰杰 (Zhou Yanjie) 	cs->rating = 400;
3965ecafc12S周琰杰 (Zhou Yanjie) 	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
3975ecafc12S周琰杰 (Zhou Yanjie) 	cs->mask = CLOCKSOURCE_MASK(32);
3985ecafc12S周琰杰 (Zhou Yanjie) 	cs->read = ingenic_ost_clocksource_read;
3995ecafc12S周琰杰 (Zhou Yanjie) 
4005ecafc12S周琰杰 (Zhou Yanjie) 	err = clocksource_register_hz(cs, rate);
4015ecafc12S周琰杰 (Zhou Yanjie) 	if (err)
4025ecafc12S周琰杰 (Zhou Yanjie) 		goto err_clk_disable;
4035ecafc12S周琰杰 (Zhou Yanjie) 
4045ecafc12S周琰杰 (Zhou Yanjie) 	return 0;
4055ecafc12S周琰杰 (Zhou Yanjie) 
4065ecafc12S周琰杰 (Zhou Yanjie) err_clk_disable:
4075ecafc12S周琰杰 (Zhou Yanjie) 	clk_disable_unprepare(ost->global_timer_clk);
4085ecafc12S周琰杰 (Zhou Yanjie) err_clk_put:
4095ecafc12S周琰杰 (Zhou Yanjie) 	clk_put(ost->global_timer_clk);
4105ecafc12S周琰杰 (Zhou Yanjie) 	return err;
4115ecafc12S周琰杰 (Zhou Yanjie) }
4125ecafc12S周琰杰 (Zhou Yanjie) 
4135ecafc12S周琰杰 (Zhou Yanjie) static const struct ingenic_soc_info x1000_soc_info = {
4145ecafc12S周琰杰 (Zhou Yanjie) 	.num_channels = 2,
4155ecafc12S周琰杰 (Zhou Yanjie) };
4165ecafc12S周琰杰 (Zhou Yanjie) 
417*870a6e15S周琰杰 (Zhou Yanjie) static const struct of_device_id __maybe_unused ingenic_ost_of_matches[] __initconst = {
418*870a6e15S周琰杰 (Zhou Yanjie) 	{ .compatible = "ingenic,x1000-ost", .data = &x1000_soc_info },
4195ecafc12S周琰杰 (Zhou Yanjie) 	{ /* sentinel */ }
4205ecafc12S周琰杰 (Zhou Yanjie) };
4215ecafc12S周琰杰 (Zhou Yanjie) 
4225ecafc12S周琰杰 (Zhou Yanjie) static int __init ingenic_ost_probe(struct device_node *np)
4235ecafc12S周琰杰 (Zhou Yanjie) {
424*870a6e15S周琰杰 (Zhou Yanjie) 	const struct of_device_id *id = of_match_node(ingenic_ost_of_matches, np);
4255ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost *ost;
4265ecafc12S周琰杰 (Zhou Yanjie) 	unsigned int i;
4275ecafc12S周琰杰 (Zhou Yanjie) 	int ret;
4285ecafc12S周琰杰 (Zhou Yanjie) 
4295ecafc12S周琰杰 (Zhou Yanjie) 	ost = kzalloc(sizeof(*ost), GFP_KERNEL);
4305ecafc12S周琰杰 (Zhou Yanjie) 	if (!ost)
4315ecafc12S周琰杰 (Zhou Yanjie) 		return -ENOMEM;
4325ecafc12S周琰杰 (Zhou Yanjie) 
4335ecafc12S周琰杰 (Zhou Yanjie) 	ost->base = of_io_request_and_map(np, 0, of_node_full_name(np));
4345ecafc12S周琰杰 (Zhou Yanjie) 	if (IS_ERR(ost->base)) {
4355ecafc12S周琰杰 (Zhou Yanjie) 		pr_err("%s: Failed to map OST registers\n", __func__);
4365ecafc12S周琰杰 (Zhou Yanjie) 		ret = PTR_ERR(ost->base);
4375ecafc12S周琰杰 (Zhou Yanjie) 		goto err_free_ost;
4385ecafc12S周琰杰 (Zhou Yanjie) 	}
4395ecafc12S周琰杰 (Zhou Yanjie) 
4405ecafc12S周琰杰 (Zhou Yanjie) 	ost->clk = of_clk_get_by_name(np, "ost");
4415ecafc12S周琰杰 (Zhou Yanjie) 	if (IS_ERR(ost->clk)) {
4425ecafc12S周琰杰 (Zhou Yanjie) 		ret = PTR_ERR(ost->clk);
4435ecafc12S周琰杰 (Zhou Yanjie) 		pr_crit("%s: Cannot get OST clock\n", __func__);
4445ecafc12S周琰杰 (Zhou Yanjie) 		goto err_free_ost;
4455ecafc12S周琰杰 (Zhou Yanjie) 	}
4465ecafc12S周琰杰 (Zhou Yanjie) 
4475ecafc12S周琰杰 (Zhou Yanjie) 	ret = clk_prepare_enable(ost->clk);
4485ecafc12S周琰杰 (Zhou Yanjie) 	if (ret) {
4495ecafc12S周琰杰 (Zhou Yanjie) 		pr_crit("%s: Unable to enable OST clock\n", __func__);
4505ecafc12S周琰杰 (Zhou Yanjie) 		goto err_put_clk;
4515ecafc12S周琰杰 (Zhou Yanjie) 	}
4525ecafc12S周琰杰 (Zhou Yanjie) 
4535ecafc12S周琰杰 (Zhou Yanjie) 	ost->soc_info = id->data;
4545ecafc12S周琰杰 (Zhou Yanjie) 
4555ecafc12S周琰杰 (Zhou Yanjie) 	ost->clocks = kzalloc(struct_size(ost->clocks, hws, ost->soc_info->num_channels),
4565ecafc12S周琰杰 (Zhou Yanjie) 			      GFP_KERNEL);
4575ecafc12S周琰杰 (Zhou Yanjie) 	if (!ost->clocks) {
4585ecafc12S周琰杰 (Zhou Yanjie) 		ret = -ENOMEM;
4595ecafc12S周琰杰 (Zhou Yanjie) 		goto err_clk_disable;
4605ecafc12S周琰杰 (Zhou Yanjie) 	}
4615ecafc12S周琰杰 (Zhou Yanjie) 
4625ecafc12S周琰杰 (Zhou Yanjie) 	ost->clocks->num = ost->soc_info->num_channels;
4635ecafc12S周琰杰 (Zhou Yanjie) 
4645ecafc12S周琰杰 (Zhou Yanjie) 	for (i = 0; i < ost->clocks->num; i++) {
465*870a6e15S周琰杰 (Zhou Yanjie) 		ret = ingenic_ost_register_clock(ost, i, &x1000_ost_clk_info[i], ost->clocks);
4665ecafc12S周琰杰 (Zhou Yanjie) 		if (ret) {
4675ecafc12S周琰杰 (Zhou Yanjie) 			pr_crit("%s: Cannot register clock %d\n", __func__, i);
4685ecafc12S周琰杰 (Zhou Yanjie) 			goto err_unregister_ost_clocks;
4695ecafc12S周琰杰 (Zhou Yanjie) 		}
4705ecafc12S周琰杰 (Zhou Yanjie) 	}
4715ecafc12S周琰杰 (Zhou Yanjie) 
4725ecafc12S周琰杰 (Zhou Yanjie) 	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ost->clocks);
4735ecafc12S周琰杰 (Zhou Yanjie) 	if (ret) {
4745ecafc12S周琰杰 (Zhou Yanjie) 		pr_crit("%s: Cannot add OF clock provider\n", __func__);
4755ecafc12S周琰杰 (Zhou Yanjie) 		goto err_unregister_ost_clocks;
4765ecafc12S周琰杰 (Zhou Yanjie) 	}
4775ecafc12S周琰杰 (Zhou Yanjie) 
4785ecafc12S周琰杰 (Zhou Yanjie) 	ingenic_ost = ost;
4795ecafc12S周琰杰 (Zhou Yanjie) 
4805ecafc12S周琰杰 (Zhou Yanjie) 	return 0;
4815ecafc12S周琰杰 (Zhou Yanjie) 
4825ecafc12S周琰杰 (Zhou Yanjie) err_unregister_ost_clocks:
4835ecafc12S周琰杰 (Zhou Yanjie) 	for (i = 0; i < ost->clocks->num; i++)
4845ecafc12S周琰杰 (Zhou Yanjie) 		if (ost->clocks->hws[i])
4855ecafc12S周琰杰 (Zhou Yanjie) 			clk_hw_unregister(ost->clocks->hws[i]);
4865ecafc12S周琰杰 (Zhou Yanjie) 	kfree(ost->clocks);
4875ecafc12S周琰杰 (Zhou Yanjie) err_clk_disable:
4885ecafc12S周琰杰 (Zhou Yanjie) 	clk_disable_unprepare(ost->clk);
4895ecafc12S周琰杰 (Zhou Yanjie) err_put_clk:
4905ecafc12S周琰杰 (Zhou Yanjie) 	clk_put(ost->clk);
4915ecafc12S周琰杰 (Zhou Yanjie) err_free_ost:
4925ecafc12S周琰杰 (Zhou Yanjie) 	kfree(ost);
4935ecafc12S周琰杰 (Zhou Yanjie) 	return ret;
4945ecafc12S周琰杰 (Zhou Yanjie) }
4955ecafc12S周琰杰 (Zhou Yanjie) 
4965ecafc12S周琰杰 (Zhou Yanjie) static int __init ingenic_ost_init(struct device_node *np)
4975ecafc12S周琰杰 (Zhou Yanjie) {
4985ecafc12S周琰杰 (Zhou Yanjie) 	struct ingenic_ost *ost;
4995ecafc12S周琰杰 (Zhou Yanjie) 	unsigned long rate;
5005ecafc12S周琰杰 (Zhou Yanjie) 	int ret;
5015ecafc12S周琰杰 (Zhou Yanjie) 
5025ecafc12S周琰杰 (Zhou Yanjie) 	ret = ingenic_ost_probe(np);
5035ecafc12S周琰杰 (Zhou Yanjie) 	if (ret) {
5045ecafc12S周琰杰 (Zhou Yanjie) 		pr_crit("%s: Failed to initialize OST clocks: %d\n", __func__, ret);
5055ecafc12S周琰杰 (Zhou Yanjie) 		return ret;
5065ecafc12S周琰杰 (Zhou Yanjie) 	}
5075ecafc12S周琰杰 (Zhou Yanjie) 
5085ecafc12S周琰杰 (Zhou Yanjie) 	of_node_clear_flag(np, OF_POPULATED);
5095ecafc12S周琰杰 (Zhou Yanjie) 
5105ecafc12S周琰杰 (Zhou Yanjie) 	ost = ingenic_ost;
5115ecafc12S周琰杰 (Zhou Yanjie) 	if (IS_ERR(ost))
5125ecafc12S周琰杰 (Zhou Yanjie) 		return PTR_ERR(ost);
5135ecafc12S周琰杰 (Zhou Yanjie) 
5145ecafc12S周琰杰 (Zhou Yanjie) 	ret = ingenic_ost_global_timer_init(np, ost);
5155ecafc12S周琰杰 (Zhou Yanjie) 	if (ret) {
5165ecafc12S周琰杰 (Zhou Yanjie) 		pr_crit("%s: Unable to init global timer: %x\n", __func__, ret);
5175ecafc12S周琰杰 (Zhou Yanjie) 		goto err_free_ingenic_ost;
5185ecafc12S周琰杰 (Zhou Yanjie) 	}
5195ecafc12S周琰杰 (Zhou Yanjie) 
5205ecafc12S周琰杰 (Zhou Yanjie) 	ret = ingenic_ost_percpu_timer_init(np, ost);
5215ecafc12S周琰杰 (Zhou Yanjie) 	if (ret)
5225ecafc12S周琰杰 (Zhou Yanjie) 		goto err_ost_global_timer_cleanup;
5235ecafc12S周琰杰 (Zhou Yanjie) 
5245ecafc12S周琰杰 (Zhou Yanjie) 	/* Register the sched_clock at the end as there's no way to undo it */
5255ecafc12S周琰杰 (Zhou Yanjie) 	rate = clk_get_rate(ost->global_timer_clk);
5265ecafc12S周琰杰 (Zhou Yanjie) 	sched_clock_register(ingenic_ost_global_timer_read_cntl, 32, rate);
5275ecafc12S周琰杰 (Zhou Yanjie) 
5285ecafc12S周琰杰 (Zhou Yanjie) 	return 0;
5295ecafc12S周琰杰 (Zhou Yanjie) 
5305ecafc12S周琰杰 (Zhou Yanjie) err_ost_global_timer_cleanup:
5315ecafc12S周琰杰 (Zhou Yanjie) 	clocksource_unregister(&ost->cs);
5325ecafc12S周琰杰 (Zhou Yanjie) 	clk_disable_unprepare(ost->global_timer_clk);
5335ecafc12S周琰杰 (Zhou Yanjie) 	clk_put(ost->global_timer_clk);
5345ecafc12S周琰杰 (Zhou Yanjie) err_free_ingenic_ost:
5355ecafc12S周琰杰 (Zhou Yanjie) 	kfree(ost);
5365ecafc12S周琰杰 (Zhou Yanjie) 	return ret;
5375ecafc12S周琰杰 (Zhou Yanjie) }
5385ecafc12S周琰杰 (Zhou Yanjie) 
5395ecafc12S周琰杰 (Zhou Yanjie) TIMER_OF_DECLARE(x1000_ost,  "ingenic,x1000-ost",  ingenic_ost_init);
540