diff options
Diffstat (limited to 'target/linux/mvebu/patches-3.18/600-armada_38x_rtc.patch')
-rw-r--r-- | target/linux/mvebu/patches-3.18/600-armada_38x_rtc.patch | 403 |
1 files changed, 0 insertions, 403 deletions
diff --git a/target/linux/mvebu/patches-3.18/600-armada_38x_rtc.patch b/target/linux/mvebu/patches-3.18/600-armada_38x_rtc.patch deleted file mode 100644 index 399421d..0000000 --- a/target/linux/mvebu/patches-3.18/600-armada_38x_rtc.patch +++ /dev/null @@ -1,403 +0,0 @@ ---- /dev/null -+++ b/Documentation/devicetree/bindings/rtc/armada-380-rtc.txt -@@ -0,0 +1,22 @@ -+* Real Time Clock of the Armada 38x SoCs -+ -+RTC controller for the Armada 38x SoCs -+ -+Required properties: -+- compatible : Should be "marvell,armada-380-rtc" -+- reg: a list of base address and size pairs, one for each entry in -+ reg-names -+- reg names: should contain: -+ * "rtc" for the RTC registers -+ * "rtc-soc" for the SoC related registers and among them the one -+ related to the interrupt. -+- interrupts: IRQ line for the RTC. -+ -+Example: -+ -+rtc@a3800 { -+ compatible = "marvell,armada-380-rtc"; -+ reg = <0xa3800 0x20>, <0x184a0 0x0c>; -+ reg-names = "rtc", "rtc-soc"; -+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; -+}; ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -1262,6 +1262,16 @@ config RTC_DRV_MV - This driver can also be built as a module. If so, the module - will be called rtc-mv. - -+config RTC_DRV_ARMADA38X -+ tristate "Armada 38x Marvell SoC RTC" -+ depends on ARCH_MVEBU -+ help -+ If you say yes here you will get support for the in-chip RTC -+ that can be found in the Armada 38x Marvell's SoC device -+ -+ This driver can also be built as a module. If so, the module -+ will be called armada38x-rtc. -+ - config RTC_DRV_PS3 - tristate "PS3 RTC" - depends on PPC_PS3 ---- a/drivers/rtc/Makefile -+++ b/drivers/rtc/Makefile -@@ -24,6 +24,7 @@ obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-8 - obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o - obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o - obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o -+obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o - obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o - obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o - obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o ---- /dev/null -+++ b/drivers/rtc/rtc-armada38x.c -@@ -0,0 +1,320 @@ -+/* -+ * RTC driver for the Armada 38x Marvell SoCs -+ * -+ * Copyright (C) 2015 Marvell -+ * -+ * Gregory Clement <gregory.clement@free-electrons.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ */ -+ -+#include <linux/delay.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/platform_device.h> -+#include <linux/rtc.h> -+ -+#define RTC_STATUS 0x0 -+#define RTC_STATUS_ALARM1 BIT(0) -+#define RTC_STATUS_ALARM2 BIT(1) -+#define RTC_IRQ1_CONF 0x4 -+#define RTC_IRQ1_AL_EN BIT(0) -+#define RTC_IRQ1_FREQ_EN BIT(1) -+#define RTC_IRQ1_FREQ_1HZ BIT(2) -+#define RTC_TIME 0xC -+#define RTC_ALARM1 0x10 -+ -+#define SOC_RTC_INTERRUPT 0x8 -+#define SOC_RTC_ALARM1 BIT(0) -+#define SOC_RTC_ALARM2 BIT(1) -+#define SOC_RTC_ALARM1_MASK BIT(2) -+#define SOC_RTC_ALARM2_MASK BIT(3) -+ -+struct armada38x_rtc { -+ struct rtc_device *rtc_dev; -+ void __iomem *regs; -+ void __iomem *regs_soc; -+ spinlock_t lock; -+ int irq; -+}; -+ -+/* -+ * According to the datasheet, the OS should wait 5us after every -+ * register write to the RTC hard macro so that the required update -+ * can occur without holding off the system bus -+ */ -+static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset) -+{ -+ writel(val, rtc->regs + offset); -+ udelay(5); -+} -+ -+static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) -+{ -+ struct armada38x_rtc *rtc = dev_get_drvdata(dev); -+ unsigned long time, time_check, flags; -+ -+ spin_lock_irqsave(&rtc->lock, flags); -+ -+ time = readl(rtc->regs + RTC_TIME); -+ /* -+ * WA for failing time set attempts. As stated in HW ERRATA if -+ * more than one second between two time reads is detected -+ * then read once again. -+ */ -+ time_check = readl(rtc->regs + RTC_TIME); -+ if ((time_check - time) > 1) -+ time_check = readl(rtc->regs + RTC_TIME); -+ -+ spin_unlock_irqrestore(&rtc->lock, flags); -+ -+ rtc_time_to_tm(time_check, tm); -+ -+ return 0; -+} -+ -+static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm) -+{ -+ struct armada38x_rtc *rtc = dev_get_drvdata(dev); -+ int ret = 0; -+ unsigned long time, flags; -+ -+ ret = rtc_tm_to_time(tm, &time); -+ -+ if (ret) -+ goto out; -+ /* -+ * Setting the RTC time not always succeeds. According to the -+ * errata we need to first write on the status register and -+ * then wait for 100ms before writing to the time register to be -+ * sure that the data will be taken into account. -+ */ -+ spin_lock_irqsave(&rtc->lock, flags); -+ -+ rtc_delayed_write(0, rtc, RTC_STATUS); -+ -+ spin_unlock_irqrestore(&rtc->lock, flags); -+ -+ msleep(100); -+ -+ spin_lock_irqsave(&rtc->lock, flags); -+ -+ rtc_delayed_write(time, rtc, RTC_TIME); -+ -+ spin_unlock_irqrestore(&rtc->lock, flags); -+out: -+ return ret; -+} -+ -+static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) -+{ -+ struct armada38x_rtc *rtc = dev_get_drvdata(dev); -+ unsigned long time, flags; -+ u32 val; -+ -+ spin_lock_irqsave(&rtc->lock, flags); -+ -+ time = readl(rtc->regs + RTC_ALARM1); -+ val = readl(rtc->regs + RTC_IRQ1_CONF) & RTC_IRQ1_AL_EN; -+ -+ spin_unlock_irqrestore(&rtc->lock, flags); -+ -+ alrm->enabled = val ? 1 : 0; -+ rtc_time_to_tm(time, &alrm->time); -+ -+ return 0; -+} -+ -+static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) -+{ -+ struct armada38x_rtc *rtc = dev_get_drvdata(dev); -+ unsigned long time, flags; -+ int ret = 0; -+ u32 val; -+ -+ ret = rtc_tm_to_time(&alrm->time, &time); -+ -+ if (ret) -+ goto out; -+ -+ spin_lock_irqsave(&rtc->lock, flags); -+ -+ rtc_delayed_write(time, rtc, RTC_ALARM1); -+ -+ if (alrm->enabled) { -+ rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF); -+ val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT); -+ writel(val | SOC_RTC_ALARM1_MASK, -+ rtc->regs_soc + SOC_RTC_INTERRUPT); -+ } -+ -+ spin_unlock_irqrestore(&rtc->lock, flags); -+ -+out: -+ return ret; -+} -+ -+static int armada38x_rtc_alarm_irq_enable(struct device *dev, -+ unsigned int enabled) -+{ -+ struct armada38x_rtc *rtc = dev_get_drvdata(dev); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&rtc->lock, flags); -+ -+ if (enabled) -+ rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF); -+ else -+ rtc_delayed_write(0, rtc, RTC_IRQ1_CONF); -+ -+ spin_unlock_irqrestore(&rtc->lock, flags); -+ -+ return 0; -+} -+ -+static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data) -+{ -+ struct armada38x_rtc *rtc = data; -+ u32 val; -+ int event = RTC_IRQF | RTC_AF; -+ -+ dev_dbg(&rtc->rtc_dev->dev, "%s:irq(%d)\n", __func__, irq); -+ -+ spin_lock(&rtc->lock); -+ -+ val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT); -+ -+ writel(val & ~SOC_RTC_ALARM1, rtc->regs_soc + SOC_RTC_INTERRUPT); -+ val = readl(rtc->regs + RTC_IRQ1_CONF); -+ /* disable all the interrupts for alarm 1 */ -+ rtc_delayed_write(0, rtc, RTC_IRQ1_CONF); -+ /* Ack the event */ -+ rtc_delayed_write(RTC_STATUS_ALARM1, rtc, RTC_STATUS); -+ -+ spin_unlock(&rtc->lock); -+ -+ if (val & RTC_IRQ1_FREQ_EN) { -+ if (val & RTC_IRQ1_FREQ_1HZ) -+ event |= RTC_UF; -+ else -+ event |= RTC_PF; -+ } -+ -+ rtc_update_irq(rtc->rtc_dev, 1, event); -+ -+ return IRQ_HANDLED; -+} -+ -+static struct rtc_class_ops armada38x_rtc_ops = { -+ .read_time = armada38x_rtc_read_time, -+ .set_time = armada38x_rtc_set_time, -+ .read_alarm = armada38x_rtc_read_alarm, -+ .set_alarm = armada38x_rtc_set_alarm, -+ .alarm_irq_enable = armada38x_rtc_alarm_irq_enable, -+}; -+ -+static __init int armada38x_rtc_probe(struct platform_device *pdev) -+{ -+ struct resource *res; -+ struct armada38x_rtc *rtc; -+ int ret; -+ -+ rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc), -+ GFP_KERNEL); -+ if (!rtc) -+ return -ENOMEM; -+ -+ spin_lock_init(&rtc->lock); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc"); -+ rtc->regs = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(rtc->regs)) -+ return PTR_ERR(rtc->regs); -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc-soc"); -+ rtc->regs_soc = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(rtc->regs_soc)) -+ return PTR_ERR(rtc->regs_soc); -+ -+ rtc->irq = platform_get_irq(pdev, 0); -+ -+ if (rtc->irq < 0) { -+ dev_err(&pdev->dev, "no irq\n"); -+ return rtc->irq; -+ } -+ if (devm_request_irq(&pdev->dev, rtc->irq, armada38x_rtc_alarm_irq, -+ 0, pdev->name, rtc) < 0) { -+ dev_warn(&pdev->dev, "Interrupt not available.\n"); -+ rtc->irq = -1; -+ /* -+ * If there is no interrupt available then we can't -+ * use the alarm -+ */ -+ armada38x_rtc_ops.set_alarm = NULL; -+ armada38x_rtc_ops.alarm_irq_enable = NULL; -+ } -+ platform_set_drvdata(pdev, rtc); -+ if (rtc->irq != -1) -+ device_init_wakeup(&pdev->dev, 1); -+ -+ rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name, -+ &armada38x_rtc_ops, THIS_MODULE); -+ if (IS_ERR(rtc->rtc_dev)) { -+ ret = PTR_ERR(rtc->rtc_dev); -+ dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); -+ return ret; -+ } -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int armada38x_rtc_suspend(struct device *dev) -+{ -+ if (device_may_wakeup(dev)) { -+ struct armada38x_rtc *rtc = dev_get_drvdata(dev); -+ -+ return enable_irq_wake(rtc->irq); -+ } -+ -+ return 0; -+} -+ -+static int armada38x_rtc_resume(struct device *dev) -+{ -+ if (device_may_wakeup(dev)) { -+ struct armada38x_rtc *rtc = dev_get_drvdata(dev); -+ -+ return disable_irq_wake(rtc->irq); -+ } -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(armada38x_rtc_pm_ops, -+ armada38x_rtc_suspend, armada38x_rtc_resume); -+ -+#ifdef CONFIG_OF -+static const struct of_device_id armada38x_rtc_of_match_table[] = { -+ { .compatible = "marvell,armada-380-rtc", }, -+ {} -+}; -+#endif -+ -+static struct platform_driver armada38x_rtc_driver = { -+ .driver = { -+ .name = "armada38x-rtc", -+ .pm = &armada38x_rtc_pm_ops, -+ .of_match_table = of_match_ptr(armada38x_rtc_of_match_table), -+ }, -+}; -+ -+module_platform_driver_probe(armada38x_rtc_driver, armada38x_rtc_probe); -+ -+MODULE_DESCRIPTION("Marvell Armada 38x RTC driver"); -+MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>"); -+MODULE_LICENSE("GPL"); ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -1136,6 +1136,7 @@ M: Sebastian Hesselbarth <sebastian.hess - L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) - S: Maintained - F: arch/arm/mach-mvebu/ -+F: drivers/rtc/armada38x-rtc - - ARM/Marvell Berlin SoC support - M: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> ---- a/arch/arm/boot/dts/armada-38x.dtsi -+++ b/arch/arm/boot/dts/armada-38x.dtsi -@@ -420,6 +420,13 @@ - clocks = <&gateclk 4>; - }; - -+ rtc@a3800 { -+ compatible = "marvell,armada-380-rtc"; -+ reg = <0xa3800 0x20>, <0x184a0 0x0c>; -+ reg-names = "rtc", "rtc-soc"; -+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; -+ }; -+ - sata@a8000 { - compatible = "marvell,armada-380-ahci"; - reg = <0xa8000 0x2000>; |