hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  DS1287 clockevent driver
 *
 *  Copyright (C) 2008    Yoichi Yuasa <yuasa@linux-mips.org>
 */
#include <linux/clockchips.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mc146818rtc.h>
#include <linux/irq.h>
 
#include <asm/time.h>
 
int ds1287_timer_state(void)
{
   return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0;
}
 
int ds1287_set_base_clock(unsigned int hz)
{
   u8 rate;
 
   switch (hz) {
   case 128:
       rate = 0x9;
       break;
   case 256:
       rate = 0x8;
       break;
   case 1024:
       rate = 0x6;
       break;
   default:
       return -EINVAL;
   }
 
   CMOS_WRITE(RTC_REF_CLCK_32KHZ | rate, RTC_REG_A);
 
   return 0;
}
 
static int ds1287_set_next_event(unsigned long delta,
                struct clock_event_device *evt)
{
   return -EINVAL;
}
 
static int ds1287_shutdown(struct clock_event_device *evt)
{
   u8 val;
 
   spin_lock(&rtc_lock);
 
   val = CMOS_READ(RTC_REG_B);
   val &= ~RTC_PIE;
   CMOS_WRITE(val, RTC_REG_B);
 
   spin_unlock(&rtc_lock);
   return 0;
}
 
static int ds1287_set_periodic(struct clock_event_device *evt)
{
   u8 val;
 
   spin_lock(&rtc_lock);
 
   val = CMOS_READ(RTC_REG_B);
   val |= RTC_PIE;
   CMOS_WRITE(val, RTC_REG_B);
 
   spin_unlock(&rtc_lock);
   return 0;
}
 
static void ds1287_event_handler(struct clock_event_device *dev)
{
}
 
static struct clock_event_device ds1287_clockevent = {
   .name            = "ds1287",
   .features        = CLOCK_EVT_FEAT_PERIODIC,
   .set_next_event        = ds1287_set_next_event,
   .set_state_shutdown    = ds1287_shutdown,
   .set_state_periodic    = ds1287_set_periodic,
   .tick_resume        = ds1287_shutdown,
   .event_handler        = ds1287_event_handler,
};
 
static irqreturn_t ds1287_interrupt(int irq, void *dev_id)
{
   struct clock_event_device *cd = &ds1287_clockevent;
 
   /* Ack the RTC interrupt. */
   CMOS_READ(RTC_REG_C);
 
   cd->event_handler(cd);
 
   return IRQ_HANDLED;
}
 
int __init ds1287_clockevent_init(int irq)
{
   unsigned long flags = IRQF_PERCPU | IRQF_TIMER;
   struct clock_event_device *cd;
 
   cd = &ds1287_clockevent;
   cd->rating = 100;
   cd->irq = irq;
   clockevent_set_clock(cd, 32768);
   cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
   cd->max_delta_ticks = 0x7fffffff;
   cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
   cd->min_delta_ticks = 0x300;
   cd->cpumask = cpumask_of(0);
 
   clockevents_register_device(&ds1287_clockevent);
 
   return request_irq(irq, ds1287_interrupt, flags, "ds1287", NULL);
}