alarmtimer: add rtc irq support for alarm
Add the rtc irq support for alarmtimer to wakeup the alarm during system suspend. Change-Id: I41b774ed4e788359321e1c6a564551cc9cd40c8e Signed-off-by: Xiaocheng Li <lix@codeaurora.org>
This commit is contained in:
parent
b11b09aa65
commit
439e21802e
1 changed files with 49 additions and 6 deletions
|
@ -53,6 +53,18 @@ static struct rtc_timer rtctimer;
|
||||||
static struct rtc_device *rtcdev;
|
static struct rtc_device *rtcdev;
|
||||||
static DEFINE_SPINLOCK(rtcdev_lock);
|
static DEFINE_SPINLOCK(rtcdev_lock);
|
||||||
|
|
||||||
|
static void alarmtimer_triggered_func(void *p)
|
||||||
|
{
|
||||||
|
struct rtc_device *rtc = rtcdev;
|
||||||
|
|
||||||
|
if (!(rtc->irq_data & RTC_AF))
|
||||||
|
return;
|
||||||
|
__pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rtc_task alarmtimer_rtc_task = {
|
||||||
|
.func = alarmtimer_triggered_func
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* alarmtimer_get_rtcdev - Return selected rtcdevice
|
* alarmtimer_get_rtcdev - Return selected rtcdevice
|
||||||
*
|
*
|
||||||
|
@ -63,7 +75,7 @@ static DEFINE_SPINLOCK(rtcdev_lock);
|
||||||
struct rtc_device *alarmtimer_get_rtcdev(void)
|
struct rtc_device *alarmtimer_get_rtcdev(void)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct rtc_device *ret;
|
struct rtc_device *ret = NULL;
|
||||||
|
|
||||||
spin_lock_irqsave(&rtcdev_lock, flags);
|
spin_lock_irqsave(&rtcdev_lock, flags);
|
||||||
ret = rtcdev;
|
ret = rtcdev;
|
||||||
|
@ -77,24 +89,36 @@ static int alarmtimer_rtc_add_device(struct device *dev,
|
||||||
struct class_interface *class_intf)
|
struct class_interface *class_intf)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
int err = 0;
|
||||||
struct rtc_device *rtc = to_rtc_device(dev);
|
struct rtc_device *rtc = to_rtc_device(dev);
|
||||||
|
|
||||||
if (rtcdev)
|
if (rtcdev)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
if (!rtc->ops->set_alarm)
|
if (!rtc->ops->set_alarm)
|
||||||
return -1;
|
return -1;
|
||||||
if (!device_may_wakeup(rtc->dev.parent))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&rtcdev_lock, flags);
|
spin_lock_irqsave(&rtcdev_lock, flags);
|
||||||
if (!rtcdev) {
|
if (!rtcdev) {
|
||||||
|
err = rtc_irq_register(rtc, &alarmtimer_rtc_task);
|
||||||
|
if (err)
|
||||||
|
goto rtc_irq_reg_err;
|
||||||
rtcdev = rtc;
|
rtcdev = rtc;
|
||||||
/* hold a reference so it doesn't go away */
|
/* hold a reference so it doesn't go away */
|
||||||
get_device(dev);
|
get_device(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtc_irq_reg_err:
|
||||||
spin_unlock_irqrestore(&rtcdev_lock, flags);
|
spin_unlock_irqrestore(&rtcdev_lock, flags);
|
||||||
return 0;
|
return err;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alarmtimer_rtc_remove_device(struct device *dev,
|
||||||
|
struct class_interface *class_intf)
|
||||||
|
{
|
||||||
|
if (rtcdev && dev == &rtcdev->dev) {
|
||||||
|
rtc_irq_unregister(rtcdev, &alarmtimer_rtc_task);
|
||||||
|
rtcdev = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void alarmtimer_rtc_timer_init(void)
|
static inline void alarmtimer_rtc_timer_init(void)
|
||||||
|
@ -104,6 +128,7 @@ static inline void alarmtimer_rtc_timer_init(void)
|
||||||
|
|
||||||
static struct class_interface alarmtimer_rtc_interface = {
|
static struct class_interface alarmtimer_rtc_interface = {
|
||||||
.add_dev = &alarmtimer_rtc_add_device,
|
.add_dev = &alarmtimer_rtc_add_device,
|
||||||
|
.remove_dev = &alarmtimer_rtc_remove_device,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int alarmtimer_rtc_interface_setup(void)
|
static int alarmtimer_rtc_interface_setup(void)
|
||||||
|
@ -271,11 +296,28 @@ static int alarmtimer_suspend(struct device *dev)
|
||||||
__pm_wakeup_event(ws, MSEC_PER_SEC);
|
__pm_wakeup_event(ws, MSEC_PER_SEC);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int alarmtimer_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct rtc_device *rtc;
|
||||||
|
|
||||||
|
rtc = alarmtimer_get_rtcdev();
|
||||||
|
/* If we have no rtcdev, just return */
|
||||||
|
if (!rtc)
|
||||||
|
return 0;
|
||||||
|
rtc_timer_cancel(rtc, &rtctimer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
static int alarmtimer_suspend(struct device *dev)
|
static int alarmtimer_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int alarmtimer_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
|
static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
|
||||||
|
@ -800,6 +842,7 @@ out:
|
||||||
/* Suspend hook structures */
|
/* Suspend hook structures */
|
||||||
static const struct dev_pm_ops alarmtimer_pm_ops = {
|
static const struct dev_pm_ops alarmtimer_pm_ops = {
|
||||||
.suspend = alarmtimer_suspend,
|
.suspend = alarmtimer_suspend,
|
||||||
|
.resume = alarmtimer_resume,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_driver alarmtimer_driver = {
|
static struct platform_driver alarmtimer_driver = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue