Skip to content

Commit 099e657

Browse files
Alessandro Zummotorvalds
authored andcommitted
rtc: add alarm/update irq interfaces
Add standard interfaces for alarm/update irqs enabling. Drivers are no more required to implement equivalent ioctl code as rtc-dev will provide it. UIE emulation should now be handled correctly and will work even for those RTC drivers who cannot be configured to do both UIE and AIE. Signed-off-by: Alessandro Zummo <a.zummo@towertech.it> Cc: David Brownell <david-b@pacbell.net> Cc: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Cc: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 54566b2 commit 099e657

File tree

4 files changed

+101
-18
lines changed

4 files changed

+101
-18
lines changed

drivers/rtc/Kconfig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,13 @@ config RTC_INTF_DEV_UIE_EMUL
102102
depends on RTC_INTF_DEV
103103
help
104104
Provides an emulation for RTC_UIE if the underlying rtc chip
105-
driver does not expose RTC_UIE ioctls. Those requests generate
105+
driver does not expose RTC_UIE ioctls. Those requests generate
106106
once-per-second update interrupts, used for synchronization.
107107

108+
The emulation code will read the time from the hardware
109+
clock several times per second, please enable this option
110+
only if you know that you really need it.
111+
108112
config RTC_DRV_TEST
109113
tristate "Test driver/device"
110114
help

drivers/rtc/interface.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,60 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
307307
}
308308
EXPORT_SYMBOL_GPL(rtc_set_alarm);
309309

