mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
Merge branch 'devicetree/for-x86' of git://git.secretlab.ca/git/linux-2.6 into x86/platform
Reason: x86 devicetree support for ce4100 depends on those device tree changes scheduled for .39. Signed-off-by: Thomas Gleixner <[email protected]>
This commit is contained in:
commit
695884fb8a
9156 changed files with 580573 additions and 277049 deletions
|
|
@ -97,18 +97,6 @@ config RTC_INTF_DEV
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
config RTC_INTF_DEV_UIE_EMUL
|
||||
bool "RTC UIE emulation on dev interface"
|
||||
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
|
||||
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
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/kdev_t.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "rtc-core.h"
|
||||
|
||||
|
|
@ -152,6 +153,18 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
|
|||
spin_lock_init(&rtc->irq_task_lock);
|
||||
init_waitqueue_head(&rtc->irq_queue);
|
||||
|
||||
/* Init timerqueue */
|
||||
timerqueue_init_head(&rtc->timerqueue);
|
||||
INIT_WORK(&rtc->irqwork, rtc_timer_do_work);
|
||||
/* Init aie timer */
|
||||
rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc);
|
||||
/* Init uie timer */
|
||||
rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc);
|
||||
/* Init pie timer */
|
||||
hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
rtc->pie_timer.function = rtc_pie_update_irq;
|
||||
rtc->pie_enabled = 0;
|
||||
|
||||
strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
|
||||
dev_set_name(&rtc->dev, "rtc%d", id);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,24 @@
|
|||
#include <linux/rtc.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
|
||||
static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
|
||||
|
||||
static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
{
|
||||
int err;
|
||||
if (!rtc->ops)
|
||||
err = -ENODEV;
|
||||
else if (!rtc->ops->read_time)
|
||||
err = -EINVAL;
|
||||
else {
|
||||
memset(tm, 0, sizeof(struct rtc_time));
|
||||
err = rtc->ops->read_time(rtc->dev.parent, tm);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
{
|
||||
|
|
@ -23,15 +41,7 @@ int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (!rtc->ops)
|
||||
err = -ENODEV;
|
||||
else if (!rtc->ops->read_time)
|
||||
err = -EINVAL;
|
||||
else {
|
||||
memset(tm, 0, sizeof(struct rtc_time));
|
||||
err = rtc->ops->read_time(rtc->dev.parent, tm);
|
||||
}
|
||||
|
||||
err = __rtc_read_time(rtc, tm);
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -106,189 +116,61 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_set_mmss);
|
||||
|
||||
static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (rtc->ops == NULL)
|
||||
err = -ENODEV;
|
||||
else if (!rtc->ops->read_alarm)
|
||||
err = -EINVAL;
|
||||
else {
|
||||
memset(alarm, 0, sizeof(struct rtc_wkalrm));
|
||||
err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
|
||||
alarm->enabled = rtc->aie_timer.enabled;
|
||||
alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires);
|
||||
}
|
||||
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
int err;
|
||||
struct rtc_time before, now;
|
||||
int first_time = 1;
|
||||
unsigned long t_now, t_alm;
|
||||
enum { none, day, month, year } missing = none;
|
||||
unsigned days;
|
||||
|
||||
/* The lower level RTC driver may return -1 in some fields,
|
||||
* creating invalid alarm->time values, for reasons like:
|
||||
*
|
||||
* - The hardware may not be capable of filling them in;
|
||||
* many alarms match only on time-of-day fields, not
|
||||
* day/month/year calendar data.
|
||||
*
|
||||
* - Some hardware uses illegal values as "wildcard" match
|
||||
* values, which non-Linux firmware (like a BIOS) may try
|
||||
* to set up as e.g. "alarm 15 minutes after each hour".
|
||||
* Linux uses only oneshot alarms.
|
||||
*
|
||||
* When we see that here, we deal with it by using values from
|
||||
* a current RTC timestamp for any missing (-1) values. The
|
||||
* RTC driver prevents "periodic alarm" modes.
|
||||
*
|
||||
* But this can be racey, because some fields of the RTC timestamp
|
||||
* may have wrapped in the interval since we read the RTC alarm,
|
||||
* which would lead to us inserting inconsistent values in place
|
||||
* of the -1 fields.
|
||||
*
|
||||
* Reading the alarm and timestamp in the reverse sequence
|
||||
* would have the same race condition, and not solve the issue.
|
||||
*
|
||||
* So, we must first read the RTC timestamp,
|
||||
* then read the RTC alarm value,
|
||||
* and then read a second RTC timestamp.
|
||||
*
|
||||
* If any fields of the second timestamp have changed
|
||||
* when compared with the first timestamp, then we know
|
||||
* our timestamp may be inconsistent with that used by
|
||||
* the low-level rtc_read_alarm_internal() function.
|
||||
*
|
||||
* So, when the two timestamps disagree, we just loop and do
|
||||
* the process again to get a fully consistent set of values.
|
||||
*
|
||||
* This could all instead be done in the lower level driver,
|
||||
* but since more than one lower level RTC implementation needs it,
|
||||
* then it's probably best best to do it here instead of there..
|
||||
*/
|
||||
|
||||
/* Get the "before" timestamp */
|
||||
err = rtc_read_time(rtc, &before);
|
||||
if (err < 0)
|
||||
return err;
|
||||
do {
|
||||
if (!first_time)
|
||||
memcpy(&before, &now, sizeof(struct rtc_time));
|
||||
first_time = 0;
|
||||
|
||||
/* get the RTC alarm values, which may be incomplete */
|
||||
err = rtc_read_alarm_internal(rtc, alarm);
|
||||
if (err)
|
||||
return err;
|
||||
if (!alarm->enabled)
|
||||
return 0;
|
||||
|
||||
/* full-function RTCs won't have such missing fields */
|
||||
if (rtc_valid_tm(&alarm->time) == 0)
|
||||
return 0;
|
||||
|
||||
/* get the "after" timestamp, to detect wrapped fields */
|
||||
err = rtc_read_time(rtc, &now);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* note that tm_sec is a "don't care" value here: */
|
||||
} while ( before.tm_min != now.tm_min
|
||||
|| before.tm_hour != now.tm_hour
|
||||
|| before.tm_mon != now.tm_mon
|
||||
|| before.tm_year != now.tm_year);
|
||||
|
||||
/* Fill in the missing alarm fields using the timestamp; we
|
||||
* know there's at least one since alarm->time is invalid.
|
||||
*/
|
||||
if (alarm->time.tm_sec == -1)
|
||||
alarm->time.tm_sec = now.tm_sec;
|
||||
if (alarm->time.tm_min == -1)
|
||||
alarm->time.tm_min = now.tm_min;
|
||||
if (alarm->time.tm_hour == -1)
|
||||
alarm->time.tm_hour = now.tm_hour;
|
||||
|
||||
/* For simplicity, only support date rollover for now */
|
||||
if (alarm->time.tm_mday == -1) {
|
||||
alarm->time.tm_mday = now.tm_mday;
|
||||
missing = day;
|
||||
}
|
||||
if (alarm->time.tm_mon == -1) {
|
||||
alarm->time.tm_mon = now.tm_mon;
|
||||
if (missing == none)
|
||||
missing = month;
|
||||
}
|
||||
if (alarm->time.tm_year == -1) {
|
||||
alarm->time.tm_year = now.tm_year;
|
||||
if (missing == none)
|
||||
missing = year;
|
||||
}
|
||||
|
||||
/* with luck, no rollover is needed */
|
||||
rtc_tm_to_time(&now, &t_now);
|
||||
rtc_tm_to_time(&alarm->time, &t_alm);
|
||||
if (t_now < t_alm)
|
||||
goto done;
|
||||
|
||||
switch (missing) {
|
||||
|
||||
/* 24 hour rollover ... if it's now 10am Monday, an alarm that
|
||||
* that will trigger at 5am will do so at 5am Tuesday, which
|
||||
* could also be in the next month or year. This is a common
|
||||
* case, especially for PCs.
|
||||
*/
|
||||
case day:
|
||||
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
|
||||
t_alm += 24 * 60 * 60;
|
||||
rtc_time_to_tm(t_alm, &alarm->time);
|
||||
break;
|
||||
|
||||
/* Month rollover ... if it's the 31th, an alarm on the 3rd will
|
||||
* be next month. An alarm matching on the 30th, 29th, or 28th
|
||||
* may end up in the month after that! Many newer PCs support
|
||||
* this type of alarm.
|
||||
*/
|
||||
case month:
|
||||
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
|
||||
do {
|
||||
if (alarm->time.tm_mon < 11)
|
||||
alarm->time.tm_mon++;
|
||||
else {
|
||||
alarm->time.tm_mon = 0;
|
||||
alarm->time.tm_year++;
|
||||
}
|
||||
days = rtc_month_days(alarm->time.tm_mon,
|
||||
alarm->time.tm_year);
|
||||
} while (days < alarm->time.tm_mday);
|
||||
break;
|
||||
|
||||
/* Year rollover ... easy except for leap years! */
|
||||
case year:
|
||||
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
|
||||
do {
|
||||
alarm->time.tm_year++;
|
||||
} while (rtc_valid_tm(&alarm->time) != 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(&rtc->dev, "alarm rollover not handled\n");
|
||||
}
|
||||
|
||||
done:
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_read_alarm);
|
||||
|
||||
int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct rtc_time tm;
|
||||
long now, scheduled;
|
||||
int err;
|
||||
|
||||
err = rtc_valid_tm(&alarm->time);
|
||||
if (err)
|
||||
return err;
|
||||
rtc_tm_to_time(&alarm->time, &scheduled);
|
||||
|
||||
/* Make sure we're not setting alarms in the past */
|
||||
err = __rtc_read_time(rtc, &tm);
|
||||
rtc_tm_to_time(&tm, &now);
|
||||
if (scheduled <= now)
|
||||
return -ETIME;
|
||||
/*
|
||||
* XXX - We just checked to make sure the alarm time is not
|
||||
* in the past, but there is still a race window where if
|
||||
* the is alarm set for the next second and the second ticks
|
||||
* over right here, before we set the alarm.
|
||||
*/
|
||||
|
||||
if (!rtc->ops)
|
||||
err = -ENODEV;
|
||||
else if (!rtc->ops->set_alarm)
|
||||
err = -EINVAL;
|
||||
else
|
||||
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
int err;
|
||||
|
|
@ -300,14 +182,14 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
|||
err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!rtc->ops)
|
||||
err = -ENODEV;
|
||||
else if (!rtc->ops->set_alarm)
|
||||
err = -EINVAL;
|
||||
else
|
||||
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
|
||||
|
||||
if (rtc->aie_timer.enabled) {
|
||||
rtc_timer_remove(rtc, &rtc->aie_timer);
|
||||
}
|
||||
rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
|
||||
rtc->aie_timer.period = ktime_set(0, 0);
|
||||
if (alarm->enabled) {
|
||||
err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
|
||||
}
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -316,6 +198,16 @@ 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->aie_timer.enabled != enabled) {
|
||||
if (enabled)
|
||||
err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
|
||||
else
|
||||
rtc_timer_remove(rtc, &rtc->aie_timer);
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -337,38 +229,111 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
|
|||
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
|
||||
/* make sure we're changing state */
|
||||
if (rtc->uie_rtctimer.enabled == enabled)
|
||||
goto out;
|
||||
|
||||
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);
|
||||
if (enabled) {
|
||||
struct rtc_time tm;
|
||||
ktime_t now, onesec;
|
||||
|
||||
__rtc_read_time(rtc, &tm);
|
||||
onesec = ktime_set(1, 0);
|
||||
now = rtc_tm_to_ktime(tm);
|
||||
rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
|
||||
rtc->uie_rtctimer.period = ktime_set(1, 0);
|
||||
err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
|
||||
} else
|
||||
rtc_timer_remove(rtc, &rtc->uie_rtctimer);
|
||||
|
||||
out:
|
||||
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_handle_legacy_irq - AIE, UIE and PIE event hook
|
||||
* @rtc: pointer to the rtc device
|
||||
*
|
||||
* This function is called when an AIE, UIE or PIE mode interrupt
|
||||
* has occured (or been emulated).
|
||||
*
|
||||
* Triggers the registered irq_task function callback.
|
||||
*/
|
||||
static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/* mark one irq of the appropriate mode */
|
||||
spin_lock_irqsave(&rtc->irq_lock, flags);
|
||||
rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode);
|
||||
spin_unlock_irqrestore(&rtc->irq_lock, flags);
|
||||
|
||||
/* call the task func */
|
||||
spin_lock_irqsave(&rtc->irq_task_lock, flags);
|
||||
if (rtc->irq_task)
|
||||
rtc->irq_task->func(rtc->irq_task->private_data);
|
||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
||||
|
||||
wake_up_interruptible(&rtc->irq_queue);
|
||||
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rtc_aie_update_irq - AIE mode rtctimer hook
|
||||
* @private: pointer to the rtc_device
|
||||
*
|
||||
* This functions is called when the aie_timer expires.
|
||||
*/
|
||||
void rtc_aie_update_irq(void *private)
|
||||
{
|
||||
struct rtc_device *rtc = (struct rtc_device *)private;
|
||||
rtc_handle_legacy_irq(rtc, 1, RTC_AF);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rtc_uie_update_irq - UIE mode rtctimer hook
|
||||
* @private: pointer to the rtc_device
|
||||
*
|
||||
* This functions is called when the uie_timer expires.
|
||||
*/
|
||||
void rtc_uie_update_irq(void *private)
|
||||
{
|
||||
struct rtc_device *rtc = (struct rtc_device *)private;
|
||||
rtc_handle_legacy_irq(rtc, 1, RTC_UF);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rtc_pie_update_irq - PIE mode hrtimer hook
|
||||
* @timer: pointer to the pie mode hrtimer
|
||||
*
|
||||
* This function is used to emulate PIE mode interrupts
|
||||
* using an hrtimer. This function is called when the periodic
|
||||
* hrtimer expires.
|
||||
*/
|
||||
enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
ktime_t period;
|
||||
int count;
|
||||
rtc = container_of(timer, struct rtc_device, pie_timer);
|
||||
|
||||
period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
|
||||
count = hrtimer_forward_now(timer, period);
|
||||
|
||||
rtc_handle_legacy_irq(rtc, count, RTC_PF);
|
||||
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
/**
|
||||
* rtc_update_irq - Triggered when a RTC interrupt occurs.
|
||||
* @rtc: the rtc device
|
||||
* @num: how many irqs are being reported (usually one)
|
||||
* @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
|
||||
|
|
@ -377,19 +342,7 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
|
|||
void rtc_update_irq(struct rtc_device *rtc,
|
||||
unsigned long num, unsigned long events)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rtc->irq_lock, flags);
|
||||
rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
|
||||
spin_unlock_irqrestore(&rtc->irq_lock, flags);
|
||||
|
||||
spin_lock_irqsave(&rtc->irq_task_lock, flags);
|
||||
if (rtc->irq_task)
|
||||
rtc->irq_task->func(rtc->irq_task->private_data);
|
||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
||||
|
||||
wake_up_interruptible(&rtc->irq_queue);
|
||||
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
|
||||
schedule_work(&rtc->irqwork);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_update_irq);
|
||||
|
||||
|
|
@ -477,18 +430,20 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
|
|||
int err = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (rtc->ops->irq_set_state == NULL)
|
||||
return -ENXIO;
|
||||
|
||||
spin_lock_irqsave(&rtc->irq_task_lock, flags);
|
||||
if (rtc->irq_task != NULL && task == NULL)
|
||||
err = -EBUSY;
|
||||
if (rtc->irq_task != task)
|
||||
err = -EACCES;
|
||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
||||
|
||||
if (err == 0)
|
||||
err = rtc->ops->irq_set_state(rtc->dev.parent, enabled);
|
||||
if (enabled) {
|
||||
ktime_t period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
|
||||
hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
|
||||
} else {
|
||||
hrtimer_cancel(&rtc->pie_timer);
|
||||
}
|
||||
rtc->pie_enabled = enabled;
|
||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -509,21 +464,203 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
|
|||
int err = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (rtc->ops->irq_set_freq == NULL)
|
||||
return -ENXIO;
|
||||
|
||||
spin_lock_irqsave(&rtc->irq_task_lock, flags);
|
||||
if (rtc->irq_task != NULL && task == NULL)
|
||||
err = -EBUSY;
|
||||
if (rtc->irq_task != task)
|
||||
err = -EACCES;
|
||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
||||
|
||||
if (err == 0) {
|
||||
err = rtc->ops->irq_set_freq(rtc->dev.parent, freq);
|
||||
if (err == 0)
|
||||
rtc->irq_freq = freq;
|
||||
rtc->irq_freq = freq;
|
||||
if (rtc->pie_enabled) {
|
||||
ktime_t period;
|
||||
hrtimer_cancel(&rtc->pie_timer);
|
||||
period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
|
||||
hrtimer_start(&rtc->pie_timer, period,
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
|
||||
|
||||
/**
|
||||
* rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue
|
||||
* @rtc rtc device
|
||||
* @timer timer being added.
|
||||
*
|
||||
* Enqueues a timer onto the rtc devices timerqueue and sets
|
||||
* the next alarm event appropriately.
|
||||
*
|
||||
* Sets the enabled bit on the added timer.
|
||||
*
|
||||
* Must hold ops_lock for proper serialization of timerqueue
|
||||
*/
|
||||
static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
{
|
||||
timer->enabled = 1;
|
||||
timerqueue_add(&rtc->timerqueue, &timer->node);
|
||||
if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
|
||||
struct rtc_wkalrm alarm;
|
||||
int err;
|
||||
alarm.time = rtc_ktime_to_tm(timer->node.expires);
|
||||
alarm.enabled = 1;
|
||||
err = __rtc_set_alarm(rtc, &alarm);
|
||||
if (err == -ETIME)
|
||||
schedule_work(&rtc->irqwork);
|
||||
else if (err) {
|
||||
timerqueue_del(&rtc->timerqueue, &timer->node);
|
||||
timer->enabled = 0;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
|
||||
* @rtc rtc device
|
||||
* @timer timer being removed.
|
||||
*
|
||||
* Removes a timer onto the rtc devices timerqueue and sets
|
||||
* the next alarm event appropriately.
|
||||
*
|
||||
* Clears the enabled bit on the removed timer.
|
||||
*
|
||||
* Must hold ops_lock for proper serialization of timerqueue
|
||||
*/
|
||||
static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
{
|
||||
struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
|
||||
timerqueue_del(&rtc->timerqueue, &timer->node);
|
||||
timer->enabled = 0;
|
||||
if (next == &timer->node) {
|
||||
struct rtc_wkalrm alarm;
|
||||
int err;
|
||||
next = timerqueue_getnext(&rtc->timerqueue);
|
||||
if (!next)
|
||||
return;
|
||||
alarm.time = rtc_ktime_to_tm(next->expires);
|
||||
alarm.enabled = 1;
|
||||
err = __rtc_set_alarm(rtc, &alarm);
|
||||
if (err == -ETIME)
|
||||
schedule_work(&rtc->irqwork);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rtc_timer_do_work - Expires rtc timers
|
||||
* @rtc rtc device
|
||||
* @timer timer being removed.
|
||||
*
|
||||
* Expires rtc timers. Reprograms next alarm event if needed.
|
||||
* Called via worktask.
|
||||
*
|
||||
* Serializes access to timerqueue via ops_lock mutex
|
||||
*/
|
||||
void rtc_timer_do_work(struct work_struct *work)
|
||||
{
|
||||
struct rtc_timer *timer;
|
||||
struct timerqueue_node *next;
|
||||
ktime_t now;
|
||||
struct rtc_time tm;
|
||||
|
||||
struct rtc_device *rtc =
|
||||
container_of(work, struct rtc_device, irqwork);
|
||||
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
again:
|
||||
__rtc_read_time(rtc, &tm);
|
||||
now = rtc_tm_to_ktime(tm);
|
||||
while ((next = timerqueue_getnext(&rtc->timerqueue))) {
|
||||
if (next->expires.tv64 > now.tv64)
|
||||
break;
|
||||
|
||||
/* expire timer */
|
||||
timer = container_of(next, struct rtc_timer, node);
|
||||
timerqueue_del(&rtc->timerqueue, &timer->node);
|
||||
timer->enabled = 0;
|
||||
if (timer->task.func)
|
||||
timer->task.func(timer->task.private_data);
|
||||
|
||||
/* Re-add/fwd periodic timers */
|
||||
if (ktime_to_ns(timer->period)) {
|
||||
timer->node.expires = ktime_add(timer->node.expires,
|
||||
timer->period);
|
||||
timer->enabled = 1;
|
||||
timerqueue_add(&rtc->timerqueue, &timer->node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set next alarm */
|
||||
if (next) {
|
||||
struct rtc_wkalrm alarm;
|
||||
int err;
|
||||
alarm.time = rtc_ktime_to_tm(next->expires);
|
||||
alarm.enabled = 1;
|
||||
err = __rtc_set_alarm(rtc, &alarm);
|
||||
if (err == -ETIME)
|
||||
goto again;
|
||||
}
|
||||
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
}
|
||||
|
||||
|
||||
/* rtc_timer_init - Initializes an rtc_timer
|
||||
* @timer: timer to be intiialized
|
||||
* @f: function pointer to be called when timer fires
|
||||
* @data: private data passed to function pointer
|
||||
*
|
||||
* Kernel interface to initializing an rtc_timer.
|
||||
*/
|
||||
void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data)
|
||||
{
|
||||
timerqueue_init(&timer->node);
|
||||
timer->enabled = 0;
|
||||
timer->task.func = f;
|
||||
timer->task.private_data = data;
|
||||
}
|
||||
|
||||
/* rtc_timer_start - Sets an rtc_timer to fire in the future
|
||||
* @ rtc: rtc device to be used
|
||||
* @ timer: timer being set
|
||||
* @ expires: time at which to expire the timer
|
||||
* @ period: period that the timer will recur
|
||||
*
|
||||
* Kernel interface to set an rtc_timer
|
||||
*/
|
||||
int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
|
||||
ktime_t expires, ktime_t period)
|
||||
{
|
||||
int ret = 0;
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
if (timer->enabled)
|
||||
rtc_timer_remove(rtc, timer);
|
||||
|
||||
timer->node.expires = expires;
|
||||
timer->period = period;
|
||||
|
||||
ret = rtc_timer_enqueue(rtc, timer);
|
||||
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* rtc_timer_cancel - Stops an rtc_timer
|
||||
* @ rtc: rtc device to be used
|
||||
* @ timer: timer being set
|
||||
*
|
||||
* Kernel interface to cancel an rtc_timer
|
||||
*/
|
||||
int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer)
|
||||
{
|
||||
int ret = 0;
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
if (timer->enabled)
|
||||
rtc_timer_remove(rtc, timer);
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
|
||||
#include <asm-generic/rtc.h>
|
||||
|
|
@ -687,7 +688,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
|||
#if defined(CONFIG_ATARI)
|
||||
address_space = 64;
|
||||
#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \
|
||||
|| defined(__sparc__) || defined(__mips__)
|
||||
|| defined(__sparc__) || defined(__mips__) \
|
||||
|| defined(__powerpc__)
|
||||
address_space = 128;
|
||||
#else
|
||||
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
|
||||
|
|
@ -850,7 +852,7 @@ static void __exit cmos_do_remove(struct device *dev)
|
|||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int cmos_suspend(struct device *dev, pm_message_t mesg)
|
||||
static int cmos_suspend(struct device *dev)
|
||||
{
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
unsigned char tmp;
|
||||
|
|
@ -898,7 +900,7 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)
|
|||
*/
|
||||
static inline int cmos_poweroff(struct device *dev)
|
||||
{
|
||||
return cmos_suspend(dev, PMSG_HIBERNATE);
|
||||
return cmos_suspend(dev);
|
||||
}
|
||||
|
||||
static int cmos_resume(struct device *dev)
|
||||
|
|
@ -945,9 +947,9 @@ static int cmos_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume);
|
||||
|
||||
#else
|
||||
#define cmos_suspend NULL
|
||||
#define cmos_resume NULL
|
||||
|
||||
static inline int cmos_poweroff(struct device *dev)
|
||||
{
|
||||
|
|
@ -1077,7 +1079,7 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
|
|||
|
||||
static int cmos_pnp_suspend(struct pnp_dev *pnp, pm_message_t mesg)
|
||||
{
|
||||
return cmos_suspend(&pnp->dev, mesg);
|
||||
return cmos_suspend(&pnp->dev);
|
||||
}
|
||||
|
||||
static int cmos_pnp_resume(struct pnp_dev *pnp)
|
||||
|
|
@ -1157,8 +1159,9 @@ static struct platform_driver cmos_platform_driver = {
|
|||
.shutdown = cmos_platform_shutdown,
|
||||
.driver = {
|
||||
.name = (char *) driver_name,
|
||||
.suspend = cmos_suspend,
|
||||
.resume = cmos_resume,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &cmos_pm_ops,
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -46,105 +46,6 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
|
||||
/*
|
||||
* Routine to poll RTC seconds field for change as often as possible,
|
||||
* after first RTC_UIE use timer to reduce polling
|
||||
*/
|
||||
static void rtc_uie_task(struct work_struct *work)
|
||||
{
|
||||
struct rtc_device *rtc =
|
||||
container_of(work, struct rtc_device, uie_task);
|
||||
struct rtc_time tm;
|
||||
int num = 0;
|
||||
int err;
|
||||
|
||||
err = rtc_read_time(rtc, &tm);
|
||||
|
||||
spin_lock_irq(&rtc->irq_lock);
|
||||
if (rtc->stop_uie_polling || err) {
|
||||
rtc->uie_task_active = 0;
|
||||
} else if (rtc->oldsecs != tm.tm_sec) {
|
||||
num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
|
||||
rtc->oldsecs = tm.tm_sec;
|
||||
rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
|
||||
rtc->uie_timer_active = 1;
|
||||
rtc->uie_task_active = 0;
|
||||
add_timer(&rtc->uie_timer);
|
||||
} else if (schedule_work(&rtc->uie_task) == 0) {
|
||||
rtc->uie_task_active = 0;
|
||||
}
|
||||
spin_unlock_irq(&rtc->irq_lock);
|
||||
if (num)
|
||||
rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF);
|
||||
}
|
||||
static void rtc_uie_timer(unsigned long data)
|
||||
{
|
||||
struct rtc_device *rtc = (struct rtc_device *)data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rtc->irq_lock, flags);
|
||||
rtc->uie_timer_active = 0;
|
||||
rtc->uie_task_active = 1;
|
||||
if ((schedule_work(&rtc->uie_task) == 0))
|
||||
rtc->uie_task_active = 0;
|
||||
spin_unlock_irqrestore(&rtc->irq_lock, flags);
|
||||
}
|
||||
|
||||
static int clear_uie(struct rtc_device *rtc)
|
||||
{
|
||||
spin_lock_irq(&rtc->irq_lock);
|
||||
if (rtc->uie_irq_active) {
|
||||
rtc->stop_uie_polling = 1;
|
||||
if (rtc->uie_timer_active) {
|
||||
spin_unlock_irq(&rtc->irq_lock);
|
||||
del_timer_sync(&rtc->uie_timer);
|
||||
spin_lock_irq(&rtc->irq_lock);
|
||||
rtc->uie_timer_active = 0;
|
||||
}
|
||||
if (rtc->uie_task_active) {
|
||||
spin_unlock_irq(&rtc->irq_lock);
|
||||
flush_scheduled_work();
|
||||
spin_lock_irq(&rtc->irq_lock);
|
||||
}
|
||||
rtc->uie_irq_active = 0;
|
||||
}
|
||||
spin_unlock_irq(&rtc->irq_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_uie(struct rtc_device *rtc)
|
||||
{
|
||||
struct rtc_time tm;
|
||||
int err;
|
||||
|
||||
err = rtc_read_time(rtc, &tm);
|
||||
if (err)
|
||||
return err;
|
||||
spin_lock_irq(&rtc->irq_lock);
|
||||
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;
|
||||
if (schedule_work(&rtc->uie_task) == 0)
|
||||
rtc->uie_task_active = 0;
|
||||
}
|
||||
rtc->irq_data = 0;
|
||||
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
|
||||
rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
||||
|
|
@ -493,11 +394,6 @@ void rtc_dev_prepare(struct rtc_device *rtc)
|
|||
|
||||
rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
|
||||
|
||||
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
|
||||
INIT_WORK(&rtc->uie_task, rtc_uie_task);
|
||||
setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
|
||||
#endif
|
||||
|
||||
cdev_init(&rtc->char_dev, &rtc_dev_fops);
|
||||
rtc->char_dev.owner = rtc->owner;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -813,7 +813,7 @@ static int __devexit ds1305_remove(struct spi_device *spi)
|
|||
if (spi->irq) {
|
||||
set_bit(FLAG_EXITING, &ds1305->flags);
|
||||
free_irq(spi->irq, ds1305);
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&ds1305->work);
|
||||
}
|
||||
|
||||
rtc_device_unregister(ds1305->rtc);
|
||||
|
|
|
|||
|
|
@ -106,9 +106,9 @@ struct ds1307 {
|
|||
struct i2c_client *client;
|
||||
struct rtc_device *rtc;
|
||||
struct work_struct work;
|
||||
s32 (*read_block_data)(struct i2c_client *client, u8 command,
|
||||
s32 (*read_block_data)(const struct i2c_client *client, u8 command,
|
||||
u8 length, u8 *values);
|
||||
s32 (*write_block_data)(struct i2c_client *client, u8 command,
|
||||
s32 (*write_block_data)(const struct i2c_client *client, u8 command,
|
||||
u8 length, const u8 *values);
|
||||
};
|
||||
|
||||
|
|
@ -158,8 +158,8 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id);
|
|||
|
||||
#define BLOCK_DATA_MAX_TRIES 10
|
||||
|
||||
static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command,
|
||||
u8 length, u8 *values)
|
||||
static s32 ds1307_read_block_data_once(const struct i2c_client *client,
|
||||
u8 command, u8 length, u8 *values)
|
||||
{
|
||||
s32 i, data;
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command,
|
|||
return i;
|
||||
}
|
||||
|
||||
static s32 ds1307_read_block_data(struct i2c_client *client, u8 command,
|
||||
static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
|
||||
u8 length, u8 *values)
|
||||
{
|
||||
u8 oldvalues[I2C_SMBUS_BLOCK_MAX];
|
||||
|
|
@ -198,7 +198,7 @@ static s32 ds1307_read_block_data(struct i2c_client *client, u8 command,
|
|||
return length;
|
||||
}
|
||||
|
||||
static s32 ds1307_write_block_data(struct i2c_client *client, u8 command,
|
||||
static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
|
||||
u8 length, const u8 *values)
|
||||
{
|
||||
u8 currvalues[I2C_SMBUS_BLOCK_MAX];
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ static int __devexit ds1374_remove(struct i2c_client *client)
|
|||
mutex_unlock(&ds1374->mutex);
|
||||
|
||||
free_irq(client->irq, client);
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&ds1374->work);
|
||||
}
|
||||
|
||||
rtc_device_unregister(ds1374->rtc);
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ static int __devexit ds3232_remove(struct i2c_client *client)
|
|||
mutex_unlock(&ds3232->mutex);
|
||||
|
||||
free_irq(client->irq, client);
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&ds3232->work);
|
||||
}
|
||||
|
||||
rtc_device_unregister(ds3232->rtc);
|
||||
|
|
|
|||
|
|
@ -117,4 +117,32 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
|
|||
}
|
||||
EXPORT_SYMBOL(rtc_tm_to_time);
|
||||
|
||||
/*
|
||||
* Convert rtc_time to ktime
|
||||
*/
|
||||
ktime_t rtc_tm_to_ktime(struct rtc_time tm)
|
||||
{
|
||||
time_t time;
|
||||
rtc_tm_to_time(&tm, &time);
|
||||
return ktime_set(time, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
|
||||
|
||||
/*
|
||||
* Convert ktime to rtc_time
|
||||
*/
|
||||
struct rtc_time rtc_ktime_to_tm(ktime_t kt)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct rtc_time ret;
|
||||
|
||||
ts = ktime_to_timespec(kt);
|
||||
/* Round up any ns */
|
||||
if (ts.tv_nsec)
|
||||
ts.tv_sec++;
|
||||
rtc_time_to_tm(ts.tv_sec, &ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -139,12 +139,13 @@ static int __devinit max6902_probe(struct spi_device *spi)
|
|||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
dev_set_drvdata(&spi->dev, rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit max6902_remove(struct spi_device *spi)
|
||||
{
|
||||
struct rtc_device *rtc = platform_get_drvdata(spi);
|
||||
struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
|
||||
|
||||
rtc_device_unregister(rtc);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/max8998.h>
|
||||
#include <linux/mfd/max8998-private.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define MAX8998_RTC_SEC 0x00
|
||||
#define MAX8998_RTC_MIN 0x01
|
||||
|
|
@ -73,6 +74,7 @@ struct max8998_rtc_info {
|
|||
struct i2c_client *rtc;
|
||||
struct rtc_device *rtc_dev;
|
||||
int irq;
|
||||
bool lp3974_bug_workaround;
|
||||
};
|
||||
|
||||
static void max8998_data_to_tm(u8 *data, struct rtc_time *tm)
|
||||
|
|
@ -124,10 +126,16 @@ static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
{
|
||||
struct max8998_rtc_info *info = dev_get_drvdata(dev);
|
||||
u8 data[8];
|
||||
int ret;
|
||||
|
||||
max8998_tm_to_data(tm, data);
|
||||
|
||||
return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
|
||||
ret = max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
|
||||
|
||||
if (info->lp3974_bug_workaround)
|
||||
msleep(2000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
|
@ -163,12 +171,29 @@ static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
|
||||
static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info)
|
||||
{
|
||||
return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
|
||||
int ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
|
||||
|
||||
if (info->lp3974_bug_workaround)
|
||||
msleep(2000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8998_rtc_start_alarm(struct max8998_rtc_info *info)
|
||||
{
|
||||
return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77);
|
||||
int ret;
|
||||
u8 alarm0_conf = 0x77;
|
||||
|
||||
/* LP3974 with delay bug chips has rtc alarm bugs with "MONTH" field */
|
||||
if (info->lp3974_bug_workaround)
|
||||
alarm0_conf = 0x57;
|
||||
|
||||
ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf);
|
||||
|
||||
if (info->lp3974_bug_workaround)
|
||||
msleep(2000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
|
@ -187,10 +212,13 @@ static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (alrm->enabled)
|
||||
return max8998_rtc_start_alarm(info);
|
||||
if (info->lp3974_bug_workaround)
|
||||
msleep(2000);
|
||||
|
||||
return 0;
|
||||
if (alrm->enabled)
|
||||
ret = max8998_rtc_start_alarm(info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8998_rtc_alarm_irq_enable(struct device *dev,
|
||||
|
|
@ -224,6 +252,7 @@ static const struct rtc_class_ops max8998_rtc_ops = {
|
|||
static int __devinit max8998_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev);
|
||||
struct max8998_rtc_info *info;
|
||||
int ret;
|
||||
|
||||
|
|
@ -249,10 +278,18 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0,
|
||||
"rtc-alarm0", info);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
|
||||
info->irq, ret);
|
||||
|
||||
dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name);
|
||||
if (pdata->rtc_delay) {
|
||||
info->lp3974_bug_workaround = true;
|
||||
dev_warn(&pdev->dev, "LP3974 with RTC REGERR option."
|
||||
" RTC updates will be extremely slow.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_rtc:
|
||||
|
|
@ -273,6 +310,12 @@ static int __devexit max8998_rtc_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id max8998_rtc_id[] = {
|
||||
{ "max8998-rtc", TYPE_MAX8998 },
|
||||
{ "lp3974-rtc", TYPE_LP3974 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver max8998_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "max8998-rtc",
|
||||
|
|
@ -280,6 +323,7 @@ static struct platform_driver max8998_rtc_driver = {
|
|||
},
|
||||
.probe = max8998_rtc_probe,
|
||||
.remove = __devexit_p(max8998_rtc_remove),
|
||||
.id_table = max8998_rtc_id,
|
||||
};
|
||||
|
||||
static int __init max8998_rtc_init(void)
|
||||
|
|
|
|||
|
|
@ -429,13 +429,14 @@ fail1:
|
|||
fail0:
|
||||
iounmap(rtc_base);
|
||||
fail:
|
||||
release_resource(mem);
|
||||
release_mem_region(mem->start, resource_size(mem));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int __exit omap_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rtc_device *rtc = platform_get_drvdata(pdev);
|
||||
struct resource *mem = dev_get_drvdata(&rtc->dev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
|
|
@ -447,8 +448,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
|
|||
if (omap_rtc_timer != omap_rtc_alarm)
|
||||
free_irq(omap_rtc_alarm, rtc);
|
||||
|
||||
release_resource(dev_get_drvdata(&rtc->dev));
|
||||
rtc_device_unregister(rtc);
|
||||
iounmap(rtc_base);
|
||||
release_mem_region(mem->start, resource_size(mem));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
{
|
||||
struct rs5c372 *rs5c = i2c_get_clientdata(client);
|
||||
unsigned char buf[8];
|
||||
unsigned char buf[7];
|
||||
int addr;
|
||||
|
||||
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
|
||||
|
|
|
|||
|
|
@ -650,7 +650,7 @@ static int __devexit rx8025_remove(struct i2c_client *client)
|
|||
mutex_unlock(lock);
|
||||
|
||||
free_irq(client->irq, client);
|
||||
flush_scheduled_work();
|
||||
cancel_work_sync(&rx8025->work);
|
||||
}
|
||||
|
||||
rx8025_sysfs_unregister(&client->dev);
|
||||
|
|
|
|||
|
|
@ -39,10 +39,10 @@
|
|||
#include <mach/regs-ost.h>
|
||||
#endif
|
||||
|
||||
#define RTC_DEF_DIVIDER 32768 - 1
|
||||
#define RTC_DEF_DIVIDER (32768 - 1)
|
||||
#define RTC_DEF_TRIM 0
|
||||
|
||||
static unsigned long rtc_freq = 1024;
|
||||
static const unsigned long RTC_FREQ = 1024;
|
||||
static unsigned long timer_freq;
|
||||
static struct rtc_time rtc_alarm;
|
||||
static DEFINE_SPINLOCK(sa1100_rtc_lock);
|
||||
|
|
@ -61,7 +61,8 @@ static inline int rtc_periodic_alarm(struct rtc_time *tm)
|
|||
* Calculate the next alarm time given the requested alarm time mask
|
||||
* and the current time.
|
||||
*/
|
||||
static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm)
|
||||
static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
|
||||
struct rtc_time *alrm)
|
||||
{
|
||||
unsigned long next_time;
|
||||
unsigned long now_time;
|
||||
|
|
@ -116,7 +117,23 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
|
|||
rtsr = RTSR;
|
||||
/* clear interrupt sources */
|
||||
RTSR = 0;
|
||||
RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2);
|
||||
/* Fix for a nasty initialization problem the in SA11xx RTSR register.
|
||||
* See also the comments in sa1100_rtc_probe(). */
|
||||
if (rtsr & (RTSR_ALE | RTSR_HZE)) {
|
||||
/* This is the original code, before there was the if test
|
||||
* above. This code does not clear interrupts that were not
|
||||
* enabled. */
|
||||
RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2);
|
||||
} else {
|
||||
/* For some reason, it is possible to enter this routine
|
||||
* without interruptions enabled, it has been tested with
|
||||
* several units (Bug in SA11xx chip?).
|
||||
*
|
||||
* This situation leads to an infinite "loop" of interrupt
|
||||
* routine calling and as a result the processor seems to
|
||||
* lock on its first call to open(). */
|
||||
RTSR = RTSR_AL | RTSR_HZ;
|
||||
}
|
||||
|
||||
/* clear alarm interrupt if it has occurred */
|
||||
if (rtsr & RTSR_AL)
|
||||
|
|
@ -139,8 +156,58 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int sa1100_irq_set_freq(struct device *dev, int freq)
|
||||
{
|
||||
if (freq < 1 || freq > timer_freq) {
|
||||
return -EINVAL;
|
||||
} else {
|
||||
struct rtc_device *rtc = (struct rtc_device *)dev;
|
||||
|
||||
rtc->irq_freq = freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int rtc_timer1_count;
|
||||
|
||||
static int sa1100_irq_set_state(struct device *dev, int enabled)
|
||||
{
|
||||
spin_lock_irq(&sa1100_rtc_lock);
|
||||
if (enabled) {
|
||||
struct rtc_device *rtc = (struct rtc_device *)dev;
|
||||
|
||||
OSMR1 = timer_freq / rtc->irq_freq + OSCR;
|
||||
OIER |= OIER_E1;
|
||||
rtc_timer1_count = 1;
|
||||
} else {
|
||||
OIER &= ~OIER_E1;
|
||||
}
|
||||
spin_unlock_irq(&sa1100_rtc_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int sa1100_timer1_retrigger(struct rtc_device *rtc)
|
||||
{
|
||||
unsigned long diff;
|
||||
unsigned long period = timer_freq / rtc->irq_freq;
|
||||
|
||||
spin_lock_irq(&sa1100_rtc_lock);
|
||||
|
||||
do {
|
||||
OSMR1 += period;
|
||||
diff = OSMR1 - OSCR;
|
||||
/* If OSCR > OSMR1, diff is a very large number (unsigned
|
||||
* math). This means we have a lost interrupt. */
|
||||
} while (diff > period);
|
||||
OIER |= OIER_E1;
|
||||
|
||||
spin_unlock_irq(&sa1100_rtc_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t timer1_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev_id);
|
||||
|
|
@ -158,7 +225,11 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id)
|
|||
rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF);
|
||||
|
||||
if (rtc_timer1_count == 1)
|
||||
rtc_timer1_count = (rtc_freq * ((1 << 30) / (timer_freq >> 2)));
|
||||
rtc_timer1_count =
|
||||
(rtc->irq_freq * ((1 << 30) / (timer_freq >> 2)));
|
||||
|
||||
/* retrigger. */
|
||||
sa1100_timer1_retrigger(rtc);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -166,8 +237,10 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id)
|
|||
static int sa1100_rtc_read_callback(struct device *dev, int data)
|
||||
{
|
||||
if (data & RTC_PF) {
|
||||
struct rtc_device *rtc = (struct rtc_device *)dev;
|
||||
|
||||
/* interpolate missed periods and set match for the next */
|
||||
unsigned long period = timer_freq / rtc_freq;
|
||||
unsigned long period = timer_freq / rtc->irq_freq;
|
||||
unsigned long oscr = OSCR;
|
||||
unsigned long osmr1 = OSMR1;
|
||||
unsigned long missed = (oscr - osmr1)/period;
|
||||
|
|
@ -178,7 +251,7 @@ static int sa1100_rtc_read_callback(struct device *dev, int data)
|
|||
* Here we compare (match - OSCR) 8 instead of 0 --
|
||||
* see comment in pxa_timer_interrupt() for explanation.
|
||||
*/
|
||||
while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) {
|
||||
while ((signed long)((osmr1 = OSMR1) - OSCR) <= 8) {
|
||||
data += 0x100;
|
||||
OSSR = OSSR_M1; /* clear match on timer 1 */
|
||||
OSMR1 = osmr1 + period;
|
||||
|
|
@ -190,25 +263,29 @@ static int sa1100_rtc_read_callback(struct device *dev, int data)
|
|||
static int sa1100_rtc_open(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct rtc_device *rtc = (struct rtc_device *)dev;
|
||||
|
||||
ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED,
|
||||
"rtc 1Hz", dev);
|
||||
"rtc 1Hz", dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz);
|
||||
goto fail_ui;
|
||||
}
|
||||
ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED,
|
||||
"rtc Alrm", dev);
|
||||
"rtc Alrm", dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm);
|
||||
goto fail_ai;
|
||||
}
|
||||
ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED,
|
||||
"rtc timer", dev);
|
||||
"rtc timer", dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1);
|
||||
goto fail_pi;
|
||||
}
|
||||
rtc->max_user_freq = RTC_FREQ;
|
||||
sa1100_irq_set_freq(dev, RTC_FREQ);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_pi:
|
||||
|
|
@ -236,7 +313,7 @@ static void sa1100_rtc_release(struct device *dev)
|
|||
static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
switch(cmd) {
|
||||
switch (cmd) {
|
||||
case RTC_AIE_OFF:
|
||||
spin_lock_irq(&sa1100_rtc_lock);
|
||||
RTSR &= ~RTSR_ALE;
|
||||
|
|
@ -257,25 +334,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
|
|||
RTSR |= RTSR_HZE;
|
||||
spin_unlock_irq(&sa1100_rtc_lock);
|
||||
return 0;
|
||||
case RTC_PIE_OFF:
|
||||
spin_lock_irq(&sa1100_rtc_lock);
|
||||
OIER &= ~OIER_E1;
|
||||
spin_unlock_irq(&sa1100_rtc_lock);
|
||||
return 0;
|
||||
case RTC_PIE_ON:
|
||||
spin_lock_irq(&sa1100_rtc_lock);
|
||||
OSMR1 = timer_freq / rtc_freq + OSCR;
|
||||
OIER |= OIER_E1;
|
||||
rtc_timer1_count = 1;
|
||||
spin_unlock_irq(&sa1100_rtc_lock);
|
||||
return 0;
|
||||
case RTC_IRQP_READ:
|
||||
return put_user(rtc_freq, (unsigned long *)arg);
|
||||
case RTC_IRQP_SET:
|
||||
if (arg < 1 || arg > timer_freq)
|
||||
return -EINVAL;
|
||||
rtc_freq = arg;
|
||||
return 0;
|
||||
}
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
|
@ -327,12 +385,15 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
|
||||
static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
struct rtc_device *rtc = (struct rtc_device *)dev;
|
||||
|
||||
seq_printf(seq, "trim/divider\t: 0x%08x\n", (u32) RTTR);
|
||||
seq_printf(seq, "update_IRQ\t: %s\n",
|
||||
(RTSR & RTSR_HZE) ? "yes" : "no");
|
||||
seq_printf(seq, "periodic_IRQ\t: %s\n",
|
||||
(OIER & OIER_E1) ? "yes" : "no");
|
||||
seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq);
|
||||
seq_printf(seq, "periodic_freq\t: %d\n", rtc->irq_freq);
|
||||
seq_printf(seq, "RTSR\t\t: 0x%08x\n", (u32)RTSR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -347,6 +408,8 @@ static const struct rtc_class_ops sa1100_rtc_ops = {
|
|||
.read_alarm = sa1100_rtc_read_alarm,
|
||||
.set_alarm = sa1100_rtc_set_alarm,
|
||||
.proc = sa1100_rtc_proc,
|
||||
.irq_set_freq = sa1100_irq_set_freq,
|
||||
.irq_set_state = sa1100_irq_set_state,
|
||||
};
|
||||
|
||||
static int sa1100_rtc_probe(struct platform_device *pdev)
|
||||
|
|
@ -364,7 +427,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
|
|||
*/
|
||||
if (RTTR == 0) {
|
||||
RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
|
||||
dev_warn(&pdev->dev, "warning: initializing default clock divider/trim value\n");
|
||||
dev_warn(&pdev->dev, "warning: "
|
||||
"initializing default clock divider/trim value\n");
|
||||
/* The current RTC value probably doesn't make sense either */
|
||||
RCNR = 0;
|
||||
}
|
||||
|
|
@ -372,13 +436,42 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
|
|||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
|
||||
THIS_MODULE);
|
||||
THIS_MODULE);
|
||||
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
/* Set the irq_freq */
|
||||
/*TODO: Find out who is messing with this value after we initialize
|
||||
* it here.*/
|
||||
rtc->irq_freq = RTC_FREQ;
|
||||
|
||||
/* Fix for a nasty initialization problem the in SA11xx RTSR register.
|
||||
* See also the comments in sa1100_rtc_interrupt().
|
||||
*
|
||||
* Sometimes bit 1 of the RTSR (RTSR_HZ) will wake up 1, which means an
|
||||
* interrupt pending, even though interrupts were never enabled.
|
||||
* In this case, this bit it must be reset before enabling
|
||||
* interruptions to avoid a nonexistent interrupt to occur.
|
||||
*
|
||||
* In principle, the same problem would apply to bit 0, although it has
|
||||
* never been observed to happen.
|
||||
*
|
||||
* This issue is addressed both here and in sa1100_rtc_interrupt().
|
||||
* If the issue is not addressed here, in the times when the processor
|
||||
* wakes up with the bit set there will be one spurious interrupt.
|
||||
*
|
||||
* The issue is also dealt with in sa1100_rtc_interrupt() to be on the
|
||||
* safe side, once the condition that lead to this strange
|
||||
* initialization is unknown and could in principle happen during
|
||||
* normal processing.
|
||||
*
|
||||
* Notice that clearing bit 1 and 0 is accomplished by writting ONES to
|
||||
* the corresponding bits in RTSR. */
|
||||
RTSR = RTSR_AL | RTSR_HZ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -386,7 +479,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct rtc_device *rtc = platform_get_drvdata(pdev);
|
||||
|
||||
if (rtc)
|
||||
if (rtc)
|
||||
rtc_device_unregister(rtc);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -761,7 +761,7 @@ err_unmap:
|
|||
clk_put(rtc->clk);
|
||||
iounmap(rtc->regbase);
|
||||
err_badmap:
|
||||
release_resource(rtc->res);
|
||||
release_mem_region(rtc->res->start, rtc->regsize);
|
||||
err_badres:
|
||||
kfree(rtc);
|
||||
|
||||
|
|
@ -786,7 +786,7 @@ static int __exit sh_rtc_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
iounmap(rtc->regbase);
|
||||
release_resource(rtc->res);
|
||||
release_mem_region(rtc->res->start, rtc->regsize);
|
||||
|
||||
clk_disable(rtc->clk);
|
||||
clk_put(rtc->clk);
|
||||
|
|
|
|||
Loading…
Reference in a new issue