From 3888c09074db2ca561c74571dcbd777949a856b8 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 21 Feb 2012 11:51:13 +0800 Subject: rtc: sa1100: declare irq in resource Avoid to hard coded irq in rtc-sa1100 driver since we could share it among arch-sa1100/arch-pxa/arch-mmp. We still keep hard coded register address since the requirement is enabling both rtc-sa1100 and rtc-pxa driver. The register addresses are conflict since they're only two wrappers on the same rtc device. Signed-off-by: Haojian Zhuang Reviewed-by: Arnd Bergmann --- drivers/rtc/rtc-sa1100.c | 98 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 31 deletions(-) (limited to 'drivers/rtc/rtc-sa1100.c') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 91d58bd..0a36c7e 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -34,24 +35,29 @@ #include #include -#ifdef CONFIG_ARCH_PXA +#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) #include #endif #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 +#define RTC_FREQ 1024 -static const unsigned long RTC_FREQ = 1024; -static DEFINE_SPINLOCK(sa1100_rtc_lock); +struct sa1100_rtc { + spinlock_t lock; + int irq_1hz; + int irq_alarm; + struct rtc_device *rtc; +}; 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 */ @@ -87,27 +93,27 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) rtc_update_irq(rtc, 1, events); - 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, IRQF_DISABLED, + ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, IRQF_DISABLED, "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, IRQF_DISABLED, + ret = request_irq(info->irq_alarm, sa1100_rtc_interrupt, IRQF_DISABLED, "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; @@ -116,29 +122,33 @@ 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: 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); } 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; } @@ -171,10 +181,11 @@ 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); + spin_lock_irq(&info->lock); ret = rtc_tm_to_time(&alrm->time, &time); if (ret != 0) goto out; @@ -185,7 +196,7 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) else RTSR &= ~RTSR_ALE; out: - spin_unlock_irq(&sa1100_rtc_lock); + spin_unlock_irq(&info->lock); return ret; } @@ -212,6 +223,21 @@ 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->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 @@ -233,10 +259,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(). @@ -263,14 +290,21 @@ static int sa1100_rtc_probe(struct platform_device *pdev) RTSR = RTSR_AL | RTSR_HZ; return 0; +err_dev: + platform_set_drvdata(pdev, NULL); + 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); + platform_set_drvdata(pdev, NULL); + kfree(info); + } return 0; } @@ -278,15 +312,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; } -- cgit v1.1 From 8e8bbcb3685ab809348d300b8e2c1f1ea0294e81 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Thu, 23 Feb 2012 23:36:37 +0800 Subject: rtc: sa1100: enable clk support Enable clock support on rtc-sa1100. Signed-off-by: Haojian Zhuang --- drivers/rtc/rtc-sa1100.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/rtc/rtc-sa1100.c') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 0a36c7e..962510c 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,7 @@ struct sa1100_rtc { int irq_1hz; int irq_alarm; struct rtc_device *rtc; + struct clk *clk; }; static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) @@ -104,6 +106,9 @@ static int sa1100_rtc_open(struct device *dev) struct rtc_device *rtc = info->rtc; int ret; + ret = clk_prepare_enable(info->clk); + if (ret) + goto fail_clk; ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, IRQF_DISABLED, "rtc 1Hz", dev); if (ret) { @@ -124,6 +129,8 @@ static int sa1100_rtc_open(struct device *dev) fail_ai: free_irq(info->irq_1hz, dev); fail_ui: + clk_disable_unprepare(info->clk); + fail_clk: return ret; } @@ -137,6 +144,7 @@ static void sa1100_rtc_release(struct device *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) @@ -234,6 +242,12 @@ static int sa1100_rtc_probe(struct platform_device *pdev) 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); @@ -292,6 +306,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) return 0; err_dev: platform_set_drvdata(pdev, NULL); + clk_put(info->clk); +err_clk: kfree(info); return ret; } @@ -302,6 +318,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev) if (info) { rtc_device_unregister(info->rtc); + clk_put(info->clk); platform_set_drvdata(pdev, NULL); kfree(info); } -- cgit v1.1 From 8bec2e9e2efa8660c88077b2f1524b7a36eda714 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 5 Mar 2012 19:26:42 +0800 Subject: rtc: sa1100: add OF support Add OF support on rtc-sa1100. Signed-off-by: Haojian Zhuang Acked-by: Arnd Bergmann --- drivers/rtc/rtc-sa1100.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/rtc/rtc-sa1100.c') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 962510c..e443b78 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -349,6 +350,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, @@ -357,6 +365,7 @@ static struct platform_driver sa1100_rtc_driver = { #ifdef CONFIG_PM .pm = &sa1100_rtc_pm_ops, #endif + .of_match_table = sa1100_rtc_dt_ids, }, }; -- cgit v1.1