1 /* 2 * DS1287 clockevent driver 3 * 4 * Copyright (C) 2008 Yoichi Yuasa <yuasa@linux-mips.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 #include <linux/clockchips.h> 21 #include <linux/init.h> 22 #include <linux/interrupt.h> 23 #include <linux/mc146818rtc.h> 24 #include <linux/irq.h> 25 26 #include <asm/time.h> 27 28 int ds1287_timer_state(void) 29 { 30 return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0; 31 } 32 33 int ds1287_set_base_clock(unsigned int hz) 34 { 35 u8 rate; 36 37 switch (hz) { 38 case 128: 39 rate = 0x9; 40 break; 41 case 256: 42 rate = 0x8; 43 break; 44 case 1024: 45 rate = 0x6; 46 break; 47 default: 48 return -EINVAL; 49 } 50 51 CMOS_WRITE(RTC_REF_CLCK_32KHZ | rate, RTC_REG_A); 52 53 return 0; 54 } 55 56 static int ds1287_set_next_event(unsigned long delta, 57 struct clock_event_device *evt) 58 { 59 return -EINVAL; 60 } 61 62 static void ds1287_set_mode(enum clock_event_mode mode, 63 struct clock_event_device *evt) 64 { 65 u8 val; 66 67 spin_lock(&rtc_lock); 68 69 val = CMOS_READ(RTC_REG_B); 70 71 switch (mode) { 72 case CLOCK_EVT_MODE_PERIODIC: 73 val |= RTC_PIE; 74 break; 75 default: 76 val &= ~RTC_PIE; 77 break; 78 } 79 80 CMOS_WRITE(val, RTC_REG_B); 81 82 spin_unlock(&rtc_lock); 83 } 84 85 static void ds1287_event_handler(struct clock_event_device *dev) 86 { 87 } 88 89 static struct clock_event_device ds1287_clockevent = { 90 .name = "ds1287", 91 .features = CLOCK_EVT_FEAT_PERIODIC, 92 .set_next_event = ds1287_set_next_event, 93 .set_mode = ds1287_set_mode, 94 .event_handler = ds1287_event_handler, 95 }; 96 97 static irqreturn_t ds1287_interrupt(int irq, void *dev_id) 98 { 99 struct clock_event_device *cd = &ds1287_clockevent; 100 101 /* Ack the RTC interrupt. */ 102 CMOS_READ(RTC_REG_C); 103 104 cd->event_handler(cd); 105 106 return IRQ_HANDLED; 107 } 108 109 static struct irqaction ds1287_irqaction = { 110 .handler = ds1287_interrupt, 111 .flags = IRQF_PERCPU | IRQF_TIMER, 112 .name = "ds1287", 113 }; 114 115 int __init ds1287_clockevent_init(int irq) 116 { 117 struct clock_event_device *cd; 118 119 cd = &ds1287_clockevent; 120 cd->rating = 100; 121 cd->irq = irq; 122 clockevent_set_clock(cd, 32768); 123 cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); 124 cd->min_delta_ns = clockevent_delta2ns(0x300, cd); 125 cd->cpumask = cpumask_of(0); 126 127 clockevents_register_device(&ds1287_clockevent); 128 129 return setup_irq(irq, &ds1287_irqaction); 130 } 131