Linux-RTC Archive on lore.kernel.org
 help / Atom feed
* [PATCH] rtc: rs5c372: Fix reading from rtc when the oscillator got interrupted.
@ 2019-01-11 13:15 Oliver.Rohe
  2019-02-05 21:55 ` Alexandre Belloni
  0 siblings, 1 reply; 4+ messages in thread
From: Oliver.Rohe @ 2019-01-11 13:15 UTC (permalink / raw)
  To: alexandre.belloni, a.zummo; +Cc: linux-rtc, linux-kernel, Oliver.Rohe

When the oscillator of the rtc gets interrupted,
e.g. due to an empty battery, reading from the rtc will now return an error
and the oscillator bit will be cleared, once the rtc is successfully reset.

Signed-off-by: Oliver Rohe <oliver.rohe@wago.com>
---
 drivers/rtc/rtc-rs5c372.c | 60 ++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 52 insertions(+), 8 deletions(-)

diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index ff35dce..91d1475 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -52,8 +52,10 @@
 #	define RS5C_CTRL1_CT4		(4 << 0)	/* 1 Hz level irq */
 #define RS5C_REG_CTRL2		15
 #	define RS5C372_CTRL2_24		(1 << 5)
-#	define R2x2x_CTRL2_XSTP		(1 << 5)	/* only if R2x2x */
-#	define RS5C_CTRL2_XSTP		(1 << 4)	/* only if !R2x2x */
+#	define RS5C_CTRL2_XSTP          (1 << 4)        /* only if !R2x2x */
+#	define R2x2x_CTRL2_VDET		(1 << 6)	/* only if  R2x2x */
+#	define R2x2x_CTRL2_XSTP		(1 << 5)	/* only if  R2x2x */
+#	define R2x2x_CTRL2_PON		(1 << 4)	/* only if  R2x2x */
 #	define RS5C_CTRL2_CTFG		(1 << 2)
 #	define RS5C_CTRL2_AAFG		(1 << 1)	/* or WAFG */
 #	define RS5C_CTRL2_BAFG		(1 << 0)	/* or DAFG */
@@ -212,10 +214,31 @@ static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm)
 	struct i2c_client *client = to_i2c_client(dev);
 	struct rs5c372	*rs5c = i2c_get_clientdata(client);
 	int		status = rs5c_get_regs(rs5c);
+	unsigned char ctrl2 = rs5c->regs[RS5C_REG_CTRL2];
 
 	if (status < 0)
 		return status;
 
+	switch (rs5c->type) {
+	case rtc_r2025sd:
+	case rtc_r2221tl:
+		if (ctrl2 & R2x2x_CTRL2_VDET)
+			dev_warn(&client->dev, "rtc battery voltage drop below threshold detected.\n");
+		if (ctrl2 & R2x2x_CTRL2_PON)
+			dev_warn(&client->dev, "rtc battery voltage drop to zero detected.\n");
+		if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) ||
+		    (rs5c->type == rtc_r2221tl &&  (ctrl2 & R2x2x_CTRL2_XSTP))) {
+			dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n");
+			return -EIO;
+		}
+		break;
+	default:
+		if (ctrl2 & RS5C_CTRL2_XSTP) {
+			dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n");
+			return -EIO;
+		}
+	}
+
 	tm->tm_sec = bcd2bin(rs5c->regs[RS5C372_REG_SECS] & 0x7f);
 	tm->tm_min = bcd2bin(rs5c->regs[RS5C372_REG_MINS] & 0x7f);
 	tm->tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C372_REG_HOURS]);
@@ -243,6 +266,7 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
 	struct i2c_client *client = to_i2c_client(dev);
 	struct rs5c372	*rs5c = i2c_get_clientdata(client);
 	unsigned char	buf[7];
+	unsigned char	ctrl2;
 	int		addr;
 
 	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
@@ -261,7 +285,32 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
 	buf[6] = bin2bcd(tm->tm_year - 100);
 
 	if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) {
-		dev_err(&client->dev, "%s: write error\n", __func__);
+		dev_dbg(&client->dev, "%s: write error in line %i\n",
+			__func__, __LINE__);
+		return -EIO;
+	}
+
+	addr = RS5C_ADDR(RS5C_REG_CTRL2);
+	ctrl2 = i2c_smbus_read_byte_data(client, addr);
+
+	/* clear rtc warning bits */
+	switch (rs5c->type) {
+	case rtc_r2025sd:
+	case rtc_r2221tl:
+		ctrl2 &= ~(R2x2x_CTRL2_VDET | R2x2x_CTRL2_PON);
+		if (rs5c->type == rtc_r2025sd)
+			ctrl2 |= R2x2x_CTRL2_XSTP;
+		else
+			ctrl2 &= ~R2x2x_CTRL2_XSTP;
+		break;
+	default:
+		ctrl2 &= ~RS5C_CTRL2_XSTP;
+		break;
+	}
+
+	if (i2c_smbus_write_byte_data(client, addr, ctrl2) < 0) {
+		dev_dbg(&client->dev, "%s: write error in line %i\n",
+			__func__, __LINE__);
 		return -EIO;
 	}
 
@@ -523,23 +572,18 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
 	buf[0] = rs5c372->regs[RS5C_REG_CTRL1];
 	buf[1] = rs5c372->regs[RS5C_REG_CTRL2];
 
-	/* handle xstp bit */
 	switch (rs5c372->type) {
 	case rtc_r2025sd:
 		if (buf[1] & R2x2x_CTRL2_XSTP)
 			return ret;
-		rs5c372->regs[RS5C_REG_CTRL2] |= R2x2x_CTRL2_XSTP;
 		break;
 	case rtc_r2221tl:
 		if (!(buf[1] & R2x2x_CTRL2_XSTP))
 			return ret;
-		rs5c372->regs[RS5C_REG_CTRL2] &= ~R2x2x_CTRL2_XSTP;
 		break;
-
 	default:
 		if (!(buf[1] & RS5C_CTRL2_XSTP))
 			return ret;
-		rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
 		break;
 	}
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] rtc: rs5c372: Fix reading from rtc when the oscillator got interrupted.
  2019-01-11 13:15 [PATCH] rtc: rs5c372: Fix reading from rtc when the oscillator got interrupted Oliver.Rohe
@ 2019-02-05 21:55 ` Alexandre Belloni
  2019-02-06  6:33   ` Oliver.Rohe
  0 siblings, 1 reply; 4+ messages in thread
From: Alexandre Belloni @ 2019-02-05 21:55 UTC (permalink / raw)
  To: Oliver.Rohe; +Cc: a.zummo, linux-rtc, linux-kernel

Hi,

On 11/01/2019 13:15:39+0000, Oliver.Rohe@wago.com wrote:
> When the oscillator of the rtc gets interrupted,
> e.g. due to an empty battery, reading from the rtc will now return an error
> and the oscillator bit will be cleared, once the rtc is successfully reset.
> 
> Signed-off-by: Oliver Rohe <oliver.rohe@wago.com>
> ---
>  drivers/rtc/rtc-rs5c372.c | 60 ++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 52 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
> index ff35dce..91d1475 100644
> --- a/drivers/rtc/rtc-rs5c372.c
> +++ b/drivers/rtc/rtc-rs5c372.c
> @@ -52,8 +52,10 @@
>  #	define RS5C_CTRL1_CT4		(4 << 0)	/* 1 Hz level irq */
>  #define RS5C_REG_CTRL2		15
>  #	define RS5C372_CTRL2_24		(1 << 5)
> -#	define R2x2x_CTRL2_XSTP		(1 << 5)	/* only if R2x2x */
> -#	define RS5C_CTRL2_XSTP		(1 << 4)	/* only if !R2x2x */
> +#	define RS5C_CTRL2_XSTP          (1 << 4)        /* only if !R2x2x */

This should probably use tabs instead of spaces

> +#	define R2x2x_CTRL2_VDET		(1 << 6)	/* only if  R2x2x */
> +#	define R2x2x_CTRL2_XSTP		(1 << 5)	/* only if  R2x2x */
> +#	define R2x2x_CTRL2_PON		(1 << 4)	/* only if  R2x2x */
>  #	define RS5C_CTRL2_CTFG		(1 << 2)
>  #	define RS5C_CTRL2_AAFG		(1 << 1)	/* or WAFG */
>  #	define RS5C_CTRL2_BAFG		(1 << 0)	/* or DAFG */
> @@ -212,10 +214,31 @@ static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm)
>  	struct i2c_client *client = to_i2c_client(dev);
>  	struct rs5c372	*rs5c = i2c_get_clientdata(client);
>  	int		status = rs5c_get_regs(rs5c);
> +	unsigned char ctrl2 = rs5c->regs[RS5C_REG_CTRL2];
>  
>  	if (status < 0)
>  		return status;
>  
> +	switch (rs5c->type) {
> +	case rtc_r2025sd:
> +	case rtc_r2221tl:
> +		if (ctrl2 & R2x2x_CTRL2_VDET)
> +			dev_warn(&client->dev, "rtc battery voltage drop below threshold detected.\n");

VDET doesn't mean anything specific regarding timekeeping so I wouldn't warn here.

> +		if (ctrl2 & R2x2x_CTRL2_PON)
> +			dev_warn(&client->dev, "rtc battery voltage drop to zero detected.\n");

You should return -EINVAL directly here

> +		if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) ||
> +		    (rs5c->type == rtc_r2221tl &&  (ctrl2 & R2x2x_CTRL2_XSTP))) {
> +			dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n");
> +			return -EIO;

-EINVAL is the correct error code here.

> +		}
> +		break;
> +	default:
> +		if (ctrl2 & RS5C_CTRL2_XSTP) {
> +			dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n");
> +			return -EIO;

and here.


-- 
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] rtc: rs5c372: Fix reading from rtc when the oscillator got interrupted.
  2019-02-05 21:55 ` Alexandre Belloni
@ 2019-02-06  6:33   ` Oliver.Rohe
  2019-02-06  9:58     ` Alexandre Belloni
  0 siblings, 1 reply; 4+ messages in thread
From: Oliver.Rohe @ 2019-02-06  6:33 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: a.zummo, linux-rtc, linux-kernel

Hi Alexandre,

thanks a lot!!

On 05.02.19 22:55, Alexandre Belloni wrote:
> Hi,
> 
> On 11/01/2019 13:15:39+0000, Oliver.Rohe@wago.com wrote:
>> When the oscillator of the rtc gets interrupted,
>> e.g. due to an empty battery, reading from the rtc will now return an error
>> and the oscillator bit will be cleared, once the rtc is successfully reset.
>>
>> Signed-off-by: Oliver Rohe <oliver.rohe@wago.com>
>> ---
>>  drivers/rtc/rtc-rs5c372.c | 60 ++++++++++++++++++++++++++++++++++++++++-------
>>  1 file changed, 52 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
>> index ff35dce..91d1475 100644
>> --- a/drivers/rtc/rtc-rs5c372.c
>> +++ b/drivers/rtc/rtc-rs5c372.c
>> @@ -52,8 +52,10 @@
>>  #	define RS5C_CTRL1_CT4		(4 << 0)	/* 1 Hz level irq */
>>  #define RS5C_REG_CTRL2		15
>>  #	define RS5C372_CTRL2_24		(1 << 5)
>> -#	define R2x2x_CTRL2_XSTP		(1 << 5)	/* only if R2x2x */
>> -#	define RS5C_CTRL2_XSTP		(1 << 4)	/* only if !R2x2x */
>> +#	define RS5C_CTRL2_XSTP          (1 << 4)        /* only if !R2x2x */
> 
> This should probably use tabs instead of spaces
:)

