linux/arch/mips/kernel/cevt-ds1287.c
<<
>>
Prefs
   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
  28int ds1287_timer_state(void)
  29{
  30        return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0;
  31}
  32
  33int 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
  56static int ds1287_set_next_event(unsigned long delta,
  57                                 struct clock_event_device *evt)
  58{
  59        return -EINVAL;
  60}
  61
  62static 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
  85static void ds1287_event_handler(struct clock_event_device *dev)
  86{
  87}
  88
  89static 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
  97static 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
 109static struct irqaction ds1287_irqaction = {
 110        .handler        = ds1287_interrupt,
 111        .flags          = IRQF_PERCPU | IRQF_TIMER,
 112        .name           = "ds1287",
 113};
 114
 115int __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