Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 21a32816 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'timers-rtc-for-linus' of...

Merge branch 'timers-rtc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'timers-rtc-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  RTC: Fix up rtc.txt documentation to reflect changes to generic rtc layer
  RTC: sa1100: Update the sa1100 RTC driver.
  RTC: Fix the cross interrupt issue on rtc-test.
  RTC: Remove UIE and PIE information from the sa1100 driver proc.
  RTC: Include information about UIE and PIE in RTC driver proc.
  RTC: Clean out UIE icotl implementations
  RTC: Cleanup rtc_class_ops->update_irq_enable()
  RTC: Cleanup rtc_class_ops->irq_set_freq()
  RTC: Cleanup rtc_class_ops->irq_set_state
  RTC: Initialize kernel state from RTC
parents 420c1c57 ea04683f
Loading
Loading
Loading
Loading
+10 −19
Original line number Original line Diff line number Diff line
@@ -178,38 +178,29 @@ RTC class framework, but can't be supported by the older driver.
	setting the longer alarm time and enabling its IRQ using a single
	setting the longer alarm time and enabling its IRQ using a single
	request (using the same model as EFI firmware).
	request (using the same model as EFI firmware).


    *	RTC_UIE_ON, RTC_UIE_OFF ... if the RTC offers IRQs, it probably
    *	RTC_UIE_ON, RTC_UIE_OFF ... if the RTC offers IRQs, the RTC framework
	also offers update IRQs whenever the "seconds" counter changes.
	will emulate this mechanism.
	If needed, the RTC framework can emulate this mechanism.


    *	RTC_PIE_ON, RTC_PIE_OFF, RTC_IRQP_SET, RTC_IRQP_READ ... another
    *	RTC_PIE_ON, RTC_PIE_OFF, RTC_IRQP_SET, RTC_IRQP_READ ... these icotls
	feature often accessible with an IRQ line is a periodic IRQ, issued
	are emulated via a kernel hrtimer.
	at settable frequencies (usually 2^N Hz).


In many cases, the RTC alarm can be a system wake event, used to force
In many cases, the RTC alarm can be a system wake event, used to force
Linux out of a low power sleep state (or hibernation) back to a fully
Linux out of a low power sleep state (or hibernation) back to a fully
operational state.  For example, a system could enter a deep power saving
operational state.  For example, a system could enter a deep power saving
state until it's time to execute some scheduled tasks.
state until it's time to execute some scheduled tasks.


Note that many of these ioctls need not actually be implemented by your
Note that many of these ioctls are handled by the common rtc-dev interface.
driver.  The common rtc-dev interface handles many of these nicely if your
Some common examples:
driver returns ENOIOCTLCMD.  Some common examples:


    *	RTC_RD_TIME, RTC_SET_TIME: the read_time/set_time functions will be
    *	RTC_RD_TIME, RTC_SET_TIME: the read_time/set_time functions will be
	called with appropriate values.
	called with appropriate values.


    *	RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: the
    *	RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: gets or sets
	set_alarm/read_alarm functions will be called.
	the alarm rtc_timer. May call the set_alarm driver function.


    *	RTC_IRQP_SET, RTC_IRQP_READ: the irq_set_freq function will be called
    *	RTC_IRQP_SET, RTC_IRQP_READ: These are emulated by the generic code.
	to set the frequency while the framework will handle the read for you
	since the frequency is stored in the irq_freq member of the rtc_device
	structure.  Your driver needs to initialize the irq_freq member during
	init.  Make sure you check the requested frequency is in range of your
	hardware in the irq_set_freq function.  If it isn't, return -EINVAL.  If
	you cannot actually change the frequency, do not define irq_set_freq.


    *	RTC_PIE_ON, RTC_PIE_OFF: the irq_set_state function will be called.
    *	RTC_PIE_ON, RTC_PIE_OFF: These are also emulated by the generic code.


If all else fails, check out the rtc-test.c driver!
If all else fails, check out the rtc-test.c driver!


+7 −0
Original line number Original line Diff line number Diff line
@@ -117,6 +117,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
					struct module *owner)
					struct module *owner)
{
{
	struct rtc_device *rtc;
	struct rtc_device *rtc;
	struct rtc_wkalrm alrm;
	int id, err;
	int id, err;


	if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
	if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
@@ -166,6 +167,12 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
	rtc->pie_timer.function = rtc_pie_update_irq;
	rtc->pie_timer.function = rtc_pie_update_irq;
	rtc->pie_enabled = 0;
	rtc->pie_enabled = 0;


	/* Check to see if there is an ALARM already set in hw */
	err = __rtc_read_alarm(rtc, &alrm);

	if (!err && !rtc_valid_tm(&alrm.time))
		rtc_set_alarm(rtc, &alrm);

	strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
	strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
	dev_set_name(&rtc->dev, "rtc%d", id);
	dev_set_name(&rtc->dev, "rtc%d", id);


+180 −0
Original line number Original line Diff line number Diff line
@@ -116,6 +116,186 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
}
}
EXPORT_SYMBOL_GPL(rtc_set_mmss);
EXPORT_SYMBOL_GPL(rtc_set_mmss);


static int rtc_read_alarm_internal(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);
	}

	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;

		/* 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;
}

int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
{
	int err;
	int err;
+0 −28
Original line number Original line Diff line number Diff line
@@ -183,33 +183,6 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
	return 0;
	return 0;
}
}


/*
 * Handle commands from user-space
 */
static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
			unsigned long arg)
{
	int ret = 0;

	pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __func__, cmd, arg);

	/* important:  scrub old status before enabling IRQs */
	switch (cmd) {
	case RTC_UIE_OFF:	/* update off */
		at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV);
		break;
	case RTC_UIE_ON:	/* update on */
		at91_sys_write(AT91_RTC_SCCR, AT91_RTC_SECEV);
		at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV);
		break;
	default:
		ret = -ENOIOCTLCMD;
		break;
	}

	return ret;
}

static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
{
	pr_debug("%s(): cmd=%08x\n", __func__, enabled);
	pr_debug("%s(): cmd=%08x\n", __func__, enabled);
@@ -269,7 +242,6 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
}
}


static const struct rtc_class_ops at91_rtc_ops = {
static const struct rtc_class_ops at91_rtc_ops = {
	.ioctl		= at91_rtc_ioctl,
	.read_time	= at91_rtc_readtime,
	.read_time	= at91_rtc_readtime,
	.set_time	= at91_rtc_settime,
	.set_time	= at91_rtc_settime,
	.read_alarm	= at91_rtc_readalarm,
	.read_alarm	= at91_rtc_readalarm,
+0 −28
Original line number Original line Diff line number Diff line
@@ -216,33 +216,6 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
	return 0;
	return 0;
}
}


/*
 * Handle commands from user-space
 */
static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
			unsigned long arg)
{
	struct sam9_rtc *rtc = dev_get_drvdata(dev);
	int ret = 0;
	u32 mr = rtt_readl(rtc, MR);

	dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr);

	switch (cmd) {
	case RTC_UIE_OFF:		/* update off */
		rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
		break;
	case RTC_UIE_ON:		/* update on */
		rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN);
		break;
	default:
		ret = -ENOIOCTLCMD;
		break;
	}

	return ret;
}

static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
{
	struct sam9_rtc *rtc = dev_get_drvdata(dev);
	struct sam9_rtc *rtc = dev_get_drvdata(dev);
@@ -303,7 +276,6 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
}
}


static const struct rtc_class_ops at91_rtc_ops = {
static const struct rtc_class_ops at91_rtc_ops = {
	.ioctl		= at91_rtc_ioctl,
	.read_time	= at91_rtc_readtime,
	.read_time	= at91_rtc_readtime,
	.set_time	= at91_rtc_settime,
	.set_time	= at91_rtc_settime,
	.read_alarm	= at91_rtc_readalarm,
	.read_alarm	= at91_rtc_readalarm,
Loading