[PATCH] x1205 fix osc on startup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Content-Disposition: inline; filename=i2c-x1205-fix-osc.patch

When the battery fails, the x1205 will refuse to run the oscillator
unless something is written to its date/time register.

On platforms where this driver is actually used (NSLU2), along with
a class based RTC core, the time is updated via /dev/rtc 
using the hwclock utility.

hwclock will wait for a seconds increment before writing the new
date/time and that's why this patch is required for it to work.

Requires i2c-x1205-cleanup.patch

Signed-off-by: Alessandro Zummo <a.zummo at towertech.it>
---
 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;
 




[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux