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:
parent
e22e2d941c
commit
83220bf38b
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue