18c2ecf20Sopenharmony_ci/***************************************************************************/
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci/*
48c2ecf20Sopenharmony_ci *  timers.c - Generic hardware timer support.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *  Copyright (C) 1993 Hamish Macdonald
78c2ecf20Sopenharmony_ci *  Copyright (C) 1999 D. Jeff Dionne
88c2ecf20Sopenharmony_ci *  Copyright (C) 2001 Georges Menie, Ken Desmet
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
118c2ecf20Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
128c2ecf20Sopenharmony_ci * for more details.
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/***************************************************************************/
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/types.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/mm.h>
208c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
218c2ecf20Sopenharmony_ci#include <linux/irq.h>
228c2ecf20Sopenharmony_ci#include <linux/clocksource.h>
238c2ecf20Sopenharmony_ci#include <linux/rtc.h>
248c2ecf20Sopenharmony_ci#include <asm/setup.h>
258c2ecf20Sopenharmony_ci#include <asm/machdep.h>
268c2ecf20Sopenharmony_ci#include <asm/MC68VZ328.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/***************************************************************************/
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#if defined(CONFIG_DRAGEN2)
318c2ecf20Sopenharmony_ci/* with a 33.16 MHz clock, this will give usec resolution to the time functions */
328c2ecf20Sopenharmony_ci#define CLOCK_SOURCE	TCTL_CLKSOURCE_SYSCLK
338c2ecf20Sopenharmony_ci#define CLOCK_PRE	7
348c2ecf20Sopenharmony_ci#define TICKS_PER_JIFFY	41450
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#elif defined(CONFIG_XCOPILOT_BUGS)
378c2ecf20Sopenharmony_ci/*
388c2ecf20Sopenharmony_ci * The only thing I know is that CLK32 is not available on Xcopilot
398c2ecf20Sopenharmony_ci * I have little idea about what frequency SYSCLK has on Xcopilot.
408c2ecf20Sopenharmony_ci * The values for prescaler and compare registers were simply
418c2ecf20Sopenharmony_ci * taken from the original source
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_ci#define CLOCK_SOURCE	TCTL_CLKSOURCE_SYSCLK
448c2ecf20Sopenharmony_ci#define CLOCK_PRE	2
458c2ecf20Sopenharmony_ci#define TICKS_PER_JIFFY	0xd7e4
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#else
488c2ecf20Sopenharmony_ci/* default to using the 32Khz clock */
498c2ecf20Sopenharmony_ci#define CLOCK_SOURCE	TCTL_CLKSOURCE_32KHZ
508c2ecf20Sopenharmony_ci#define CLOCK_PRE	31
518c2ecf20Sopenharmony_ci#define TICKS_PER_JIFFY	10
528c2ecf20Sopenharmony_ci#endif
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic u32 m68328_tick_cnt;
558c2ecf20Sopenharmony_cistatic irq_handler_t timer_interrupt;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/***************************************************************************/
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic irqreturn_t hw_tick(int irq, void *dummy)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	/* Reset Timer1 */
628c2ecf20Sopenharmony_ci	TSTAT &= 0;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	m68328_tick_cnt += TICKS_PER_JIFFY;
658c2ecf20Sopenharmony_ci	return timer_interrupt(irq, dummy);
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/***************************************************************************/
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic u64 m68328_read_clk(struct clocksource *cs)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	unsigned long flags;
738c2ecf20Sopenharmony_ci	u32 cycles;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	local_irq_save(flags);
768c2ecf20Sopenharmony_ci	cycles = m68328_tick_cnt + TCN;
778c2ecf20Sopenharmony_ci	local_irq_restore(flags);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return cycles;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/***************************************************************************/
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic struct clocksource m68328_clk = {
858c2ecf20Sopenharmony_ci	.name	= "timer",
868c2ecf20Sopenharmony_ci	.rating	= 250,
878c2ecf20Sopenharmony_ci	.read	= m68328_read_clk,
888c2ecf20Sopenharmony_ci	.mask	= CLOCKSOURCE_MASK(32),
898c2ecf20Sopenharmony_ci	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/***************************************************************************/
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_civoid hw_timer_init(irq_handler_t handler)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	int ret;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/* disable timer 1 */
998c2ecf20Sopenharmony_ci	TCTL = 0;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/* set ISR */
1028c2ecf20Sopenharmony_ci	ret = request_irq(TMR_IRQ_NUM, hw_tick, IRQF_TIMER, "timer", NULL);
1038c2ecf20Sopenharmony_ci	if (ret) {
1048c2ecf20Sopenharmony_ci		pr_err("Failed to request irq %d (timer): %pe\n", TMR_IRQ_NUM,
1058c2ecf20Sopenharmony_ci		       ERR_PTR(ret));
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/* Restart mode, Enable int, Set clock source */
1098c2ecf20Sopenharmony_ci	TCTL = TCTL_OM | TCTL_IRQEN | CLOCK_SOURCE;
1108c2ecf20Sopenharmony_ci	TPRER = CLOCK_PRE;
1118c2ecf20Sopenharmony_ci	TCMP = TICKS_PER_JIFFY;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* Enable timer 1 */
1148c2ecf20Sopenharmony_ci	TCTL |= TCTL_TEN;
1158c2ecf20Sopenharmony_ci	clocksource_register_hz(&m68328_clk, TICKS_PER_JIFFY*HZ);
1168c2ecf20Sopenharmony_ci	timer_interrupt = handler;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/***************************************************************************/
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ciint m68328_hwclk(int set, struct rtc_time *t)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	if (!set) {
1248c2ecf20Sopenharmony_ci		long now = RTCTIME;
1258c2ecf20Sopenharmony_ci		t->tm_year = 1;
1268c2ecf20Sopenharmony_ci		t->tm_mon = 0;
1278c2ecf20Sopenharmony_ci		t->tm_mday = 1;
1288c2ecf20Sopenharmony_ci		t->tm_hour = (now >> 24) % 24;
1298c2ecf20Sopenharmony_ci		t->tm_min = (now >> 16) % 60;
1308c2ecf20Sopenharmony_ci		t->tm_sec = now % 60;
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return 0;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/***************************************************************************/
137