310+
int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
311+
{
312+
int err = mutex_lock_interruptible(&rtc->ops_lock);
313+
if (err)
314+
return err;
315+
316+
if (!rtc->ops)
317+
err = -ENODEV;
318+
else if (!rtc->ops->alarm_irq_enable)
319+
err = -EINVAL;
320+
else
321+
err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled);
322+
323+
mutex_unlock(&rtc->ops_lock);
324+
return err;
325+
}
326+
EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
327+
328+
int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
329+
{
330+
int err = mutex_lock_interruptible(&rtc->ops_lock);
331+
if (err)
332+
return err;
333+
334+
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
335+
if (enabled == 0 && rtc->uie_irq_active) {
336+
mutex_unlock(&rtc->ops_lock);
337+
return rtc_dev_update_irq_enable_emul(rtc, enabled);
338+
}
339+
#endif
340+
341+
if (!rtc->ops)
342+
err = -ENODEV;
343+
else if (!rtc->ops->update_irq_enable)
344+
err = -EINVAL;
345+
else
346+
err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled);
347+
348+
mutex_unlock(&rtc->ops_lock);
349+
350+
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
351+
/*
352+
* Enable emulation if the driver did not provide
353+
* the update_irq_enable function pointer or if returned
354+
* -EINVAL to signal that it has been configured without
355+
* interrupts or that are not available at the moment.
356+
*/
357+
if (err == -EINVAL)
358+
err = rtc_dev_update_irq_enable_emul(rtc, enabled);
359+
#endif
360+
return err;
361+
}
362+
EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
363+
310364
/**
311365
* rtc_update_irq - report RTC periodic, alarm, and/or update irqs
312366
* @rtc: the rtc device

drivers/rtc/rtc-dev.c

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ static void rtc_uie_timer(unsigned long data)
9292
spin_unlock_irqrestore(&rtc->irq_lock, flags);
9393
}
9494

95-
static void clear_uie(struct rtc_device *rtc)
95+
static int clear_uie(struct rtc_device *rtc)
9696
{
9797
spin_lock_irq(&rtc->irq_lock);
98-
if (rtc->irq_active) {
98+
if (rtc->uie_irq_active) {
9999
rtc->stop_uie_polling = 1;
100100
if (rtc->uie_timer_active) {
101101
spin_unlock_irq(&rtc->irq_lock);
@@ -108,9 +108,10 @@ static void clear_uie(struct rtc_device *rtc)
108108
flush_scheduled_work();
109109
spin_lock_irq(&rtc->irq_lock);
110110
}
111-
rtc->irq_active = 0;
111+
rtc->uie_irq_active = 0;
112112
}
113113
spin_unlock_irq(&rtc->irq_lock);
114+
return 0;
114115
}
115116

116117
static int set_uie(struct rtc_device *rtc)
@@ -122,8 +123,8 @@ static int set_uie(struct rtc_device *rtc)
122123
if (err)
123124
return err;
124125
spin_lock_irq(&rtc->irq_lock);
125-
if (!rtc->irq_active) {
126-
rtc->irq_active = 1;
126+
if (!rtc->uie_irq_active) {
127+
rtc->uie_irq_active = 1;
127128
rtc->stop_uie_polling = 0;
128129
rtc->oldsecs = tm.tm_sec;
129130
rtc->uie_task_active = 1;
@@ -134,6 +135,16 @@ static int set_uie(struct rtc_device *rtc)
134135
spin_unlock_irq(&rtc->irq_lock);
135136
return 0;
136137
}
138+
139+
int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled)
140+
{
141+
if (enabled)
142+
return set_uie(rtc);
143+
else
144+
return clear_uie(rtc);
145+
}
146+
EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul);
147+
137148
#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
138149

139150
static ssize_t
@@ -357,6 +368,22 @@ static long rtc_dev_ioctl(struct file *file,
357368
err = rtc_irq_set_state(rtc, NULL, 0);
358369
break;
359370

371+
case RTC_AIE_ON:
372+
mutex_unlock(&rtc->ops_lock);
373+
return rtc_alarm_irq_enable(rtc, 1);
374+
375+
case RTC_AIE_OFF:
376+
mutex_unlock(&rtc->ops_lock);
377+
return rtc_alarm_irq_enable(rtc, 0);
378+
379+
case RTC_UIE_ON:
380+
mutex_unlock(&rtc->ops_lock);
381+
return rtc_update_irq_enable(rtc, 1);
382+
383+
case RTC_UIE_OFF:
384+
mutex_unlock(&rtc->ops_lock);
385+
return rtc_update_irq_enable(rtc, 0);
386+
360387
case RTC_IRQP_SET:
361388
err = rtc_irq_set_freq(rtc, NULL, arg);
362389
break;
@@ -401,17 +428,6 @@ static long rtc_dev_ioctl(struct file *file,
401428
err = -EFAULT;
402429
return err;
403430

404-
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
405-
case RTC_UIE_OFF:
406-
mutex_unlock(&rtc->ops_lock);
407-
clear_uie(rtc);
408-
return 0;
409-
410-
case RTC_UIE_ON:
411-
mutex_unlock(&rtc->ops_lock);
412-
err = set_uie(rtc);
413-
return err;
414-
#endif
415431
default:
416432
err = -ENOTTY;
417433
break;
@@ -440,7 +456,10 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
440456
* Leave the alarm alone; it may be set to trigger a system wakeup
441457
* later, or be used by kernel code, and is a one-shot event anyway.
442458
*/
459+
460+
/* Keep ioctl until all drivers are converted */
443461
rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
462+
rtc_update_irq_enable(rtc, 0);
444463
rtc_irq_set_state(rtc, NULL, 0);
445464

446465
if (rtc->ops->release)

include/linux/rtc.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ struct rtc_class_ops {
145145
int (*irq_set_state)(struct device *, int enabled);
146146
int (*irq_set_freq)(struct device *, int freq);
147147
int (*read_callback)(struct device *, int data);
148+
int (*alarm_irq_enable)(struct device *, unsigned int enabled);
149+
int (*update_irq_enable)(struct device *, unsigned int enabled);
148150
};
149151

150152
#define RTC_DEVICE_NAME_SIZE 20
@@ -181,7 +183,7 @@ struct rtc_device
181183
struct timer_list uie_timer;
182184
/* Those fields are protected by rtc->irq_lock */
183185
unsigned int oldsecs;
184-
unsigned int irq_active:1;
186+
unsigned int uie_irq_active:1;
185187
unsigned int stop_uie_polling:1;
186188
unsigned int uie_task_active:1;
187189
unsigned int uie_timer_active:1;
@@ -216,6 +218,10 @@ extern int rtc_irq_set_state(struct rtc_device *rtc,
216218
struct rtc_task *task, int enabled);
217219
extern int rtc_irq_set_freq(struct rtc_device *rtc,
218220
struct rtc_task *task, int freq);
221+
extern int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled);
222+
extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled);
223+
extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc,
224+
unsigned int enabled);
219225

220226
typedef struct rtc_task {
221227
void (*func)(void *private_data);

0 commit comments

Comments
 (0)