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