void __init atmel_time_init (void) { register volatile struct at91_timers* tt = (struct at91_timers*) (AT91_TC_BASE); register volatile struct at91_timer_channel* tc = &tt->chans[KERNEL_TIMER].ch; unsigned long v; /* enable Kernel timer */ HW_AT91_TIMER_INIT(KERNEL_TIMER) /* No SYNC */ tt->bcr = 0; /* program NO signal on XC1 */ v = tt->bmr; v &= ~TCNXCNS(KERNEL_TIMER,3); v |= TCNXCNS(KERNEL_TIMER,1); tt->bmr = v; tc->ccr = 2; /* disable the channel */ /* select ACLK/128 as inupt frequency for TC1 and enable CPCTRG */ tc->cmr = 3 | (1 << 14); tc->idr = ~0ul; /* disable all interrupt */ tc->rc = ((ARM_CLK/128)/HZ - 1); /* load the count limit into the CR register */ tc->ier = TC_CPCS; /* enable CPCS interrupt */ /* * @todo do those really need to be function pointers ? */ gettimeoffset = atmel_gettimeoffset; atmel_timer_irq.handler = atmel_timer_interrupt; /* set up the interrupt */ setup_irq(KERNEL_TIMER_IRQ_NUM, &atmel_timer_irq); /* enable the channel */ tc->ccr = TC_SWTRG|TC_CLKEN; }
void at91_ipipe_init(struct clock_event_device *host_timer) { unsigned char tc_divisors[] = { 2, 8, 32, 128, 0, }; unsigned master_freq, divisor = 0, divided_freq = 0; unsigned long long wrap_ns; int tc_timer_clock; unsigned short v; struct clk *clk; #ifdef CONFIG_ARCH_AT91SAM9263 clk = clk_get(NULL, "tcb_clk"); #elif defined(CONFIG_ARCH_AT91SAM9G45) clk = clk_get(NULL, "tcb0_clk"); #else /* not AT91SAM9263 or AT91SAM9G45*/ clk = clk_get(NULL, "tc"__stringify(CONFIG_IPIPE_AT91_TC) "_clk"); #endif clk_enable(clk); /* Disable the channel */ at91_tc_write(AT91_TC_CCR, AT91_TC_CLKDIS); /* Disable all interrupts. */ at91_tc_write(AT91_TC_IDR, ~0ul); master_freq = clk_get_rate(clk_get(NULL, "mck")); /* Find the first frequency above 1 MHz */ for (tc_timer_clock = ARRAY_SIZE(tc_divisors) - 1; tc_timer_clock >= 0; tc_timer_clock--) { divisor = tc_divisors[tc_timer_clock]; divided_freq = (divisor ? master_freq / divisor : AT91_SLOW_CLOCK); if (divided_freq > 1000000) break; } wrap_ns = (unsigned long long) (AT91_TC_REG_MASK + 1) * NSEC_PER_SEC; do_div(wrap_ns, divided_freq); if (divided_freq < 1000000) printk(KERN_INFO "AT91 I-pipe warning: could not find a" " frequency greater than 1MHz\n"); printk(KERN_INFO "AT91 I-pipe timer: div: %u, freq: %u.%06u MHz, wrap: " "%u.%06u ms\n", divisor, divided_freq / 1000000, divided_freq % 1000000, (unsigned) wrap_ns / 1000000, (unsigned) wrap_ns % 1000000); /* Add a 1ms margin. It means that when an interrupt occurs, update_tsc must be called within 1ms. update_tsc is called by acktimer when no higher domain handles the timer, and called through set_dec when a higher domain handles the timer. */ wrap_ns -= 1000000; /* Set up the interrupt. */ if (host_timer && host_timer->features & CLOCK_EVT_FEAT_ONESHOT && host_timer->max_delta_ns > wrap_ns) host_timer->max_delta_ns = wrap_ns; /* No Sync. */ at91_tc_write(AT91_TC_BCR, 0); /* program NO signal on XCN */ v = readl((void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR)); v &= ~TCNXCNS(CONFIG_IPIPE_AT91_TC, 3); v |= TCNXCNS(CONFIG_IPIPE_AT91_TC, 1); /* AT91_TC_TCNXCNS_NONE */ writel(v, (void __iomem *) (AT91_VA_BASE_TCB0 + AT91_TC_BMR)); /* Use the clock selected as input clock. */ at91_tc_write(AT91_TC_CMR, tc_timer_clock); /* Load the TC register C. */ write_RC(0xffff); /* Enable the channel. */ at91_tc_write(AT91_TC_CCR, AT91_TC_CLKEN | AT91_TC_SWTRG); at91_itimer.freq = divided_freq; at91_itimer.min_delay_ticks = ipipe_timer_ns2ticks(&at91_itimer, 2000); max_delta_ticks = ipipe_timer_ns2ticks(&at91_itimer, wrap_ns); ipipe_timer_register(&at91_itimer); tsc_info.freq = divided_freq; __ipipe_tsc_register(&tsc_info); at91_pic_muter_register(); }