[PATCH] S3C RTC driver: add support for S3C64xx

From: Maurus Cuelenaere
Date: Mon Mar 08 2010 - 15:12:43 EST


Add support for the S3C64xx SoC to the generic S3C RTC driver.

Signed-off-by: Maurus Cuelenaere <mcuelenaere@xxxxxxxxx>
Acked-By: Ben Dooks <ben-linux@xxxxxxxxx>
---

This was sent to rtc-linux before (2010-01-12), but no response was
received yet.
See http://groups.google.com/group/rtc-linux/browse_thread/thread/2a2dfc23a8042f3d/2812dcbafd9a0a85
for the full thread.

Âarch/arm/plat-s3c/include/plat/regs-rtc.h | Â Â4 +
Âdrivers/rtc/Kconfig            |  Â2 +-
Âdrivers/rtc/rtc-s3c.c           | Â107 +++++++++++++++++++++++------
Â3 files changed, 92 insertions(+), 21 deletions(-)

diff --git a/arch/arm/plat-s3c/include/plat/regs-rtc.h
b/arch/arm/plat-s3c/include/plat/regs-rtc.h
index d5837cf..65c190d 100644
--- a/arch/arm/plat-s3c/include/plat/regs-rtc.h
+++ b/arch/arm/plat-s3c/include/plat/regs-rtc.h
@@ -20,6 +20,10 @@
Â#define S3C2410_RTCCON_CLKSEL (1<<1)
Â#define S3C2410_RTCCON_CNTSEL (1<<2)
Â#define S3C2410_RTCCON_CLKRST (1<<3)
+#define S3C64XX_RTCCON_TICEN Â(1<<8)
+
+#define S3C64XX_RTCCON_TICMSK (0xF<<7)
+#define S3C64XX_RTCCON_TICSHT (7)

Â#define S3C2410_TICNT Â Â Â ÂS3C2410_RTCREG(0x44)
Â#define S3C2410_TICNT_ENABLE Â(1<<7)
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 8167e9e..b44db44 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -620,7 +620,7 @@ config RTC_DRV_OMAP

Âconfig RTC_DRV_S3C
   Âtristate "Samsung S3C series SoC RTC"
- Â Â Â depends on ARCH_S3C2410
+ Â Â Â depends on ARCH_S3C2410 || ARCH_S3C64XX
   Âhelp
    ÂRTC (Realtime Clock) driver for the clock inbuilt into the
    ÂSamsung S3C24XX series of SoCs. This can provide periodic
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index e0d7b99..798d2dd 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -28,6 +28,11 @@
Â#include <asm/irq.h>
Â#include <plat/regs-rtc.h>

+enum s3c_cpu_type {
+ Â Â Â TYPE_S3C2410,
+ Â Â Â TYPE_S3C64XX,
+};
+
Â/* I have yet to find an S3C implementation with more than one
Â* of these rtc blocks in */

@@ -36,6 +41,7 @@ static struct resource *s3c_rtc_mem;
Âstatic void __iomem *s3c_rtc_base;
Âstatic int s3c_rtc_alarmno = NO_IRQ;
Âstatic int s3c_rtc_tickno Â= NO_IRQ;
+static enum s3c_cpu_type s3c_rtc_cpu_type;

Âstatic DEFINE_SPINLOCK(s3c_rtc_pie_lock);

@@ -79,12 +85,25 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
   Âpr_debug("%s: pie=%d\n", __func__, enabled);

   Âspin_lock_irq(&s3c_rtc_pie_lock);
- Â Â Â tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;

- Â Â Â if (enabled)
- Â Â Â Â Â Â Â tmp |= S3C2410_TICNT_ENABLE;
+ Â Â Â if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+ Â Â Â Â Â Â Â tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
+ Â Â Â Â Â Â Â tmp &= ~S3C64XX_RTCCON_TICEN;
+
+ Â Â Â Â Â Â Â if (enabled)
+ Â Â Â Â Â Â Â Â Â Â Â tmp |= S3C64XX_RTCCON_TICEN;
+
+ Â Â Â Â Â Â Â writeb(tmp, s3c_rtc_base + S3C2410_RTCCON);
+ Â Â Â } else {
+ Â Â Â Â Â Â Â tmp = readb(s3c_rtc_base + S3C2410_TICNT);
+ Â Â Â Â Â Â Â tmp &= ~S3C2410_TICNT_ENABLE;
+
+ Â Â Â Â Â Â Â if (enabled)
+ Â Â Â Â Â Â Â Â Â Â Â tmp |= S3C2410_TICNT_ENABLE;
+
+ Â Â Â Â Â Â Â writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
+ Â Â Â }

- Â Â Â writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
   Âspin_unlock_irq(&s3c_rtc_pie_lock);

   Âreturn 0;
@@ -92,15 +111,21 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)

Âstatic int s3c_rtc_setfreq(struct device *dev, int freq)
Â{
- Â Â Â unsigned int tmp;
+ Â Â Â struct platform_device *pdev = to_platform_device(dev);
+ Â Â Â struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
+ Â Â Â unsigned int tmp = 0;

   Âif (!is_power_of_2(freq))
       Âreturn -EINVAL;

   Âspin_lock_irq(&s3c_rtc_pie_lock);

- Â Â Â tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
- Â Â Â tmp |= (128 / freq)-1;
+ Â Â Â if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+ Â Â Â Â Â Â Â tmp = readb(s3c_rtc_base + S3C2410_TICNT);
+ Â Â Â Â Â Â Â tmp &= S3C2410_TICNT_ENABLE;
+ Â Â Â }
+
+ Â Â Â tmp |= (rtc_dev->max_user_freq / freq)-1;

   Âwriteb(tmp, s3c_rtc_base + S3C2410_TICNT);
   Âspin_unlock_irq(&s3c_rtc_pie_lock);
@@ -282,10 +307,17 @@ static int s3c_rtc_setalarm(struct device *dev,
struct rtc_wkalrm *alrm)

Âstatic int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
Â{
- Â Â Â unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
+ Â Â Â unsigned int ticnt;

- Â Â Â seq_printf(seq, "periodic_IRQ\t: %s\n",
- Â Â Â Â Â Â Â Â Â Â(ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
+ Â Â Â if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+ Â Â Â Â Â Â Â ticnt = readb(s3c_rtc_base + S3C2410_RTCCON);
+ Â Â Â Â Â Â Â ticnt &= S3C64XX_RTCCON_TICEN;
+ Â Â Â } else {
+ Â Â Â Â Â Â Â ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
+ Â Â Â Â Â Â Â ticnt &= S3C2410_TICNT_ENABLE;
+ Â Â Â }
+
+ Â Â Â seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt Â? "yes" : "no");
   Âreturn 0;
Â}

@@ -352,10 +384,16 @@ static void s3c_rtc_enable(struct
platform_device *pdev, int en)

   Âif (!en) {
       Âtmp = readb(base + S3C2410_RTCCON);
- Â Â Â Â Â Â Â writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON);
-
- Â Â Â Â Â Â Â tmp = readb(base + S3C2410_TICNT);
- Â Â Â Â Â Â Â writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT);
+ Â Â Â Â Â Â Â if (s3c_rtc_cpu_type == TYPE_S3C64XX)
+ Â Â Â Â Â Â Â Â Â Â Â tmp &= ~S3C64XX_RTCCON_TICEN;
+ Â Â Â Â Â Â Â tmp &= ~S3C2410_RTCCON_RTCEN;
+ Â Â Â Â Â Â Â writeb(tmp, base + S3C2410_RTCCON);
+
+ Â Â Â Â Â Â Â if (s3c_rtc_cpu_type == TYPE_S3C2410) {
+ Â Â Â Â Â Â Â Â Â Â Â tmp = readb(base + S3C2410_TICNT);
+ Â Â Â Â Â Â Â Â Â Â Â tmp &= ~S3C2410_TICNT_ENABLE;
+ Â Â Â Â Â Â Â Â Â Â Â writeb(tmp, base + S3C2410_TICNT);
+ Â Â Â Â Â Â Â }
   Â} else {
       Â/* re-enable the device, and check it is ok */

@@ -471,7 +509,12 @@ static int __devinit s3c_rtc_probe(struct
platform_device *pdev)
       Âgoto err_nortc;
   Â}

