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