]>
Commit | Line | Data |
---|---|---|
16216333 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
6457d9fc YY |
2 | /* |
3 | * DS1287 clockevent driver | |
4 | * | |
70342287 | 5 | * Copyright (C) 2008 Yoichi Yuasa <yuasa@linux-mips.org> |
6457d9fc YY |
6 | */ |
7 | #include <linux/clockchips.h> | |
8 | #include <linux/init.h> | |
9 | #include <linux/interrupt.h> | |
10 | #include <linux/mc146818rtc.h> | |
ca4d3e67 | 11 | #include <linux/irq.h> |
6457d9fc YY |
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 | ||
9f95618f | 49 | static int ds1287_shutdown(struct clock_event_device *evt) |
6457d9fc YY |
50 | { |
51 | u8 val; | |
52 | ||
53 | spin_lock(&rtc_lock); | |
54 | ||
55 | val = CMOS_READ(RTC_REG_B); | |
9f95618f VK |
56 | val &= ~RTC_PIE; |
57 | CMOS_WRITE(val, RTC_REG_B); | |
6457d9fc | 58 | |
9f95618f VK |
59 | spin_unlock(&rtc_lock); |
60 | return 0; | |
61 | } | |
6457d9fc | 62 | |
9f95618f VK |
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; | |
6457d9fc YY |
71 | CMOS_WRITE(val, RTC_REG_B); |
72 | ||
73 | spin_unlock(&rtc_lock); | |
9f95618f | 74 | return 0; |
6457d9fc YY |
75 | } |
76 | ||
77 | static void ds1287_event_handler(struct clock_event_device *dev) | |
78 | { | |
79 | } | |
80 | ||
81 | static struct clock_event_device ds1287_clockevent = { | |
9f95618f VK |
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, | |
6457d9fc YY |
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 | static struct irqaction ds1287_irqaction = { | |
104 | .handler = ds1287_interrupt, | |
8b5690f8 | 105 | .flags = IRQF_PERCPU | IRQF_TIMER, |
6457d9fc YY |
106 | .name = "ds1287", |
107 | }; | |
108 | ||
109 | int __init ds1287_clockevent_init(int irq) | |
110 | { | |
111 | struct clock_event_device *cd; | |
112 | ||
113 | cd = &ds1287_clockevent; | |
114 | cd->rating = 100; | |
115 | cd->irq = irq; | |
116 | clockevent_set_clock(cd, 32768); | |
117 | cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); | |
e4db9253 | 118 | cd->max_delta_ticks = 0x7fffffff; |
6457d9fc | 119 | cd->min_delta_ns = clockevent_delta2ns(0x300, cd); |
e4db9253 | 120 | cd->min_delta_ticks = 0x300; |
320ab2b0 | 121 | cd->cpumask = cpumask_of(0); |
6457d9fc YY |
122 | |
123 | clockevents_register_device(&ds1287_clockevent); | |
124 | ||
125 | return setup_irq(irq, &ds1287_irqaction); | |
126 | } |