[i2c] [PATCH] DS1339: oscillator code added.

David Brownell david-b at pacbell.net
Mon Jun 25 19:40:31 CEST 2007


On Tuesday 19 June 2007, Rodolfo Giometti wrote:
> --- a/drivers/rtc/rtc-ds1307.c
> +++ b/drivers/rtc/rtc-ds1307.c
> @@ -292,10 +292,12 @@ static int __devinit ds1307_probe(struct i2c_client *client)
>  		/* 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;
> +			dev_info(&client->dev,
> +				"oscillator is off. Turned on!\n");
> +			i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
> +				ds1307->regs[0] & ~DS1337_BIT_nEOSC);

Docs don't couple nEOSC with OSF that tightly though...

> +			i2c_smbus_write_byte_data(client, DS1337_REG_STATUS,
> +				ds1307->regs[1] & ~DS1337_BIT_OSF);

... because OSF can be set (and thus need a warning) even
if the oscillator got started again, or didn't stop.  For
example, first time powerup, Vcc too low, noise.


>  		}
>  		break;
>  	default:
> @@ -331,7 +333,9 @@ read_rtc:
>  	case ds_1340:
>  		/* FIXME write code to start the oscillator */
>  		if (tmp & DS1307_BIT_CH)
> -			goto no_osc_start;
> +			printk(KERN_ERR "no %s oscillator code\n",
> +				chip->name);
> +			goto exit_free;

Notice that this is missing brackets, and thus would prevent
a ds1340 from *ever* working ...


>  		break;
>  	default:
>  		break;

Try the appended patch instead.  Not only does it fix those bugs,
but it handles DS1338 and DS1340 oscillator issues better too.

- Dave

============	CUT HERE
From: Rodolfo Giometti <giometti at enneenne.com>

When we find a ds1337 or ds1339 with the oscillator powered off,
turn it on; and if the oscillator fault flag was set, clear it
and warn that the clock needs to be set.

Signed-off-by: Rodolfo Giometti <giometti at linux.it>

Bugfixes; provide corresponding update for DS1338.  Use a common
warning message ("SET TIME!") whenever the clock needs to be set
after oscillator fault (or enable, if that's not separate status).

Signed-off-by: David Brownell <dbrownell at users.sourceforge.net>
---
Applies on top of the ds1307 cleanup patch that's now in MM.

 drivers/rtc/rtc-ds1307.c |   55 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 19 deletions(-)

--- at91.orig/drivers/rtc/rtc-ds1307.c	2007-06-25 09:56:11.000000000 -0700
+++ at91/drivers/rtc/rtc-ds1307.c	2007-06-25 10:26:43.000000000 -0700
@@ -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
@@ -296,11 +297,10 @@ ds1307_detect(struct i2c_adapter *adapte
 	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 +311,16 @@ ds1307_detect(struct i2c_adapter *adapte
 		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 +343,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 +396,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)) {




More information about the i2c mailing list