diff options
author | Donggeun Kim <dg77.kim@samsung.com> | 2011-07-25 20:13:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-25 23:57:17 -0400 |
commit | cefe4fbbaab8e20a7581a187db82d33c1e3320c0 (patch) | |
tree | a40203a65c87c09136a38d3927c643a119364f7f | |
parent | 955dbea3c7133d3ccfaa79c7eba1244c1de42865 (diff) |
drivers/rtc/rtc-s3c.c: support clock gating
Add support for clock gating. Power consumption can be reduced by setting
rtc_clk disabled state except for when RTC related registers are accessed.
Signed-off-by: Donggeun Kim <dg77.kim@samsung.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: KyungMin Park <kyungmin.park@samsung.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Ben Dooks <ben@fluff.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 16512ecae31a..53c99b1a3c92 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c | |||
@@ -57,11 +57,13 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) | |||
57 | { | 57 | { |
58 | struct rtc_device *rdev = id; | 58 | struct rtc_device *rdev = id; |
59 | 59 | ||
60 | clk_enable(rtc_clk); | ||
60 | rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); | 61 | rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); |
61 | 62 | ||
62 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) | 63 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) |
63 | writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP); | 64 | writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP); |
64 | 65 | ||
66 | clk_disable(rtc_clk); | ||
65 | return IRQ_HANDLED; | 67 | return IRQ_HANDLED; |
66 | } | 68 | } |
67 | 69 | ||
@@ -69,11 +71,13 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id) | |||
69 | { | 71 | { |
70 | struct rtc_device *rdev = id; | 72 | struct rtc_device *rdev = id; |
71 | 73 | ||
74 | clk_enable(rtc_clk); | ||
72 | rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); | 75 | rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); |
73 | 76 | ||
74 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) | 77 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) |
75 | writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP); | 78 | writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP); |
76 | 79 | ||
80 | clk_disable(rtc_clk); | ||
77 | return IRQ_HANDLED; | 81 | return IRQ_HANDLED; |
78 | } | 82 | } |
79 | 83 | ||
@@ -84,12 +88,14 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) | |||
84 | 88 | ||
85 | pr_debug("%s: aie=%d\n", __func__, enabled); | 89 | pr_debug("%s: aie=%d\n", __func__, enabled); |
86 | 90 | ||
91 | clk_enable(rtc_clk); | ||
87 | tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; | 92 | tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; |
88 | 93 | ||
89 | if (enabled) | 94 | if (enabled) |
90 | tmp |= S3C2410_RTCALM_ALMEN; | 95 | tmp |= S3C2410_RTCALM_ALMEN; |
91 | 96 | ||
92 | writeb(tmp, s3c_rtc_base + S3C2410_RTCALM); | 97 | writeb(tmp, s3c_rtc_base + S3C2410_RTCALM); |
98 | clk_disable(rtc_clk); | ||
93 | 99 | ||
94 | return 0; | 100 | return 0; |
95 | } | 101 | } |
@@ -103,6 +109,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) | |||
103 | if (!is_power_of_2(freq)) | 109 | if (!is_power_of_2(freq)) |
104 | return -EINVAL; | 110 | return -EINVAL; |
105 | 111 | ||
112 | clk_enable(rtc_clk); | ||
106 | spin_lock_irq(&s3c_rtc_pie_lock); | 113 | spin_lock_irq(&s3c_rtc_pie_lock); |
107 | 114 | ||
108 | if (s3c_rtc_cpu_type == TYPE_S3C2410) { | 115 | if (s3c_rtc_cpu_type == TYPE_S3C2410) { |
@@ -114,6 +121,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) | |||
114 | 121 | ||
115 | writel(tmp, s3c_rtc_base + S3C2410_TICNT); | 122 | writel(tmp, s3c_rtc_base + S3C2410_TICNT); |
116 | spin_unlock_irq(&s3c_rtc_pie_lock); | 123 | spin_unlock_irq(&s3c_rtc_pie_lock); |
124 | clk_disable(rtc_clk); | ||
117 | 125 | ||
118 | return 0; | 126 | return 0; |
119 | } | 127 | } |
@@ -125,6 +133,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) | |||
125 | unsigned int have_retried = 0; | 133 | unsigned int have_retried = 0; |
126 | void __iomem *base = s3c_rtc_base; | 134 | void __iomem *base = s3c_rtc_base; |
127 | 135 | ||
136 | clk_enable(rtc_clk); | ||
128 | retry_get_time: | 137 | retry_get_time: |
129 | rtc_tm->tm_min = readb(base + S3C2410_RTCMIN); | 138 | rtc_tm->tm_min = readb(base + S3C2410_RTCMIN); |
130 | rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR); | 139 | rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR); |
@@ -157,6 +166,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) | |||
157 | rtc_tm->tm_year += 100; | 166 | rtc_tm->tm_year += 100; |
158 | rtc_tm->tm_mon -= 1; | 167 | rtc_tm->tm_mon -= 1; |
159 | 168 | ||
169 | clk_disable(rtc_clk); | ||
160 | return rtc_valid_tm(rtc_tm); | 170 | return rtc_valid_tm(rtc_tm); |
161 | } | 171 | } |
162 | 172 | ||
@@ -165,6 +175,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) | |||
165 | void __iomem *base = s3c_rtc_base; | 175 | void __iomem *base = s3c_rtc_base; |
166 | int year = tm->tm_year - 100; | 176 | int year = tm->tm_year - 100; |
167 | 177 | ||
178 | clk_enable(rtc_clk); | ||
168 | pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", | 179 | pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", |
169 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, | 180 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
170 | tm->tm_hour, tm->tm_min, tm->tm_sec); | 181 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
@@ -182,6 +193,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) | |||
182 | writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE); | 193 | writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE); |
183 | writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON); | 194 | writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON); |
184 | writeb(bin2bcd(year), base + S3C2410_RTCYEAR); | 195 | writeb(bin2bcd(year), base + S3C2410_RTCYEAR); |
196 | clk_disable(rtc_clk); | ||
185 | 197 | ||
186 | return 0; | 198 | return 0; |
187 | } | 199 | } |
@@ -192,6 +204,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
192 | void __iomem *base = s3c_rtc_base; | 204 | void __iomem *base = s3c_rtc_base; |
193 | unsigned int alm_en; | 205 | unsigned int alm_en; |
194 | 206 | ||
207 | clk_enable(rtc_clk); | ||
195 | alm_tm->tm_sec = readb(base + S3C2410_ALMSEC); | 208 | alm_tm->tm_sec = readb(base + S3C2410_ALMSEC); |
196 | alm_tm->tm_min = readb(base + S3C2410_ALMMIN); | 209 | alm_tm->tm_min = readb(base + S3C2410_ALMMIN); |
197 | alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR); | 210 | alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR); |
@@ -243,6 +256,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
243 | else | 256 | else |
244 | alm_tm->tm_year = -1; | 257 | alm_tm->tm_year = -1; |
245 | 258 | ||
259 | clk_disable(rtc_clk); | ||
246 | return 0; | 260 | return 0; |
247 | } | 261 | } |
248 | 262 | ||
@@ -252,6 +266,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
252 | void __iomem *base = s3c_rtc_base; | 266 | void __iomem *base = s3c_rtc_base; |
253 | unsigned int alrm_en; | 267 | unsigned int alrm_en; |
254 | 268 | ||
269 | clk_enable(rtc_clk); | ||
255 | pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", | 270 | pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", |
256 | alrm->enabled, | 271 | alrm->enabled, |
257 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, | 272 | 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
@@ -282,6 +297,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
282 | 297 | ||
283 | s3c_rtc_setaie(dev, alrm->enabled); | 298 | s3c_rtc_setaie(dev, alrm->enabled); |
284 | 299 | ||
300 | clk_disable(rtc_clk); | ||
285 | return 0; | 301 | return 0; |
286 | } | 302 | } |
287 | 303 | ||
@@ -289,6 +305,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) | |||
289 | { | 305 | { |
290 | unsigned int ticnt; | 306 | unsigned int ticnt; |
291 | 307 | ||
308 | clk_enable(rtc_clk); | ||
292 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { | 309 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { |
293 | ticnt = readw(s3c_rtc_base + S3C2410_RTCCON); | 310 | ticnt = readw(s3c_rtc_base + S3C2410_RTCCON); |
294 | ticnt &= S3C64XX_RTCCON_TICEN; | 311 | ticnt &= S3C64XX_RTCCON_TICEN; |
@@ -298,6 +315,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) | |||
298 | } | 315 | } |
299 | 316 | ||
300 | seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); | 317 | seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); |
318 | clk_disable(rtc_clk); | ||
301 | return 0; | 319 | return 0; |
302 | } | 320 | } |
303 | 321 | ||
@@ -360,6 +378,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) | |||
360 | if (s3c_rtc_base == NULL) | 378 | if (s3c_rtc_base == NULL) |
361 | return; | 379 | return; |
362 | 380 | ||
381 | clk_enable(rtc_clk); | ||
363 | if (!en) { | 382 | if (!en) { |
364 | tmp = readw(base + S3C2410_RTCCON); | 383 | tmp = readw(base + S3C2410_RTCCON); |
365 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) | 384 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) |
@@ -399,6 +418,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) | |||
399 | base + S3C2410_RTCCON); | 418 | base + S3C2410_RTCCON); |
400 | } | 419 | } |
401 | } | 420 | } |
421 | clk_disable(rtc_clk); | ||
402 | } | 422 | } |
403 | 423 | ||
404 | static int __devexit s3c_rtc_remove(struct platform_device *dev) | 424 | static int __devexit s3c_rtc_remove(struct platform_device *dev) |
@@ -410,7 +430,6 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) | |||
410 | 430 | ||
411 | s3c_rtc_setaie(&dev->dev, 0); | 431 | s3c_rtc_setaie(&dev->dev, 0); |
412 | 432 | ||
413 | clk_disable(rtc_clk); | ||
414 | clk_put(rtc_clk); | 433 | clk_put(rtc_clk); |
415 | rtc_clk = NULL; | 434 | rtc_clk = NULL; |
416 | 435 | ||
@@ -530,6 +549,8 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) | |||
530 | 549 | ||
531 | s3c_rtc_setfreq(&pdev->dev, 1); | 550 | s3c_rtc_setfreq(&pdev->dev, 1); |
532 | 551 | ||
552 | clk_disable(rtc_clk); | ||
553 | |||
533 | return 0; | 554 | return 0; |
534 | 555 | ||
535 | err_nortc: | 556 | err_nortc: |
@@ -555,6 +576,7 @@ static int ticnt_save, ticnt_en_save; | |||
555 | 576 | ||
556 | static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) | 577 | static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) |
557 | { | 578 | { |
579 | clk_enable(rtc_clk); | ||
558 | /* save TICNT for anyone using periodic interrupts */ | 580 | /* save TICNT for anyone using periodic interrupts */ |
559 | ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); | 581 | ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); |
560 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { | 582 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { |
@@ -569,6 +591,7 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) | |||
569 | else | 591 | else |
570 | dev_err(&pdev->dev, "enable_irq_wake failed\n"); | 592 | dev_err(&pdev->dev, "enable_irq_wake failed\n"); |
571 | } | 593 | } |
594 | clk_disable(rtc_clk); | ||
572 | 595 | ||
573 | return 0; | 596 | return 0; |
574 | } | 597 | } |
@@ -577,6 +600,7 @@ static int s3c_rtc_resume(struct platform_device *pdev) | |||
577 | { | 600 | { |
578 | unsigned int tmp; | 601 | unsigned int tmp; |
579 | 602 | ||
603 | clk_enable(rtc_clk); | ||
580 | s3c_rtc_enable(pdev, 1); | 604 | s3c_rtc_enable(pdev, 1); |
581 | writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); | 605 | writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); |
582 | if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { | 606 | if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { |
@@ -588,6 +612,7 @@ static int s3c_rtc_resume(struct platform_device *pdev) | |||
588 | disable_irq_wake(s3c_rtc_alarmno); | 612 | disable_irq_wake(s3c_rtc_alarmno); |
589 | wake_en = false; | 613 | wake_en = false; |
590 | } | 614 | } |
615 | clk_disable(rtc_clk); | ||
591 | 616 | ||
592 | return 0; | 617 | return 0; |
593 | } | 618 | } |