Skip to content

Commit 3a1246b

Browse files
ukleinekgregkh
authored andcommitted
rtc: s35390a: improve irq handling
commit 3bd32722c827d00eafe8e6d5b83e9f3148ea7c7e upstream. On some QNAP NAS devices the rtc can wake the machine. Several people noticed that once the machine was woken this way it fails to shut down. That's because the driver fails to acknowledge the interrupt and so it keeps active and restarts the machine immediatly after shutdown. See https://bugs.debian.org/794266 for a bug report. Doing this correctly requires to interpret the INT2 flag of the first read of the STATUS1 register because this bit is cleared by read. Note this is not maximally robust though because a pending irq isn't detected when the STATUS1 register was already read (and so INT2 is not set) but the irq was not disabled. But that is a hardware imposed problem that cannot easily be fixed by software. Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a55ae9d commit 3a1246b

1 file changed

Lines changed: 31 additions & 17 deletions

File tree

drivers/rtc/rtc-s35390a.c

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,14 @@
3535
#define S35390A_ALRM_BYTE_HOURS 1
3636
#define S35390A_ALRM_BYTE_MINS 2
3737

38+
/* flags for STATUS1 */
3839
#define S35390A_FLAG_POC 0x01
3940
#define S35390A_FLAG_BLD 0x02
41+
#define S35390A_FLAG_INT2 0x04
4042
#define S35390A_FLAG_24H 0x40
4143
#define S35390A_FLAG_RESET 0x80
44+
45+
/* flag for STATUS2 */
4246
#define S35390A_FLAG_TEST 0x01
4347

4448
#define S35390A_INT2_MODE_MASK 0xF0
@@ -408,11 +412,11 @@ static struct i2c_driver s35390a_driver;
408412
static int s35390a_probe(struct i2c_client *client,
409413
const struct i2c_device_id *id)
410414
{
411-
int err;
415+
int err, err_reset;
412416
unsigned int i;
413417
struct s35390a *s35390a;
414418
struct rtc_time tm;
415-
char buf[1], status1;
419+
char buf, status1;
416420

417421
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
418422
err = -ENODEV;
@@ -441,29 +445,35 @@ static int s35390a_probe(struct i2c_client *client,
441445
}
442446
}
443447

444-
err = s35390a_reset(s35390a, &status1);
445-
if (err < 0) {
448+
err_reset = s35390a_reset(s35390a, &status1);
449+
if (err_reset < 0) {
450+
err = err_reset;
446451
dev_err(&client->dev, "error resetting chip\n");
447452
goto exit_dummy;
448453
}
449454

450-
err = s35390a_disable_test_mode(s35390a);
451-
if (err < 0) {
452-
dev_err(&client->dev, "error disabling test mode\n");
453-
goto exit_dummy;
454-
}
455-
456-
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
457-
if (err < 0) {
458-
dev_err(&client->dev, "error checking 12/24 hour mode\n");
459-
goto exit_dummy;
460-
}
461-
if (buf[0] & S35390A_FLAG_24H)
455+
if (status1 & S35390A_FLAG_24H)
462456
s35390a->twentyfourhour = 1;
463457
else
464458
s35390a->twentyfourhour = 0;
465459

466-
if (s35390a_get_datetime(client, &tm) < 0)
460+
if (status1 & S35390A_FLAG_INT2) {
461+
/* disable alarm (and maybe test mode) */
462+
buf = 0;
463+
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
464+
if (err < 0) {
465+
dev_err(&client->dev, "error disabling alarm");
466+
goto exit_dummy;
467+
}
468+
} else {
469+
err = s35390a_disable_test_mode(s35390a);
470+
if (err < 0) {
471+
dev_err(&client->dev, "error disabling test mode\n");
472+
goto exit_dummy;
473+
}
474+
}
475+
476+
if (err_reset > 0 || s35390a_get_datetime(client, &tm) < 0)
467477
dev_warn(&client->dev, "clock needs to be set\n");
468478

469479
device_set_wakeup_capable(&client->dev, 1);
@@ -476,6 +486,10 @@ static int s35390a_probe(struct i2c_client *client,
476486
err = PTR_ERR(s35390a->rtc);
477487
goto exit_dummy;
478488
}
489+
490+
if (status1 & S35390A_FLAG_INT2)
491+
rtc_update_irq(s35390a->rtc, 1, RTC_AF);
492+
479493
return 0;
480494

481495
exit_dummy:

0 commit comments

Comments
 (0)