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