linux/arch/mips/kernel/cevt-ds1287.c
<<
>>
Prefs
   1/*
   2 *  DS1287 clockevent driver
   3 *
   4 *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
   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
  25#include <asm/time.h>
  26
  27int ds1287_timer_state(void)
  28{
  29        return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0;
  30}
  31
  32int ds1287_set_base_clock(unsigned int hz)
  33{
  34        u8 rate;
  35
  36        switch (hz) {
  37        case 128:
  38                rate = 0x9;
  39                break;
  40        case 256:
  41                rate = 0x8;
  42                break;
  43        case 1024:
  44                rate = 0x6;
  45                break;
  46        default:
  47                return -EINVAL;
  48        }
  49
  50        CMOS_WRITE(RTC_REF_CLCK_32KHZ | rate, RTC_REG_A);
  51
  52        return 0;
  53}
  54
  55static int ds1287_set_next_event(unsigned long delta,
  56                                 struct clock_event_device *evt)
  57{
  58        return -EINVAL;
  59}
  60
  61static void ds1287_set_mode(enum clock_event_mode mode,
  62                            struct clock_event_device *evt)
  63{
  64        u8 val;
  65
  66        spin_lock(&rtc_lock);
  67
  68        val = CMOS_READ(RTC_REG_B);
  69
  70        switch (mode) {
  71        case CLOCK_EVT_MODE_PERIODIC:
  72                val |= RTC_PIE;
  73                break;
  74        default:
  75                val &= ~RTC_PIE;
  76                break;
  77        }
  78
  79        CMOS_WRITE(val, RTC_REG_B);
  80
  81        spin_unlock(&rtc_lock);
  82}
  83
  84static void ds1287_event_handler(struct clock_event_device *dev)
  85{
  86}
  87
  88static struct clock_event_device ds1287_clockevent = {
  89        .name           = "ds1287",
  90        .features       = CLOCK_EVT_FEAT_PERIODIC,
  91        .set_next_event = ds1287_set_next_event,
  92        .set_mode       = ds1287_set_mode,
  93        .event_handler  = ds1287_event_handler,
  94};
  95
  96static irqreturn_t ds1287_interrupt(int irq, void *dev_id)
  97{
  98        struct clock_event_device *cd = &ds1287_clockevent;
  99
 100        /* Ack the RTC interrupt. */
 101        CMOS_READ(RTC_REG_C);
 102
 103        cd->event_handler(cd);
 104
 105        return IRQ_HANDLED;
 106}
 107
 108static struct irqaction ds1287_irqaction = {
 109        .handler        = ds1287_interrupt,
 110        .flags          = IRQF_DISABLED | IRQF_PERCPU,
 111        .name           = "ds1287",
 112};
 113
 114int __init ds1287_clockevent_init(int irq)
 115{
 116        struct clock_event_device *cd;
 117
 118        cd = &ds1287_clockevent;
 119        cd->rating = 100;
 120        cd->irq = irq;
 121        clockevent_set_clock(cd, 32768);
 122        cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
 123        cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
 124        cd->cpumask = cpumask_of(0);
 125
 126        clockevents_register_device(&ds1287_clockevent);
 127
 128        return setup_irq(irq, &ds1287_irqaction);
 129}
 130