Commit 9f4123b7 authored by Maurus Cuelenaere's avatar Maurus Cuelenaere Committed by Linus Torvalds

s3c rtc driver: add support for S3C64xx

Add support for the S3C64xx SoC to the generic S3C RTC driver.
Signed-off-by: default avatarMaurus Cuelenaere <mcuelenaere@gmail.com>
Acked-by: default avatarBen Dooks <ben-linux@fluff.org>
Cc: Frans Pop <elendil@planet.nl>
Cc: Paul Gortmaker <p_gortmaker@yahoo.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 337bbfdb
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
#define S3C2410_RTCCON_CLKSEL (1<<1) #define S3C2410_RTCCON_CLKSEL (1<<1)
#define S3C2410_RTCCON_CNTSEL (1<<2) #define S3C2410_RTCCON_CNTSEL (1<<2)
#define S3C2410_RTCCON_CLKRST (1<<3) #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 S3C2410_RTCREG(0x44)
#define S3C2410_TICNT_ENABLE (1<<7) #define S3C2410_TICNT_ENABLE (1<<7)
......
...@@ -640,7 +640,7 @@ config RTC_DRV_OMAP ...@@ -640,7 +640,7 @@ config RTC_DRV_OMAP
config RTC_DRV_S3C config RTC_DRV_S3C
tristate "Samsung S3C series SoC RTC" tristate "Samsung S3C series SoC RTC"
depends on ARCH_S3C2410 depends on ARCH_S3C2410 || ARCH_S3C64XX
help help
RTC (Realtime Clock) driver for the clock inbuilt into the RTC (Realtime Clock) driver for the clock inbuilt into the
Samsung S3C24XX series of SoCs. This can provide periodic Samsung S3C24XX series of SoCs. This can provide periodic
......
...@@ -29,6 +29,11 @@ ...@@ -29,6 +29,11 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <plat/regs-rtc.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 /* I have yet to find an S3C implementation with more than one
* of these rtc blocks in */ * of these rtc blocks in */
...@@ -37,6 +42,7 @@ static struct resource *s3c_rtc_mem; ...@@ -37,6 +42,7 @@ static struct resource *s3c_rtc_mem;
static void __iomem *s3c_rtc_base; static void __iomem *s3c_rtc_base;
static int s3c_rtc_alarmno = NO_IRQ; static int s3c_rtc_alarmno = NO_IRQ;
static int s3c_rtc_tickno = 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); static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
...@@ -80,12 +86,25 @@ static int s3c_rtc_setpie(struct device *dev, int enabled) ...@@ -80,12 +86,25 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
pr_debug("%s: pie=%d\n", __func__, enabled); pr_debug("%s: pie=%d\n", __func__, enabled);
spin_lock_irq(&s3c_rtc_pie_lock); spin_lock_irq(&s3c_rtc_pie_lock);
tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
if (enabled) if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
tmp |= S3C2410_TICNT_ENABLE; 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); spin_unlock_irq(&s3c_rtc_pie_lock);
return 0; return 0;
...@@ -93,15 +112,21 @@ static int s3c_rtc_setpie(struct device *dev, int enabled) ...@@ -93,15 +112,21 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
static int s3c_rtc_setfreq(struct device *dev, int freq) 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)) if (!is_power_of_2(freq))
return -EINVAL; return -EINVAL;
spin_lock_irq(&s3c_rtc_pie_lock); spin_lock_irq(&s3c_rtc_pie_lock);
tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE; if (s3c_rtc_cpu_type == TYPE_S3C2410) {
tmp |= (128 / freq)-1; 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); writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
spin_unlock_irq(&s3c_rtc_pie_lock); spin_unlock_irq(&s3c_rtc_pie_lock);
...@@ -283,10 +308,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -283,10 +308,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) 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", if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
(ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" ); 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; return 0;
} }
...@@ -353,10 +385,16 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) ...@@ -353,10 +385,16 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
if (!en) { if (!en) {
tmp = readb(base + S3C2410_RTCCON); tmp = readb(base + S3C2410_RTCCON);
writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON); if (s3c_rtc_cpu_type == TYPE_S3C64XX)
tmp &= ~S3C64XX_RTCCON_TICEN;
tmp = readb(base + S3C2410_TICNT); tmp &= ~S3C2410_RTCCON_RTCEN;
writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT); 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 { } else {
/* re-enable the device, and check it is ok */ /* re-enable the device, and check it is ok */
...@@ -472,7 +510,12 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) ...@@ -472,7 +510,12 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
goto err_nortc; 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); platform_set_drvdata(pdev, rtc);
return 0; return 0;
...@@ -492,20 +535,30 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) ...@@ -492,20 +535,30 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
/* RTC Power management control */ /* 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) static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{ {
/* save TICNT for anyone using periodic interrupts */ /* save TICNT for anyone using periodic interrupts */
ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); 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); s3c_rtc_enable(pdev, 0);
return 0; return 0;
} }
static int s3c_rtc_resume(struct platform_device *pdev) static int s3c_rtc_resume(struct platform_device *pdev)
{ {
unsigned int tmp;
s3c_rtc_enable(pdev, 1); s3c_rtc_enable(pdev, 1);
writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); 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; return 0;
} }
#else #else
...@@ -513,13 +566,27 @@ static int s3c_rtc_resume(struct platform_device *pdev) ...@@ -513,13 +566,27 @@ static int s3c_rtc_resume(struct platform_device *pdev)
#define s3c_rtc_resume NULL #define s3c_rtc_resume NULL
#endif #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, .probe = s3c_rtc_probe,
.remove = __devexit_p(s3c_rtc_remove), .remove = __devexit_p(s3c_rtc_remove),
.suspend = s3c_rtc_suspend, .suspend = s3c_rtc_suspend,
.resume = s3c_rtc_resume, .resume = s3c_rtc_resume,
.id_table = s3c_rtc_driver_ids,
.driver = { .driver = {
.name = "s3c2410-rtc", .name = "s3c-rtc",
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
}; };
...@@ -529,12 +596,12 @@ static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics ...@@ -529,12 +596,12 @@ static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics
static int __init s3c_rtc_init(void) static int __init s3c_rtc_init(void)
{ {
printk(banner); printk(banner);
return platform_driver_register(&s3c2410_rtc_driver); return platform_driver_register(&s3c_rtc_driver);
} }
static void __exit s3c_rtc_exit(void) static void __exit s3c_rtc_exit(void)
{ {
platform_driver_unregister(&s3c2410_rtc_driver); platform_driver_unregister(&s3c_rtc_driver);
} }
module_init(s3c_rtc_init); module_init(s3c_rtc_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment