xref: /linux/arch/mips/kernel/cevt-ds1287.c (revision 320ab2b0)
16457d9fcSYoichi Yuasa /*
26457d9fcSYoichi Yuasa  *  DS1287 clockevent driver
36457d9fcSYoichi Yuasa  *
46457d9fcSYoichi Yuasa  *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
56457d9fcSYoichi Yuasa  *
66457d9fcSYoichi Yuasa  *  This program is free software; you can redistribute it and/or modify
76457d9fcSYoichi Yuasa  *  it under the terms of the GNU General Public License as published by
86457d9fcSYoichi Yuasa  *  the Free Software Foundation; either version 2 of the License, or
96457d9fcSYoichi Yuasa  *  (at your option) any later version.
106457d9fcSYoichi Yuasa  *
116457d9fcSYoichi Yuasa  *  This program is distributed in the hope that it will be useful,
126457d9fcSYoichi Yuasa  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
136457d9fcSYoichi Yuasa  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
146457d9fcSYoichi Yuasa  *  GNU General Public License for more details.
156457d9fcSYoichi Yuasa  *
166457d9fcSYoichi Yuasa  *  You should have received a copy of the GNU General Public License
176457d9fcSYoichi Yuasa  *  along with this program; if not, write to the Free Software
186457d9fcSYoichi Yuasa  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
196457d9fcSYoichi Yuasa  */
206457d9fcSYoichi Yuasa #include <linux/clockchips.h>
216457d9fcSYoichi Yuasa #include <linux/init.h>
226457d9fcSYoichi Yuasa #include <linux/interrupt.h>
236457d9fcSYoichi Yuasa #include <linux/mc146818rtc.h>
246457d9fcSYoichi Yuasa 
256457d9fcSYoichi Yuasa #include <asm/time.h>
266457d9fcSYoichi Yuasa 
276457d9fcSYoichi Yuasa int ds1287_timer_state(void)
286457d9fcSYoichi Yuasa {
296457d9fcSYoichi Yuasa 	return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0;
306457d9fcSYoichi Yuasa }
316457d9fcSYoichi Yuasa 
326457d9fcSYoichi Yuasa int ds1287_set_base_clock(unsigned int hz)
336457d9fcSYoichi Yuasa {
346457d9fcSYoichi Yuasa 	u8 rate;
356457d9fcSYoichi Yuasa 
366457d9fcSYoichi Yuasa 	switch (hz) {
376457d9fcSYoichi Yuasa 	case 128:
386457d9fcSYoichi Yuasa 		rate = 0x9;
396457d9fcSYoichi Yuasa 		break;
406457d9fcSYoichi Yuasa 	case 256:
416457d9fcSYoichi Yuasa 		rate = 0x8;
426457d9fcSYoichi Yuasa 		break;
436457d9fcSYoichi Yuasa 	case 1024:
446457d9fcSYoichi Yuasa 		rate = 0x6;
456457d9fcSYoichi Yuasa 		break;
466457d9fcSYoichi Yuasa 	default:
476457d9fcSYoichi Yuasa 		return -EINVAL;
486457d9fcSYoichi Yuasa 	}
496457d9fcSYoichi Yuasa 
506457d9fcSYoichi Yuasa 	CMOS_WRITE(RTC_REF_CLCK_32KHZ | rate, RTC_REG_A);
516457d9fcSYoichi Yuasa 
526457d9fcSYoichi Yuasa 	return 0;
536457d9fcSYoichi Yuasa }
546457d9fcSYoichi Yuasa 
556457d9fcSYoichi Yuasa static int ds1287_set_next_event(unsigned long delta,
566457d9fcSYoichi Yuasa 				 struct clock_event_device *evt)
576457d9fcSYoichi Yuasa {
586457d9fcSYoichi Yuasa 	return -EINVAL;
596457d9fcSYoichi Yuasa }
606457d9fcSYoichi Yuasa 
616457d9fcSYoichi Yuasa static void ds1287_set_mode(enum clock_event_mode mode,
626457d9fcSYoichi Yuasa 			    struct clock_event_device *evt)
636457d9fcSYoichi Yuasa {
646457d9fcSYoichi Yuasa 	u8 val;
656457d9fcSYoichi Yuasa 
666457d9fcSYoichi Yuasa 	spin_lock(&rtc_lock);
676457d9fcSYoichi Yuasa 
686457d9fcSYoichi Yuasa 	val = CMOS_READ(RTC_REG_B);
696457d9fcSYoichi Yuasa 
706457d9fcSYoichi Yuasa 	switch (mode) {
716457d9fcSYoichi Yuasa 	case CLOCK_EVT_MODE_PERIODIC:
726457d9fcSYoichi Yuasa 		val |= RTC_PIE;
736457d9fcSYoichi Yuasa 		break;
746457d9fcSYoichi Yuasa 	default:
756457d9fcSYoichi Yuasa 		val &= ~RTC_PIE;
766457d9fcSYoichi Yuasa 		break;
776457d9fcSYoichi Yuasa 	}
786457d9fcSYoichi Yuasa 
796457d9fcSYoichi Yuasa 	CMOS_WRITE(val, RTC_REG_B);
806457d9fcSYoichi Yuasa 
816457d9fcSYoichi Yuasa 	spin_unlock(&rtc_lock);
826457d9fcSYoichi Yuasa }
836457d9fcSYoichi Yuasa 
846457d9fcSYoichi Yuasa static void ds1287_event_handler(struct clock_event_device *dev)
856457d9fcSYoichi Yuasa {
866457d9fcSYoichi Yuasa }
876457d9fcSYoichi Yuasa 
886457d9fcSYoichi Yuasa static struct clock_event_device ds1287_clockevent = {
896457d9fcSYoichi Yuasa 	.name		= "ds1287",
906457d9fcSYoichi Yuasa 	.features	= CLOCK_EVT_FEAT_PERIODIC,
916457d9fcSYoichi Yuasa 	.set_next_event	= ds1287_set_next_event,
926457d9fcSYoichi Yuasa 	.set_mode	= ds1287_set_mode,
936457d9fcSYoichi Yuasa 	.event_handler	= ds1287_event_handler,
946457d9fcSYoichi Yuasa };
956457d9fcSYoichi Yuasa 
966457d9fcSYoichi Yuasa static irqreturn_t ds1287_interrupt(int irq, void *dev_id)
976457d9fcSYoichi Yuasa {
986457d9fcSYoichi Yuasa 	struct clock_event_device *cd = &ds1287_clockevent;
996457d9fcSYoichi Yuasa 
1006457d9fcSYoichi Yuasa 	/* Ack the RTC interrupt. */
1016457d9fcSYoichi Yuasa 	CMOS_READ(RTC_REG_C);
1026457d9fcSYoichi Yuasa 
1036457d9fcSYoichi Yuasa 	cd->event_handler(cd);
1046457d9fcSYoichi Yuasa 
1056457d9fcSYoichi Yuasa 	return IRQ_HANDLED;
1066457d9fcSYoichi Yuasa }
1076457d9fcSYoichi Yuasa 
1086457d9fcSYoichi Yuasa static struct irqaction ds1287_irqaction = {
1096457d9fcSYoichi Yuasa 	.handler	= ds1287_interrupt,
1106457d9fcSYoichi Yuasa 	.flags		= IRQF_DISABLED | IRQF_PERCPU,
1116457d9fcSYoichi Yuasa 	.name		= "ds1287",
1126457d9fcSYoichi Yuasa };
1136457d9fcSYoichi Yuasa 
1146457d9fcSYoichi Yuasa int __init ds1287_clockevent_init(int irq)
1156457d9fcSYoichi Yuasa {
1166457d9fcSYoichi Yuasa 	struct clock_event_device *cd;
1176457d9fcSYoichi Yuasa 
1186457d9fcSYoichi Yuasa 	cd = &ds1287_clockevent;
1196457d9fcSYoichi Yuasa 	cd->rating = 100;
1206457d9fcSYoichi Yuasa 	cd->irq = irq;
1216457d9fcSYoichi Yuasa 	clockevent_set_clock(cd, 32768);
1226457d9fcSYoichi Yuasa 	cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
1236457d9fcSYoichi Yuasa 	cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
124*320ab2b0SRusty Russell 	cd->cpumask = cpumask_of(0);
1256457d9fcSYoichi Yuasa 
1266457d9fcSYoichi Yuasa 	clockevents_register_device(&ds1287_clockevent);
1276457d9fcSYoichi Yuasa 
1286457d9fcSYoichi Yuasa 	return setup_irq(irq, &ds1287_irqaction);
1296457d9fcSYoichi Yuasa }
130