summaryrefslogtreecommitdiff
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/class.c2
-rw-r--r--drivers/rtc/lib.c24
-rw-r--r--drivers/rtc/rtc-cmos.c10
-rw-r--r--drivers/rtc/rtc-ds1307.c6
-rw-r--r--drivers/rtc/rtc-hym8563.c2
-rw-r--r--drivers/rtc/rtc-nct3018y.c2
-rw-r--r--drivers/rtc/rtc-pcf85063.c21
-rw-r--r--drivers/rtc/rtc-pcf8563.c2
-rw-r--r--drivers/rtc/rtc-rv3028.c2
-rw-r--r--drivers/rtc/rtc-rv3032.c2
-rw-r--r--drivers/rtc/rtc-sh.c12
11 files changed, 61 insertions, 24 deletions
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index e5b7b48cffac..adf2a3d475ca 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -323,7 +323,7 @@ static void rtc_device_get_offset(struct rtc_device *rtc)
*
* Otherwise the offset seconds should be 0.
*/
- if (rtc->start_secs > rtc->range_max ||
+ if ((rtc->start_secs >= 0 && rtc->start_secs > rtc->range_max) ||
rtc->start_secs + range_secs - 1 < rtc->range_min)
rtc->offset_secs = rtc->start_secs - rtc->range_min;
else if (rtc->start_secs > rtc->range_min)
diff --git a/drivers/rtc/lib.c b/drivers/rtc/lib.c
index fe361652727a..13b5b1f20465 100644
--- a/drivers/rtc/lib.c
+++ b/drivers/rtc/lib.c
@@ -46,24 +46,38 @@ EXPORT_SYMBOL(rtc_year_days);
* rtc_time64_to_tm - converts time64_t to rtc_time.
*
* @time: The number of seconds since 01-01-1970 00:00:00.
- * (Must be positive.)
+ * Works for values since at least 1900
* @tm: Pointer to the struct rtc_time.
*/
void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
{
- unsigned int secs;
- int days;
+ int days, secs;
u64 u64tmp;
u32 u32tmp, udays, century, day_of_century, year_of_century, year,
day_of_year, month, day;
bool is_Jan_or_Feb, is_leap_year;
- /* time must be positive */
+ /*
+ * Get days and seconds while preserving the sign to
+ * handle negative time values (dates before 1970-01-01)
+ */
days = div_s64_rem(time, 86400, &secs);
+ /*
+ * We need 0 <= secs < 86400 which isn't given for negative
+ * values of time. Fixup accordingly.
+ */
+ if (secs < 0) {
+ days -= 1;
+ secs += 86400;
+ }
+
/* day of the week, 1970-01-01 was a Thursday */
tm->tm_wday = (days + 4) % 7;
+ /* Ensure tm_wday is always positive */
+ if (tm->tm_wday < 0)
+ tm->tm_wday += 7;
/*
* The following algorithm is, basically, Proposition 6.3 of Neri
@@ -93,7 +107,7 @@ void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
* thus, is slightly different from [1].
*/
- udays = ((u32) days) + 719468;
+ udays = days + 719468;
u32tmp = 4 * udays + 3;
century = u32tmp / 146097;
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 5f43773900d1..1442c629d0d5 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -697,8 +697,12 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
{
u8 irqstat;
u8 rtc_control;
+ unsigned long flags;
- spin_lock(&rtc_lock);
+ /* We cannot use spin_lock() here, as cmos_interrupt() is also called
+ * in a non-irq context.
+ */
+ spin_lock_irqsave(&rtc_lock, flags);
/* When the HPET interrupt handler calls us, the interrupt
* status is passed as arg1 instead of the irq number. But
@@ -732,7 +736,7 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
hpet_mask_rtc_irq_bit(RTC_AIE);
CMOS_READ(RTC_INTR_FLAGS);
}
- spin_unlock(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
if (is_intr(irqstat)) {
rtc_update_irq(p, 1, irqstat);
@@ -1289,9 +1293,7 @@ static void cmos_check_wkalrm(struct device *dev)
* ACK the rtc irq here
*/
if (t_now >= cmos->alarm_expires && cmos_use_acpi_alarm()) {
- local_irq_disable();
cmos_interrupt(0, (void *)cmos->rtc);
- local_irq_enable();
return;
}
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index d51565bcc189..73f2dd3af4d4 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -1461,7 +1461,7 @@ static long ds3231_clk_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
return ds3231_clk_sqw_rates[i];
}
- return 0;
+ return ds3231_clk_sqw_rates[ARRAY_SIZE(ds3231_clk_sqw_rates) - 1];
}
static int ds3231_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -1802,10 +1802,8 @@ static int ds1307_probe(struct i2c_client *client,
* For some variants, be sure alarms can trigger when we're
* running on Vbackup (BBSQI/BBSQW)
*/
- if (want_irq || ds1307_can_wakeup_device) {
+ if (want_irq || ds1307_can_wakeup_device)
regs[0] |= DS1337_BIT_INTCN | chip->bbsqi_bit;
- regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
- }
regmap_write(ds1307->regmap, DS1337_REG_CONTROL,
regs[0]);
diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c
index cc710d682121..2f52aabd129a 100644
--- a/drivers/rtc/rtc-hym8563.c
+++ b/drivers/rtc/rtc-hym8563.c
@@ -294,7 +294,7 @@ static long hym8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
if (clkout_rates[i] <= rate)
return clkout_rates[i];
- return 0;
+ return clkout_rates[0];
}
static int hym8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/drivers/rtc/rtc-nct3018y.c b/drivers/rtc/rtc-nct3018y.c
index 108eced8f003..43b01f3e640a 100644
--- a/drivers/rtc/rtc-nct3018y.c
+++ b/drivers/rtc/rtc-nct3018y.c
@@ -342,7 +342,7 @@ static long nct3018y_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
if (clkout_rates[i] <= rate)
return clkout_rates[i];
- return 0;
+ return clkout_rates[0];
}
static int nct3018y_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 6ffdc10b32d3..b095663d5ebc 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -35,6 +35,7 @@
#define PCF85063_REG_CTRL1_CAP_SEL BIT(0)
#define PCF85063_REG_CTRL1_STOP BIT(5)
#define PCF85063_REG_CTRL1_EXT_TEST BIT(7)
+#define PCF85063_REG_CTRL1_SWR 0x58
#define PCF85063_REG_CTRL2 0x01
#define PCF85063_CTRL2_AF BIT(6)
@@ -409,7 +410,7 @@ static long pcf85063_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
if (clkout_rates[i] <= rate)
return clkout_rates[i];
- return 0;
+ return clkout_rates[0];
}
static int pcf85063_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -606,7 +607,7 @@ static int pcf85063_probe(struct i2c_client *client)
i2c_set_clientdata(client, pcf85063);
- err = regmap_read(pcf85063->regmap, PCF85063_REG_CTRL1, &tmp);
+ err = regmap_read(pcf85063->regmap, PCF85063_REG_SC, &tmp);
if (err) {
dev_err(&client->dev, "RTC chip is not present\n");
return err;
@@ -616,6 +617,22 @@ static int pcf85063_probe(struct i2c_client *client)
if (IS_ERR(pcf85063->rtc))
return PTR_ERR(pcf85063->rtc);
+ /*
+ * If a Power loss is detected, SW reset the device.
+ * From PCF85063A datasheet:
+ * There is a low probability that some devices will have corruption
+ * of the registers after the automatic power-on reset...
+ */
+ if (tmp & PCF85063_REG_SC_OS) {
+ dev_warn(&client->dev,
+ "POR issue detected, sending a SW reset\n");
+ err = regmap_write(pcf85063->regmap, PCF85063_REG_CTRL1,
+ PCF85063_REG_CTRL1_SWR);
+ if (err < 0)
+ dev_warn(&client->dev,
+ "SW reset failed, trying to continue\n");
+ }
+
err = pcf85063_load_capacitance(pcf85063, client->dev.of_node,
config->force_cap_7000 ? 7000 : 0);
if (err < 0)
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 11fa9788558b..dd27acae137c 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -386,7 +386,7 @@ static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
if (clkout_rates[i] <= rate)
return clkout_rates[i];
- return 0;
+ return clkout_rates[0];
}
static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c
index dd170e3efd83..436523605f8f 100644
--- a/drivers/rtc/rtc-rv3028.c
+++ b/drivers/rtc/rtc-rv3028.c
@@ -738,7 +738,7 @@ static long rv3028_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
if (clkout_rates[i] <= rate)
return clkout_rates[i];
- return 0;
+ return clkout_rates[0];
}
static int rv3028_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c
index c3bee305eacc..9c85ecd9afb8 100644
--- a/drivers/rtc/rtc-rv3032.c
+++ b/drivers/rtc/rtc-rv3032.c
@@ -69,7 +69,7 @@
#define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5)
#define RV3032_CLKOUT2_OS BIT(7)
-#define RV3032_CTRL1_EERD BIT(3)
+#define RV3032_CTRL1_EERD BIT(2)
#define RV3032_CTRL1_WADA BIT(5)
#define RV3032_CTRL2_STOP BIT(0)
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index cd146b574143..341b1b776e1a 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -485,9 +485,15 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
return -ENOENT;
}
- rtc->periodic_irq = ret;
- rtc->carry_irq = platform_get_irq(pdev, 1);
- rtc->alarm_irq = platform_get_irq(pdev, 2);
+ if (!pdev->dev.of_node) {
+ rtc->periodic_irq = ret;
+ rtc->carry_irq = platform_get_irq(pdev, 1);
+ rtc->alarm_irq = platform_get_irq(pdev, 2);
+ } else {
+ rtc->alarm_irq = ret;
+ rtc->periodic_irq = platform_get_irq(pdev, 1);
+ rtc->carry_irq = platform_get_irq(pdev, 2);
+ }
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)