Commit a2e3ddf5 authored by Mohit Aggarwal's avatar Mohit Aggarwal Committed by Kleber Sacilotto de Souza

rtc: pm8xxx: Fix issue in RTC write path

BugLink: https://bugs.launchpad.net/bugs/1875905

[ Upstream commit 83220bf3 ]

In order to set time in rtc, need to disable
rtc hw before writing into rtc registers.

Also fixes disabling of alarm while setting
rtc time.
Signed-off-by: default avatarMohit Aggarwal <maggarwa@codeaurora.org>
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarIan May <ian.may@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent ca5db5d6
...@@ -74,16 +74,18 @@ struct pm8xxx_rtc { ...@@ -74,16 +74,18 @@ struct pm8xxx_rtc {
/* /*
* Steps to write the RTC registers. * Steps to write the RTC registers.
* 1. Disable alarm if enabled. * 1. Disable alarm if enabled.
* 2. Write 0x00 to LSB. * 2. Disable rtc if enabled.
* 3. Write Byte[1], Byte[2], Byte[3] then Byte[0]. * 3. Write 0x00 to LSB.
* 4. Enable alarm if disabled in step 1. * 4. Write Byte[1], Byte[2], Byte[3] then Byte[0].
* 5. Enable rtc if disabled in step 2.
* 6. Enable alarm if disabled in step 1.
*/ */
static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
{ {
int rc, i; int rc, i;
unsigned long secs, irq_flags; unsigned long secs, irq_flags;
u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0; u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, rtc_disabled = 0;
unsigned int ctrl_reg; unsigned int ctrl_reg, rtc_ctrl_reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
...@@ -92,23 +94,38 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) ...@@ -92,23 +94,38 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
rtc_tm_to_time(tm, &secs); rtc_tm_to_time(tm, &secs);
dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
value[i] = secs & 0xFF; value[i] = secs & 0xFF;
secs >>= 8; secs >>= 8;
} }
dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg); rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
if (rc) if (rc)
goto rtc_rw_fail; goto rtc_rw_fail;
if (ctrl_reg & regs->alarm_en) { if (ctrl_reg & regs->alarm_en) {
alarm_enabled = 1; alarm_enabled = 1;
ctrl_reg &= ~regs->alarm_en; ctrl_reg &= ~regs->alarm_en;
rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg); rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC Alarm control register failed\n");
goto rtc_rw_fail;
}
}
/* Disable RTC H/w before writing on RTC register */
rc = regmap_read(rtc_dd->regmap, regs->ctrl, &rtc_ctrl_reg);
if (rc)
goto rtc_rw_fail;
if (rtc_ctrl_reg & PM8xxx_RTC_ENABLE) {
rtc_disabled = 1;
rtc_ctrl_reg &= ~PM8xxx_RTC_ENABLE;
rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
if (rc) { if (rc) {
dev_err(dev, "Write to RTC control register failed\n"); dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail; goto rtc_rw_fail;
...@@ -137,11 +154,21 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) ...@@ -137,11 +154,21 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
goto rtc_rw_fail; goto rtc_rw_fail;
} }
/* Enable RTC H/w after writing on RTC register */
if (rtc_disabled) {
rtc_ctrl_reg |= PM8xxx_RTC_ENABLE;
rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
}
if (alarm_enabled) { if (alarm_enabled) {
ctrl_reg |= regs->alarm_en; ctrl_reg |= regs->alarm_en;
rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg); rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
if (rc) { if (rc) {
dev_err(dev, "Write to RTC control register failed\n"); dev_err(dev, "Write to RTC Alarm control register failed\n");
goto rtc_rw_fail; goto rtc_rw_fail;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment