Skip to content

Commit 1a7ed2f

Browse files
niyasmydeenalexandrebelloni
authored andcommitted
rtc: m41t80: kickstart ocillator upon failure
The ocillator on the m41t62 (and other chips of this type) needs a kickstart upon a failure; the RTC read routine will notice the oscillator failure and fail reads. This is added in the RTC write routine; this allows the system to know that the time in the RTC is accurate. This is following the procedure described in section 3.11 of "https://www.st.com/resource/en/datasheet/m41t62.pdf" Signed-off-by: A. Niyas Ahamed Mydeen <[email protected]> Reviewed-by: Corey Minyard <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexandre Belloni <[email protected]>
1 parent 818b670 commit 1a7ed2f

File tree

1 file changed

+48
-20
lines changed

1 file changed

+48
-20
lines changed

drivers/rtc/rtc-m41t80.c

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/slab.h>
2323
#include <linux/mutex.h>
2424
#include <linux/string.h>
25+
#include <linux/delay.h>
2526
#ifdef CONFIG_RTC_DRV_M41T80_WDT
2627
#include <linux/fs.h>
2728
#include <linux/ioctl.h>
@@ -204,7 +205,7 @@ static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm)
204205
return flags;
205206

206207
if (flags & M41T80_FLAGS_OF) {
207-
dev_err(&client->dev, "Oscillator failure, data is invalid.\n");
208+
dev_err(&client->dev, "Oscillator failure, time may not be accurate, write time to RTC to fix it.\n");
208209
return -EINVAL;
209210
}
210211

@@ -227,21 +228,31 @@ static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm)
227228
return 0;
228229
}
229230

230-
static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
231+
static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *in_tm)
231232
{
232233
struct i2c_client *client = to_i2c_client(dev);
233234
struct m41t80_data *clientdata = i2c_get_clientdata(client);
235+
struct rtc_time tm = *in_tm;
234236
unsigned char buf[8];
235237
int err, flags;
238+
time64_t time = 0;
236239

240+
flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
241+
if (flags < 0)
242+
return flags;
243+
if (flags & M41T80_FLAGS_OF) {
244+
/* add 4sec of oscillator stablize time otherwise we are behind 4sec */
245+
time = rtc_tm_to_time64(&tm);
246+
rtc_time64_to_tm(time + 4, &tm);
247+
}
237248
buf[M41T80_REG_SSEC] = 0;
238-
buf[M41T80_REG_SEC] = bin2bcd(tm->tm_sec);
239-
buf[M41T80_REG_MIN] = bin2bcd(tm->tm_min);
240-
buf[M41T80_REG_HOUR] = bin2bcd(tm->tm_hour);
241-
buf[M41T80_REG_DAY] = bin2bcd(tm->tm_mday);
242-
buf[M41T80_REG_MON] = bin2bcd(tm->tm_mon + 1);
243-
buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
244-
buf[M41T80_REG_WDAY] = tm->tm_wday;
249+
buf[M41T80_REG_SEC] = bin2bcd(tm.tm_sec);
250+
buf[M41T80_REG_MIN] = bin2bcd(tm.tm_min);
251+
buf[M41T80_REG_HOUR] = bin2bcd(tm.tm_hour);
252+
buf[M41T80_REG_DAY] = bin2bcd(tm.tm_mday);
253+
buf[M41T80_REG_MON] = bin2bcd(tm.tm_mon + 1);
254+
buf[M41T80_REG_YEAR] = bin2bcd(tm.tm_year - 100);
255+
buf[M41T80_REG_WDAY] = tm.tm_wday;
245256

246257
/* If the square wave output is controlled in the weekday register */
247258
if (clientdata->features & M41T80_FEATURE_SQ_ALT) {
@@ -260,17 +271,34 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
260271
dev_err(&client->dev, "Unable to write to date registers\n");
261272
return err;
262273
}
263-
264-
/* Clear the OF bit of Flags Register */
265-
flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
266-
if (flags < 0)
267-
return flags;
268-
269-
err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
270-
flags & ~M41T80_FLAGS_OF);
271-
if (err < 0) {
272-
dev_err(&client->dev, "Unable to write flags register\n");
273-
return err;
274+
if (flags & M41T80_FLAGS_OF) {
275+
/* OF cannot be immediately reset: oscillator has to be restarted. */
276+
dev_warn(&client->dev, "OF bit is still set, kickstarting clock.\n");
277+
err = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, M41T80_SEC_ST);
278+
if (err < 0) {
279+
dev_err(&client->dev, "Can't set ST bit\n");
280+
return err;
281+
}
282+
err = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, flags & ~M41T80_SEC_ST);
283+
if (err < 0) {
284+
dev_err(&client->dev, "Can't clear ST bit\n");
285+
return err;
286+
}
287+
/* oscillator must run for 4sec before we attempt to reset OF bit */
288+
msleep(4000);
289+
/* Clear the OF bit of Flags Register */
290+
err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, flags & ~M41T80_FLAGS_OF);
291+
if (err < 0) {
292+
dev_err(&client->dev, "Unable to write flags register\n");
293+
return err;
294+
}
295+
flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
296+
if (flags < 0) {
297+
return flags;
298+
} else if (flags & M41T80_FLAGS_OF) {
299+
dev_err(&client->dev, "Can't clear the OF bit check battery\n");
300+
return err;
301+
}
274302
}
275303

276304
return err;

0 commit comments

Comments
 (0)