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