diff options
author | Alessandro Zummo <a.zummo@towertech.it> | 2006-03-27 04:16:45 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-27 11:44:52 -0500 |
commit | fd507e2ff3a5adaccbefa05f4bc9f58f44e930db (patch) | |
tree | e34d6ada2e2da94afd73f018e3ac098593bc63f2 | |
parent | 7520b94debdc61620e1582fb4f5cca4a830f91cd (diff) |
[PATCH] RTC subsystem: EP93XX driver
This patch adds a driver for the RTC embedded in the Cirrus Logic EP93XX
family of processors.
Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/rtc/Kconfig | 11 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-ep93xx.c | 162 |
3 files changed, 174 insertions, 1 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 609f55593459..b399259784e2 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -117,6 +117,17 @@ config RTC_DRV_RS5C372 | |||
117 | This driver can also be built as a module. If so, the module | 117 | This driver can also be built as a module. If so, the module |
118 | will be called rtc-rs5c372. | 118 | will be called rtc-rs5c372. |
119 | 119 | ||
120 | config RTC_DRV_EP93XX | ||
121 | tristate "Cirrus Logic EP93XX" | ||
122 | depends on RTC_CLASS && ARCH_EP93XX | ||
123 | help | ||
124 | If you say yes here you get support for the | ||
125 | RTC embedded in the Cirrus Logic EP93XX processors. | ||
126 | |||
127 | This driver can also be built as a module. If so, the module | ||
128 | will be called rtc-ep93xx. | ||
129 | |||
130 | |||
120 | config RTC_DRV_TEST | 131 | config RTC_DRV_TEST |
121 | tristate "Test driver/device" | 132 | tristate "Test driver/device" |
122 | depends on RTC_CLASS | 133 | depends on RTC_CLASS |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d2b4b1735598..38b4d87939e1 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -16,4 +16,4 @@ obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o | |||
16 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o | 16 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o |
17 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o | 17 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o |
18 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o | 18 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o |
19 | 19 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | |
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c new file mode 100644 index 000000000000..0dd80ea686a9 --- /dev/null +++ b/drivers/rtc/rtc-ep93xx.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * A driver for the RTC embedded in the Cirrus Logic EP93XX processors | ||
3 | * Copyright (c) 2006 Tower Technologies | ||
4 | * | ||
5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/rtc.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <asm/hardware.h> | ||
16 | |||
17 | #define EP93XX_RTC_REG(x) (EP93XX_RTC_BASE + (x)) | ||
18 | #define EP93XX_RTC_DATA EP93XX_RTC_REG(0x0000) | ||
19 | #define EP93XX_RTC_LOAD EP93XX_RTC_REG(0x000C) | ||
20 | #define EP93XX_RTC_SWCOMP EP93XX_RTC_REG(0x0108) | ||
21 | |||
22 | #define DRV_VERSION "0.2" | ||
23 | |||
24 | static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload, | ||
25 | unsigned short *delete) | ||
26 | { | ||
27 | unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP); | ||
28 | |||
29 | if (preload) | ||
30 | *preload = comp & 0xffff; | ||
31 | |||
32 | if (delete) | ||
33 | *delete = (comp >> 16) & 0x1f; | ||
34 | |||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
39 | { | ||
40 | unsigned long time = __raw_readl(EP93XX_RTC_DATA); | ||
41 | |||
42 | rtc_time_to_tm(time, tm); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) | ||
47 | { | ||
48 | __raw_writel(secs + 1, EP93XX_RTC_LOAD); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
53 | { | ||
54 | int err; | ||
55 | unsigned long secs; | ||
56 | |||
57 | err = rtc_tm_to_time(tm, &secs); | ||
58 | if (err != 0) | ||
59 | return err; | ||
60 | |||
61 | return ep93xx_rtc_set_mmss(dev, secs); | ||
62 | } | ||
63 | |||
64 | static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) | ||
65 | { | ||
66 | unsigned short preload, delete; | ||
67 | |||
68 | ep93xx_get_swcomp(dev, &preload, &delete); | ||
69 | |||
70 | seq_printf(seq, "24hr\t\t: yes\n"); | ||
71 | seq_printf(seq, "preload\t\t: %d\n", preload); | ||
72 | seq_printf(seq, "delete\t\t: %d\n", delete); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static struct rtc_class_ops ep93xx_rtc_ops = { | ||
78 | .read_time = ep93xx_rtc_read_time, | ||
79 | .set_time = ep93xx_rtc_set_time, | ||
80 | .set_mmss = ep93xx_rtc_set_mmss, | ||
81 | .proc = ep93xx_rtc_proc, | ||
82 | }; | ||
83 | |||
84 | static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev, | ||
85 | struct device_attribute *attr, char *buf) | ||
86 | { | ||
87 | unsigned short preload; | ||
88 | |||
89 | ep93xx_get_swcomp(dev, &preload, NULL); | ||
90 | |||
91 | return sprintf(buf, "%d\n", preload); | ||
92 | } | ||
93 | static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL); | ||
94 | |||
95 | static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev, | ||
96 | struct device_attribute *attr, char *buf) | ||
97 | { | ||
98 | unsigned short delete; | ||
99 | |||
100 | ep93xx_get_swcomp(dev, NULL, &delete); | ||
101 | |||
102 | return sprintf(buf, "%d\n", delete); | ||
103 | } | ||
104 | static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL); | ||
105 | |||
106 | |||
107 | static int __devinit ep93xx_rtc_probe(struct platform_device *dev) | ||
108 | { | ||
109 | struct rtc_device *rtc = rtc_device_register("ep93xx", | ||
110 | &dev->dev, &ep93xx_rtc_ops, THIS_MODULE); | ||
111 | |||
112 | if (IS_ERR(rtc)) { | ||
113 | dev_err(&dev->dev, "unable to register\n"); | ||
114 | return PTR_ERR(rtc); | ||
115 | } | ||
116 | |||
117 | platform_set_drvdata(dev, rtc); | ||
118 | |||
119 | device_create_file(&dev->dev, &dev_attr_comp_preload); | ||
120 | device_create_file(&dev->dev, &dev_attr_comp_delete); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int __devexit ep93xx_rtc_remove(struct platform_device *dev) | ||
126 | { | ||
127 | struct rtc_device *rtc = platform_get_drvdata(dev); | ||
128 | |||
129 | if (rtc) | ||
130 | rtc_device_unregister(rtc); | ||
131 | |||
132 | platform_set_drvdata(dev, NULL); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static struct platform_driver ep93xx_rtc_platform_driver = { | ||
138 | .driver = { | ||
139 | .name = "ep93xx-rtc", | ||
140 | .owner = THIS_MODULE, | ||
141 | }, | ||
142 | .probe = ep93xx_rtc_probe, | ||
143 | .remove = __devexit_p(ep93xx_rtc_remove), | ||
144 | }; | ||
145 | |||
146 | static int __init ep93xx_rtc_init(void) | ||
147 | { | ||
148 | return platform_driver_register(&ep93xx_rtc_platform_driver); | ||
149 | } | ||
150 | |||
151 | static void __exit ep93xx_rtc_exit(void) | ||
152 | { | ||
153 | platform_driver_unregister(&ep93xx_rtc_platform_driver); | ||
154 | } | ||
155 | |||
156 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
157 | MODULE_DESCRIPTION("EP93XX RTC driver"); | ||
158 | MODULE_LICENSE("GPL"); | ||
159 | MODULE_VERSION(DRV_VERSION); | ||
160 | |||
161 | module_init(ep93xx_rtc_init); | ||
162 | module_exit(ep93xx_rtc_exit); | ||