Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 50d6c0ea authored by Alexandre Belloni's avatar Alexandre Belloni
Browse files

rtc: ds1307: fix century bit support



Add an option to properly support the century bit of ds1337 and compatibles
and ds1340.
Because the driver had a bug until now, it is not possible to switch users
to the fixed code directly as RTCs in the field will wrongly have the
century bit set.

Acked-by: default avatarArnaud Ebalard <arno@natisbad.org>
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@free-electrons.com>
parent 59e5e70c
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -234,6 +234,20 @@ config RTC_DRV_DS1307_HWMON
	  Say Y here if you want to expose temperature sensor data on
	  rtc-ds1307 (only DS3231)

config RTC_DRV_DS1307_CENTURY
	bool "Century bit support for rtc-ds1307"
	depends on RTC_DRV_DS1307
	default n
	help
	  The DS1307 driver suffered from a bug where it was enabling the
	  century bit inconditionnally but never used it when reading the time.
	  It made the driver unable to support dates beyond 2099.
	  Setting this option will add proper support for the century bit but if
	  the time was previously set using a kernel predating this option,
	  reading the date will return a date in the next century.
	  To solve that, you could boot a kernel without this option set, set
	  the RTC date and then boot a kernel with this option set.

config RTC_DRV_DS1374
	tristate "Dallas/Maxim DS1374"
	help
+43 −5
Original line number Diff line number Diff line
@@ -382,10 +382,25 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
	t->tm_mday = bcd2bin(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
	tmp = ds1307->regs[DS1307_REG_MONTH] & 0x1f;
	t->tm_mon = bcd2bin(tmp) - 1;

	/* assume 20YY not 19YY, and ignore DS1337_BIT_CENTURY */
	t->tm_year = bcd2bin(ds1307->regs[DS1307_REG_YEAR]) + 100;

#ifdef CONFIG_RTC_DRV_DS1307_CENTURY
	switch (ds1307->type) {
	case ds_1337:
	case ds_1339:
	case ds_3231:
		if (ds1307->regs[DS1307_REG_MONTH] & DS1337_BIT_CENTURY)
			t->tm_year += 100;
		break;
	case ds_1340:
		if (ds1307->regs[DS1307_REG_HOUR] & DS1340_BIT_CENTURY)
			t->tm_year += 100;
		break;
	default:
		break;
	}
#endif

	dev_dbg(dev, "%s secs=%d, mins=%d, "
		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
		"read", t->tm_sec, t->tm_min,
@@ -409,6 +424,27 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
		t->tm_hour, t->tm_mday,
		t->tm_mon, t->tm_year, t->tm_wday);

#ifdef CONFIG_RTC_DRV_DS1307_CENTURY
	if (t->tm_year < 100)
		return -EINVAL;

	switch (ds1307->type) {
	case ds_1337:
	case ds_1339:
	case ds_3231:
	case ds_1340:
		if (t->tm_year > 299)
			return -EINVAL;
	default:
		if (t->tm_year > 199)
			return -EINVAL;
		break;
	}
#else
	if (t->tm_year < 100 || t->tm_year > 199)
		return -EINVAL;
#endif

	buf[DS1307_REG_SECS] = bin2bcd(t->tm_sec);
	buf[DS1307_REG_MIN] = bin2bcd(t->tm_min);
	buf[DS1307_REG_HOUR] = bin2bcd(t->tm_hour);
@@ -424,11 +460,13 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
	case ds_1337:
	case ds_1339:
	case ds_3231:
		if (t->tm_year > 199)
			buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
		break;
	case ds_1340:
		buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
				| DS1340_BIT_CENTURY;
		buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN;
		if (t->tm_year > 199)
			buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY;
		break;
	case mcp794xx:
		/*