>> +#	define R2x2x_CTRL2_VDET		(1 << 6)	/* only if  R2x2x */
>> +#	define R2x2x_CTRL2_XSTP		(1 << 5)	/* only if  R2x2x */
>> +#	define R2x2x_CTRL2_PON		(1 << 4)	/* only if  R2x2x */
>>  #	define RS5C_CTRL2_CTFG		(1 << 2)
>>  #	define RS5C_CTRL2_AAFG		(1 << 1)	/* or WAFG */
>>  #	define RS5C_CTRL2_BAFG		(1 << 0)	/* or DAFG */
>> @@ -212,10 +214,31 @@ static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm)
>>  	struct i2c_client *client = to_i2c_client(dev);
>>  	struct rs5c372	*rs5c = i2c_get_clientdata(client);
>>  	int		status = rs5c_get_regs(rs5c);
>> +	unsigned char ctrl2 = rs5c->regs[RS5C_REG_CTRL2];
>>  
>>  	if (status < 0)
>>  		return status;
>>  
>> +	switch (rs5c->type) {
>> +	case rtc_r2025sd:
>> +	case rtc_r2221tl:
>> +		if (ctrl2 & R2x2x_CTRL2_VDET)
>> +			dev_warn(&client->dev, "rtc battery voltage drop below threshold detected.\n");
> 
> VDET doesn't mean anything specific regarding timekeeping so I wouldn't warn here.

VDET means in case the chip is powered by a battery, that is about to die sometime soon, it gives you heads up.
> 
>> +		if (ctrl2 & R2x2x_CTRL2_PON)
>> +			dev_warn(&client->dev, "rtc battery voltage drop to zero detected.\n");
> 
> You should return -EINVAL directly here

The PON implies the XSTP bit, so I only return from there, just to print all the warning messages, but I can return directly from here if you want.
> 
>> +		if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) ||
>> +		    (rs5c->type == rtc_r2221tl &&  (ctrl2 & R2x2x_CTRL2_XSTP))) {
>> +			dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n");
>> +			return -EIO;
> 
> -EINVAL is the correct error code here.

Ok
> 
>> +		}
>> +		break;
>> +	default:
>> +		if (ctrl2 & RS5C_CTRL2_XSTP) {
>> +			dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n");
>> +			return -EIO;
> 
> and here.

OK
> 
> 
^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] rtc: rs5c372: Fix reading from rtc when the oscillator got interrupted.
  2019-02-06  6:33   ` Oliver.Rohe
@ 2019-02-06  9:58     ` Alexandre Belloni
  0 siblings, 0 replies; 4+ messages in thread
