From be5f59f4b67fbd4de26802a291bbcc2c623302b7 Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Tue, 17 Jul 2007 04:05:06 -0700 Subject: [PATCH] rtc-ds1307: oscillator restart for ds13{37,38,39,40} When we find a ds1337 or ds1339 with the oscillator powered off, turn it on. If the oscillator fault flag was set, clear it and warn that the clock needs to be set. David Brownell: Bugfixes; provide corresponding update for ds1338, and the core of the fix for ds1340. Use a common warning message ("SET TIME!") whenever the clock needs to be set after oscillator fault (or oscillator enable, if fault is not a separate status). Signed-off-by: Rodolfo Giometti Signed-off-by: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ds1307.c | 66 +++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 75e30c6a7d..5306a1a5b8 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -52,6 +52,7 @@ I2C_CLIENT_INSMOD; /* RTC registers don't differ much, except for the century flag */ #define DS1307_REG_SECS 0x00 /* 00-59 */ # define DS1307_BIT_CH 0x80 +# define DS1340_BIT_nEOSC 0x80 #define DS1307_REG_MIN 0x01 /* 00-59 */ #define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */ # define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */ @@ -68,7 +69,7 @@ I2C_CLIENT_INSMOD; */ #define DS1307_REG_CONTROL 0x07 /* or ds1338 */ # define DS1307_BIT_OUT 0x80 -# define DS1338_BIT_STOP 0x20 +# define DS1338_BIT_OSF 0x20 # define DS1307_BIT_SQWE 0x10 # define DS1307_BIT_RS1 0x02 # define DS1307_BIT_RS0 0x01 @@ -84,8 +85,8 @@ I2C_CLIENT_INSMOD; # define DS1340_BIT_FT 0x40 # define DS1340_BIT_CALIB_SIGN 0x20 # define DS1340_M_CALIBRATION 0x1f -#define DS1338_REG_FLAG 0x09 -# define DS1338_BIT_OSF 0x80 +#define DS1340_REG_FLAG 0x09 +# define DS1340_BIT_OSF 0x80 #define DS1337_REG_STATUS 0x0f # define DS1337_BIT_OSF 0x80 # define DS1337_BIT_A2I 0x02 @@ -215,11 +216,18 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) tmp = t->tm_year - 100; buf[DS1307_REG_YEAR] = BIN2BCD(tmp); - if (ds1307->type == ds_1337) + switch (ds1307->type) { + case ds_1337: + case ds_1339: buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY; - else if (ds1307->type == ds_1340) + break; + case ds_1340: buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN | DS1340_BIT_CENTURY; + break; + default: + break; + } ds1307->msg[1].flags = 0; ds1307->msg[1].len = 8; @@ -296,11 +304,10 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind) switch (ds1307->type) { case ds_1337: case ds_1339: - ds1307->type = ds_1337; - ds1307->reg_addr = DS1337_REG_CONTROL; ds1307->msg[1].len = 2; + /* get registers that the "rtc" read below won't read... */ tmp = i2c_transfer(adapter, ds1307->msg, 2); if (tmp != 2) { pr_debug("read error %d\n", tmp); @@ -311,13 +318,16 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind) ds1307->reg_addr = 0; ds1307->msg[1].len = sizeof(ds1307->regs); - /* oscillator is off; need to turn it on */ - if ((ds1307->regs[0] & DS1337_BIT_nEOSC) - || (ds1307->regs[1] & DS1337_BIT_OSF)) { -no_osc_start: - printk(KERN_ERR "no %s oscillator code\n", - chip->name); - goto exit_free; + /* oscillator off? turn it on, so clock can tick. */ + if (ds1307->regs[0] & DS1337_BIT_nEOSC) + i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, + ds1307->regs[0] & ~DS1337_BIT_nEOSC); + + /* oscillator fault? clear flag, and warn */ + if (ds1307->regs[1] & DS1337_BIT_OSF) { + i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, + ds1307->regs[1] & ~DS1337_BIT_OSF); + dev_warn(&client->dev, "SET TIME!\n"); } break; default: @@ -340,20 +350,33 @@ read_rtc: */ tmp = ds1307->regs[DS1307_REG_SECS]; switch (ds1307->type) { + case ds_1340: + /* FIXME read register with DS1340_BIT_OSF, use that to + * trigger the "set time" warning (*after* restarting the + * oscillator!) instead of this weaker ds1307/m41t00 test. + */ case ds_1307: - case ds_1338: case m41t00: + /* clock halted? turn it on, so clock can tick. */ if (tmp & DS1307_BIT_CH) { - i2c_smbus_write_byte_data(client, 0, 0); - dev_warn(&client->dev, - "oscillator started; SET TIME!\n"); + i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0); + dev_warn(&client->dev, "SET TIME!\n"); goto read_rtc; } break; - case ds_1340: - /* FIXME write code to start the oscillator */ + case ds_1338: + /* clock halted? turn it on, so clock can tick. */ if (tmp & DS1307_BIT_CH) - goto no_osc_start; + i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0); + + /* oscillator fault? clear flag, and warn */ + if (ds1307->regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) { + i2c_smbus_write_byte_data(client, DS1307_REG_CONTROL, + ds1307->regs[DS1337_REG_CONTROL] + & ~DS1338_BIT_OSF); + dev_warn(&client->dev, "SET TIME!\n"); + goto read_rtc; + } break; default: break; @@ -380,6 +403,7 @@ read_rtc: * * REVISIT forcing 24 hour mode can prevent multi-master * configs from sharing this RTC ... don't do this. + * The clock needs to be reset after changing it, too... */ tmp = ds1307->regs[DS1307_REG_HOUR]; if (tmp & (1 << 6)) { -- 2.39.5