- Â Â Â rtc->max_user_freq = 128;
+ Â Â Â if (s3c_rtc_cpu_type == TYPE_S3C64XX)
+ Â Â Â Â Â Â Â rtc->max_user_freq = 32768;
+ Â Â Â else
+ Â Â Â Â Â Â Â rtc->max_user_freq = 128;
+
+ Â Â Â s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;

   Âplatform_set_drvdata(pdev, rtc);
   Âreturn 0;
@@ -491,20 +534,30 @@ static int __devinit s3c_rtc_probe(struct
platform_device *pdev)

Â/* RTC Power management control */

-static int ticnt_save;
+static int ticnt_save, ticnt_en_save;

Âstatic int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
Â{
   Â/* save TICNT for anyone using periodic interrupts */
   Âticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
+ Â Â Â if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+ Â Â Â Â Â Â Â ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON);
+ Â Â Â Â Â Â Â ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+ Â Â Â }
   Âs3c_rtc_enable(pdev, 0);
   Âreturn 0;
Â}

Âstatic int s3c_rtc_resume(struct platform_device *pdev)
Â{
+ Â Â Â unsigned int tmp;
+
   Âs3c_rtc_enable(pdev, 1);
   Âwriteb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+ Â Â Â if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
+ Â Â Â Â Â Â Â tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
+ Â Â Â Â Â Â Â writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+ Â Â Â }
   Âreturn 0;
Â}
Â#else
@@ -512,13 +565,27 @@ static int s3c_rtc_resume(struct platform_device *pdev)
Â#define s3c_rtc_resume ÂNULL
Â#endif

-static struct platform_driver s3c2410_rtc_driver = {
+static struct platform_device_id s3c_rtc_driver_ids[] = {
+ Â Â Â {
+        .name      = "s3c2410-rtc",
+        .driver_data  Â= TYPE_S3C2410,
+ Â Â Â }, {
+        .name      = "s3c64xx-rtc",
+        .driver_data  Â= TYPE_S3C64XX,
+ Â Â Â },
+ Â Â Â { }
+};
+
+MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
+
+static struct platform_driver s3c_rtc_driver = {
   Â.probe     Â= s3c_rtc_probe,
   Â.remove     = __devexit_p(s3c_rtc_remove),
   Â.suspend    Â= s3c_rtc_suspend,
   Â.resume     = s3c_rtc_resume,
+    .id_table    = s3c_rtc_driver_ids,
   Â.driver     = {
-        .name  = "s3c2410-rtc",
+        .name  = "s3c-rtc",
       Â.owner Â= THIS_MODULE,
   Â},
Â};
@@ -528,12 +595,12 @@ static char __initdata banner[] = "S3C24XX RTC,
(c) 2004,2006 Simtec Electronics
Âstatic int __init s3c_rtc_init(void)
Â{
   Âprintk(banner);
- Â Â Â return platform_driver_register(&s3c2410_rtc_driver);
+ Â Â Â return platform_driver_register(&s3c_rtc_driver);
Â}

Âstatic void __exit s3c_rtc_exit(void)
Â{
- Â Â Â platform_driver_unregister(&s3c2410_rtc_driver);
+ Â Â Â platform_driver_unregister(&s3c_rtc_driver);
Â}

Âmodule_init(s3c_rtc_init);
--
1.6.6
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/