Factor out checking and fixing the weekday. In addition fix two issues with the old implementation: - For variable timestamp use correct type time64_t instead of unsigned long which may be just 32bit long. - Updating the weekday register only may be racy, therefore write all timekeeping registers. Signed-off-by: Heiner Kallweit <hkallweit1@xxxxxxxxx> --- drivers/rtc/rtc-ds1307.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index ea88e4b3..69f514b6 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1368,6 +1368,29 @@ static void ds1307_trickle_init(struct ds1307 *ds1307) } } +static void ds1307_fix_weekday(struct ds1307 *ds1307) +{ + struct rtc_time tm; + time64_t timestamp; + int wday; + + if (ds1307_get_time(ds1307->dev, &tm)) + return; + + wday = tm.tm_wday; + timestamp = rtc_tm_to_time64(&tm); + rtc_time64_to_tm(timestamp, &tm); + + /* + * Check if reset wday is different from the computed wday + * If different then set the wday which we computed using + * timestamp + * Set not only wday but complete date to avoid potential races. + */ + if (wday != tm.tm_wday) + ds1307_set_time(ds1307->dev, &tm); +} + static const struct regmap_config regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -1378,13 +1401,11 @@ static int ds1307_probe(struct i2c_client *client, { struct ds1307 *ds1307; int err = -ENODEV; - int tmp, wday; + int tmp; const struct chip_desc *chip; bool want_irq; bool ds1307_can_wakeup_device = false; unsigned char *buf; - struct rtc_time tm; - unsigned long timestamp; ds1307 = devm_kzalloc(&client->dev, sizeof(struct ds1307), GFP_KERNEL); if (!ds1307) @@ -1642,20 +1663,7 @@ static int ds1307_probe(struct i2c_client *client, * Some IPs have weekday reset value = 0x1 which might not correct * hence compute the wday using the current date/month/year values */ - ds1307_get_time(ds1307->dev, &tm); - wday = tm.tm_wday; - timestamp = rtc_tm_to_time64(&tm); - rtc_time64_to_tm(timestamp, &tm); - - /* - * Check if reset wday is different from the computed wday - * If different then set the wday which we computed using - * timestamp - */ - if (wday != tm.tm_wday) - regmap_update_bits(ds1307->regmap, MCP794XX_REG_WEEKDAY, - MCP794XX_REG_WEEKDAY_WDAY_MASK, - tm.tm_wday + 1); + ds1307_fix_weekday(ds1307); if (want_irq || ds1307_can_wakeup_device) { device_set_wakeup_capable(ds1307->dev, true); -- 2.14.1