Adding Alexander On Thu, Jan 16, 2025 at 11:56:41AM +0530, nmydeen@xxxxxxxxxx wrote: > From: "A. Niyas Ahamed Mydeen" <nmydeen@xxxxxxxxxx> > > 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" Any comments on this? I just saw that Alexander wasn't on the email, not sure if they are still involved. -corey > > Signed-off-by: A. Niyas Ahamed Mydeen <nmydeen@xxxxxxxxxx> > Reviewed-by: Corey Minyard <cminyard@xxxxxxxxxx> > --- > drivers/rtc/rtc-m41t80.c | 70 ++++++++++++++++++++++++++++------------ > 1 file changed, 49 insertions(+), 21 deletions(-) > > diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c > index 1f58ae8b151e..77c21c91bae3 100644 > --- a/drivers/rtc/rtc-m41t80.c > +++ b/drivers/rtc/rtc-m41t80.c > @@ -22,6 +22,7 @@ > #include <linux/slab.h> > #include <linux/mutex.h> > #include <linux/string.h> > +#include <linux/delay.h> > #ifdef CONFIG_RTC_DRV_M41T80_WDT > #include <linux/fs.h> > #include <linux/ioctl.h> > @@ -204,7 +205,7 @@ static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm) > return flags; > > if (flags & M41T80_FLAGS_OF) { > - dev_err(&client->dev, "Oscillator failure, data is invalid.\n"); > + dev_err(&client->dev, "Oscillator failure, time may not be accurate, write time to RTC to fix it.\n"); > return -EINVAL; > } > > @@ -227,21 +228,60 @@ static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm) > return 0; > } > > -static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm) > +static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *in_tm) > { > struct i2c_client *client = to_i2c_client(dev); > struct m41t80_data *clientdata = i2c_get_clientdata(client); > + struct rtc_time tm = *in_tm; > unsigned char buf[8]; > int err, flags; > + time64_t time = 0; > > + flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); > + if (flags < 0) > + return flags; > + if (flags & M41T80_FLAGS_OF) { > + /* OF cannot be immediately reset: oscillator has to be restarted. */ > + dev_warn(&client->dev, "OF bit is still set, kickstarting clock.\n"); > + err = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, M41T80_SEC_ST); > + if (err < 0) { > + dev_err(&client->dev, "Can't set ST bit\n"); > + return err; > + } > + err = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, > + flags & ~M41T80_SEC_ST); > + if (err < 0) { > + dev_err(&client->dev, "Can't clear ST bit\n"); > + return err; > + } > + /* oscillator must run for 4sec before we attempt to reset OF bit */ > + msleep(4000); > + /* Clear the OF bit of Flags Register */ > + err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, > + flags & ~M41T80_FLAGS_OF); > + if (err < 0) { > + dev_err(&client->dev, "Unable to write flags register\n"); > + return err; > + } > + flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); > + if (flags < 0) > + return flags; > + else if (flags & M41T80_FLAGS_OF) { > + dev_err(&client->dev, "Can't clear the OF bit check battery\n"); > + return err; > + } > + /* add 4sec of oscillator stablize time otherwise we are behind 4sec */ > + time = rtc_tm_to_time64(&tm); > + rtc_time64_to_tm(time+4, &tm); > + } > buf[M41T80_REG_SSEC] = 0; > - buf[M41T80_REG_SEC] = bin2bcd(tm->tm_sec); > - buf[M41T80_REG_MIN] = bin2bcd(tm->tm_min); > - buf[M41T80_REG_HOUR] = bin2bcd(tm->tm_hour); > - buf[M41T80_REG_DAY] = bin2bcd(tm->tm_mday); > - buf[M41T80_REG_MON] = bin2bcd(tm->tm_mon + 1); > - buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100); > - buf[M41T80_REG_WDAY] = tm->tm_wday; > + buf[M41T80_REG_SEC] = bin2bcd(tm.tm_sec); > + buf[M41T80_REG_MIN] = bin2bcd(tm.tm_min); > + buf[M41T80_REG_HOUR] = bin2bcd(tm.tm_hour); > + buf[M41T80_REG_DAY] = bin2bcd(tm.tm_mday); > + buf[M41T80_REG_MON] = bin2bcd(tm.tm_mon + 1); > + buf[M41T80_REG_YEAR] = bin2bcd(tm.tm_year - 100); > + buf[M41T80_REG_WDAY] = tm.tm_wday; > > /* If the square wave output is controlled in the weekday register */ > if (clientdata->features & M41T80_FEATURE_SQ_ALT) { > @@ -261,18 +301,6 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm) > return err; > } > > - /* Clear the OF bit of Flags Register */ > - flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); > - if (flags < 0) > - return flags; > - > - err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, > - flags & ~M41T80_FLAGS_OF); > - if (err < 0) { > - dev_err(&client->dev, "Unable to write flags register\n"); > - return err; > - } > - > return err; > } > > -- > 2.34.1 >
<<attachment: smime.p7s>>