diff options
| author | Alessandro Zummo <a.zummo@towertech.it> | 2009-01-04 12:00:54 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-04 13:33:20 -0800 | 
| commit | 099e657625e801adf82054c8050dde5aceb68452 (patch) | |
| tree | d6c28df68ab390fa237b8339c6081e4db380aa5f /drivers/rtc | |
| parent | 54566b2c1594c2326a645a3551f9d989f7ba3c5e (diff) | |
| download | olio-linux-3.10-099e657625e801adf82054c8050dde5aceb68452.tar.xz olio-linux-3.10-099e657625e801adf82054c8050dde5aceb68452.zip  | |
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>
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 6 | ||||
| -rw-r--r-- | drivers/rtc/interface.c | 54 | ||||
| -rw-r--r-- | drivers/rtc/rtc-dev.c | 51 | 
3 files changed, 94 insertions, 17 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 123092d8a98..165a8184335 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -102,9 +102,13 @@ config RTC_INTF_DEV_UIE_EMUL  	depends on RTC_INTF_DEV  	help  	  Provides an emulation for RTC_UIE if the underlying rtc chip -	  driver does not expose RTC_UIE ioctls.  Those requests generate +	  driver does not expose RTC_UIE ioctls. Those requests generate  	  once-per-second update interrupts, used for synchronization. +	  The emulation code will read the time from the hardware +	  clock several times per second, please enable this option +	  only if you know that you really need it. +  config RTC_DRV_TEST  	tristate "Test driver/device"  	help diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index a04c1b6b157..fd2c652504f 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -307,6 +307,60 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)  }  EXPORT_SYMBOL_GPL(rtc_set_alarm); +int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) +{ +	int err = mutex_lock_interruptible(&rtc->ops_lock); +	if (err) +		return err; + +	if (!rtc->ops) +		err = -ENODEV; +	else if (!rtc->ops->alarm_irq_enable) +		err = -EINVAL; +	else +		err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled); + +	mutex_unlock(&rtc->ops_lock); +	return err; +} +EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable); + +int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) +{ +	int err = mutex_lock_interruptible(&rtc->ops_lock); +	if (err) +		return err; + +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL +	if (enabled == 0 && rtc->uie_irq_active) { +		mutex_unlock(&rtc->ops_lock); +		return rtc_dev_update_irq_enable_emul(rtc, enabled); +	} +#endif + +	if (!rtc->ops) +		err = -ENODEV; +	else if (!rtc->ops->update_irq_enable) +		err = -EINVAL; +	else +		err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled); + +	mutex_unlock(&rtc->ops_lock); + +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL +	/* +	 * Enable emulation if the driver did not provide +	 * the update_irq_enable function pointer or if returned +	 * -EINVAL to signal that it has been configured without +	 * interrupts or that are not available at the moment. +	 */ +	if (err == -EINVAL) +		err = rtc_dev_update_irq_enable_emul(rtc, enabled); +#endif +	return err; +} +EXPORT_SYMBOL_GPL(rtc_update_irq_enable); +  /**   * rtc_update_irq - report RTC periodic, alarm, and/or update irqs   * @rtc: the rtc device diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index ecdea44ae4e..45152f4952d 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -92,10 +92,10 @@ static void rtc_uie_timer(unsigned long data)  	spin_unlock_irqrestore(&rtc->irq_lock, flags);  } -static void clear_uie(struct rtc_device *rtc) +static int clear_uie(struct rtc_device *rtc)  {  	spin_lock_irq(&rtc->irq_lock); -	if (rtc->irq_active) { +	if (rtc->uie_irq_active) {  		rtc->stop_uie_polling = 1;  		if (rtc->uie_timer_active) {  			spin_unlock_irq(&rtc->irq_lock); @@ -108,9 +108,10 @@ static void clear_uie(struct rtc_device *rtc)  			flush_scheduled_work();  			spin_lock_irq(&rtc->irq_lock);  		} -		rtc->irq_active = 0; +		rtc->uie_irq_active = 0;  	}  	spin_unlock_irq(&rtc->irq_lock); +	return 0;  }  static int set_uie(struct rtc_device *rtc) @@ -122,8 +123,8 @@ static int set_uie(struct rtc_device *rtc)  	if (err)  		return err;  	spin_lock_irq(&rtc->irq_lock); -	if (!rtc->irq_active) { -		rtc->irq_active = 1; +	if (!rtc->uie_irq_active) { +		rtc->uie_irq_active = 1;  		rtc->stop_uie_polling = 0;  		rtc->oldsecs = tm.tm_sec;  		rtc->uie_task_active = 1; @@ -134,6 +135,16 @@ static int set_uie(struct rtc_device *rtc)  	spin_unlock_irq(&rtc->irq_lock);  	return 0;  } + +int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled) +{ +	if (enabled) +		return set_uie(rtc); +	else +		return clear_uie(rtc); +} +EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul); +  #endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */  static ssize_t @@ -357,6 +368,22 @@ static long rtc_dev_ioctl(struct file *file,  		err = rtc_irq_set_state(rtc, NULL, 0);  		break; +	case RTC_AIE_ON: +		mutex_unlock(&rtc->ops_lock); +		return rtc_alarm_irq_enable(rtc, 1); + +	case RTC_AIE_OFF: +		mutex_unlock(&rtc->ops_lock); +		return rtc_alarm_irq_enable(rtc, 0); + +	case RTC_UIE_ON: +		mutex_unlock(&rtc->ops_lock); +		return rtc_update_irq_enable(rtc, 1); + +	case RTC_UIE_OFF: +		mutex_unlock(&rtc->ops_lock); +		return rtc_update_irq_enable(rtc, 0); +  	case RTC_IRQP_SET:  		err = rtc_irq_set_freq(rtc, NULL, arg);  		break; @@ -401,17 +428,6 @@ static long rtc_dev_ioctl(struct file *file,  			err = -EFAULT;  		return err; -#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL -	case RTC_UIE_OFF: -		mutex_unlock(&rtc->ops_lock); -		clear_uie(rtc); -		return 0; - -	case RTC_UIE_ON: -		mutex_unlock(&rtc->ops_lock); -		err = set_uie(rtc); -		return err; -#endif  	default:  		err = -ENOTTY;  		break; @@ -440,7 +456,10 @@ static int rtc_dev_release(struct inode *inode, struct file *file)  	 * Leave the alarm alone; it may be set to trigger a system wakeup  	 * later, or be used by kernel code, and is a one-shot event anyway.  	 */ + +	/* Keep ioctl until all drivers are converted */  	rtc_dev_ioctl(file, RTC_UIE_OFF, 0); +	rtc_update_irq_enable(rtc, 0);  	rtc_irq_set_state(rtc, NULL, 0);  	if (rtc->ops->release)  |