--- linux-2.6.15-rc5-pm854/drivers/i2c/chips/rtc8564.c.ori 2005-12-15 15:43:02.000000000 +0100
+++ linux-2.6.15-rc5-pm854/drivers/i2c/chips/rtc8564.c 2005-12-15 16:03:43.000000000 +0100
@@ -11,6 +11,7 @@
* published by the Free Software Foundation.
*
* Driver for system3's EPSON RTC 8564 chip
+ * this driver is also compatible to the Philips PCF 8563 chip
*/
#include <linux/module.h>
#include <linux/kernel.h>
@@ -35,9 +36,12 @@
struct rtc8564_data {
struct i2c_client client;
+ struct list_head list;
u16 ctrl;
};
+static LIST_HEAD(rtc8564_clients);
+
static inline u8 _rtc8564_ctrl1(struct i2c_client *client)
{
struct rtc8564_data *data = i2c_get_clientdata(client);
@@ -55,7 +59,7 @@ static inline u8 _rtc8564_ctrl2(struct i
#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
-static int debug;;
+static int debug;
module_param(debug, int, S_IRUGO | S_IWUSR);
static struct i2c_driver rtc8564_driver;
@@ -153,6 +157,8 @@ static int rtc8564_attach(struct i2c_ada
ret = -ENOMEM;
goto done;
}
+ INIT_LIST_HEAD(&d->list);
+
new_client = &d->client;
strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE);
@@ -188,6 +194,9 @@ static int rtc8564_attach(struct i2c_ada
data[0], data[1]);
ret = i2c_attach_client(new_client);
+ /* Add client to local list */
+ list_add(&d->list, &rtc8564_clients);
+
done:
if (ret) {
kfree(d);
@@ -202,8 +211,11 @@ static int rtc8564_probe(struct i2c_adap
static int rtc8564_detach(struct i2c_client *client)
{
+ struct rtc8564_data *data = i2c_get_clientdata(client);
+
i2c_detach_client(client);
kfree(i2c_get_clientdata(client));
+ list_del(&data->list);
return 0;
}
@@ -222,10 +234,25 @@ static int rtc8564_get_datetime(struct i
ret = rtc8564_read(client, 0, buf, 15);
if (ret)
return ret;
-
+#if 0
/* century stored in minute alarm reg */
dt->year = BCD_TO_BIN(buf[RTC8564_REG_YEAR]);
dt->year += 100 * BCD_TO_BIN(buf[RTC8564_REG_AL_MIN] & 0x3f);
+#endif
+ /* century stored in the century bit
+ * RTC8564 datasheet: his 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, but in fact the first year in the 21 century
+ * should be 2001.
+ * 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 */
+ dt->year = 1900 + BCD_TO_BIN(buf[RTC8564_REG_YEAR]);
+ if (buf[RTC8564_REG_MON_CENT] & 0x80)
+ dt->year += 100;
+
dt->mday = BCD_TO_BIN(buf[RTC8564_REG_DAY] & 0x3f);
dt->wday = BCD_TO_BIN(buf[RTC8564_REG_WDAY] & 7);
dt->mon = BCD_TO_BIN(buf[RTC8564_REG_MON_CENT] & 0x1f);
@@ -245,7 +272,8 @@ rtc8564_set_datetime(struct i2c_client *
{
int ret, len = 5;
unsigned char buf[15];
-
+ unsigned char val;
+
_DBG(1, "client=%p, dt=%p", client, dt);
if (!dt)
@@ -264,9 +292,19 @@ rtc8564_set_datetime(struct i2c_client *
buf[RTC8564_REG_DAY] = BIN_TO_BCD(dt->mday);
buf[RTC8564_REG_WDAY] = BIN_TO_BCD(dt->wday);
buf[RTC8564_REG_MON_CENT] = BIN_TO_BCD(dt->mon) & 0x1f;
+#if 0
/* century stored in minute alarm reg */
buf[RTC8564_REG_YEAR] = BIN_TO_BCD(dt->year % 100);
buf[RTC8564_REG_AL_MIN] = BIN_TO_BCD(dt->year / 100);
+#endif
+ /* century stored in the century bit */
+ if (dt->tm_year >= 2000) {
+ val = dt->tm_year - 2000;
+ buf[RTC8564_REG_MON_CENT] |= (1 << 7);
+ } else {
+ val = dt->tm_year - 1900;
+ }
+ buf[RTC8564_REG_YEAR] = BIN_TO_BCD(val);
}
ret = rtc8564_write(client, 0, buf, len);
@@ -360,6 +398,23 @@ rtc8564_command(struct i2c_client *clien
}
}
+/*
+ * Public API for access to specific device. Useful for low-level
+ * RTC access from kernel code.
+ */
+int rtc8564_do_command(int bus, int cmd, void *arg)
+{
+ struct list_head *walk;
+ struct list_head *tmp;
+ struct rtc8564_data *data;
+ list_for_each_safe(walk, tmp, &rtc8564_clients) {
+ data = list_entry(walk, struct rtc8564_data, list);
+ if (data->client.adapter->nr == bus)
+ return rtc8564_command(&data->client, cmd, arg);
+ }
+ return -ENODEV;
+}
+
static struct i2c_driver rtc8564_driver = {
.owner = THIS_MODULE,
.name = "RTC8564",
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index f9fae28..705675e 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -66,10 +66,11 @@ config SENSORS_PCF8591
will be called pcf8591.
config SENSORS_RTC8564
- tristate "Epson 8564 RTC chip"
+ tristate "Epson RTC8564 and Philips PCF8653 RTC chip"
depends on I2C && EXPERIMENTAL
help
- If you say yes here you get support for the Epson 8564 RTC chip.
+ If you say yes here you get support for the Epson 8564 RTC or
+ to the compatible Philips PCF8563 chip.
This driver can also be built as a module. If so, the module
will be called i2c-rtc8564.