static irqreturn_t mxs_nomatch_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *c = dev_id; /* timer 0 */ if (__raw_readl(online_timer->base + HW_TIMROT_TIMCTRLn(0)) & BM_TIMROT_TIMCTRLn_IRQ) { __raw_writel(BM_TIMROT_TIMCTRLn_IRQ, online_timer->base + HW_TIMROT_TIMCTRLn_CLR(0)); c->event_handler(c); } /* timer 1 */ else if (__raw_readl(online_timer->base + HW_TIMROT_TIMCTRLn(1)) & BM_TIMROT_TIMCTRLn_IRQ) { __raw_writel(BM_TIMROT_TIMCTRLn_IRQ, online_timer->base + HW_TIMROT_TIMCTRLn_CLR(1)); __raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, online_timer->base + HW_TIMROT_TIMCTRLn_CLR(1)); __raw_writel(0xFFFF, online_timer->base + HW_TIMROT_TIMCOUNTn(1)); } return IRQ_HANDLED; }
static void __init mxs_timer_init(struct device_node *np) { struct clk *timer_clk; int irq; mxs_timrot_base = of_iomap(np, 0); WARN_ON(!mxs_timrot_base); timer_clk = of_clk_get(np, 0); if (IS_ERR(timer_clk)) { pr_err("%s: failed to get clk\n", __func__); return; } clk_prepare_enable(timer_clk); /* * Initialize timers to a known state */ stmp_reset_block(mxs_timrot_base + HW_TIMROT_ROTCTRL); /* get timrot version */ timrot_major_version = __raw_readl(mxs_timrot_base + (of_device_is_compatible(np, "fsl,imx23-timrot") ? MX23_TIMROT_VERSION_OFFSET : MX28_TIMROT_VERSION_OFFSET)); timrot_major_version >>= BP_TIMROT_MAJOR_VERSION; /* one for clock_event */ __raw_writel((timrot_is_v1() ? BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL : BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) | BM_TIMROT_TIMCTRLn_UPDATE | BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base + HW_TIMROT_TIMCTRLn(0)); /* another for clocksource */ __raw_writel((timrot_is_v1() ? BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL : BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) | BM_TIMROT_TIMCTRLn_RELOAD, mxs_timrot_base + HW_TIMROT_TIMCTRLn(1)); /* set clocksource timer fixed count to the maximum */ if (timrot_is_v1()) __raw_writel(0xffff, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)); else __raw_writel(0xffffffff, mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); /* init and register the timer to the framework */ mxs_clocksource_init(timer_clk); mxs_clockevent_init(timer_clk); /* Make irqs happen */ irq = irq_of_parse_and_map(np, 0); setup_irq(irq, &mxs_timer_irq); }
static int timrotv1_set_next_event(unsigned long evt, struct clock_event_device *dev) { /* timrot decrements the count */ __raw_writel(evt, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(0)); return 0; }
static int mxs_nomatch_timrot_set_next_event(unsigned long delta, struct clock_event_device *dev) { /* reload the timer */ __raw_writel(delta, online_timer->base + HW_TIMROT_TIMCOUNTn(0)); return 0; }
/* * Set up timer interrupt, and return the current time in seconds. */ void mxs_nomatch_timer_init(struct mxs_sys_timer *timer) { if (online_timer) return; online_timer = timer; cksrc_mxs_nomatch.mult = clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_mxs_nomatch.shift); ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_timrot.shift); ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot); ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot); ckevt_timrot.cpumask = cpumask_of(0); /* clear two timers */ __raw_writel(0, online_timer->base + HW_TIMROT_TIMCOUNTn(0)); __raw_writel(0, online_timer->base + HW_TIMROT_TIMCOUNTn(1)); /* configure them */ __raw_writel( (8 << BP_TIMROT_TIMCTRLn_SELECT) | /* 32 kHz */ BM_TIMROT_TIMCTRLn_RELOAD | BM_TIMROT_TIMCTRLn_UPDATE | BM_TIMROT_TIMCTRLn_IRQ_EN, online_timer->base + HW_TIMROT_TIMCTRLn(0)); __raw_writel( (8 << BP_TIMROT_TIMCTRLn_SELECT) | /* 32 kHz */ BM_TIMROT_TIMCTRLn_RELOAD | BM_TIMROT_TIMCTRLn_UPDATE | BM_TIMROT_TIMCTRLn_IRQ_EN, online_timer->base + HW_TIMROT_TIMCTRLn(1)); __raw_writel(CLOCK_TICK_RATE / HZ - 1, online_timer->base + HW_TIMROT_TIMCOUNTn(0)); __raw_writel(0xFFFF, online_timer->base + HW_TIMROT_TIMCOUNTn(1)); setup_irq(IRQ_TIMER0, &mxs_nomatch_timer_irq); clocksource_register(&cksrc_mxs_nomatch); clockevents_register_device(&ckevt_timrot); }
void mxs_nomatch_resume_timer(void) { __raw_writel(BM_TIMROT_ROTCTRL_SFTRST | BM_TIMROT_ROTCTRL_CLKGATE, online_timer->base + HW_TIMROT_ROTCTRL_CLR); __raw_writel( 8 << BP_TIMROT_TIMCTRLn_SELECT | /* 32 kHz */ BM_TIMROT_TIMCTRLn_RELOAD | BM_TIMROT_TIMCTRLn_UPDATE | BM_TIMROT_TIMCTRLn_IRQ_EN, online_timer->base + HW_TIMROT_TIMCTRLn(0)); __raw_writel( 8 << BP_TIMROT_TIMCTRLn_SELECT | /* 32 kHz */ BM_TIMROT_TIMCTRLn_RELOAD | BM_TIMROT_TIMCTRLn_UPDATE | BM_TIMROT_TIMCTRLn_IRQ_EN, online_timer->base + HW_TIMROT_TIMCTRLn(1)); __raw_writel(CLOCK_TICK_RATE / HZ - 1, online_timer->base + HW_TIMROT_TIMCOUNTn(0)); __raw_writel(0xFFFF, online_timer->base + HW_TIMROT_TIMCOUNTn(1)); }
void __init mxs_timer_init(int irq) { struct clk *timer_clk; timer_clk = clk_get_sys("timrot", NULL); if (IS_ERR(timer_clk)) { pr_err("%s: failed to get clk\n", __func__); return; } clk_prepare_enable(timer_clk); /* * Initialize timers to a known state */ mxs_reset_block(mxs_timrot_base + HW_TIMROT_ROTCTRL); /* get timrot version */ timrot_major_version = __raw_readl(mxs_timrot_base + (cpu_is_mx23() ? MX23_TIMROT_VERSION_OFFSET : MX28_TIMROT_VERSION_OFFSET)); timrot_major_version >>= BP_TIMROT_MAJOR_VERSION; /* one for clock_event */ __raw_writel((timrot_is_v1() ? BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL : BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL) | BM_TIMROT_TIMCTRLn_UPDATE | BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base + HW_TIMROT_TIMCTRLn(0)); /* another for clocksource */ __raw_writel((timrot_is_v1() ? BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL : BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL) | BM_TIMROT_TIMCTRLn_RELOAD, mxs_timrot_base + HW_TIMROT_TIMCTRLn(1)); /* set clocksource timer fixed count to the maximum */ if (timrot_is_v1()) __raw_writel(0xffff, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)); else __raw_writel(0xffffffff, mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); /* init and register the timer to the framework */ mxs_clocksource_init(timer_clk); mxs_clockevent_init(timer_clk); /* Make irqs happen */ setup_irq(irq, &mxs_timer_irq); }
static void mxs_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { /* Disable interrupt in timer module */ timrot_irq_disable(); if (mode != mxs_clockevent_mode) { /* Set event time into the furthest future */ if (timrot_is_v1()) __raw_writel(0xffff, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)); else __raw_writel(0xffffffff, mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); /* Clear pending interrupt */ timrot_irq_acknowledge(); } #ifdef DEBUG pr_info("%s: changing mode from %s to %s\n", __func__, clock_event_mode_label[mxs_clockevent_mode], clock_event_mode_label[mode]); #endif /* DEBUG */ /* Remember timer mode */ mxs_clockevent_mode = mode; switch (mode) { case CLOCK_EVT_MODE_PERIODIC: pr_err("%s: Periodic mode is not implemented\n", __func__); break; case CLOCK_EVT_MODE_ONESHOT: timrot_irq_enable(); break; case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_RESUME: /* Left event sources disabled, no more interrupts appear */ break; } }
void imx233_timrot_setup(unsigned timer_nr, bool reload, unsigned count, unsigned src, unsigned prescale, bool polarity, imx233_timer_fn_t fn) { int oldstatus = disable_interrupt_save(IRQ_FIQ_STATUS); /* only enable interrupt if function is set */ bool irq = fn != NULL; timer_fns[timer_nr] = fn; /* make sure we start from stop state */ HW_TIMROT_TIMCTRLn(timer_nr) = BF_OR2(TIMROT_TIMCTRLn, SELECT(BV_TIMROT_TIMCTRLn_SELECT__NEVER_TICK), UPDATE(1)); /* write count and take effect immediately with UPDATE * manual says count-1 for reload timers */ HW_TIMROT_TIMCOUNTn(timer_nr) = reload ? count - 1 : count; /* start timer */ HW_TIMROT_TIMCTRLn(timer_nr) = BF_OR6(TIMROT_TIMCTRLn, SELECT(src), PRESCALE(prescale), POLARITY(polarity), RELOAD(reload), IRQ(irq), IRQ_EN(irq)); imx233_icoll_enable_interrupt(INT_SRC_TIMER(timer_nr), irq); restore_interrupt(oldstatus); }
static cycle_t timrotv1_get_cycles(struct clocksource *cs) { return ~((__raw_readl(mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)) & 0xffff0000) >> 16); }
static cycle_t mxs_nomatch_clock_read(struct clocksource *cs) { return ~((__raw_readl(online_timer->base + HW_TIMROT_TIMCOUNTn(1)) & 0xFFFF0000) >> 16); }