1bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer/* 2bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * arch/arm/mach-netx/time.c 3bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * 4bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix 5bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * 6bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * This program is free software; you can redistribute it and/or modify 7bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * it under the terms of the GNU General Public License version 2 8bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * as published by the Free Software Foundation. 9bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * 10bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * This program is distributed in the hope that it will be useful, 11bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * but WITHOUT ANY WARRANTY; without even the implied warranty of 12bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * GNU General Public License for more details. 14bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * 15bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * You should have received a copy of the GNU General Public License 16bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * along with this program; if not, write to the Free Software 17bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer */ 19bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 20bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer#include <linux/init.h> 21bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer#include <linux/interrupt.h> 221a815aed1e03c73fcd0390109c7da9c69dc97490Sascha Hauer#include <linux/irq.h> 231a815aed1e03c73fcd0390109c7da9c69dc97490Sascha Hauer#include <linux/clocksource.h> 242fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König#include <linux/clockchips.h> 25fced80c735941fa518ac67c0b61bbe153fb8c050Russell King#include <linux/io.h> 26bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 27a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/hardware.h> 28bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer#include <asm/mach/time.h> 29a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/netx-regs.h> 30bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 315e3e27637959155bf3b06f52c5fbe9e9b0ffbdfeUwe Kleine-König#define NETX_CLOCK_FREQ 100000000 325e3e27637959155bf3b06f52c5fbe9e9b0ffbdfeUwe Kleine-König#define NETX_LATCH DIV_ROUND_CLOSEST(NETX_CLOCK_FREQ, HZ) 335e3e27637959155bf3b06f52c5fbe9e9b0ffbdfeUwe Kleine-König 342fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König#define TIMER_CLOCKEVENT 0 3524e7857677fe3cb87f1dd7fa1418a73795e9f4c5Uwe Kleine-König#define TIMER_CLOCKSOURCE 1 3624e7857677fe3cb87f1dd7fa1418a73795e9f4c5Uwe Kleine-König 372fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-Königstatic void netx_set_mode(enum clock_event_mode mode, 382fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König struct clock_event_device *clk) 392fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König{ 402fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König u32 tmode; 412fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 422fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König /* disable timer */ 432fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT)); 442fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 452fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König switch (mode) { 462fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König case CLOCK_EVT_MODE_PERIODIC: 475e3e27637959155bf3b06f52c5fbe9e9b0ffbdfeUwe Kleine-König writel(NETX_LATCH, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT)); 482fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König tmode = NETX_GPIO_COUNTER_CTRL_RST_EN | 492fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König NETX_GPIO_COUNTER_CTRL_IRQ_EN | 502fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König NETX_GPIO_COUNTER_CTRL_RUN; 512fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König break; 522fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 532fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König case CLOCK_EVT_MODE_ONESHOT: 542fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König writel(0, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT)); 552fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König tmode = NETX_GPIO_COUNTER_CTRL_IRQ_EN | 562fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König NETX_GPIO_COUNTER_CTRL_RUN; 572fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König break; 582fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 592fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König default: 602fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König WARN(1, "%s: unhandled mode %d\n", __func__, mode); 612fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König /* fall through */ 622fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 632fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König case CLOCK_EVT_MODE_SHUTDOWN: 642fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König case CLOCK_EVT_MODE_UNUSED: 652fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König case CLOCK_EVT_MODE_RESUME: 662fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König tmode = 0; 672fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König break; 682fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König } 692fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 702fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König writel(tmode, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT)); 712fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König} 722fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 732fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-Königstatic int netx_set_next_event(unsigned long evt, 742fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König struct clock_event_device *clk) 752fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König{ 762fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König writel(0 - evt, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKEVENT)); 772fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König return 0; 782fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König} 792fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 802fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-Königstatic struct clock_event_device netx_clockevent = { 812fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König .name = "netx-timer" __stringify(TIMER_CLOCKEVENT), 822fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 832fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König .set_next_event = netx_set_next_event, 842fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König .set_mode = netx_set_mode, 852fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König}; 862fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 87bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer/* 88bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * IRQ handler for the timer 89bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer */ 90bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauerstatic irqreturn_t 910cd61b68c340a4f901a06e8bb5e0dea4353161c0Linus Torvaldsnetx_timer_interrupt(int irq, void *dev_id) 92bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer{ 932fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König struct clock_event_device *evt = &netx_clockevent; 941a815aed1e03c73fcd0390109c7da9c69dc97490Sascha Hauer 95bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer /* acknowledge interrupt */ 96bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer writel(COUNTER_BIT(0), NETX_GPIO_IRQ); 97bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 982fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König evt->event_handler(evt); 992fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 100bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer return IRQ_HANDLED; 101bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer} 102bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 103bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauerstatic struct irqaction netx_timer_irq = { 1049853848860d7ece7d84ac43cfde5390b2638eb89Uwe Kleine-König .name = "NetX Timer Tick", 10578f6db99522bbdd2f2a90c963744bd51c8602990Michael Opdenacker .flags = IRQF_TIMER | IRQF_IRQPOLL, 1069853848860d7ece7d84ac43cfde5390b2638eb89Uwe Kleine-König .handler = netx_timer_interrupt, 107bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer}; 108bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 109bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer/* 110bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer * Set up timer interrupt 111bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer */ 1126bb27d7349db51b50c40534710fe164ca0d58902Stephen Warrenvoid __init netx_timer_init(void) 113bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer{ 114bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer /* disable timer initially */ 115bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer writel(0, NETX_GPIO_COUNTER_CTRL(0)); 116bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 117bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer /* Reset the timer value to zero */ 118bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer writel(0, NETX_GPIO_COUNTER_CURRENT(0)); 119bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 1205e3e27637959155bf3b06f52c5fbe9e9b0ffbdfeUwe Kleine-König writel(NETX_LATCH, NETX_GPIO_COUNTER_MAX(0)); 121bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 122bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer /* acknowledge interrupt */ 123bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer writel(COUNTER_BIT(0), NETX_GPIO_IRQ); 124bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 1259853848860d7ece7d84ac43cfde5390b2638eb89Uwe Kleine-König /* Enable the interrupt in the specific timer 1269853848860d7ece7d84ac43cfde5390b2638eb89Uwe Kleine-König * register and start timer 1279853848860d7ece7d84ac43cfde5390b2638eb89Uwe Kleine-König */ 128bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer writel(COUNTER_BIT(0), NETX_GPIO_IRQ_ENABLE); 129bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer writel(NETX_GPIO_COUNTER_CTRL_IRQ_EN | NETX_GPIO_COUNTER_CTRL_RUN, 1309853848860d7ece7d84ac43cfde5390b2638eb89Uwe Kleine-König NETX_GPIO_COUNTER_CTRL(0)); 131bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer 132bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer setup_irq(NETX_IRQ_TIMER0, &netx_timer_irq); 1331a815aed1e03c73fcd0390109c7da9c69dc97490Sascha Hauer 1341a815aed1e03c73fcd0390109c7da9c69dc97490Sascha Hauer /* Setup timer one for clocksource */ 13524e7857677fe3cb87f1dd7fa1418a73795e9f4c5Uwe Kleine-König writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE)); 13624e7857677fe3cb87f1dd7fa1418a73795e9f4c5Uwe Kleine-König writel(0, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE)); 13724e7857677fe3cb87f1dd7fa1418a73795e9f4c5Uwe Kleine-König writel(0xffffffff, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKSOURCE)); 1381a815aed1e03c73fcd0390109c7da9c69dc97490Sascha Hauer 1399853848860d7ece7d84ac43cfde5390b2638eb89Uwe Kleine-König writel(NETX_GPIO_COUNTER_CTRL_RUN, 14024e7857677fe3cb87f1dd7fa1418a73795e9f4c5Uwe Kleine-König NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE)); 1411a815aed1e03c73fcd0390109c7da9c69dc97490Sascha Hauer 142234b6ceddb4fc2a4bc5b9a7670f070f6e69e0868Russell King clocksource_mmio_init(NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE), 1435e3e27637959155bf3b06f52c5fbe9e9b0ffbdfeUwe Kleine-König "netx_timer", NETX_CLOCK_FREQ, 200, 32, clocksource_mmio_readl_up); 1442fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König 1452fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König /* with max_delta_ns >= delta2ns(0x800) the system currently runs fine. 1462fcfe6b872b21639dcffbaf3ca2a84ec01d104e0Uwe Kleine-König * Adding some safety ... */ 1472927926707d07f846154842bc12bed6d817d9412Russell King netx_clockevent.cpumask = cpumask_of(0); 1485e3e27637959155bf3b06f52c5fbe9e9b0ffbdfeUwe Kleine-König clockevents_config_and_register(&netx_clockevent, NETX_CLOCK_FREQ, 149838a2ae80a6ab52139fb1bf0a93ea8c5eff94488Shawn Guo 0xa00, 0xfffffffe); 150bb6d8c8828123e01e2ae6c9d9c4870477889fd94Sascha Hauer} 151