rtc: stm32: add stm32mp1 rtc support

This patch adds support for stm32mp1 RTC.
Some common registers with previous RTC version have a different offset.
It is the case for Control Register (CR) and ALaRMA Register (ALRMAR).
There are also new registers regarding event flags: now, Alarm event flag
is in Status Register (SR) and write 1 in Status Clear Register (SCR) is
required to clear the event.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
Amelie Delaunay 2018-05-17 14:04:26 +02:00 committed by Alexandre Belloni
parent 5c4554d62b
commit b72252b658

View File

@ -11,6 +11,7 @@
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
@ -39,7 +40,7 @@
#define STM32_RTC_CR_ALRAE BIT(8) #define STM32_RTC_CR_ALRAE BIT(8)
#define STM32_RTC_CR_ALRAIE BIT(12) #define STM32_RTC_CR_ALRAIE BIT(12)
/* STM32_RTC_ISR bit fields */ /* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
#define STM32_RTC_ISR_ALRAWF BIT(0) #define STM32_RTC_ISR_ALRAWF BIT(0)
#define STM32_RTC_ISR_INITS BIT(4) #define STM32_RTC_ISR_INITS BIT(4)
#define STM32_RTC_ISR_RSF BIT(5) #define STM32_RTC_ISR_RSF BIT(5)
@ -71,21 +72,36 @@
#define STM32_RTC_ALRMXR_WDAY GENMASK(27, 24) #define STM32_RTC_ALRMXR_WDAY GENMASK(27, 24)
#define STM32_RTC_ALRMXR_DATE_MASK BIT(31) #define STM32_RTC_ALRMXR_DATE_MASK BIT(31)
/* STM32_RTC_SR/_SCR bit fields */
#define STM32_RTC_SR_ALRA BIT(0)
/* STM32_RTC_VERR bit fields */
#define STM32_RTC_VERR_MINREV_SHIFT 0
#define STM32_RTC_VERR_MINREV GENMASK(3, 0)
#define STM32_RTC_VERR_MAJREV_SHIFT 4
#define STM32_RTC_VERR_MAJREV GENMASK(7, 4)
/* STM32_RTC_WPR key constants */ /* STM32_RTC_WPR key constants */
#define RTC_WPR_1ST_KEY 0xCA #define RTC_WPR_1ST_KEY 0xCA
#define RTC_WPR_2ND_KEY 0x53 #define RTC_WPR_2ND_KEY 0x53
#define RTC_WPR_WRONG_KEY 0xFF #define RTC_WPR_WRONG_KEY 0xFF
/* Max STM32 RTC register offset is 0x3FC */
#define UNDEF_REG 0xFFFF
struct stm32_rtc; struct stm32_rtc;
struct stm32_rtc_registers { struct stm32_rtc_registers {
u8 tr; u16 tr;
u8 dr; u16 dr;
u8 cr; u16 cr;
u8 isr; u16 isr;
u8 prer; u16 prer;
u8 alrmar; u16 alrmar;
u8 wpr; u16 wpr;
u16 sr;
u16 scr;
u16 verr;
}; };
struct stm32_rtc_events { struct stm32_rtc_events {
@ -98,6 +114,7 @@ struct stm32_rtc_data {
void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags); void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags);
bool has_pclk; bool has_pclk;
bool need_dbp; bool need_dbp;
bool has_wakeirq;
}; };
struct stm32_rtc { struct stm32_rtc {
@ -110,6 +127,7 @@ struct stm32_rtc {
struct clk *rtc_ck; struct clk *rtc_ck;
const struct stm32_rtc_data *data; const struct stm32_rtc_data *data;
int irq_alarm; int irq_alarm;
int wakeirq_alarm;
}; };
static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc) static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
@ -193,7 +211,7 @@ static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
mutex_lock(&rtc->rtc_dev->ops_lock); mutex_lock(&rtc->rtc_dev->ops_lock);
status = readl_relaxed(rtc->base + regs->isr); status = readl_relaxed(rtc->base + regs->sr);
cr = readl_relaxed(rtc->base + regs->cr); cr = readl_relaxed(rtc->base + regs->cr);
if ((status & evts->alra) && if ((status & evts->alra) &&
@ -325,7 +343,7 @@ static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
alrmar = readl_relaxed(rtc->base + regs->alrmar); alrmar = readl_relaxed(rtc->base + regs->alrmar);
cr = readl_relaxed(rtc->base + regs->cr); cr = readl_relaxed(rtc->base + regs->cr);
status = readl_relaxed(rtc->base + regs->isr); status = readl_relaxed(rtc->base + regs->sr);
if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) { if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
/* /*
@ -533,6 +551,7 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc,
static const struct stm32_rtc_data stm32_rtc_data = { static const struct stm32_rtc_data stm32_rtc_data = {
.has_pclk = false, .has_pclk = false,
.need_dbp = true, .need_dbp = true,
.has_wakeirq = false,
.regs = { .regs = {
.tr = 0x00, .tr = 0x00,
.dr = 0x04, .dr = 0x04,
@ -541,6 +560,9 @@ static const struct stm32_rtc_data stm32_rtc_data = {
.prer = 0x10, .prer = 0x10,
.alrmar = 0x1C, .alrmar = 0x1C,
.wpr = 0x24, .wpr = 0x24,
.sr = 0x0C, /* set to ISR offset to ease alarm management */
.scr = UNDEF_REG,
.verr = UNDEF_REG,
}, },
.events = { .events = {
.alra = STM32_RTC_ISR_ALRAF, .alra = STM32_RTC_ISR_ALRAF,
@ -551,6 +573,7 @@ static const struct stm32_rtc_data stm32_rtc_data = {
static const struct stm32_rtc_data stm32h7_rtc_data = { static const struct stm32_rtc_data stm32h7_rtc_data = {
.has_pclk = true, .has_pclk = true,
.need_dbp = true, .need_dbp = true,
.has_wakeirq = false,
.regs = { .regs = {
.tr = 0x00, .tr = 0x00,
.dr = 0x04, .dr = 0x04,
@ -559,6 +582,9 @@ static const struct stm32_rtc_data stm32h7_rtc_data = {
.prer = 0x10, .prer = 0x10,
.alrmar = 0x1C, .alrmar = 0x1C,
.wpr = 0x24, .wpr = 0x24,
.sr = 0x0C, /* set to ISR offset to ease alarm management */
.scr = UNDEF_REG,
.verr = UNDEF_REG,
}, },
.events = { .events = {
.alra = STM32_RTC_ISR_ALRAF, .alra = STM32_RTC_ISR_ALRAF,
@ -566,9 +592,41 @@ static const struct stm32_rtc_data stm32h7_rtc_data = {
.clear_events = stm32_rtc_clear_events, .clear_events = stm32_rtc_clear_events,
}; };
static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc,
unsigned int flags)
{
struct stm32_rtc_registers regs = rtc->data->regs;
/* Flags are cleared by writing 1 in RTC_SCR */
writel_relaxed(flags, rtc->base + regs.scr);
}
static const struct stm32_rtc_data stm32mp1_data = {
.has_pclk = true,
.need_dbp = false,
.has_wakeirq = true,
.regs = {
.tr = 0x00,
.dr = 0x04,
.cr = 0x18,
.isr = 0x0C, /* named RTC_ICSR on stm32mp1 */
.prer = 0x10,
.alrmar = 0x40,
.wpr = 0x24,
.sr = 0x50,
.scr = 0x5C,
.verr = 0x3F4,
},
.events = {
.alra = STM32_RTC_SR_ALRA,
},
.clear_events = stm32mp1_rtc_clear_events,
};
static const struct of_device_id stm32_rtc_of_match[] = { static const struct of_device_id stm32_rtc_of_match[] = {
{ .compatible = "st,stm32-rtc", .data = &stm32_rtc_data }, { .compatible = "st,stm32-rtc", .data = &stm32_rtc_data },
{ .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data }, { .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data },
{ .compatible = "st,stm32mp1-rtc", .data = &stm32mp1_data },
{} {}
}; };
MODULE_DEVICE_TABLE(of, stm32_rtc_of_match); MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
@ -727,12 +785,19 @@ static int stm32_rtc_probe(struct platform_device *pdev)
goto err; goto err;
} }
platform_set_drvdata(pdev, rtc);
ret = device_init_wakeup(&pdev->dev, true); ret = device_init_wakeup(&pdev->dev, true);
if (rtc->data->has_wakeirq) {
rtc->wakeirq_alarm = platform_get_irq(pdev, 1);
if (rtc->wakeirq_alarm <= 0)
ret = rtc->wakeirq_alarm;
else
ret = dev_pm_set_dedicated_wake_irq(&pdev->dev,
rtc->wakeirq_alarm);
}
if (ret) if (ret)
dev_warn(&pdev->dev, dev_warn(&pdev->dev, "alarm can't wake up the system: %d", ret);
"alarm won't be able to wake up the system");
platform_set_drvdata(pdev, rtc);
rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name, rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
&stm32_rtc_ops, THIS_MODULE); &stm32_rtc_ops, THIS_MODULE);
@ -760,6 +825,14 @@ static int stm32_rtc_probe(struct platform_device *pdev)
if (!(readl_relaxed(rtc->base + regs->isr) & STM32_RTC_ISR_INITS)) if (!(readl_relaxed(rtc->base + regs->isr) & STM32_RTC_ISR_INITS))
dev_warn(&pdev->dev, "Date/Time must be initialized\n"); dev_warn(&pdev->dev, "Date/Time must be initialized\n");
if (regs->verr != UNDEF_REG) {
u32 ver = readl_relaxed(rtc->base + regs->verr);
dev_info(&pdev->dev, "registered rev:%d.%d\n",
(ver >> STM32_RTC_VERR_MAJREV_SHIFT) & 0xF,
(ver >> STM32_RTC_VERR_MINREV_SHIFT) & 0xF);
}
return 0; return 0;
err: err:
if (rtc->data->has_pclk) if (rtc->data->has_pclk)
@ -769,6 +842,7 @@ err:
if (rtc->data->need_dbp) if (rtc->data->need_dbp)
regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0); regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false); device_init_wakeup(&pdev->dev, false);
return ret; return ret;
@ -795,6 +869,7 @@ static int stm32_rtc_remove(struct platform_device *pdev)
if (rtc->data->need_dbp) if (rtc->data->need_dbp)
regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0); regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false); device_init_wakeup(&pdev->dev, false);
return 0; return 0;