Commit cbb94502 authored by Atsushi Nemoto's avatar Atsushi Nemoto Committed by Linus Torvalds

[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: default avatarAtsushi Nemoto <anemo@mba.ocn.ne.jp>
Cc: Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@teamlog.com>
Cc: <stable@kernel.org>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 68a696a0
...@@ -53,6 +53,25 @@ I2C_CLIENT_INSMOD; ...@@ -53,6 +53,25 @@ I2C_CLIENT_INSMOD;
#define PCF8563_SC_LV 0x80 /* low voltage */ #define PCF8563_SC_LV 0x80 /* low voltage */
#define PCF8563_MO_C 0x80 /* century */ #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_probe(struct i2c_adapter *adapter, int address, int kind);
static int pcf8563_detach(struct i2c_client *client); static int pcf8563_detach(struct i2c_client *client);
...@@ -62,6 +81,7 @@ 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) 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 }; unsigned char buf[13] = { PCF8563_REG_ST1 };
struct i2c_msg msgs[] = { struct i2c_msg msgs[] = {
...@@ -94,8 +114,12 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) ...@@ -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_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F);
tm->tm_wday = buf[PCF8563_REG_DW] & 0x07; tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */ tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]) tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]);
+ (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 0 : 100); 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, " dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n", "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) ...@@ -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) 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; int i, err;
unsigned char buf[9]; unsigned char buf[9];
...@@ -135,7 +160,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm) ...@@ -135,7 +160,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
/* year and century */ /* year and century */
buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100); 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_MO] |= PCF8563_MO_C;
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
...@@ -248,6 +273,7 @@ static struct i2c_driver pcf8563_driver = { ...@@ -248,6 +273,7 @@ static struct i2c_driver pcf8563_driver = {
static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
{ {
struct pcf8563 *pcf8563;
struct i2c_client *client; struct i2c_client *client;
struct rtc_device *rtc; struct rtc_device *rtc;
...@@ -260,11 +286,12 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) ...@@ -260,11 +286,12 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
goto exit; goto exit;
} }
if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) {
err = -ENOMEM; err = -ENOMEM;
goto exit; goto exit;
} }
client = &pcf8563->client;
client->addr = address; client->addr = address;
client->driver = &pcf8563_driver; client->driver = &pcf8563_driver;
client->adapter = adapter; client->adapter = adapter;
...@@ -301,7 +328,7 @@ exit_detach: ...@@ -301,7 +328,7 @@ exit_detach:
i2c_detach_client(client); i2c_detach_client(client);
exit_kfree: exit_kfree:
kfree(client); kfree(pcf8563);
exit: exit:
return err; return err;
...@@ -309,6 +336,7 @@ exit: ...@@ -309,6 +336,7 @@ exit:
static int pcf8563_detach(struct i2c_client *client) static int pcf8563_detach(struct i2c_client *client)
{ {
struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
int err; int err;
struct rtc_device *rtc = i2c_get_clientdata(client); struct rtc_device *rtc = i2c_get_clientdata(client);
...@@ -318,7 +346,7 @@ static int pcf8563_detach(struct i2c_client *client) ...@@ -318,7 +346,7 @@ static int pcf8563_detach(struct i2c_client *client)
if ((err = i2c_detach_client(client))) if ((err = i2c_detach_client(client)))
return err; return err;
kfree(client); kfree(pcf8563);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment