From: Atsushi Nemoto Date: Thu, 8 Feb 2007 22:20:24 +0000 (-0800) Subject: [PATCH] rtc-pcf8563: detect polarity of century bit automatically X-Git-Tag: v2.6.21-rc1~83^2~24 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cbb9450234fb28f60fea36520cd710a988ac5812;p=linux-2.6 [PATCH] 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 Cc: Jean-Baptiste Maneyrol Cc: Cc: David Brownell Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 4b72b8ef5d..038118bbfa 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; }