Message ID | 200907101857.n6AIvP7J001896@pogo.cesa.opbu.xerox.com |
---|---|
State | New, archived |
Headers | show |
On Fri, 10 Jul 2009 11:57:25 -0700 Andrew Klossner <andrew@cesa.opbu.xerox.com> wrote: Mark, any thoughts on this? > > rtc-m48t59: add support for the M48T201 chip. > > Also: > Fix a bug in m48t59_rtc_probe failure return that would iounmap an > address that hadn't been ioremapped. > Fix a Y2K bug for the M48T59: 31-Dec-1999 would step to 1-Jan-1900. > Fix diagnostic outputs to show the date correctly. > Add a FIXME comment describing a likely bug in alarm-setting code. > > Signed-off-by: Andrew Klossner <andrew@cesa.opbu.xerox.com> > > --- > diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c > index 33921a6..c06e88f 100644 > --- a/drivers/rtc/rtc-m48t59.c > +++ b/drivers/rtc/rtc-m48t59.c > @@ -82,8 +82,10 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) > tm->tm_mday = bcd2bin(M48T59_READ(M48T59_MDAY)); > > val = M48T59_READ(M48T59_WDAY); > - if ((pdata->type == M48T59RTC_TYPE_M48T59) && > - (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { > + if (pdata->type == M48T59RTC_TYPE_M48T201) > + tm->tm_year += (bcd2bin(M48T59_READ(M48T59_CENTURY))-19) * 100; > + else if ((pdata->type == M48T59RTC_TYPE_M48T59) && > + (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { > dev_dbg(dev, "Century bit is enabled\n"); > tm->tm_year += 100; /* one century */ > } > @@ -101,8 +103,8 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) > M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); > spin_unlock_irqrestore(&m48t59->lock, flags); > > - dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d/%02d/%02d\n", > - tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, > + dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d:%02d:%02d\n", > + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, > tm->tm_hour, tm->tm_min, tm->tm_sec); > return 0; > } > @@ -121,8 +123,8 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) > year -= 68; > #endif > > - dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n", > - year + 1900, tm->tm_mon, tm->tm_mday, > + dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d:%02d:%02d\n", > + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, > tm->tm_hour, tm->tm_min, tm->tm_sec); > > if (year < 0) > @@ -139,11 +141,17 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) > /* tm_mon is 0-11 */ > M48T59_WRITE((bin2bcd(tm->tm_mon + 1) & 0x1F), M48T59_MONTH); > M48T59_WRITE(bin2bcd(year % 100), M48T59_YEAR); > - > - if (pdata->type == M48T59RTC_TYPE_M48T59 && (year / 100)) > - val = (M48T59_WDAY_CEB | M48T59_WDAY_CB); > + if (pdata->type == M48T59RTC_TYPE_M48T59) { > + /* The Century Enable Bit must be set regardless of whether > + * the Century Bit is set, otherwise the clock would advance > + * from 31-Dec-1999 to 1-Jan-1900. > + */ > + val = M48T59_WDAY_CEB | (year >= 100 ? M48T59_WDAY_CB : 0); > + } > val |= (bin2bcd(tm->tm_wday) & 0x07); > M48T59_WRITE(val, M48T59_WDAY); > + if (pdata->type == M48T59RTC_TYPE_M48T201) > + M48T59_WRITE(bin2bcd(year / 100 + 19), M48T59_CENTURY); > > /* Clear the WRITE bit */ > M48T59_CLEAR_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); > @@ -177,10 +185,15 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) > tm->tm_year += 68; > #endif > /* tm_mon is 0-11 */ > - tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1; > + if (pdata->type == M48T59RTC_TYPE_M48T201) > + tm->tm_mon = bcd2bin(M48T59_READ(M48T59_INTR) & 0x1f) - 1; > + else > + tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1; > > val = M48T59_READ(M48T59_WDAY); > - if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) > + if (pdata->type == M48T59RTC_TYPE_M48T201) > + tm->tm_year += (bcd2bin(M48T59_READ(M48T59_CENTURY))-19) * 100; > + else if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) > tm->tm_year += 100; /* one century */ > > tm->tm_mday = bcd2bin(M48T59_READ(M48T59_ALARM_DATE)); > @@ -192,8 +205,8 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) > M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); > spin_unlock_irqrestore(&m48t59->lock, flags); > > - dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d/%02d/%02d\n", > - tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, > + dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d:%02d:%02d\n", > + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, > tm->tm_hour, tm->tm_min, tm->tm_sec); > return 0; > } > @@ -228,6 +241,10 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) > */ > mday = tm->tm_mday; > mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff; > + /* > + * FIXME: this is wrong when we're setting an alarm to go off after > + * midnight tonight. The alarm will never happen. > + */ > if (mday == 0xff) > mday = M48T59_READ(M48T59_MDAY); > > @@ -244,6 +261,10 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) > /* Issue the WRITE command */ > M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); > > + if (pdata->type == M48T59RTC_TYPE_M48T201) > + M48T59_WRITE((M48T59_READ(M48T59_INTR) & 0xe0) | > + (bin2bcd(tm->tm_mon + 1) & 0x1f), > + M48T59_INTR); > M48T59_WRITE(mday, M48T59_ALARM_DATE); > M48T59_WRITE(hour, M48T59_ALARM_HOUR); > M48T59_WRITE(min, M48T59_ALARM_MIN); > @@ -253,8 +274,8 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) > M48T59_CLEAR_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); > spin_unlock_irqrestore(&m48t59->lock, flags); > > - dev_dbg(dev, "RTC set alarm time %04d-%02d-%02d %02d/%02d/%02d\n", > - year + 1900, tm->tm_mon, tm->tm_mday, > + dev_dbg(dev, "RTC set alarm time %04d-%02d-%02d %02d:%02d:%02d\n", > + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, > tm->tm_hour, tm->tm_min, tm->tm_sec); > return 0; > } > @@ -272,12 +293,16 @@ static int m48t59_rtc_ioctl(struct device *dev, unsigned int cmd, > int ret = 0; > > spin_lock_irqsave(&m48t59->lock, flags); > + /* > + * Preserve the other fields in M48T59_INTR in case it's an M48T201 > + * and they contain the alarm month. > + */ > switch (cmd) { > case RTC_AIE_OFF: /* alarm interrupt off */ > - M48T59_WRITE(0x00, M48T59_INTR); > + M48T59_CLEAR_BITS(M48T59_INTR_AFE, M48T59_INTR); > break; > case RTC_AIE_ON: /* alarm interrupt on */ > - M48T59_WRITE(M48T59_INTR_AFE, M48T59_INTR); > + M48T59_SET_BITS(M48T59_INTR_AFE, M48T59_INTR); > break; > default: > ret = -ENOIOCTLCMD; > @@ -475,6 +500,11 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) > ops = &m48t02_rtc_ops; > pdata->offset = 0x1ff0; > break; > + case M48T59RTC_TYPE_M48T201: > + name = "m48t201"; > + ops = &m48t59_rtc_ops; > + pdata->offset = 0x7fff0; > + break; > default: > dev_err(&pdev->dev, "Unknown RTC type\n"); > ret = -ENODEV; > @@ -502,7 +532,7 @@ out: > rtc_device_unregister(m48t59->rtc); > if (m48t59->irq != NO_IRQ) > free_irq(m48t59->irq, &pdev->dev); > - if (m48t59->ioaddr) > + if (m48t59->ioaddr && !pdata->ioaddr) > iounmap(m48t59->ioaddr); > if (m48t59) > kfree(m48t59); > diff --git a/include/linux/rtc/m48t59.h b/include/linux/rtc/m48t59.h > index 6fc9614..8e2df6f 100644 > --- a/include/linux/rtc/m48t59.h > +++ b/include/linux/rtc/m48t59.h > @@ -38,7 +38,7 @@ > #define M48T59_ALARM_HOUR 0x4 > #define M48T59_ALARM_MIN 0x3 > #define M48T59_ALARM_SEC 0x2 > -#define M48T59_UNUSED 0x1 > +#define M48T59_CENTURY 0x1 /* Century (M48T201 only) */ > #define M48T59_FLAGS 0x0 > #define M48T59_FLAGS_WDT 0x80 /* watchdog timer expired */ > #define M48T59_FLAGS_AF 0x40 /* alarm */ > @@ -47,6 +47,7 @@ > #define M48T59RTC_TYPE_M48T59 0 /* to keep compatibility */ > #define M48T59RTC_TYPE_M48T02 1 > #define M48T59RTC_TYPE_M48T08 2 > +#define M48T59RTC_TYPE_M48T201 3 > > struct m48t59_plat_data { > /* The method to access M48T59 registers */ > > --~--~---------~--~----~------------~-------~--~----~ > You received this message because you are subscribed to "rtc-linux". > Membership options at http://groups.google.com/group/rtc-linux . > Please read http://groups.google.com/group/rtc-linux/web/checklist > before submitting a driver. > -~----------~----~----~----~------~----~------~--~--- >
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 33921a6..c06e88f 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -82,8 +82,10 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_mday = bcd2bin(M48T59_READ(M48T59_MDAY)); val = M48T59_READ(M48T59_WDAY); - if ((pdata->type == M48T59RTC_TYPE_M48T59) && - (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { + if (pdata->type == M48T59RTC_TYPE_M48T201) + tm->tm_year += (bcd2bin(M48T59_READ(M48T59_CENTURY))-19) * 100; + else if ((pdata->type == M48T59RTC_TYPE_M48T59) && + (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) { dev_dbg(dev, "Century bit is enabled\n"); tm->tm_year += 100; /* one century */ } @@ -101,8 +103,8 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); spin_unlock_irqrestore(&m48t59->lock, flags); - dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d/%02d/%02d\n", - tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, + dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d:%02d:%02d\n", + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); return 0; } @@ -121,8 +123,8 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) year -= 68; #endif - dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n", - year + 1900, tm->tm_mon, tm->tm_mday, + dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d:%02d:%02d\n", + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); if (year < 0) @@ -139,11 +141,17 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) /* tm_mon is 0-11 */ M48T59_WRITE((bin2bcd(tm->tm_mon + 1) & 0x1F), M48T59_MONTH); M48T59_WRITE(bin2bcd(year % 100), M48T59_YEAR); - - if (pdata->type == M48T59RTC_TYPE_M48T59 && (year / 100)) - val = (M48T59_WDAY_CEB | M48T59_WDAY_CB); + if (pdata->type == M48T59RTC_TYPE_M48T59) { + /* The Century Enable Bit must be set regardless of whether + * the Century Bit is set, otherwise the clock would advance + * from 31-Dec-1999 to 1-Jan-1900. + */ + val = M48T59_WDAY_CEB | (year >= 100 ? M48T59_WDAY_CB : 0); + } val |= (bin2bcd(tm->tm_wday) & 0x07); M48T59_WRITE(val, M48T59_WDAY); + if (pdata->type == M48T59RTC_TYPE_M48T201) + M48T59_WRITE(bin2bcd(year / 100 + 19), M48T59_CENTURY); /* Clear the WRITE bit */ M48T59_CLEAR_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); @@ -177,10 +185,15 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) tm->tm_year += 68; #endif /* tm_mon is 0-11 */ - tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1; + if (pdata->type == M48T59RTC_TYPE_M48T201) + tm->tm_mon = bcd2bin(M48T59_READ(M48T59_INTR) & 0x1f) - 1; + else + tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1; val = M48T59_READ(M48T59_WDAY); - if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) + if (pdata->type == M48T59RTC_TYPE_M48T201) + tm->tm_year += (bcd2bin(M48T59_READ(M48T59_CENTURY))-19) * 100; + else if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) tm->tm_year += 100; /* one century */ tm->tm_mday = bcd2bin(M48T59_READ(M48T59_ALARM_DATE)); @@ -192,8 +205,8 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); spin_unlock_irqrestore(&m48t59->lock, flags); - dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d/%02d/%02d\n", - tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, + dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d:%02d:%02d\n", + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); return 0; } @@ -228,6 +241,10 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) */ mday = tm->tm_mday; mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff; + /* + * FIXME: this is wrong when we're setting an alarm to go off after + * midnight tonight. The alarm will never happen. + */ if (mday == 0xff) mday = M48T59_READ(M48T59_MDAY); @@ -244,6 +261,10 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) /* Issue the WRITE command */ M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); + if (pdata->type == M48T59RTC_TYPE_M48T201) + M48T59_WRITE((M48T59_READ(M48T59_INTR) & 0xe0) | + (bin2bcd(tm->tm_mon + 1) & 0x1f), + M48T59_INTR); M48T59_WRITE(mday, M48T59_ALARM_DATE); M48T59_WRITE(hour, M48T59_ALARM_HOUR); M48T59_WRITE(min, M48T59_ALARM_MIN); @@ -253,8 +274,8 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) M48T59_CLEAR_BITS(M48T59_CNTL_WRITE, M48T59_CNTL); spin_unlock_irqrestore(&m48t59->lock, flags); - dev_dbg(dev, "RTC set alarm time %04d-%02d-%02d %02d/%02d/%02d\n", - year + 1900, tm->tm_mon, tm->tm_mday, + dev_dbg(dev, "RTC set alarm time %04d-%02d-%02d %02d:%02d:%02d\n", + tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); return 0; } @@ -272,12 +293,16 @@ static int m48t59_rtc_ioctl(struct device *dev, unsigned int cmd, int ret = 0; spin_lock_irqsave(&m48t59->lock, flags); + /* + * Preserve the other fields in M48T59_INTR in case it's an M48T201 + * and they contain the alarm month. + */ switch (cmd) { case RTC_AIE_OFF: /* alarm interrupt off */ - M48T59_WRITE(0x00, M48T59_INTR); + M48T59_CLEAR_BITS(M48T59_INTR_AFE, M48T59_INTR); break; case RTC_AIE_ON: /* alarm interrupt on */ - M48T59_WRITE(M48T59_INTR_AFE, M48T59_INTR); + M48T59_SET_BITS(M48T59_INTR_AFE, M48T59_INTR); break; default: ret = -ENOIOCTLCMD; @@ -475,6 +500,11 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) ops = &m48t02_rtc_ops; pdata->offset = 0x1ff0; break; + case M48T59RTC_TYPE_M48T201: + name = "m48t201"; + ops = &m48t59_rtc_ops; + pdata->offset = 0x7fff0; + break; default: dev_err(&pdev->dev, "Unknown RTC type\n"); ret = -ENODEV; @@ -502,7 +532,7 @@ out: rtc_device_unregister(m48t59->rtc); if (m48t59->irq != NO_IRQ) free_irq(m48t59->irq, &pdev->dev); - if (m48t59->ioaddr) + if (m48t59->ioaddr && !pdata->ioaddr) iounmap(m48t59->ioaddr); if (m48t59) kfree(m48t59); diff --git a/include/linux/rtc/m48t59.h b/include/linux/rtc/m48t59.h index 6fc9614..8e2df6f 100644 --- a/include/linux/rtc/m48t59.h +++ b/include/linux/rtc/m48t59.h @@ -38,7 +38,7 @@ #define M48T59_ALARM_HOUR 0x4 #define M48T59_ALARM_MIN 0x3 #define M48T59_ALARM_SEC 0x2 -#define M48T59_UNUSED 0x1 +#define M48T59_CENTURY 0x1 /* Century (M48T201 only) */ #define M48T59_FLAGS 0x0 #define M48T59_FLAGS_WDT 0x80 /* watchdog timer expired */ #define M48T59_FLAGS_AF 0x40 /* alarm */ @@ -47,6 +47,7 @@ #define M48T59RTC_TYPE_M48T59 0 /* to keep compatibility */ #define M48T59RTC_TYPE_M48T02 1 #define M48T59RTC_TYPE_M48T08 2 +#define M48T59RTC_TYPE_M48T201 3 struct m48t59_plat_data { /* The method to access M48T59 registers */
rtc-m48t59: add support for the M48T201 chip. Also: Fix a bug in m48t59_rtc_probe failure return that would iounmap an address that hadn't been ioremapped. Fix a Y2K bug for the M48T59: 31-Dec-1999 would step to 1-Jan-1900. Fix diagnostic outputs to show the date correctly. Add a FIXME comment describing a likely bug in alarm-setting code. Signed-off-by: Andrew Klossner <andrew@cesa.opbu.xerox.com> --- --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to "rtc-linux". Membership options at http://groups.google.com/group/rtc-linux . Please read http://groups.google.com/group/rtc-linux/web/checklist before submitting a driver. -~----------~----~----~----~------~----~------~--~---