[lm-sensors] [PATCH] x1205 fix osc on startup
Alessandro Zummo
azummo-lists at towertech.it
Tue Dec 13 21:47:42 CET 2005
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;
More information about the lm-sensors
mailing list