summaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/class.c14
-rw-r--r--drivers/rtc/interface.c3
-rw-r--r--drivers/rtc/rtc-at91rm9200.c19
-rw-r--r--drivers/rtc/rtc-cmos.c50
-rw-r--r--drivers/rtc/rtc-pcf8583.c29
-rw-r--r--drivers/rtc/rtc-sa1100.c12
7 files changed, 86 insertions, 51 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 4bbca500d3d..95826b92ca4 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -101,7 +101,7 @@ comment "RTC drivers"
config RTC_DRV_CMOS
tristate "PC-style 'CMOS' real time clock"
- depends on RTC_CLASS && (X86_PC || ALPHA || ARM26 || ARM \
+ depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
|| M32R || ATARI || POWERPC)
help
Say "yes" here to get direct support for the real time clock
@@ -207,10 +207,12 @@ config RTC_DRV_PCF8563
config RTC_DRV_PCF8583
tristate "Philips PCF8583"
- depends on RTC_CLASS && I2C
+ depends on RTC_CLASS && I2C && ARCH_RPC
help
- If you say yes here you get support for the
- Philips PCF8583 RTC chip.
+ If you say yes here you get support for the Philips PCF8583
+ RTC chip found on Acorn RiscPCs. This driver supports the
+ platform specific method of retrieving the current year from
+ the RTC's SRAM.
This driver can also be built as a module. If so, the module
will be called rtc-pcf8583.
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 7a0d8ee2de9..04aaa634723 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -113,10 +113,16 @@ EXPORT_SYMBOL_GPL(rtc_device_register);
*/
void rtc_device_unregister(struct rtc_device *rtc)
{
- mutex_lock(&rtc->ops_lock);
- rtc->ops = NULL;
- mutex_unlock(&rtc->ops_lock);
- class_device_unregister(&rtc->class_dev);
+ if (class_device_get(&rtc->class_dev) != NULL) {
+ mutex_lock(&rtc->ops_lock);
+ /* remove innards of this RTC, then disable it, before
+ * letting any rtc_class_open() users access it again
+ */
+ class_device_unregister(&rtc->class_dev);
+ rtc->ops = NULL;
+ mutex_unlock(&rtc->ops_lock);
+ class_device_put(&rtc->class_dev);
+ }
}
EXPORT_SYMBOL_GPL(rtc_device_unregister);
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 6f11f6dfdd9..ef40df0f169 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -179,7 +179,7 @@ struct class_device *rtc_class_open(char *name)
down(&rtc_class->sem);
list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
- class_dev = class_dev_tmp;
+ class_dev = class_device_get(class_dev_tmp);
break;
}
}
@@ -197,6 +197,7 @@ EXPORT_SYMBOL_GPL(rtc_class_open);
void rtc_class_close(struct class_device *class_dev)
{
module_put(to_rtc_device(class_dev)->owner);
+ class_device_put(class_dev);
}
EXPORT_SYMBOL_GPL(rtc_class_close);
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index a724ab49a79..ac0e68e2f02 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -164,6 +164,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
tm.tm_min = alrm->time.tm_min;
tm.tm_sec = alrm->time.tm_sec;
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
at91_sys_write(AT91_RTC_TIMALR,
BIN2BCD(tm.tm_sec) << 0
| BIN2BCD(tm.tm_min) << 8
@@ -174,6 +175,9 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
| BIN2BCD(tm.tm_mday) << 24
| AT91_RTC_DATEEN | AT91_RTC_MTHEN);
+ if (alrm->enabled)
+ at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
+
pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
tm.tm_min, tm.tm_sec);
@@ -303,6 +307,12 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
return ret;
}
+ /* cpu init code should really have flagged this device as
+ * being wake-capable; if it didn't, do that here.
+ */
+ if (!device_can_wakeup(&pdev->dev))
+ device_init_wakeup(&pdev->dev, 1);
+
rtc = rtc_device_register(pdev->name, &pdev->dev,
&at91_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
@@ -310,7 +320,6 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
return PTR_ERR(rtc);
}
platform_set_drvdata(pdev, rtc);
- device_init_wakeup(&pdev->dev, 1);
printk(KERN_INFO "AT91 Real Time Clock driver.\n");
return 0;
@@ -319,7 +328,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
/*
* Disable and remove the RTC driver
*/
-static int __devexit at91_rtc_remove(struct platform_device *pdev)
+static int __exit at91_rtc_remove(struct platform_device *pdev)
{
struct rtc_device *rtc = platform_get_drvdata(pdev);
@@ -331,7 +340,6 @@ static int __devexit at91_rtc_remove(struct platform_device *pdev)
rtc_device_unregister(rtc);
platform_set_drvdata(pdev, NULL);
- device_init_wakeup(&pdev->dev, 0);
return 0;
}
@@ -404,8 +412,7 @@ static int at91_rtc_resume(struct platform_device *pdev)
#endif
static struct platform_driver at91_rtc_driver = {
- .probe = at91_rtc_probe,
- .remove = at91_rtc_remove,
+ .remove = __exit_p(at91_rtc_remove),
.suspend = at91_rtc_suspend,
.resume = at91_rtc_resume,
.driver = {
@@ -416,7 +423,7 @@ static struct platform_driver at91_rtc_driver = {
static int __init at91_rtc_init(void)
{
- return platform_driver_register(&at91_rtc_driver);
+ return platform_driver_probe(&at91_rtc_driver, at91_rtc_probe);
}
static void __exit at91_rtc_exit(void)
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 85bf795abdc..7c0d6091007 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -59,6 +59,19 @@ struct cmos_rtc {
static const char driver_name[] = "rtc_cmos";
+/* The RTC_INTR register may have e.g. RTC_PF set even if RTC_PIE is clear;
+ * always mask it against the irq enable bits in RTC_CONTROL. Bit values
+ * are the same: PF==PIE, AF=AIE, UF=UIE; so RTC_IRQMASK works with both.
+ */
+#define RTC_IRQMASK (RTC_PF | RTC_AF | RTC_UF)
+
+static inline int is_intr(u8 rtc_intr)
+{
+ if (!(rtc_intr & RTC_IRQF))
+ return 0;
+ return rtc_intr & RTC_IRQMASK;
+}
+
/*----------------------------------------------------------------*/
static int cmos_read_time(struct device *dev, struct rtc_time *t)
@@ -188,7 +201,8 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
rtc_control &= ~RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL);
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
- if (rtc_intr)
+ rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+ if (is_intr(rtc_intr))
rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
/* update alarm */
@@ -207,7 +221,8 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
rtc_control |= RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL);
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
- if (rtc_intr)
+ rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+ if (is_intr(rtc_intr))
rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
}
@@ -287,7 +302,8 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
}
CMOS_WRITE(rtc_control, RTC_CONTROL);
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
- if (rtc_intr)
+ rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+ if (is_intr(rtc_intr))
rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
@@ -353,12 +369,10 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
spin_lock(&rtc_lock);
irqstat = CMOS_READ(RTC_INTR_FLAGS);
+ irqstat &= (CMOS_READ(RTC_CONTROL) & RTC_IRQMASK) | RTC_IRQF;
spin_unlock(&rtc_lock);
- if (irqstat) {
- /* NOTE: irqstat may have e.g. RTC_PF set
- * even when RTC_PIE is clear...
- */
+ if (is_intr(irqstat)) {
rtc_update_irq(p, 1, irqstat);
return IRQ_HANDLED;
} else
@@ -525,25 +539,26 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
int do_wake = device_may_wakeup(dev);
- unsigned char tmp, irqstat;
+ unsigned char tmp;
/* only the alarm might be a wakeup event source */
spin_lock_irq(&rtc_lock);
cmos->suspend_ctrl = tmp = CMOS_READ(RTC_CONTROL);
if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
+ unsigned char irqstat;
+
if (do_wake)
tmp &= ~(RTC_PIE|RTC_UIE);
else
tmp &= ~(RTC_PIE|RTC_AIE|RTC_UIE);
CMOS_WRITE(tmp, RTC_CONTROL);
irqstat = CMOS_READ(RTC_INTR_FLAGS);
- } else
- irqstat = 0;
+ irqstat &= (tmp & RTC_IRQMASK) | RTC_IRQF;
+ if (is_intr(irqstat))
+ rtc_update_irq(&cmos->rtc->class_dev, 1, irqstat);
+ }
spin_unlock_irq(&rtc_lock);
- if (irqstat)
- rtc_update_irq(&cmos->rtc->class_dev, 1, irqstat);
-
/* ACPI HOOK: enable ACPI_EVENT_RTC when (tmp & RTC_AIE)
* ... it'd be best if we could do that under rtc_lock.
*/
@@ -573,9 +588,10 @@ static int cmos_resume(struct device *dev)
spin_lock_irq(&rtc_lock);
CMOS_WRITE(tmp, RTC_CONTROL);
tmp = CMOS_READ(RTC_INTR_FLAGS);
- spin_unlock_irq(&rtc_lock);
- if (tmp)
+ tmp &= (cmos->suspend_ctrl & RTC_IRQMASK) | RTC_IRQF;
+ if (is_intr(tmp))
rtc_update_irq(&cmos->rtc->class_dev, 1, tmp);
+ spin_unlock_irq(&rtc_lock);
}
pr_debug("%s: resume, ctrl %02x\n",
@@ -594,7 +610,7 @@ static int cmos_resume(struct device *dev)
/*----------------------------------------------------------------*/
/* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems,
- * the device node may alternatively be created as a PNP device.
+ * the device node will always be created as a PNPACPI device.
*/
#ifdef CONFIG_PNPACPI
@@ -673,7 +689,7 @@ module_exit(cmos_exit);
/*----------------------------------------------------------------*/
/* Platform setup should have set up an RTC device, when PNPACPI is
- * unavailable ... this is the normal case, common even on PCs.
+ * unavailable ... this could happen even on (older) PCs.
*/
static int __init cmos_platform_probe(struct platform_device *pdev)
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 5875ebb8c79..d48b0337458 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -40,7 +40,7 @@ struct pcf8583 {
#define CTRL_ALARM 0x02
#define CTRL_TIMER 0x01
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
/* Module parameters */
I2C_CLIENT_INSMOD;
@@ -81,11 +81,11 @@ static int pcf8583_get_datetime(struct i2c_client *client, struct rtc_time *dt)
buf[4] &= 0x3f;
buf[5] &= 0x1f;
- dt->tm_sec = BCD_TO_BIN(buf[1]);
- dt->tm_min = BCD_TO_BIN(buf[2]);
- dt->tm_hour = BCD_TO_BIN(buf[3]);
- dt->tm_mday = BCD_TO_BIN(buf[4]);
- dt->tm_mon = BCD_TO_BIN(buf[5]);
+ dt->tm_sec = BCD2BIN(buf[1]);
+ dt->tm_min = BCD2BIN(buf[2]);
+ dt->tm_hour = BCD2BIN(buf[3]);
+ dt->tm_mday = BCD2BIN(buf[4]);
+ dt->tm_mon = BCD2BIN(buf[5]) - 1;
}
return ret == 2 ? 0 : -EIO;
@@ -99,14 +99,14 @@ static int pcf8583_set_datetime(struct i2c_client *client, struct rtc_time *dt,
buf[0] = 0;
buf[1] = get_ctrl(client) | 0x80;
buf[2] = 0;
- buf[3] = BIN_TO_BCD(dt->tm_sec);
- buf[4] = BIN_TO_BCD(dt->tm_min);
- buf[5] = BIN_TO_BCD(dt->tm_hour);
+ buf[3] = BIN2BCD(dt->tm_sec);
+ buf[4] = BIN2BCD(dt->tm_min);
+ buf[5] = BIN2BCD(dt->tm_hour);
if (datetoo) {
len = 8;
- buf[6] = BIN_TO_BCD(dt->tm_mday) | (dt->tm_year << 6);
- buf[7] = BIN_TO_BCD(dt->tm_mon) | (dt->tm_wday << 5);
+ buf[6] = BIN2BCD(dt->tm_mday) | (dt->tm_year << 6);
+ buf[7] = BIN2BCD(dt->tm_mon + 1) | (dt->tm_wday << 5);
}
ret = i2c_master_send(client, (char *)buf, len);
@@ -226,7 +226,7 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
*/
year_offset += 4;
- tm->tm_year = real_year + year_offset + year[1] * 100;
+ tm->tm_year = (real_year + year_offset + year[1] * 100) - 1900;
return 0;
}
@@ -237,6 +237,7 @@ static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
unsigned char year[2], chk;
struct rtc_mem cmos_year = { CMOS_YEAR, sizeof(year), year };
struct rtc_mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
+ unsigned int proper_year = tm->tm_year + 1900;
int ret;
/*
@@ -258,8 +259,8 @@ static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
chk -= year[1] + year[0];
- year[1] = tm->tm_year / 100;
- year[0] = tm->tm_year % 100;
+ year[1] = proper_year / 100;
+ year[0] = proper_year % 100;
chk += year[1] + year[0];
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 9c8ead43a59..677bae820dc 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -263,8 +263,12 @@ static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
+ u32 rtsr;
+
memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
- alrm->pending = RTSR & RTSR_AL ? 1 : 0;
+ rtsr = RTSR;
+ alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0;
+ alrm->pending = (rtsr & RTSR_AL) ? 1 : 0;
return 0;
}
@@ -275,12 +279,10 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
spin_lock_irq(&sa1100_rtc_lock);
ret = rtc_update_alarm(&alrm->time);
if (ret == 0) {
- memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
-
if (alrm->enabled)
- enable_irq_wake(IRQ_RTCAlrm);
+ RTSR |= RTSR_ALE;
else
- disable_irq_wake(IRQ_RTCAlrm);
+ RTSR &= ~RTSR_ALE;
}
spin_unlock_irq(&sa1100_rtc_lock);