From 6575bd7cbcc40dcdffb62e710ab2cd05355396c6 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 23 Sep 2014 13:13:29 +0200 Subject: rtc: at91sam9: remove references to mach specific headers In order to support multi platform kernel drivers should not include machine specific headers. Copy RTT macros in the driver code and remove any machine specific headers. Signed-off-by: Boris BREZILLON Acked-by: Alexandre Belloni Acked-by: Johan Hovold Acked-by: Arnd Bergmann Signed-off-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 596374304532..51f0038949df 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -22,10 +22,6 @@ #include #include -#include -#include -#include - /* * This driver uses two configurable hardware resources that live in the * AT91SAM9 backup power domain (intended to be powered at all times) @@ -47,6 +43,24 @@ * registers available, likewise usable for more than "RTC" support. */ +#define AT91_RTT_MR 0x00 /* Real-time Mode Register */ +#define AT91_RTT_RTPRES (0xffff << 0) /* Real-time Timer Prescaler Value */ +#define AT91_RTT_ALMIEN (1 << 16) /* Alarm Interrupt Enable */ +#define AT91_RTT_RTTINCIEN (1 << 17) /* Real Time Timer Increment Interrupt Enable */ +#define AT91_RTT_RTTRST (1 << 18) /* Real Time Timer Restart */ + +#define AT91_RTT_AR 0x04 /* Real-time Alarm Register */ +#define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */ + +#define AT91_RTT_VR 0x08 /* Real-time Value Register */ +#define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */ + +#define AT91_RTT_SR 0x0c /* Real-time Status Register */ +#define AT91_RTT_ALMS (1 << 0) /* Real-time Alarm Status */ +#define AT91_RTT_RTTINC (1 << 1) /* Real-time Timer Increment */ + +#define AT91_SLOW_CLOCK 32768 + /* * We store ALARM_DISABLED in ALMV to record that no alarm is set. * It's also the reset value for that field. -- cgit v1.2.3 From 272f1dfa617ac2eb02a34f534d8d24a6b97eeb08 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 23 Sep 2014 13:13:52 +0200 Subject: rtc: at91sam9: use standard readl/writel functions instead of raw versions Raw versions of writel and writel should not be directly used and should be replaced by their relaxed versions (readl/writel_relaxed), which take endianness conversion into account. In this driver we prefer the standard readl/writel function which add the appropriate memory barrier around the access (the performance penalty is negligible for this kind of application). Signed-off-by: Boris BREZILLON Acked-by: Alexandre Belloni Acked-by: Johan Hovold Acked-by: Arnd Bergmann Signed-off-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 51f0038949df..74a9ca0bbeb4 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -77,14 +77,14 @@ struct sam9_rtc { }; #define rtt_readl(rtc, field) \ - __raw_readl((rtc)->rtt + AT91_RTT_ ## field) + readl((rtc)->rtt + AT91_RTT_ ## field) #define rtt_writel(rtc, field, val) \ - __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field) + writel((val), (rtc)->rtt + AT91_RTT_ ## field) #define gpbr_readl(rtc) \ - __raw_readl((rtc)->gpbr) + readl((rtc)->gpbr) #define gpbr_writel(rtc, val) \ - __raw_writel((val), (rtc)->gpbr) + writel((val), (rtc)->gpbr) /* * Read current time and date in RTC -- cgit v1.2.3 From d41da3ee1a9c46d175ca4cdca369f35c35f89cdc Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 23 Sep 2014 13:14:09 +0200 Subject: rtc: at91sam9: replace devm_ioremap by devm_ioremap_resource Replace devm_ioremap calls by devm_ioremap_resource which already check resource consistency (resource != NULL) and print an error in case of failure. Signed-off-by: Boris BREZILLON Acked-by: Alexandre Belloni Acked-by: Johan Hovold Acked-by: Arnd Bergmann Signed-off-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 74a9ca0bbeb4..38a26931b659 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -306,18 +306,11 @@ static const struct rtc_class_ops at91_rtc_ops = { */ static int at91_rtc_probe(struct platform_device *pdev) { - struct resource *r, *r_gpbr; + struct resource *r; struct sam9_rtc *rtc; int ret, irq; u32 mr; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!r || !r_gpbr) { - dev_err(&pdev->dev, "need 2 ressources\n"); - return -ENODEV; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get interrupt resource\n"); @@ -335,18 +328,16 @@ static int at91_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, rtc); - rtc->rtt = devm_ioremap(&pdev->dev, r->start, resource_size(r)); - if (!rtc->rtt) { - dev_err(&pdev->dev, "failed to map registers, aborting.\n"); - return -ENOMEM; - } - rtc->gpbr = devm_ioremap(&pdev->dev, r_gpbr->start, - resource_size(r_gpbr)); - if (!rtc->gpbr) { - dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n"); - return -ENOMEM; - } + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rtc->rtt = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(rtc->rtt)) + return PTR_ERR(rtc->rtt); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 1); + rtc->gpbr = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(rtc->gpbr)) + return PTR_ERR(rtc->rtt); mr = rtt_readl(rtc, MR); -- cgit v1.2.3 From 07d4d72450ef9bf317dff3d9f3bcad8d1f220f58 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 23 Sep 2014 13:14:24 +0200 Subject: rtc: at91sam9: add DT support Add of_match_table to the existing driver so that rtt nodes defined in at91 DTs can be attached to this driver. Signed-off-by: Boris BREZILLON Acked-by: Alexandre Belloni Acked-by: Johan Hovold Acked-by: Arnd Bergmann Signed-off-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 38a26931b659..d72c34d3f130 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -445,6 +445,14 @@ static int at91_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); +#ifdef CONFIG_OF +static const struct of_device_id at91_rtc_dt_ids[] = { + { .compatible = "atmel,at91sam9260-rtt" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); +#endif + static struct platform_driver at91_rtc_driver = { .probe = at91_rtc_probe, .remove = at91_rtc_remove, @@ -453,6 +461,7 @@ static struct platform_driver at91_rtc_driver = { .name = "rtc-at91sam9", .owner = THIS_MODULE, .pm = &at91_rtc_pm_ops, + .of_match_table = of_match_ptr(at91_rtc_dt_ids), }, }; -- cgit v1.2.3 From 43e112bb3dea87f392871220fcde175c814e26ca Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 23 Sep 2014 13:14:44 +0200 Subject: rtc: at91sam9: make use of syscon/regmap to access GPBR registers The GPBR registers are not part of the RTT block and thus should not be defined in the reg property of the rtt node. Use syscon to provide a proper DT representation and reference the GPBR syscon device in a new "atmel,rtt-rtc-time-reg" property which store both the syscon device phandle and the register offset within the GPBR block. When using non DT boards, we won't be able to retrieve the syscon regmap, hence we need to create our own regmap using the memory region defined in the 2nd memory resource assigned to the RTT platform device. Signed-off-by: Boris BREZILLON Acked-by: Alexandre Belloni Acked-by: Johan Hovold Acked-by: Arnd Bergmann Signed-off-by: Nicolas Ferre --- drivers/rtc/Kconfig | 1 + drivers/rtc/rtc-at91sam9.c | 64 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 56 insertions(+), 9 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 94ae1798d48a..7b1f59258062 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1111,6 +1111,7 @@ config RTC_DRV_AT91RM9200 config RTC_DRV_AT91SAM9 tristate "AT91SAM9x/AT91CAP9 RTT as RTC" depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40) + select MFD_SYSCON help RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT (Real Time Timer). These timers are powered by the backup power diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index d72c34d3f130..be9c28b9d057 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include /* * This driver uses two configurable hardware resources that live in the @@ -72,7 +74,8 @@ struct sam9_rtc { void __iomem *rtt; struct rtc_device *rtcdev; u32 imr; - void __iomem *gpbr; + struct regmap *gpbr; + unsigned int gpbr_offset; int irq; }; @@ -81,10 +84,19 @@ struct sam9_rtc { #define rtt_writel(rtc, field, val) \ writel((val), (rtc)->rtt + AT91_RTT_ ## field) -#define gpbr_readl(rtc) \ - readl((rtc)->gpbr) -#define gpbr_writel(rtc, val) \ - writel((val), (rtc)->gpbr) +static inline unsigned int gpbr_readl(struct sam9_rtc *rtc) +{ + unsigned int val; + + regmap_read(rtc->gpbr, rtc->gpbr_offset, &val); + + return val; +} + +static inline void gpbr_writel(struct sam9_rtc *rtc, unsigned int val) +{ + regmap_write(rtc->gpbr, rtc->gpbr_offset, val); +} /* * Read current time and date in RTC @@ -301,6 +313,12 @@ static const struct rtc_class_ops at91_rtc_ops = { .alarm_irq_enable = at91_rtc_alarm_irq_enable, }; +static struct regmap_config gpbr_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + /* * Initialize and install RTC driver */ @@ -334,10 +352,38 @@ static int at91_rtc_probe(struct platform_device *pdev) if (IS_ERR(rtc->rtt)) return PTR_ERR(rtc->rtt); - r = platform_get_resource(pdev, IORESOURCE_MEM, 1); - rtc->gpbr = devm_ioremap_resource(&pdev->dev, r); - if (IS_ERR(rtc->gpbr)) - return PTR_ERR(rtc->rtt); + if (!pdev->dev.of_node) { + /* + * TODO: Remove this code chunk when removing non DT board + * support. Remember to remove the gpbr_regmap_config + * variable too. + */ + void __iomem *gpbr; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 1); + gpbr = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(gpbr)) + return PTR_ERR(gpbr); + + rtc->gpbr = regmap_init_mmio(NULL, gpbr, + &gpbr_regmap_config); + } else { + struct of_phandle_args args; + + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "atmel,rtt-rtc-time-reg", 1, 0, + &args); + if (ret) + return ret; + + rtc->gpbr = syscon_node_to_regmap(args.np); + rtc->gpbr_offset = args.args[0]; + } + + if (IS_ERR(rtc->gpbr)) { + dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n"); + return -ENOMEM; + } mr = rtt_readl(rtc, MR); -- cgit v1.2.3 From 3969eb48ad7f3f3bef61f5474b7214e601fd2d75 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 23 Sep 2014 13:16:05 +0200 Subject: rtc: at91sam9: rework the Kconfig description Remove all references to AT91CAP9 SoC which has been removed. Rework help message to remove any specific references to AT91SAM9 SoCs. State that RTC_DRV_AT91SAM9_RTT and RTC_DRV_AT91SAM9_GPBR options are only used when booting non DT boards. Signed-off-by: Boris BREZILLON Acked-by: Johan Hovold Acked-by: Arnd Bergmann Signed-off-by: Nicolas Ferre --- drivers/rtc/Kconfig | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 7b1f59258062..5bdd6524f91b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1109,17 +1109,18 @@ config RTC_DRV_AT91RM9200 this is powered by the backup power supply. config RTC_DRV_AT91SAM9 - tristate "AT91SAM9x/AT91CAP9 RTT as RTC" + tristate "AT91SAM9 RTT as RTC" depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40) select MFD_SYSCON help - RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT - (Real Time Timer). These timers are powered by the backup power - supply (such as a small coin cell battery), but do not need to - be used as RTCs. - - (On AT91SAM9rl and AT91SAM9G45 chips you probably want to use the - dedicated RTC module and leave the RTT available for other uses.) + Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which + can be used as an RTC thanks to the backup power supply (e.g. a + small coin cell battery) which keeps this block and the GPBR + (General Purpose Backup Registers) block powered when the device + is shutdown. + Some AT91SAM9 SoCs provide a real RTC block, on those ones you'd + probably want to use the real RTC block instead of the "RTT as an + RTC" driver. config RTC_DRV_AT91SAM9_RTT int @@ -1128,6 +1129,9 @@ config RTC_DRV_AT91SAM9_RTT prompt "RTT module Number" if ARCH_AT91SAM9263 depends on RTC_DRV_AT91SAM9 help + This option is only relevant for legacy board support and + won't be used when booting a DT board. + More than one RTT module is available. You can choose which one will be used as an RTC. The default of zero is normally OK to use, though some systems use that for non-RTC purposes. @@ -1140,6 +1144,9 @@ config RTC_DRV_AT91SAM9_GPBR prompt "Backup Register Number" depends on RTC_DRV_AT91SAM9 help + This option is only relevant for legacy board support and + won't be used when booting a DT board. + The RTC driver needs to use one of the General Purpose Backup Registers (GPBRs) as well as the RTT. You can choose which one will be used. The default of zero is normally OK to use, but -- cgit v1.2.3 From a975f47f6e9a4e9762c81973cf2305003aa5b7dc Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 23 Sep 2014 16:41:07 +0200 Subject: rtc: at91sam9: use clk API instead of relying on AT91_SLOW_CLOCK The RTT block is using the slow clock which is accessible through the clk API. Use the clk API to retrieve, enable and get the slow clk rate instead of the AT91_SLOW_CLOCK macro (which hardcodes the slow clk rate). Doing this allows us to reference the clk thus preventing the CCF from disabling it during the "disable unused" phase. Signed-off-by: Boris BREZILLON Acked-by: Alexandre Belloni Acked-by: Johan Hovold Acked-by: Arnd Bergmann Signed-off-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index be9c28b9d057..abac38abd38e 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -23,6 +23,7 @@ #include #include #include +#include /* * This driver uses two configurable hardware resources that live in the @@ -61,8 +62,6 @@ #define AT91_RTT_ALMS (1 << 0) /* Real-time Alarm Status */ #define AT91_RTT_RTTINC (1 << 1) /* Real-time Timer Increment */ -#define AT91_SLOW_CLOCK 32768 - /* * We store ALARM_DISABLED in ALMV to record that no alarm is set. * It's also the reset value for that field. @@ -77,6 +76,7 @@ struct sam9_rtc { struct regmap *gpbr; unsigned int gpbr_offset; int irq; + struct clk *sclk; }; #define rtt_readl(rtc, field) \ @@ -328,6 +328,7 @@ static int at91_rtc_probe(struct platform_device *pdev) struct sam9_rtc *rtc; int ret, irq; u32 mr; + unsigned int sclk_rate; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -385,11 +386,27 @@ static int at91_rtc_probe(struct platform_device *pdev) return -ENOMEM; } + rtc->sclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(rtc->sclk)) + return PTR_ERR(rtc->sclk); + + sclk_rate = clk_get_rate(rtc->sclk); + if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) { + dev_err(&pdev->dev, "Invalid slow clock rate\n"); + return -EINVAL; + } + + ret = clk_prepare_enable(rtc->sclk); + if (ret) { + dev_err(&pdev->dev, "Could not enable slow clock\n"); + return ret; + } + mr = rtt_readl(rtc, MR); /* unless RTT is counting at 1 Hz, re-initialize it */ - if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) { - mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES); + if ((mr & AT91_RTT_RTPRES) != sclk_rate) { + mr = AT91_RTT_RTTRST | (sclk_rate & AT91_RTT_RTPRES); gpbr_writel(rtc, 0); } @@ -434,6 +451,9 @@ static int at91_rtc_remove(struct platform_device *pdev) /* disable all interrupts */ rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); + if (!IS_ERR(rtc->sclk)) + clk_disable_unprepare(rtc->sclk); + return 0; } -- cgit v1.2.3