diff options
author | Gregory CLEMENT <gregory.clement@free-electrons.com> | 2017-02-20 18:38:49 +0100 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2017-02-21 23:21:30 +0100 |
commit | 34f54f579a9988e96e85e22fc151c15955ae40f0 (patch) | |
tree | bc95b0472cebefc575f96ddd93a4a3b87d8cb3ee /drivers/rtc | |
parent | 75faea9179a775fbc3380e918ac90dc9991dc450 (diff) | |
download | linux-34f54f579a9988e96e85e22fc151c15955ae40f0.tar.gz linux-34f54f579a9988e96e85e22fc151c15955ae40f0.tar.bz2 linux-34f54f579a9988e96e85e22fc151c15955ae40f0.zip |
rtc: armada38x: Add support for Armada 7K/8K
The Armada 7K/8K use the same RTC IP than the Armada 38x. However the SOC
integration differs in 2 points:
- MBUS bridge timing initialization
- IRQ configuration at SoC level
Moreover the Armada 7K/8K have an issue preventing to get the interrupt
from alarm 1. This commit allows to use alarm 2 for these A7K/8K but to
still use alarm 1 for the Armada 38x.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/rtc-armada38x.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index b2a8e2ed71ca..21f355c37eab 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -24,18 +24,36 @@ #define RTC_STATUS_ALARM1 BIT(0) #define RTC_STATUS_ALARM2 BIT(1) #define RTC_IRQ1_CONF 0x4 +#define RTC_IRQ2_CONF 0x8 #define RTC_IRQ_AL_EN BIT(0) #define RTC_IRQ_FREQ_EN BIT(1) #define RTC_IRQ_FREQ_1HZ BIT(2) #define RTC_TIME 0xC #define RTC_ALARM1 0x10 +#define RTC_ALARM2 0x14 + +/* Armada38x SoC registers */ #define RTC_38X_BRIDGE_TIMING_CTL 0x0 #define RTC_38X_PERIOD_OFFS 0 #define RTC_38X_PERIOD_MASK (0x3FF << RTC_38X_PERIOD_OFFS) #define RTC_38X_READ_DELAY_OFFS 26 #define RTC_38X_READ_DELAY_MASK (0x1F << RTC_38X_READ_DELAY_OFFS) +/* Armada 7K/8K registers */ +#define RTC_8K_BRIDGE_TIMING_CTL0 0x0 +#define RTC_8K_WRCLK_PERIOD_OFFS 0 +#define RTC_8K_WRCLK_PERIOD_MASK (0xFFFF << RTC_8K_WRCLK_PERIOD_OFFS) +#define RTC_8K_WRCLK_SETUP_OFFS 16 +#define RTC_8K_WRCLK_SETUP_MASK (0xFFFF << RTC_8K_WRCLK_SETUP_OFFS) +#define RTC_8K_BRIDGE_TIMING_CTL1 0x4 +#define RTC_8K_READ_DELAY_OFFS 0 +#define RTC_8K_READ_DELAY_MASK (0xFFFF << RTC_8K_READ_DELAY_OFFS) + +#define RTC_8K_ISR 0x10 +#define RTC_8K_IMR 0x14 +#define RTC_8K_ALARM2 BIT(0) + #define SOC_RTC_INTERRUPT 0x8 #define SOC_RTC_ALARM1 BIT(0) #define SOC_RTC_ALARM2 BIT(1) @@ -60,6 +78,8 @@ struct armada38x_rtc { }; #define ALARM1 0 +#define ALARM2 1 + #define ALARM_REG(base, alarm) ((base) + (alarm) * sizeof(u32)) struct armada38x_rtc_data { @@ -102,6 +122,28 @@ static void rtc_update_38x_mbus_timing_params(struct armada38x_rtc *rtc) writel(reg, rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL); } +static void rtc_update_8k_mbus_timing_params(struct armada38x_rtc *rtc) +{ + u32 reg; + + reg = readl(rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL0); + reg &= ~RTC_8K_WRCLK_PERIOD_MASK; + reg |= 0x3FF << RTC_8K_WRCLK_PERIOD_OFFS; + reg &= ~RTC_8K_WRCLK_SETUP_MASK; + reg |= 0x29 << RTC_8K_WRCLK_SETUP_OFFS; + writel(reg, rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL0); + + reg = readl(rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL1); + reg &= ~RTC_8K_READ_DELAY_MASK; + reg |= 0x3F << RTC_8K_READ_DELAY_OFFS; + writel(reg, rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL1); +} + +static u32 read_rtc_register(struct armada38x_rtc *rtc, u8 rtc_reg) +{ + return readl(rtc->regs + rtc_reg); +} + static u32 read_rtc_register_38x_wa(struct armada38x_rtc *rtc, u8 rtc_reg) { int i, index_max = 0, max = 0; @@ -157,6 +199,17 @@ static void armada38x_unmask_interrupt(struct armada38x_rtc *rtc) writel(val | SOC_RTC_ALARM1_MASK, rtc->regs_soc + SOC_RTC_INTERRUPT); } + +static void armada8k_clear_isr(struct armada38x_rtc *rtc) +{ + writel(RTC_8K_ALARM2, rtc->regs_soc + RTC_8K_ISR); +} + +static void armada8k_unmask_interrupt(struct armada38x_rtc *rtc) +{ + writel(RTC_8K_ALARM2, rtc->regs_soc + RTC_8K_IMR); +} + static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct armada38x_rtc *rtc = dev_get_drvdata(dev); @@ -312,12 +365,24 @@ static const struct armada38x_rtc_data armada38x_data = { .alarm = ALARM1, }; +static const struct armada38x_rtc_data armada8k_data = { + .update_mbus_timing = rtc_update_8k_mbus_timing_params, + .read_rtc_reg = read_rtc_register, + .clear_isr = armada8k_clear_isr, + .unmask_interrupt = armada8k_unmask_interrupt, + .alarm = ALARM2, +}; + #ifdef CONFIG_OF static const struct of_device_id armada38x_rtc_of_match_table[] = { { .compatible = "marvell,armada-380-rtc", .data = &armada38x_data, }, + { + .compatible = "marvell,armada-8k-rtc", + .data = &armada8k_data, + }, {} }; MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table); |