diff options
Diffstat (limited to 'packages/linux/nslu2-kernel/2.6.15/35-x1205-fix-osc.patch')
-rw-r--r-- | packages/linux/nslu2-kernel/2.6.15/35-x1205-fix-osc.patch | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/packages/linux/nslu2-kernel/2.6.15/35-x1205-fix-osc.patch b/packages/linux/nslu2-kernel/2.6.15/35-x1205-fix-osc.patch new file mode 100644 index 0000000000..44f2636c5c --- /dev/null +++ b/packages/linux/nslu2-kernel/2.6.15/35-x1205-fix-osc.patch @@ -0,0 +1,204 @@ + drivers/i2c/chips/x1205.c | 116 ++++++++++++++++++++++++++++++---------------- + 1 file changed, 76 insertions(+), 40 deletions(-) + +--- linux-nslu2.orig/drivers/i2c/chips/x1205.c 2005-12-12 18:59:07.000000000 +0100 ++++ linux-nslu2/drivers/i2c/chips/x1205.c 2005-12-13 21:31:32.000000000 +0100 +@@ -22,9 +22,9 @@ + #include <linux/string.h> + #include <linux/bcd.h> + #include <linux/rtc.h> ++#include <linux/delay.h> + +- +-#define DRV_VERSION "1.0.0" ++#define DRV_VERSION "1.0.1" + + /* Addresses to scan: none. This chip is located at + * 0x6f and uses a two bytes register addressing. +@@ -141,35 +141,19 @@ static int x1205_validate_tm(struct rtc_ + * Epoch is initialized as 2000. Time is set to UTC. + */ + static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, +- u8 reg_base) ++ unsigned char reg_base) + { + unsigned char dt_addr[2] = { 0, reg_base }; +- static unsigned char sr_addr[2] = { 0, X1205_REG_SR }; + +- unsigned char buf[8], sr; ++ unsigned char buf[8]; + + struct i2c_msg msgs[] = { +- { client->addr, 0, 2, sr_addr }, /* setup read ptr */ +- { client->addr, I2C_M_RD, 1, &sr }, /* read status */ + { client->addr, 0, 2, dt_addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 8, buf }, /* read date */ + }; + +- /* read status register */ +- if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { +- dev_err(&client->dev, "%s: read error\n", __FUNCTION__); +- return -EIO; +- } +- +- /* check for battery failure */ +- if (sr & X1205_SR_RTCF) { +- dev_warn(&client->dev, +- "Clock had a power failure, you must set the date.\n"); +- return -EINVAL; +- } +- + /* read date registers */ +- if ((i2c_transfer(client->adapter, &msgs[2], 2)) != 2) { ++ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } +@@ -199,11 +183,28 @@ static int x1205_get_datetime(struct i2c + return 0; + } + ++static int x1205_get_status(struct i2c_client *client, unsigned char *sr) ++{ ++ static unsigned char sr_addr[2] = { 0, X1205_REG_SR }; ++ ++ struct i2c_msg msgs[] = { ++ { client->addr, 0, 2, sr_addr }, /* setup read ptr */ ++ { client->addr, I2C_M_RD, 1, sr }, /* read status */ ++ }; ++ ++ /* read status register */ ++ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { ++ dev_err(&client->dev, "%s: read error\n", __FUNCTION__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ + static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, + int datetoo, u8 reg_base) + { +- int i, err, xfer; +- ++ int i, xfer; + unsigned char buf[8]; + + static const unsigned char wel[3] = { 0, X1205_REG_SR, +@@ -214,15 +215,10 @@ static int x1205_set_datetime(struct i2c + + static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 }; + +- /* check if all values in the tm struct are correct */ +- if ((err = x1205_validate_tm(tm)) < 0) +- return err; +- +- dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " +- "mday=%d, mon=%d, year=%d, wday=%d\n", ++ dev_dbg(&client->dev, ++ "%s: secs=%d, mins=%d, hours=%d\n", + __FUNCTION__, +- tm->tm_sec, tm->tm_min, tm->tm_hour, +- tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); ++ tm->tm_sec, tm->tm_min, tm->tm_hour); + + buf[CCR_SEC] = BIN2BCD(tm->tm_sec); + buf[CCR_MIN] = BIN2BCD(tm->tm_min); +@@ -232,6 +228,11 @@ static int x1205_set_datetime(struct i2c + + /* should we also set the date? */ + if (datetoo) { ++ dev_dbg(&client->dev, ++ "%s: mday=%d, mon=%d, year=%d, wday=%d\n", ++ __FUNCTION__, ++ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); ++ + buf[CCR_MDAY] = BIN2BCD(tm->tm_mday); + + /* month, 0 - 11 */ +@@ -280,6 +281,22 @@ static int x1205_set_datetime(struct i2c + return 0; + } + ++static int x1205_fix_osc(struct i2c_client *client) ++{ ++ int err; ++ struct rtc_time tm; ++ ++ tm.tm_hour = 0; ++ tm.tm_min = 0; ++ tm.tm_sec = 0; ++ ++ if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0) ++ dev_err(&client->dev, ++ "unable to restart the clock\n"); ++ ++ return err; ++} ++ + static int x1205_get_dtrim(struct i2c_client *client, int *trim) + { + unsigned char dtr; +@@ -352,14 +369,17 @@ static int x1205_hctosys(struct i2c_clie + + struct rtc_time tm; + struct timespec tv; ++ unsigned char sr; + ++ if ((err = x1205_get_status(client, &sr)) < 0) ++ return err; + +- err = x1205_get_datetime(client, &tm, X1205_CCR_BASE); +- if (err) { +- dev_err(&client->dev, +- "Unable to set the system clock\n"); ++ /* Don't set if we had a power failure */ ++ if (sr & X1205_SR_RTCF) ++ return -EINVAL; ++ ++ if ((err = x1205_get_datetime(client, &tm, X1205_CCR_BASE)) < 0) + return err; +- } + + /* IMPORTANT: the RTC only stores whole seconds. It is arbitrary + * whether it stores the most close value or the value with partial +@@ -506,9 +526,9 @@ static int x1205_attach(struct i2c_adapt + + static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) + { +- struct i2c_client *client; +- + int err = 0; ++ unsigned char sr; ++ struct i2c_client *client; + + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); + +@@ -543,9 +563,25 @@ static int x1205_probe(struct i2c_adapte + + dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + ++ /* Check for power failures and eventualy enable the osc */ ++ if ((err = x1205_get_status(client, &sr)) == 0) { ++ if (sr & X1205_SR_RTCF) { ++ dev_err(&client->dev, ++ "power failure detected, " ++ "please set the clock\n"); ++ udelay(50); ++ x1205_fix_osc(client); ++ } ++ } ++ else ++ dev_err(&client->dev, "couldn't read status\n"); ++ + /* If requested, set the system time */ +- if (hctosys) +- x1205_hctosys(client); ++ if (hctosys) { ++ if ((err = x1205_hctosys(client)) < 0) ++ dev_err(&client->dev, ++ "unable to set the system clock\n"); ++ } + + return 0; + |