aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorFeng Tang <feng.tang@intel.com>2010-11-10 12:29:17 -0500
committerThomas Gleixner <tglx@linutronix.de>2010-11-11 05:34:27 -0500
commit0146f26145af75d53e12dbf23a36996aff373680 (patch)
tree3eb42ef8ccbf1af5fb85695accd8b8e84ebe0634 /drivers/rtc
parent7309282c90d251cde77fe3b520a8276e25315c49 (diff)
rtc: Add drivers/rtc/rtc-mrst.c
Provide the standard kernel rtc driver interface on top of the vrtc layer added in the previous patch. Signed-off-by: Feng Tang <feng.tang@intel.com> LKML-Reference: <20101110172911.3311.20593.stgit@localhost.localdomain> [Fixed swapped arguments on IPC] Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> [Cleaned up and the device creation moved to arch/x86/platform] Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig12
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-mrst.c578
3 files changed, 591 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2883428d5ac..4941cade319 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -463,6 +463,18 @@ config RTC_DRV_CMOS
463 This driver can also be built as a module. If so, the module 463 This driver can also be built as a module. If so, the module
464 will be called rtc-cmos. 464 will be called rtc-cmos.
465 465
466config RTC_DRV_VRTC
467 tristate "Virtual RTC for Moorestown platforms"
468 depends on X86_MRST
469 default y if X86_MRST
470
471 help
472 Say "yes" here to get direct support for the real time clock
473 found on Moorestown platforms. The VRTC is a emulated RTC that
474 derives its clock source from a real RTC in the PMIC. The MC146818
475 style programming interface is mostly conserved, but any
476 updates are done via IPC calls to the system controller FW.
477
466config RTC_DRV_DS1216 478config RTC_DRV_DS1216
467 tristate "Dallas DS1216" 479 tristate "Dallas DS1216"
468 depends on SNI_RM 480 depends on SNI_RM
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 4c2832df469..2afdaf3ff98 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
30obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o 30obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
31obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o 31obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o
32obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o 32obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o
33obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
33obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o 34obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
34obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o 35obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
35obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o 36obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c
new file mode 100644
index 00000000000..67b6be2b874
--- /dev/null
+++ b/drivers/rtc/rtc-mrst.c
@@ -0,0 +1,578 @@
1/*
2 * rtc-mrst.c: Driver for Moorestown virtual RTC
3 *
4 * (C) Copyright 2009 Intel Corporation
5 * Author: Jacob Pan (jacob.jun.pan@intel.com)
6 * Feng Tang (feng.tang@intel.com)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; version 2
11 * of the License.
12 *
13 * Note:
14 * VRTC is emulated by system controller firmware, the real HW
15 * RTC is located in the PMIC device. SCU FW shadows PMIC RTC
16 * in a memory mapped IO space that is visible to the host IA
17 * processor.
18 *
19 * This driver is based upon drivers/rtc/rtc-cmos.c
20 */
21
22/*
23 * Note:
24 * * vRTC only supports binary mode and 24H mode
25 * * vRTC only support PIE and AIE, no UIE, and its PIE only happens
26 * at 23:59:59pm everyday, no support for adjustable frequency
27 * * Alarm function is also limited to hr/min/sec.
28 */
29
30#include <linux/mod_devicetable.h>
31#include <linux/platform_device.h>
32#include <linux/interrupt.h>
33#include <linux/spinlock.h>
34#include <linux/kernel.h>
35#include <linux/module.h>
36#include <linux/init.h>
37#include <linux/sfi.h>
38
39#include <asm-generic/rtc.h>
40#include <asm/intel_scu_ipc.h>
41#include <asm/mrst.h>
42#include <asm/mrst-vrtc.h>
43
44struct mrst_rtc {
45 struct rtc_device *rtc;
46 struct device *dev;
47 int irq;
48 struct resource *iomem;
49
50 u8 enabled_wake;
51 u8 suspend_ctrl;
52};
53
54static const char driver_name[] = "rtc_mrst";
55
56#define RTC_IRQMASK (RTC_PF | RTC_AF)
57
58static inline int is_intr(u8 rtc_intr)
59{
60 if (!(rtc_intr & RTC_IRQF))
61 return 0;
62 return rtc_intr & RTC_IRQMASK;
63}
64
65/*
66 * rtc_time's year contains the increment over 1900, but vRTC's YEAR
67 * register can't be programmed to value larger than 0x64, so vRTC
68 * driver chose to use 1960 (1970 is UNIX time start point) as the base,
69 * and does the translation at read/write time
70 */
71static int mrst_read_time(struct device *dev, struct rtc_time *time)
72{
73 unsigned long flags;
74
75 if (rtc_is_updating())
76 mdelay(20);
77
78 spin_lock_irqsave(&rtc_lock, flags);
79 time->tm_sec = vrtc_cmos_read(RTC_SECONDS);
80 time->tm_min = vrtc_cmos_read(RTC_MINUTES);
81 time->tm_hour = vrtc_cmos_read(RTC_HOURS);
82 time->tm_mday = vrtc_cmos_read(RTC_DAY_OF_MONTH);
83 time->tm_mon = vrtc_cmos_read(RTC_MONTH);
84 time->tm_year = vrtc_cmos_read(RTC_YEAR);
85 spin_unlock_irqrestore(&rtc_lock, flags);
86
87 /* Adjust for the 1960/1900 */
88 time->tm_year += 60;
89 time->tm_mon--;
90 return RTC_24H;
91}
92
93static int mrst_set_time(struct device *dev, struct rtc_time *time)
94{
95 int ret;
96 unsigned long flags;
97 unsigned char mon, day, hrs, min, sec;
98 unsigned int yrs;
99
100 yrs = time->tm_year;
101 mon = time->tm_mon + 1; /* tm_mon starts at zero */
102 day = time->tm_mday;
103 hrs = time->tm_hour;
104 min = time->tm_min;
105 sec = time->tm_sec;
106
107 if (yrs < 70 || yrs > 138)
108 return -EINVAL;
109 yrs -= 60;
110
111 spin_lock_irqsave(&rtc_lock, flags);
112
113 vrtc_cmos_write(yrs, RTC_YEAR);
114 vrtc_cmos_write(mon, RTC_MONTH);
115 vrtc_cmos_write(day, RTC_DAY_OF_MONTH);
116 vrtc_cmos_write(hrs, RTC_HOURS);
117 vrtc_cmos_write(min, RTC_MINUTES);
118 vrtc_cmos_write(sec, RTC_SECONDS);
119
120 spin_unlock_irqrestore(&rtc_lock, flags);
121
122 ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME);
123 return ret;
124}
125
126static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t)
127{
128 struct mrst_rtc *mrst = dev_get_drvdata(dev);
129 unsigned char rtc_control;
130
131 if (mrst->irq <= 0)
132 return -EIO;
133
134 /* Basic alarms only support hour, minute, and seconds fields.
135 * Some also support day and month, for alarms up to a year in
136 * the future.
137 */
138 t->time.tm_mday = -1;
139 t->time.tm_mon = -1;
140 t->time.tm_year = -1;
141
142 /* vRTC only supports binary mode */
143 spin_lock_irq(&rtc_lock);
144 t->time.tm_sec = vrtc_cmos_read(RTC_SECONDS_ALARM);
145 t->time.tm_min = vrtc_cmos_read(RTC_MINUTES_ALARM);
146 t->time.tm_hour = vrtc_cmos_read(RTC_HOURS_ALARM);
147
148 rtc_control = vrtc_cmos_read(RTC_CONTROL);
149 spin_unlock_irq(&rtc_lock);
150
151 t->enabled = !!(rtc_control & RTC_AIE);
152 t->pending = 0;
153
154 return 0;
155}
156
157static void mrst_checkintr(struct mrst_rtc *mrst, unsigned char rtc_control)
158{
159 unsigned char rtc_intr;
160
161 /*
162 * NOTE after changing RTC_xIE bits we always read INTR_FLAGS;
163 * allegedly some older rtcs need that to handle irqs properly
164 */
165 rtc_intr = vrtc_cmos_read(RTC_INTR_FLAGS);
166 rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
167 if (is_intr(rtc_intr))
168 rtc_update_irq(mrst->rtc, 1, rtc_intr);
169}
170
171static void mrst_irq_enable(struct mrst_rtc *mrst, unsigned char mask)
172{
173 unsigned char rtc_control;
174
175 /*
176 * Flush any pending IRQ status, notably for update irqs,
177 * before we enable new IRQs
178 */
179 rtc_control = vrtc_cmos_read(RTC_CONTROL);
180 mrst_checkintr(mrst, rtc_control);
181
182 rtc_control |= mask;
183 vrtc_cmos_write(rtc_control, RTC_CONTROL);
184
185 mrst_checkintr(mrst, rtc_control);
186}
187
188static void mrst_irq_disable(struct mrst_rtc *mrst, unsigned char mask)
189{
190 unsigned char rtc_control;
191
192 rtc_control = vrtc_cmos_read(RTC_CONTROL);
193 rtc_control &= ~mask;
194 vrtc_cmos_write(rtc_control, RTC_CONTROL);
195 mrst_checkintr(mrst, rtc_control);
196}
197
198static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
199{
200 struct mrst_rtc *mrst = dev_get_drvdata(dev);
201 unsigned char hrs, min, sec;
202 int ret = 0;
203
204 if (!mrst->irq)
205 return -EIO;
206
207 hrs = t->time.tm_hour;
208 min = t->time.tm_min;
209 sec = t->time.tm_sec;
210
211 spin_lock_irq(&rtc_lock);
212 /* Next rtc irq must not be from previous alarm setting */
213 mrst_irq_disable(mrst, RTC_AIE);
214
215 /* Update alarm */
216 vrtc_cmos_write(hrs, RTC_HOURS_ALARM);
217 vrtc_cmos_write(min, RTC_MINUTES_ALARM);
218 vrtc_cmos_write(sec, RTC_SECONDS_ALARM);
219
220 spin_unlock_irq(&rtc_lock);
221
222 ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM);
223 if (ret)
224 return ret;
225
226 spin_lock_irq(&rtc_lock);
227 if (t->enabled)
228 mrst_irq_enable(mrst, RTC_AIE);
229
230 spin_unlock_irq(&rtc_lock);
231
232 return 0;
233}
234
235static int mrst_irq_set_state(struct device *dev, int enabled)
236{
237 struct mrst_rtc *mrst = dev_get_drvdata(dev);
238 unsigned long flags;
239
240 if (!mrst->irq)
241 return -ENXIO;
242
243 spin_lock_irqsave(&rtc_lock, flags);
244
245 if (enabled)
246 mrst_irq_enable(mrst, RTC_PIE);
247 else
248 mrst_irq_disable(mrst, RTC_PIE);
249
250 spin_unlock_irqrestore(&rtc_lock, flags);
251 return 0;
252}
253
254#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
255
256/* Currently, the vRTC doesn't support UIE ON/OFF */
257static int
258mrst_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
259{
260 struct mrst_rtc *mrst = dev_get_drvdata(dev);
261 unsigned long flags;
262
263 switch (cmd) {
264 case RTC_AIE_OFF:
265 case RTC_AIE_ON:
266 if (!mrst->irq)
267 return -EINVAL;
268 break;
269 default:
270 /* PIE ON/OFF is handled by mrst_irq_set_state() */
271 return -ENOIOCTLCMD;
272 }
273
274 spin_lock_irqsave(&rtc_lock, flags);
275 switch (cmd) {
276 case RTC_AIE_OFF: /* alarm off */
277 mrst_irq_disable(mrst, RTC_AIE);
278 break;
279 case RTC_AIE_ON: /* alarm on */
280 mrst_irq_enable(mrst, RTC_AIE);
281 break;
282 }
283 spin_unlock_irqrestore(&rtc_lock, flags);
284 return 0;
285}
286
287#else
288#define mrst_rtc_ioctl NULL
289#endif
290
291#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
292
293static int mrst_procfs(struct device *dev, struct seq_file *seq)
294{
295 unsigned char rtc_control, valid;
296
297 spin_lock_irq(&rtc_lock);
298 rtc_control = vrtc_cmos_read(RTC_CONTROL);
299 valid = vrtc_cmos_read(RTC_VALID);
300 spin_unlock_irq(&rtc_lock);
301
302 return seq_printf(seq,
303 "periodic_IRQ\t: %s\n"
304 "alarm\t\t: %s\n"
305 "BCD\t\t: no\n"
306 "periodic_freq\t: daily (not adjustable)\n",
307 (rtc_control & RTC_PIE) ? "on" : "off",
308 (rtc_control & RTC_AIE) ? "on" : "off");
309}
310
311#else
312#define mrst_procfs NULL
313#endif
314
315static const struct rtc_class_ops mrst_rtc_ops = {
316 .ioctl = mrst_rtc_ioctl,
317 .read_time = mrst_read_time,
318 .set_time = mrst_set_time,
319 .read_alarm = mrst_read_alarm,
320 .set_alarm = mrst_set_alarm,
321 .proc = mrst_procfs,
322 .irq_set_state = mrst_irq_set_state,
323};
324
325static struct mrst_rtc mrst_rtc;
326
327/*
328 * When vRTC IRQ is captured by SCU FW, FW will clear the AIE bit in
329 * Reg B, so no need for this driver to clear it
330 */
331static irqreturn_t mrst_rtc_irq(int irq, void *p)
332{
333 u8 irqstat;
334
335 spin_lock(&rtc_lock);
336 /* This read will clear all IRQ flags inside Reg C */
337 irqstat = vrtc_cmos_read(RTC_INTR_FLAGS);
338 spin_unlock(&rtc_lock);
339
340 irqstat &= RTC_IRQMASK | RTC_IRQF;
341 if (is_intr(irqstat)) {
342 rtc_update_irq(p, 1, irqstat);
343 return IRQ_HANDLED;
344 }
345 return IRQ_NONE;
346}
347
348static int __init
349vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq)
350{
351 int retval = 0;
352 unsigned char rtc_control;
353
354 /* There can be only one ... */
355 if (mrst_rtc.dev)
356 return -EBUSY;
357
358 if (!iomem)
359 return -ENODEV;
360
361 iomem = request_mem_region(iomem->start,
362 iomem->end + 1 - iomem->start,
363 driver_name);
364 if (!iomem) {
365 dev_dbg(dev, "i/o mem already in use.\n");
366 return -EBUSY;
367 }
368
369 mrst_rtc.irq = rtc_irq;
370 mrst_rtc.iomem = iomem;
371
372 mrst_rtc.rtc = rtc_device_register(driver_name, dev,
373 &mrst_rtc_ops, THIS_MODULE);
374 if (IS_ERR(mrst_rtc.rtc)) {
375 retval = PTR_ERR(mrst_rtc.rtc);
376 goto cleanup0;
377 }
378
379 mrst_rtc.dev = dev;
380 dev_set_drvdata(dev, &mrst_rtc);
381 rename_region(iomem, dev_name(&mrst_rtc.rtc->dev));
382
383 spin_lock_irq(&rtc_lock);
384 mrst_irq_disable(&mrst_rtc, RTC_PIE | RTC_AIE);
385 rtc_control = vrtc_cmos_read(RTC_CONTROL);
386 spin_unlock_irq(&rtc_lock);
387
388 if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))
389 dev_dbg(dev, "TODO: support more than 24-hr BCD mode\n");
390
391 if (rtc_irq) {
392 retval = request_irq(rtc_irq, mrst_rtc_irq,
393 IRQF_DISABLED, dev_name(&mrst_rtc.rtc->dev),
394 mrst_rtc.rtc);
395 if (retval < 0) {
396 dev_dbg(dev, "IRQ %d is already in use, err %d\n",
397 rtc_irq, retval);
398 goto cleanup1;
399 }
400 }
401 dev_dbg(dev, "initialised\n");
402 return 0;
403
404cleanup1:
405 mrst_rtc.dev = NULL;
406 rtc_device_unregister(mrst_rtc.rtc);
407cleanup0:
408 release_region(iomem->start, iomem->end + 1 - iomem->start);
409 dev_err(dev, "rtc-mrst: unable to initialise\n");
410 return retval;
411}
412
413static void rtc_mrst_do_shutdown(void)
414{
415 spin_lock_irq(&rtc_lock);
416 mrst_irq_disable(&mrst_rtc, RTC_IRQMASK);
417 spin_unlock_irq(&rtc_lock);
418}
419
420static void __exit rtc_mrst_do_remove(struct device *dev)
421{
422 struct mrst_rtc *mrst = dev_get_drvdata(dev);
423 struct resource *iomem;
424
425 rtc_mrst_do_shutdown();
426
427 if (mrst->irq)
428 free_irq(mrst->irq, mrst->rtc);
429
430 rtc_device_unregister(mrst->rtc);
431 mrst->rtc = NULL;
432
433 iomem = mrst->iomem;
434 release_region(iomem->start, iomem->end + 1 - iomem->start);
435 mrst->iomem = NULL;
436
437 mrst->dev = NULL;
438 dev_set_drvdata(dev, NULL);
439}
440
441#ifdef CONFIG_PM
442static int mrst_suspend(struct device *dev, pm_message_t mesg)
443{
444 struct mrst_rtc *mrst = dev_get_drvdata(dev);
445 unsigned char tmp;
446
447 /* Only the alarm might be a wakeup event source */
448 spin_lock_irq(&rtc_lock);
449 mrst->suspend_ctrl = tmp = vrtc_cmos_read(RTC_CONTROL);
450 if (tmp & (RTC_PIE | RTC_AIE)) {
451 unsigned char mask;
452
453 if (device_may_wakeup(dev))
454 mask = RTC_IRQMASK & ~RTC_AIE;
455 else
456 mask = RTC_IRQMASK;
457 tmp &= ~mask;
458 vrtc_cmos_write(tmp, RTC_CONTROL);
459
460 mrst_checkintr(mrst, tmp);
461 }
462 spin_unlock_irq(&rtc_lock);
463
464 if (tmp & RTC_AIE) {
465 mrst->enabled_wake = 1;
466 enable_irq_wake(mrst->irq);
467 }
468
469 dev_dbg(&mrst_rtc.rtc->dev, "suspend%s, ctrl %02x\n",
470 (tmp & RTC_AIE) ? ", alarm may wake" : "",
471 tmp);
472
473 return 0;
474}
475
476/*
477 * We want RTC alarms to wake us from the deep power saving state
478 */
479static inline int mrst_poweroff(struct device *dev)
480{
481 return mrst_suspend(dev, PMSG_HIBERNATE);
482}
483
484static int mrst_resume(struct device *dev)
485{
486 struct mrst_rtc *mrst = dev_get_drvdata(dev);
487 unsigned char tmp = mrst->suspend_ctrl;
488
489 /* Re-enable any irqs previously active */
490 if (tmp & RTC_IRQMASK) {
491 unsigned char mask;
492
493 if (mrst->enabled_wake) {
494 disable_irq_wake(mrst->irq);
495 mrst->enabled_wake = 0;
496 }
497
498 spin_lock_irq(&rtc_lock);
499 do {
500 vrtc_cmos_write(tmp, RTC_CONTROL);
501
502 mask = vrtc_cmos_read(RTC_INTR_FLAGS);
503 mask &= (tmp & RTC_IRQMASK) | RTC_IRQF;
504 if (!is_intr(mask))
505 break;
506
507 rtc_update_irq(mrst->rtc, 1, mask);
508 tmp &= ~RTC_AIE;
509 } while (mask & RTC_AIE);
510 spin_unlock_irq(&rtc_lock);
511 }
512
513 dev_dbg(&mrst_rtc.rtc->dev, "resume, ctrl %02x\n", tmp);
514
515 return 0;
516}
517
518#else
519#define mrst_suspend NULL
520#define mrst_resume NULL
521
522static inline int mrst_poweroff(struct device *dev)
523{
524 return -ENOSYS;
525}
526
527#endif
528
529static int __init vrtc_mrst_platform_probe(struct platform_device *pdev)
530{
531 return vrtc_mrst_do_probe(&pdev->dev,
532 platform_get_resource(pdev, IORESOURCE_MEM, 0),
533 platform_get_irq(pdev, 0));
534}
535
536static int __exit vrtc_mrst_platform_remove(struct platform_device *pdev)
537{
538 rtc_mrst_do_remove(&pdev->dev);
539 return 0;
540}
541
542static void vrtc_mrst_platform_shutdown(struct platform_device *pdev)
543{
544 if (system_state == SYSTEM_POWER_OFF && !mrst_poweroff(&pdev->dev))
545 return;
546
547 rtc_mrst_do_shutdown();
548}
549
550MODULE_ALIAS("platform:vrtc_mrst");
551
552static struct platform_driver vrtc_mrst_platform_driver = {
553 .probe = vrtc_mrst_platform_probe,
554 .remove = __exit_p(vrtc_mrst_platform_remove),
555 .shutdown = vrtc_mrst_platform_shutdown,
556 .driver = {
557 .name = (char *) driver_name,
558 .suspend = mrst_suspend,
559 .resume = mrst_resume,
560 }
561};
562
563static int __init vrtc_mrst_init(void)
564{
565 return platform_driver_register(&vrtc_mrst_platform_driver);
566}
567
568static void __exit vrtc_mrst_exit(void)
569{
570 platform_driver_unregister(&vrtc_mrst_platform_driver);
571}
572
573module_init(vrtc_mrst_init);
574module_exit(vrtc_mrst_exit);
575
576MODULE_AUTHOR("Jacob Pan; Feng Tang");
577MODULE_DESCRIPTION("Driver for Moorestown virtual RTC");
578MODULE_LICENSE("GPL");