Skip to content

Commit a55ae9d

Browse files
ukleinekgregkh
authored andcommitted
rtc: s35390a: implement reset routine as suggested by the reference
commit 8e6583f1b5d1f5f129b873f1428b7e414263d847 upstream. There were two deviations from the reference manual: you have to wait half a second when POC is active and you might have to repeat initialization when POC or BLD are still set after the sequence. Note however that as POC and BLD are cleared by read the driver might not be able to detect that a reset is necessary. I don't have a good idea how to fix this. Additionally report the value read from STATUS1 to the caller. This prepares the next patch. 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 fdd4bc9 commit a55ae9d

1 file changed

Lines changed: 55 additions & 10 deletions

File tree

drivers/rtc/rtc-s35390a.c

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/bitrev.h>
1616
#include <linux/bcd.h>
1717
#include <linux/slab.h>
18+
#include <linux/delay.h>
1819

1920
#define S35390A_CMD_STATUS1 0
2021
#define S35390A_CMD_STATUS2 1
@@ -94,19 +95,63 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
9495
return 0;
9596
}
9697

97-
static int s35390a_reset(struct s35390a *s35390a)
98+
/*
99+
* Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
100+
* To keep the information if an irq is pending, pass the value read from
101+
* STATUS1 to the caller.
102+
*/
103+
static int s35390a_reset(struct s35390a *s35390a, char *status1)
98104
{
99-
char buf[1];
105+
char buf;
106+
int ret;
107+
unsigned initcount = 0;
100108

101-
if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0)
102-
return -EIO;
109+
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
110+
if (ret < 0)
111+
return ret;
103112

104-
if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD)))
113+
if (*status1 & S35390A_FLAG_POC)
114+
/*
115+
* Do not communicate for 0.5 seconds since the power-on
116+
* detection circuit is in operation.
117+
*/
118+
msleep(500);
119+
else if (!(*status1 & S35390A_FLAG_BLD))
120+
/*
121+
* If both POC and BLD are unset everything is fine.
122+
*/
105123
return 0;
106124

107-
buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H);
108-
buf[0] &= 0xf0;
109-
return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
125+
/*
126+
* At least one of POC and BLD are set, so reinitialise chip. Keeping
127+
* this information in the hardware to know later that the time isn't
128+
* valid is unfortunately not possible because POC and BLD are cleared
129+
* on read. So the reset is best done now.
130+
*
131+
* The 24H bit is kept over reset, so set it already here.
132+
*/
133+
initialize:
134+
*status1 = S35390A_FLAG_24H;
135+
buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
136+
ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
137+
138+
if (ret < 0)
139+
return ret;
140+
141+
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
142+
if (ret < 0)
143+
return ret;
144+
145+
if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
146+
/* Try up to five times to reset the chip */
147+
if (initcount < 5) {
148+
++initcount;
149+
goto initialize;
150+
} else
151+
return -EIO;
152+
}
153+
154+
return 1;
110155
}
111156

112157
static int s35390a_disable_test_mode(struct s35390a *s35390a)
@@ -367,7 +412,7 @@ static int s35390a_probe(struct i2c_client *client,
367412
unsigned int i;
368413
struct s35390a *s35390a;
369414
struct rtc_time tm;
370-
char buf[1];
415+
char buf[1], status1;
371416

372417
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
373418
err = -ENODEV;
@@ -396,7 +441,7 @@ static int s35390a_probe(struct i2c_client *client,
396441
}
397442
}
398443

399-
err = s35390a_reset(s35390a);
444+
err = s35390a_reset(s35390a, &status1);
400445
if (err < 0) {
401446
dev_err(&client->dev, "error resetting chip\n");
402447
goto exit_dummy;

0 commit comments

Comments
 (0)