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 int ds1287_shutdown(struct clock_event_device *evt)
  63{
  64        u8 val;
  65
  66        spin_lock(&rtc_lock);
  67
  68        val = CMOS_READ(RTC_REG_B);
  69        val &= ~RTC_PIE;
  70        CMOS_WRITE(val, RTC_REG_B);
  71
  72        spin_unlock(&rtc_lock);
  73        return 0;
  74}
  75
  76static int ds1287_set_periodic(struct clock_event_device *evt)
  77{
  78        u8 val;
  79
  80        spin_lock(&rtc_lock);
  81
  82        val = CMOS_READ(RTC_REG_B);
  83        val |= RTC_PIE;
  84        CMOS_WRITE(val, RTC_REG_B);
  85
  86        spin_unlock(&rtc_lock);
  87        return 0;
  88}
  89
  90static void ds1287_event_handler(struct clock_event_device *dev)
  91{
  92}
  93
  94static struct clock_event_device ds1287_clockevent = {
  95        .name                   = "ds1287",
  96        .features               = CLOCK_EVT_FEAT_PERIODIC,
  97        .set_next_event         = ds1287_set_next_event,
  98        .set_state_shutdown     = ds1287_shutdown,
  99        .set_state_periodic     = ds1287_set_periodic,
 100        .tick_resume            = ds1287_shutdown,
 101        .event_handler          = ds1287_event_handler,
 102};
 103
 104static irqreturn_t ds1287_interrupt(int irq, void *dev_id)
 105{
 106        struct clock_event_device *cd = &ds1287_clockevent;
 107
 108        /* Ack the RTC interrupt. */
 109        CMOS_READ(RTC_REG_C);
 110
 111        cd->event_handler(cd);
 112
 113        return IRQ_HANDLED;
 114}
 115
 116static struct irqaction ds1287_irqaction = {
 117        .handler        = ds1287_interrupt,
 118        .flags          = IRQF_PERCPU | IRQF_TIMER,
 119        .name           = "ds1287",
 120};
 121
 122int __init ds1287_clockevent_init(int irq)
 123{
 124        struct clock_event_device *cd;
 125
 126        cd = &ds1287_clockevent;
 127        cd->rating = 100;
 128        cd->irq = irq;
 129        clockevent_set_clock(cd, 32768);
 130        cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
 131        cd->max_delta_ticks = 0x7fffffff;
 132        cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
 133        cd->min_delta_ticks = 0x300;
 134        cd->cpumask = cpumask_of(0);
 135
 136        clockevents_register_device(&ds1287_clockevent);
 137
 138        return setup_irq(irq, &ds1287_irqaction);
 139}
 140