diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 6 | ||||
-rw-r--r-- | drivers/rtc/interface.c | 5 | ||||
-rw-r--r-- | drivers/rtc/rtc-88pm860x.c | 31 | ||||
-rw-r--r-- | drivers/rtc/rtc-at91sam9.c | 85 | ||||
-rw-r--r-- | drivers/rtc/rtc-mpc5121.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-mv.c | 9 | ||||
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 71 | ||||
-rw-r--r-- | drivers/rtc/rtc-sa1100.c | 211 |
8 files changed, 241 insertions, 179 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4f9fb25f945..8c8377d50c4 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -755,7 +755,7 @@ config HAVE_S3C_RTC config RTC_DRV_S3C tristate "Samsung S3C series SoC RTC" - depends on ARCH_S3C2410 || ARCH_S3C64XX || HAVE_S3C_RTC + depends on ARCH_S3C64XX || HAVE_S3C_RTC help RTC (Realtime Clock) driver for the clock inbuilt into the Samsung S3C24XX series of SoCs. This can provide periodic @@ -780,8 +780,8 @@ config RTC_DRV_EP93XX will be called rtc-ep93xx. config RTC_DRV_SA1100 - tristate "SA11x0/PXA2xx" - depends on ARCH_SA1100 || ARCH_PXA + tristate "SA11x0/PXA2xx/PXA910" + depends on ARCH_SA1100 || ARCH_PXA || ARCH_MMP help If you say Y here you will get access to the real time clock built into your SA11x0 or PXA2xx CPU. diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index dc87eda6581..eb415bd7649 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -458,6 +458,11 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) if (rtc->uie_rtctimer.enabled == enabled) goto out; + if (rtc->uie_unsupported) { + err = -EINVAL; + goto out; + } + if (enabled) { struct rtc_time tm; ktime_t now, onesec; diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index f04761e6622..feddefc4210 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -72,9 +72,9 @@ static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) struct pm860x_rtc_info *info = dev_get_drvdata(dev); if (enabled) - pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM); + pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, ALARM_EN); else - pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0); + pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0); return 0; } @@ -376,6 +376,9 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work); schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL); #endif /* VRTC_CALIBRATION */ + + device_init_wakeup(&pdev->dev, 1); + return 0; out_rtc: free_irq(info->irq, info); @@ -401,10 +404,34 @@ static int __devexit pm860x_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int pm860x_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); + + if (device_may_wakeup(dev)) + chip->wakeup_flag |= 1 << PM8607_IRQ_RTC; + return 0; +} +static int pm860x_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); + + if (device_may_wakeup(dev)) + chip->wakeup_flag &= ~(1 << PM8607_IRQ_RTC); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pm860x_rtc_pm_ops, pm860x_rtc_suspend, pm860x_rtc_resume); + static struct platform_driver pm860x_rtc_driver = { .driver = { .name = "88pm860x-rtc", .owner = THIS_MODULE, + .pm = &pm860x_rtc_pm_ops, }, .probe = pm860x_rtc_probe, .remove = __devexit_p(pm860x_rtc_remove), diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 274a0aafe42..831868904e0 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -57,6 +57,7 @@ struct sam9_rtc { void __iomem *rtt; struct rtc_device *rtcdev; u32 imr; + void __iomem *gpbr; }; #define rtt_readl(rtc, field) \ @@ -65,9 +66,9 @@ struct sam9_rtc { __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field) #define gpbr_readl(rtc) \ - at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR) + __raw_readl((rtc)->gpbr) #define gpbr_writel(rtc, val) \ - at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val)) + __raw_writel((val), (rtc)->gpbr) /* * Read current time and date in RTC @@ -287,16 +288,19 @@ static const struct rtc_class_ops at91_rtc_ops = { /* * Initialize and install RTC driver */ -static int __init at91_rtc_probe(struct platform_device *pdev) +static int __devinit at91_rtc_probe(struct platform_device *pdev) { - struct resource *r; + struct resource *r, *r_gpbr; struct sam9_rtc *rtc; int ret; u32 mr; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) + r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!r || !r_gpbr) { + dev_err(&pdev->dev, "need 2 ressources\n"); return -ENODEV; + } rtc = kzalloc(sizeof *rtc, GFP_KERNEL); if (!rtc) @@ -314,6 +318,13 @@ static int __init at91_rtc_probe(struct platform_device *pdev) goto fail; } + rtc->gpbr = ioremap(r_gpbr->start, resource_size(r_gpbr)); + if (!rtc->gpbr) { + dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n"); + ret = -ENOMEM; + goto fail_gpbr; + } + mr = rtt_readl(rtc, MR); /* unless RTT is counting at 1 Hz, re-initialize it */ @@ -340,7 +351,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) if (ret) { dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS); rtc_device_unregister(rtc->rtcdev); - goto fail; + goto fail_register; } /* NOTE: sam9260 rev A silicon has a ROM bug which resets the @@ -356,6 +367,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev) return 0; fail_register: + iounmap(rtc->gpbr); +fail_gpbr: iounmap(rtc->rtt); fail: platform_set_drvdata(pdev, NULL); @@ -366,7 +379,7 @@ fail: /* * Disable and remove the RTC driver */ -static int __exit at91_rtc_remove(struct platform_device *pdev) +static int __devexit at91_rtc_remove(struct platform_device *pdev) { struct sam9_rtc *rtc = platform_get_drvdata(pdev); u32 mr = rtt_readl(rtc, MR); @@ -377,6 +390,7 @@ static int __exit at91_rtc_remove(struct platform_device *pdev) rtc_device_unregister(rtc->rtcdev); + iounmap(rtc->gpbr); iounmap(rtc->rtt); platform_set_drvdata(pdev, NULL); kfree(rtc); @@ -440,63 +454,20 @@ static int at91_rtc_resume(struct platform_device *pdev) #endif static struct platform_driver at91_rtc_driver = { - .driver.name = "rtc-at91sam9", - .driver.owner = THIS_MODULE, - .remove = __exit_p(at91_rtc_remove), + .probe = at91_rtc_probe, + .remove = __devexit_p(at91_rtc_remove), .shutdown = at91_rtc_shutdown, .suspend = at91_rtc_suspend, .resume = at91_rtc_resume, + .driver = { + .name = "rtc-at91sam9", + .owner = THIS_MODULE, + }, }; -/* Chips can have more than one RTT module, and they can be used for more - * than just RTCs. So we can't just register as "the" RTT driver. - * - * A normal approach in such cases is to create a library to allocate and - * free the modules. Here we just use bus_find_device() as like such a - * library, binding directly ... no runtime "library" footprint is needed. - */ -static int __init at91_rtc_match(struct device *dev, void *v) -{ - struct platform_device *pdev = to_platform_device(dev); - int ret; - - /* continue searching if this isn't the RTT we need */ - if (strcmp("at91_rtt", pdev->name) != 0 - || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT) - goto fail; - - /* else we found it ... but fail unless we can bind to the RTC driver */ - if (dev->driver) { - dev_dbg(dev, "busy, can't use as RTC!\n"); - goto fail; - } - dev->driver = &at91_rtc_driver.driver; - if (device_attach(dev) == 0) { - dev_dbg(dev, "can't attach RTC!\n"); - goto fail; - } - ret = at91_rtc_probe(pdev); - if (ret == 0) - return true; - - dev_dbg(dev, "RTC probe err %d!\n", ret); -fail: - return false; -} - static int __init at91_rtc_init(void) { - int status; - struct device *rtc; - - status = platform_driver_register(&at91_rtc_driver); - if (status) - return status; - rtc = bus_find_device(&platform_bus_type, NULL, - NULL, at91_rtc_match); - if (!rtc) - platform_driver_unregister(&at91_rtc_driver); - return rtc ? 0 : -ENODEV; + return platform_driver_register(&at91_rtc_driver); } module_init(at91_rtc_init); diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index e954a759ba8..42f5f829b3e 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -360,6 +360,8 @@ static int __devinit mpc5121_rtc_probe(struct platform_device *op) &mpc5200_rtc_ops, THIS_MODULE); } + rtc->rtc->uie_unsupported = 1; + if (IS_ERR(rtc->rtc)) { err = PTR_ERR(rtc->rtc); goto out_free_irq; diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index 1300962486d..b2185f4255a 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -12,6 +12,7 @@ #include <linux/bcd.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <linux/delay.h> #include <linux/gfp.h> #include <linux/module.h> @@ -294,11 +295,19 @@ static int __exit mv_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static struct of_device_id rtc_mv_of_match_table[] = { + { .compatible = "mrvl,orion-rtc", }, + {} +}; +#endif + static struct platform_driver mv_rtc_driver = { .remove = __exit_p(mv_rtc_remove), .driver = { .name = "rtc-mv", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtc_mv_of_match_table), }, }; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index c543f6f1eec..9ccea134a99 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -35,6 +35,8 @@ enum s3c_cpu_type { TYPE_S3C2410, + TYPE_S3C2416, + TYPE_S3C2443, TYPE_S3C64XX, }; @@ -132,6 +134,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) struct platform_device *pdev = to_platform_device(dev); struct rtc_device *rtc_dev = platform_get_drvdata(pdev); unsigned int tmp = 0; + int val; if (!is_power_of_2(freq)) return -EINVAL; @@ -139,12 +142,22 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) clk_enable(rtc_clk); spin_lock_irq(&s3c_rtc_pie_lock); - if (s3c_rtc_cpu_type == TYPE_S3C2410) { + if (s3c_rtc_cpu_type != TYPE_S3C64XX) { tmp = readb(s3c_rtc_base + S3C2410_TICNT); tmp &= S3C2410_TICNT_ENABLE; } - tmp |= (rtc_dev->max_user_freq / freq)-1; + val = (rtc_dev->max_user_freq / freq) - 1; + + if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) { + tmp |= S3C2443_TICNT_PART(val); + writel(S3C2443_TICNT1_PART(val), s3c_rtc_base + S3C2443_TICNT1); + + if (s3c_rtc_cpu_type == TYPE_S3C2416) + writel(S3C2416_TICNT2_PART(val), s3c_rtc_base + S3C2416_TICNT2); + } else { + tmp |= val; + } writel(tmp, s3c_rtc_base + S3C2410_TICNT); spin_unlock_irq(&s3c_rtc_pie_lock); @@ -371,7 +384,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) tmp &= ~S3C2410_RTCCON_RTCEN; writew(tmp, base + S3C2410_RTCCON); - if (s3c_rtc_cpu_type == TYPE_S3C2410) { + if (s3c_rtc_cpu_type != TYPE_S3C64XX) { tmp = readb(base + S3C2410_TICNT); tmp &= ~S3C2410_TICNT_ENABLE; writeb(tmp, base + S3C2410_TICNT); @@ -428,12 +441,27 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) return 0; } +static const struct of_device_id s3c_rtc_dt_match[]; + +static inline int s3c_rtc_get_driver_data(struct platform_device *pdev) +{ +#ifdef CONFIG_OF + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node); + return match->data; + } +#endif + return platform_get_device_id(pdev)->driver_data; +} + static int __devinit s3c_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct rtc_time rtc_tm; struct resource *res; int ret; + int tmp; pr_debug("%s: probe=%p\n", __func__, pdev); @@ -508,13 +536,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) goto err_nortc; } -#ifdef CONFIG_OF - if (pdev->dev.of_node) - s3c_rtc_cpu_type = of_device_is_compatible(pdev->dev.of_node, - "samsung,s3c6410-rtc") ? TYPE_S3C64XX : TYPE_S3C2410; - else -#endif - s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; + s3c_rtc_cpu_type = s3c_rtc_get_driver_data(pdev); /* Check RTC Time */ @@ -533,11 +555,17 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); } - if (s3c_rtc_cpu_type == TYPE_S3C64XX) + if (s3c_rtc_cpu_type != TYPE_S3C2410) rtc->max_user_freq = 32768; else rtc->max_user_freq = 128; + if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) { + tmp = readw(s3c_rtc_base + S3C2410_RTCCON); + tmp |= S3C2443_RTCCON_TICSEL; + writew(tmp, s3c_rtc_base + S3C2410_RTCCON); + } + platform_set_drvdata(pdev, rtc); s3c_rtc_setfreq(&pdev->dev, 1); @@ -638,8 +666,19 @@ static int s3c_rtc_resume(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id s3c_rtc_dt_match[] = { - { .compatible = "samsung,s3c2410-rtc" }, - { .compatible = "samsung,s3c6410-rtc" }, + { + .compatible = "samsung,s3c2410-rtc" + .data = TYPE_S3C2410, + }, { + .compatible = "samsung,s3c2416-rtc" + .data = TYPE_S3C2416, + }, { + .compatible = "samsung,s3c2443-rtc" + .data = TYPE_S3C2443, + }, { + .compatible = "samsung,s3c6410-rtc" + .data = TYPE_S3C64XX, + }, {}, }; MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); @@ -652,6 +691,12 @@ static struct platform_device_id s3c_rtc_driver_ids[] = { .name = "s3c2410-rtc", .driver_data = TYPE_S3C2410, }, { + .name = "s3c2416-rtc", + .driver_data = TYPE_S3C2416, + }, { + .name = "s3c2443-rtc", + .driver_data = TYPE_S3C2443, + }, { .name = "s3c64xx-rtc", .driver_data = TYPE_S3C64XX, }, diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index fb758db9d0f..50a5c4adee4 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -23,94 +23,45 @@ #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/clk.h> #include <linux/rtc.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/interrupt.h> +#include <linux/slab.h> #include <linux/string.h> +#include <linux/of.h> #include <linux/pm.h> #include <linux/bitops.h> +#include <linux/io.h> #include <mach/hardware.h> -#include <asm/irq.h> +#include <mach/irqs.h> -#ifdef CONFIG_ARCH_PXA +#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) #include <mach/regs-rtc.h> #endif #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 - -static const unsigned long RTC_FREQ = 1024; -static struct rtc_time rtc_alarm; -static DEFINE_SPINLOCK(sa1100_rtc_lock); - -static inline int rtc_periodic_alarm(struct rtc_time *tm) -{ - return (tm->tm_year == -1) || - ((unsigned)tm->tm_mon >= 12) || - ((unsigned)(tm->tm_mday - 1) >= 31) || - ((unsigned)tm->tm_hour > 23) || - ((unsigned)tm->tm_min > 59) || - ((unsigned)tm->tm_sec > 59); -} - -/* - * Calculate the next alarm time given the requested alarm time mask - * and the current time. - */ -static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, - struct rtc_time *alrm) -{ - unsigned long next_time; - unsigned long now_time; - - next->tm_year = now->tm_year; - next->tm_mon = now->tm_mon; - next->tm_mday = now->tm_mday; - next->tm_hour = alrm->tm_hour; - next->tm_min = alrm->tm_min; - next->tm_sec = alrm->tm_sec; - - rtc_tm_to_time(now, &now_time); - rtc_tm_to_time(next, &next_time); - - if (next_time < now_time) { - /* Advance one day */ - next_time += 60 * 60 * 24; - rtc_time_to_tm(next_time, next); - } -} - -static int rtc_update_alarm(struct rtc_time *alrm) -{ - struct rtc_time alarm_tm, now_tm; - unsigned long now, time; - int ret; - - do { - now = RCNR; - rtc_time_to_tm(now, &now_tm); - rtc_next_alarm_time(&alarm_tm, &now_tm, alrm); - ret = rtc_tm_to_time(&alarm_tm, &time); - if (ret != 0) - break; - - RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); - RTAR = time; - } while (now != RCNR); - - return ret; -} +#define RTC_FREQ 1024 + +struct sa1100_rtc { + spinlock_t lock; + int irq_1hz; + int irq_alarm; + struct rtc_device *rtc; + struct clk *clk; +}; static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) { - struct platform_device *pdev = to_platform_device(dev_id); - struct rtc_device *rtc = platform_get_drvdata(pdev); + struct sa1100_rtc *info = dev_get_drvdata(dev_id); + struct rtc_device *rtc = info->rtc; unsigned int rtsr; unsigned long events = 0; - spin_lock(&sa1100_rtc_lock); + spin_lock(&info->lock); rtsr = RTSR; /* clear interrupt sources */ @@ -146,29 +97,28 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) rtc_update_irq(rtc, 1, events); - if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm)) - rtc_update_alarm(&rtc_alarm); - - spin_unlock(&sa1100_rtc_lock); + spin_unlock(&info->lock); return IRQ_HANDLED; } static int sa1100_rtc_open(struct device *dev) { + struct sa1100_rtc *info = dev_get_drvdata(dev); + struct rtc_device *rtc = info->rtc; int ret; - struct platform_device *plat_dev = to_platform_device(dev); - struct rtc_device *rtc = platform_get_drvdata(plat_dev); - ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev); + ret = clk_prepare_enable(info->clk); + if (ret) + goto fail_clk; + ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev); if (ret) { - dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); + dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz); goto fail_ui; } - ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, 0, - "rtc Alrm", dev); + ret = request_irq(info->irq_alarm, sa1100_rtc_interrupt, 0, "rtc Alrm", dev); if (ret) { - dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); + dev_err(dev, "IRQ %d already in use.\n", info->irq_alarm); goto fail_ai; } rtc->max_user_freq = RTC_FREQ; @@ -177,29 +127,36 @@ static int sa1100_rtc_open(struct device *dev) return 0; fail_ai: - free_irq(IRQ_RTC1Hz, dev); + free_irq(info->irq_1hz, dev); fail_ui: + clk_disable_unprepare(info->clk); + fail_clk: return ret; } static void sa1100_rtc_release(struct device *dev) { - spin_lock_irq(&sa1100_rtc_lock); + struct sa1100_rtc *info = dev_get_drvdata(dev); + + spin_lock_irq(&info->lock); RTSR = 0; - spin_unlock_irq(&sa1100_rtc_lock); + spin_unlock_irq(&info->lock); - free_irq(IRQ_RTCAlrm, dev); - free_irq(IRQ_RTC1Hz, dev); + free_irq(info->irq_alarm, dev); + free_irq(info->irq_1hz, dev); + clk_disable_unprepare(info->clk); } static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - spin_lock_irq(&sa1100_rtc_lock); + struct sa1100_rtc *info = dev_get_drvdata(dev); + + spin_lock_irq(&info->lock); if (enabled) RTSR |= RTSR_ALE; else RTSR &= ~RTSR_ALE; - spin_unlock_irq(&sa1100_rtc_lock); + spin_unlock_irq(&info->lock); return 0; } @@ -224,7 +181,6 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { u32 rtsr; - memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time)); rtsr = RTSR; alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0; alrm->pending = (rtsr & RTSR_AL) ? 1 : 0; @@ -233,17 +189,22 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { + struct sa1100_rtc *info = dev_get_drvdata(dev); + unsigned long time; int ret; - spin_lock_irq(&sa1100_rtc_lock); - ret = rtc_update_alarm(&alrm->time); - if (ret == 0) { - if (alrm->enabled) - RTSR |= RTSR_ALE; - else - RTSR &= ~RTSR_ALE; - } - spin_unlock_irq(&sa1100_rtc_lock); + spin_lock_irq(&info->lock); + ret = rtc_tm_to_time(&alrm->time, &time); + if (ret != 0) + goto out; + RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); + RTAR = time; + if (alrm->enabled) + RTSR |= RTSR_ALE; + else + RTSR &= ~RTSR_ALE; +out: + spin_unlock_irq(&info->lock); return ret; } @@ -270,6 +231,27 @@ static const struct rtc_class_ops sa1100_rtc_ops = { static int sa1100_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; + struct sa1100_rtc *info; + int irq_1hz, irq_alarm, ret = 0; + + irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); + irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); + if (irq_1hz < 0 || irq_alarm < 0) + return -ENODEV; + + info = kzalloc(sizeof(struct sa1100_rtc), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(info->clk)) { + dev_err(&pdev->dev, "failed to find rtc clock source\n"); + ret = PTR_ERR(info->clk); + goto err_clk; + } + info->irq_1hz = irq_1hz; + info->irq_alarm = irq_alarm; + spin_lock_init(&info->lock); + platform_set_drvdata(pdev, info); /* * According to the manual we should be able to let RTTR be zero @@ -291,10 +273,11 @@ static int sa1100_rtc_probe(struct platform_device *pdev) rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - platform_set_drvdata(pdev, rtc); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto err_dev; + } + info->rtc = rtc; /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_interrupt(). @@ -321,14 +304,24 @@ static int sa1100_rtc_probe(struct platform_device *pdev) RTSR = RTSR_AL | RTSR_HZ; return 0; +err_dev: + platform_set_drvdata(pdev, NULL); + clk_put(info->clk); +err_clk: + kfree(info); + return ret; } static int sa1100_rtc_remove(struct platform_device *pdev) { - struct rtc_device *rtc = platform_get_drvdata(pdev); + struct sa1100_rtc *info = platform_get_drvdata(pdev); - if (rtc) - rtc_device_unregister(rtc); + if (info) { + rtc_device_unregister(info->rtc); + clk_put(info->clk); + platform_set_drvdata(pdev, NULL); + kfree(info); + } return 0; } @@ -336,15 +329,17 @@ static int sa1100_rtc_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int sa1100_rtc_suspend(struct device *dev) { + struct sa1100_rtc *info = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - enable_irq_wake(IRQ_RTCAlrm); + enable_irq_wake(info->irq_alarm); return 0; } static int sa1100_rtc_resume(struct device *dev) { + struct sa1100_rtc *info = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - disable_irq_wake(IRQ_RTCAlrm); + disable_irq_wake(info->irq_alarm); return 0; } @@ -354,6 +349,13 @@ static const struct dev_pm_ops sa1100_rtc_pm_ops = { }; #endif +static struct of_device_id sa1100_rtc_dt_ids[] = { + { .compatible = "mrvl,sa1100-rtc", }, + { .compatible = "mrvl,mmp-rtc", }, + {} +}; +MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids); + static struct platform_driver sa1100_rtc_driver = { .probe = sa1100_rtc_probe, .remove = sa1100_rtc_remove, @@ -362,6 +364,7 @@ static struct platform_driver sa1100_rtc_driver = { #ifdef CONFIG_PM .pm = &sa1100_rtc_pm_ops, #endif + .of_match_table = sa1100_rtc_dt_ids, }, }; |