162306a36Sopenharmony_ci/***************************************************************************/
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci *  timers.c - Generic hardware timer support.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Copyright (C) 1993 Hamish Macdonald
762306a36Sopenharmony_ci *  Copyright (C) 1999 D. Jeff Dionne
862306a36Sopenharmony_ci *  Copyright (C) 2001 Georges Menie, Ken Desmet
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
1162306a36Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
1262306a36Sopenharmony_ci * for more details.
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/***************************************************************************/
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/types.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/mm.h>
2062306a36Sopenharmony_ci#include <linux/interrupt.h>
2162306a36Sopenharmony_ci#include <linux/irq.h>
2262306a36Sopenharmony_ci#include <linux/clocksource.h>
2362306a36Sopenharmony_ci#include <linux/rtc.h>
2462306a36Sopenharmony_ci#include <asm/setup.h>
2562306a36Sopenharmony_ci#include <asm/machdep.h>
2662306a36Sopenharmony_ci#include <asm/MC68VZ328.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/***************************************************************************/
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#if defined(CONFIG_DRAGEN2)
3162306a36Sopenharmony_ci/* with a 33.16 MHz clock, this will give usec resolution to the time functions */
3262306a36Sopenharmony_ci#define CLOCK_SOURCE	TCTL_CLKSOURCE_SYSCLK
3362306a36Sopenharmony_ci#define CLOCK_PRE	7
3462306a36Sopenharmony_ci#define TICKS_PER_JIFFY	41450
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#elif defined(CONFIG_XCOPILOT_BUGS)
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * The only thing I know is that CLK32 is not available on Xcopilot
3962306a36Sopenharmony_ci * I have little idea about what frequency SYSCLK has on Xcopilot.
4062306a36Sopenharmony_ci * The values for prescaler and compare registers were simply
4162306a36Sopenharmony_ci * taken from the original source
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ci#define CLOCK_SOURCE	TCTL_CLKSOURCE_SYSCLK
4462306a36Sopenharmony_ci#define CLOCK_PRE	2
4562306a36Sopenharmony_ci#define TICKS_PER_JIFFY	0xd7e4
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#else
4862306a36Sopenharmony_ci/* default to using the 32Khz clock */
4962306a36Sopenharmony_ci#define CLOCK_SOURCE	TCTL_CLKSOURCE_32KHZ
5062306a36Sopenharmony_ci#define CLOCK_PRE	31
5162306a36Sopenharmony_ci#define TICKS_PER_JIFFY	10
5262306a36Sopenharmony_ci#endif
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic u32 m68328_tick_cnt;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/***************************************************************************/
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic irqreturn_t hw_tick(int irq, void *dummy)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	/* Reset Timer1 */
6162306a36Sopenharmony_ci	TSTAT &= 0;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	m68328_tick_cnt += TICKS_PER_JIFFY;
6462306a36Sopenharmony_ci	legacy_timer_tick(1);
6562306a36Sopenharmony_ci	return IRQ_HANDLED;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/***************************************************************************/
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic u64 m68328_read_clk(struct clocksource *cs)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	unsigned long flags;
7362306a36Sopenharmony_ci	u32 cycles;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	local_irq_save(flags);
7662306a36Sopenharmony_ci	cycles = m68328_tick_cnt + TCN;
7762306a36Sopenharmony_ci	local_irq_restore(flags);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return cycles;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/***************************************************************************/
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic struct clocksource m68328_clk = {
8562306a36Sopenharmony_ci	.name	= "timer",
8662306a36Sopenharmony_ci	.rating	= 250,
8762306a36Sopenharmony_ci	.read	= m68328_read_clk,
8862306a36Sopenharmony_ci	.mask	= CLOCKSOURCE_MASK(32),
8962306a36Sopenharmony_ci	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/***************************************************************************/
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_civoid hw_timer_init(void)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	int ret;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/* disable timer 1 */
9962306a36Sopenharmony_ci	TCTL = 0;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* set ISR */
10262306a36Sopenharmony_ci	ret = request_irq(TMR_IRQ_NUM, hw_tick, IRQF_TIMER, "timer", NULL);
10362306a36Sopenharmony_ci	if (ret) {
10462306a36Sopenharmony_ci		pr_err("Failed to request irq %d (timer): %pe\n", TMR_IRQ_NUM,
10562306a36Sopenharmony_ci		       ERR_PTR(ret));
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Restart mode, Enable int, Set clock source */
10962306a36Sopenharmony_ci	TCTL = TCTL_OM | TCTL_IRQEN | CLOCK_SOURCE;
11062306a36Sopenharmony_ci	TPRER = CLOCK_PRE;
11162306a36Sopenharmony_ci	TCMP = TICKS_PER_JIFFY;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* Enable timer 1 */
11462306a36Sopenharmony_ci	TCTL |= TCTL_TEN;
11562306a36Sopenharmony_ci	clocksource_register_hz(&m68328_clk, TICKS_PER_JIFFY*HZ);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/***************************************************************************/
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ciint m68328_hwclk(int set, struct rtc_time *t)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	if (!set) {
12362306a36Sopenharmony_ci		long now = RTCTIME;
12462306a36Sopenharmony_ci		t->tm_year = 1;
12562306a36Sopenharmony_ci		t->tm_mon = 0;
12662306a36Sopenharmony_ci		t->tm_mday = 1;
12762306a36Sopenharmony_ci		t->tm_hour = (now >> 24) % 24;
12862306a36Sopenharmony_ci		t->tm_min = (now >> 16) % 60;
12962306a36Sopenharmony_ci		t->tm_sec = now % 60;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return 0;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/***************************************************************************/
136