rtc: pm8xxx: Fix issue in RTC write path

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: Mohit Aggarwal <maggarwa@codeaurora.org>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
Mohit Aggarwal 2018-03-05 14:35:58 +05:30 committed by Alexandre Belloni
parent e22e2d941c
commit 83220bf38b
1 changed files with 39 additions and 12 deletions

View File

@ -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)
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,15 +154,25 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
goto rtc_rw_fail; goto rtc_rw_fail;
} }
if (alarm_enabled) { /* Enable RTC H/w after writing on RTC register */
ctrl_reg |= regs->alarm_en; if (rtc_disabled) {
rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg); 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;
} }
} }
if (alarm_enabled) {
ctrl_reg |= regs->alarm_en;
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;
}
}
rtc_rw_fail: rtc_rw_fail:
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);