diff options
| author | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
|---|---|---|
| committer | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
| commit | 5c34202b8bf942da411b6599668a76b07449bbfd (patch) | |
| tree | 5719c361321eaddc8e4f1b0c8a7994f0e9a6fdd3 /drivers/rtc/rtc-cmos.c | |
| parent | 0d4804b31f91cfbcff6d62af0bc09a893a1c8ae0 (diff) | |
| parent | 1f8a6b658a943b4f04a1fc7b3a420360202c86cd (diff) | |
Merge /pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/rtc/rtc-cmos.c')
| -rw-r--r-- | drivers/rtc/rtc-cmos.c | 79 | 
1 files changed, 48 insertions, 31 deletions
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 7c0d6091007..6085261aa2c 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -46,6 +46,10 @@ struct cmos_rtc {  	int			irq;  	struct resource		*iomem; +	void			(*wake_on)(struct device *); +	void			(*wake_off)(struct device *); + +	u8			enabled_wake;  	u8			suspend_ctrl;  	/* newer hardware extends the original register set */ @@ -203,7 +207,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)  	rtc_intr = CMOS_READ(RTC_INTR_FLAGS);  	rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;  	if (is_intr(rtc_intr)) -		rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); +		rtc_update_irq(cmos->rtc, 1, rtc_intr);  	/* update alarm */  	CMOS_WRITE(hrs, RTC_HOURS_ALARM); @@ -223,7 +227,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)  		rtc_intr = CMOS_READ(RTC_INTR_FLAGS);  		rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;  		if (is_intr(rtc_intr)) -			rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); +			rtc_update_irq(cmos->rtc, 1, rtc_intr);  	}  	spin_unlock_irq(&rtc_lock); @@ -304,7 +308,7 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)  	rtc_intr = CMOS_READ(RTC_INTR_FLAGS);  	rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;  	if (is_intr(rtc_intr)) -		rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); +		rtc_update_irq(cmos->rtc, 1, rtc_intr);  	spin_unlock_irqrestore(&rtc_lock, flags);  	return 0;  } @@ -379,12 +383,12 @@ static irqreturn_t cmos_interrupt(int irq, void *p)  		return IRQ_NONE;  } -#ifdef	CONFIG_PNPACPI -#define	is_pnpacpi()	1 +#ifdef	CONFIG_PNP +#define	is_pnp()	1  #define	INITSECTION  #else -#define	is_pnpacpi()	0 +#define	is_pnp()	0  #define	INITSECTION	__init  #endif @@ -405,13 +409,20 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	cmos_rtc.irq = rtc_irq;  	cmos_rtc.iomem = ports; -	/* For ACPI systems the info comes from the FADT.  On others, -	 * board specific setup provides it as appropriate. +	/* For ACPI systems extension info comes from the FADT.  On others, +	 * board specific setup provides it as appropriate.  Systems where +	 * the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and +	 * some almost-clones) can provide hooks to make that behave.  	 */  	if (info) {  		cmos_rtc.day_alrm = info->rtc_day_alarm;  		cmos_rtc.mon_alrm = info->rtc_mon_alarm;  		cmos_rtc.century = info->rtc_century; + +		if (info->wake_on && info->wake_off) { +			cmos_rtc.wake_on = info->wake_on; +			cmos_rtc.wake_off = info->wake_off; +		}  	}  	cmos_rtc.rtc = rtc_device_register(driver_name, dev, @@ -427,14 +438,14 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	 * REVISIT for non-x86 systems we may need to handle io memory  	 * resources: ioremap them, and request_mem_region().  	 */ -	if (is_pnpacpi()) { +	if (is_pnp()) {  		retval = request_resource(&ioport_resource, ports);  		if (retval < 0) {  			dev_dbg(dev, "i/o registers already in use\n");  			goto cleanup0;  		}  	} -	rename_region(ports, cmos_rtc.rtc->class_dev.class_id); +	rename_region(ports, cmos_rtc.rtc->dev.bus_id);  	spin_lock_irq(&rtc_lock); @@ -470,8 +481,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	if (is_valid_irq(rtc_irq))  		retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED, -				cmos_rtc.rtc->class_dev.class_id, -				&cmos_rtc.rtc->class_dev); +				cmos_rtc.rtc->dev.bus_id, +				cmos_rtc.rtc);  	if (retval < 0) {  		dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);  		goto cleanup1; @@ -483,7 +494,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	 */  	pr_info("%s: alarms up to one %s%s\n", -			cmos_rtc.rtc->class_dev.class_id, +			cmos_rtc.rtc->dev.bus_id,  			is_valid_irq(rtc_irq)  				?  (cmos_rtc.mon_alrm  					? "year" @@ -520,12 +531,12 @@ static void __exit cmos_do_remove(struct device *dev)  	cmos_do_shutdown(); -	if (is_pnpacpi()) +	if (is_pnp())  		release_resource(cmos->iomem);  	rename_region(cmos->iomem, NULL);  	if (is_valid_irq(cmos->irq)) -		free_irq(cmos->irq, &cmos_rtc.rtc->class_dev); +		free_irq(cmos->irq, cmos_rtc.rtc);  	rtc_device_unregister(cmos_rtc.rtc); @@ -555,16 +566,20 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)  		irqstat = CMOS_READ(RTC_INTR_FLAGS);  		irqstat &= (tmp & RTC_IRQMASK) | RTC_IRQF;  		if (is_intr(irqstat)) -			rtc_update_irq(&cmos->rtc->class_dev, 1, irqstat); +			rtc_update_irq(cmos->rtc, 1, irqstat);  	}  	spin_unlock_irq(&rtc_lock); -	/* ACPI HOOK:  enable ACPI_EVENT_RTC when (tmp & RTC_AIE) -	 * ... it'd be best if we could do that under rtc_lock. -	 */ +	if (tmp & RTC_AIE) { +		cmos->enabled_wake = 1; +		if (cmos->wake_on) +			cmos->wake_on(dev); +		else +			enable_irq_wake(cmos->irq); +	}  	pr_debug("%s: suspend%s, ctrl %02x\n", -			cmos_rtc.rtc->class_dev.class_id, +			cmos_rtc.rtc->dev.bus_id,  			(tmp & RTC_AIE) ? ", alarm may wake" : "",  			tmp); @@ -576,26 +591,28 @@ static int cmos_resume(struct device *dev)  	struct cmos_rtc	*cmos = dev_get_drvdata(dev);  	unsigned char	tmp = cmos->suspend_ctrl; -	/* REVISIT:  a mechanism to resync the system clock (jiffies) -	 * on resume should be portable between platforms ... -	 */ -  	/* re-enable any irqs previously active */  	if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { -		/* ACPI HOOK:  disable ACPI_EVENT_RTC when (tmp & RTC_AIE) */ +		if (cmos->enabled_wake) { +			if (cmos->wake_off) +				cmos->wake_off(dev); +			else +				disable_irq_wake(cmos->irq); +			cmos->enabled_wake = 0; +		}  		spin_lock_irq(&rtc_lock);  		CMOS_WRITE(tmp, RTC_CONTROL);  		tmp = CMOS_READ(RTC_INTR_FLAGS);  		tmp &= (cmos->suspend_ctrl & RTC_IRQMASK) | RTC_IRQF;  		if (is_intr(tmp)) -			rtc_update_irq(&cmos->rtc->class_dev, 1, tmp); +			rtc_update_irq(cmos->rtc, 1, tmp);  		spin_unlock_irq(&rtc_lock);  	}  	pr_debug("%s: resume, ctrl %02x\n", -			cmos_rtc.rtc->class_dev.class_id, +			cmos_rtc.rtc->dev.bus_id,  			cmos->suspend_ctrl); @@ -613,7 +630,7 @@ static int cmos_resume(struct device *dev)   * the device node will always be created as a PNPACPI device.   */ -#ifdef	CONFIG_PNPACPI +#ifdef	CONFIG_PNP  #include <linux/pnp.h> @@ -684,11 +701,11 @@ static void __exit cmos_exit(void)  }  module_exit(cmos_exit); -#else	/* no PNPACPI */ +#else	/* no PNP */  /*----------------------------------------------------------------*/ -/* Platform setup should have set up an RTC device, when PNPACPI is +/* Platform setup should have set up an RTC device, when PNP is   * unavailable ... this could happen even on (older) PCs.   */ @@ -734,7 +751,7 @@ static void __exit cmos_exit(void)  module_exit(cmos_exit); -#endif	/* !PNPACPI */ +#endif	/* !PNP */  MODULE_AUTHOR("David Brownell");  MODULE_DESCRIPTION("Driver for PC-style 'CMOS' RTCs");  | 
