summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2007-02-03 23:16:36 +0900
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-23 16:24:25 -0800
commit0b141b1ffd0271eccd6d84633a05b41cde6b1f20 (patch)
tree48155c77ab430e64c1b71e1d31d90f1a301b949c
parent38141b5aa58969bd3dcd8259711b99fd64c8963b (diff)
rtc-pcf8563: detect polarity of century bit automatically
The usage of the century bit was inverted on 2.6.19 following to PCF8563's description, but it was not match to usage suggested by RTC8564's datasheet. Anyway what MO_C=1 means can vary on each platform. This patch is to detect its polarity in get_datetime routine. The default value of c_polarity is 0 (MO_C=1 means 19xx) so that this patch does not change current behavior even if get_datetime was not called before set_datetime. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Cc: Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@teamlog.com> Cc: David Brownell <dbrownell@users.sourceforge.net> Cc: Alessandro Zummo <a.zummo@towertech.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/rtc/rtc-pcf8563.c40
1 files changed, 34 insertions, 6 deletions
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index a760cf69af90..5842a4833d06 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -53,6 +53,25 @@ I2C_CLIENT_INSMOD;
#define PCF8563_SC_LV 0x80 /* low voltage */
#define PCF8563_MO_C 0x80 /* century */
+struct pcf8563 {
+ struct i2c_client client;
+ /*
+ * The meaning of MO_C bit varies by the chip type.
+ * From PCF8563 datasheet: this bit is toggled when the years
+ * register overflows from 99 to 00
+ * 0 indicates the century is 20xx
+ * 1 indicates the century is 19xx
+ * From RTC8564 datasheet: this bit indicates change of
+ * century. When the year digit data overflows from 99 to 00,
+ * this bit is set. By presetting it to 0 while still in the
+ * 20th century, it will be set in year 2000, ...
+ * There seems no reliable way to know how the system use this
+ * bit. So let's do it heuristically, assuming we are live in
+ * 1970...2069.
+ */
+ int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
+};
+
static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind);
static int pcf8563_detach(struct i2c_client *client);
@@ -62,6 +81,7 @@ static int pcf8563_detach(struct i2c_client *client);
*/
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
unsigned char buf[13] = { PCF8563_REG_ST1 };
struct i2c_msg msgs[] = {
@@ -94,8 +114,12 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F);
tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
- tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR])
- + (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 0 : 100);
+ tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]);
+ if (tm->tm_year < 70)
+ tm->tm_year += 100; /* assume we are in 1970...2069 */
+ /* detect the polarity heuristically. see note above. */
+ pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
+ (tm->tm_year >= 100) : (tm->tm_year < 100);
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -114,6 +138,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
int i, err;
unsigned char buf[9];
@@ -135,7 +160,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
/* year and century */
buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100);
- if (tm->tm_year < 100)
+ if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
@@ -248,6 +273,7 @@ static struct i2c_driver pcf8563_driver = {
static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
{
+ struct pcf8563 *pcf8563;
struct i2c_client *client;
struct rtc_device *rtc;
@@ -260,11 +286,12 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
goto exit;
}
- if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+ if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
+ client = &pcf8563->client;
client->addr = address;
client->driver = &pcf8563_driver;
client->adapter = adapter;
@@ -301,7 +328,7 @@ exit_detach:
i2c_detach_client(client);
exit_kfree:
- kfree(client);
+ kfree(pcf8563);
exit:
return err;
@@ -309,6 +336,7 @@ exit:
static int pcf8563_detach(struct i2c_client *client)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
@@ -318,7 +346,7 @@ static int pcf8563_detach(struct i2c_client *client)
if ((err = i2c_detach_client(client)))
return err;
- kfree(client);
+ kfree(pcf8563);
return 0;
}