From: Alexandre Belloni @ 2019-02-06  9:58 UTC (permalink / raw)
  To: Oliver.Rohe; +Cc: a.zummo, linux-rtc, linux-kernel

On 06/02/2019 06:33:39+0000, Oliver.Rohe@wago.com wrote:
> >> +	switch (rs5c->type) {
> >> +	case rtc_r2025sd:
> >> +	case rtc_r2221tl:
> >> +		if (ctrl2 & R2x2x_CTRL2_VDET)
> >> +			dev_warn(&client->dev, "rtc battery voltage drop below threshold detected.\n");
> > 
> > VDET doesn't mean anything specific regarding timekeeping so I wouldn't warn here.
> 
> VDET means in case the chip is powered by a battery, that is about to die sometime soon, it gives you heads up.

Yes but my statement stands true, this doesn't have any direct
implication regarding timekeeping.

There is the RTC_VL_READ ioctl to check voltage low. It is not weel
designed but this is what we have now.

> > 
> >> +		if (ctrl2 & R2x2x_CTRL2_PON)
> >> +			dev_warn(&client->dev, "rtc battery voltage drop to zero detected.\n");
> > 
> > You should return -EINVAL directly here
> 
> The PON implies the XSTP bit, so I only return from there, just to print all the warning messages, but I can return directly from here if you want.

As you said, PON implies XSTP so I'm not sure it is valuable to have both
warnings.


-- 
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, back to index

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-11 13:15 [PATCH] rtc: rs5c372: Fix reading from rtc when the oscillator got interrupted Oliver.Rohe
2019-02-05 21:55 ` Alexandre Belloni
2019-02-06  6:33   ` Oliver.Rohe
2019-02-06  9:58     ` Alexandre Belloni

Linux-RTC Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-rtc/0 linux-rtc/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-rtc linux-rtc/ https://lore.kernel.org/linux-rtc \
		linux-rtc@vger.kernel.org linux-rtc@archiver.kernel.org
	public-inbox-index linux-rtc


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-rtc


AGPL code for this site: git clone https://public-inbox.org/ public-inbox