aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 11:13:35 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 11:13:35 -0500
commitadf9904dc774f23f04a5425f0198483ea61f878b (patch)
treedfe0527c7f3877eb4d155ddb20fd303c1d8328c0 /drivers/rtc
parentbb592cf474404e51cbf3c419fb72fda83c4b7d72 (diff)
parent49966bae8446f5ba7e8afbd01bde82af4e00628a (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k: m68k: parport_mfc3 - Not makes it a bool before the comparison. m68k: don't export static inline functions fbdev: atafb - add palette register check m68k: Remove the BKL from sys_execve m68k: Cleanup linker scripts using new linker script macros. m68k: Make thread_info.h usable from assembly. m68knommu: define arch_has_single_step() and friends m68k: ptrace fixes m68k: use generic code for ptrace requests rtc: Add an RTC driver for the Ricoh RP5C01 rtc: Add an RTC driver for the Oki MSM6242
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig19
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/rtc-msm6242.c269
-rw-r--r--drivers/rtc/rtc-rp5c01.c222
4 files changed, 512 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e11e1cda4ba2..f2e1004d12c7 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -509,6 +509,15 @@ config RTC_DRV_M48T59
509 This driver can also be built as a module, if so, the module 509 This driver can also be built as a module, if so, the module
510 will be called "rtc-m48t59". 510 will be called "rtc-m48t59".
511 511
512config RTC_DRV_MSM6242
513 tristate "Oki MSM6242"
514 help
515 If you say yes here you get support for the Oki MSM6242
516 timekeeping chip. It is used in some Amiga models (e.g. A2000).
517
518 This driver can also be built as a module. If so, the module
519 will be called rtc-msm6242.
520
512config RTC_MXC 521config RTC_MXC
513 tristate "Freescale MXC Real Time Clock" 522 tristate "Freescale MXC Real Time Clock"
514 depends on ARCH_MXC 523 depends on ARCH_MXC
@@ -529,6 +538,16 @@ config RTC_DRV_BQ4802
529 This driver can also be built as a module. If so, the module 538 This driver can also be built as a module. If so, the module
530 will be called rtc-bq4802. 539 will be called rtc-bq4802.
531 540
541config RTC_DRV_RP5C01
542 tristate "Ricoh RP5C01"
543 help
544 If you say yes here you get support for the Ricoh RP5C01
545 timekeeping chip. It is used in some Amiga models (e.g. A3000
546 and A4000).
547
548 This driver can also be built as a module. If so, the module
549 will be called rtc-rp5c01.
550
532config RTC_DRV_V3020 551config RTC_DRV_V3020
533 tristate "EM Microelectronic V3020" 552 tristate "EM Microelectronic V3020"
534 help 553 help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index aa3fbd5517a1..af1ba7ae2857 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
52obj-$(CONFIG_RTC_MXC) += rtc-mxc.o 52obj-$(CONFIG_RTC_MXC) += rtc-mxc.o
53obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o 53obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
54obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o 54obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
55obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
55obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o 56obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
56obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o 57obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
57obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o 58obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
@@ -64,6 +65,7 @@ obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
64obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o 65obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
65obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o 66obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
66obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o 67obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
68obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
67obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o 69obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
68obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o 70obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
69obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o 71obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c
new file mode 100644
index 000000000000..5f5968a48925
--- /dev/null
+++ b/drivers/rtc/rtc-msm6242.c
@@ -0,0 +1,269 @@
1/*
2 * Oki MSM6242 RTC Driver
3 *
4 * Copyright 2009 Geert Uytterhoeven
5 *
6 * Based on the A2000 TOD code in arch/m68k/amiga/config.c
7 * Copyright (C) 1993 Hamish Macdonald
8 */
9
10#include <linux/delay.h>
11#include <linux/io.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/rtc.h>
16
17
18enum {
19 MSM6242_SECOND1 = 0x0, /* 1-second digit register */
20 MSM6242_SECOND10 = 0x1, /* 10-second digit register */
21 MSM6242_MINUTE1 = 0x2, /* 1-minute digit register */
22 MSM6242_MINUTE10 = 0x3, /* 10-minute digit register */
23 MSM6242_HOUR1 = 0x4, /* 1-hour digit register */
24 MSM6242_HOUR10 = 0x5, /* PM/AM, 10-hour digit register */
25 MSM6242_DAY1 = 0x6, /* 1-day digit register */
26 MSM6242_DAY10 = 0x7, /* 10-day digit register */
27 MSM6242_MONTH1 = 0x8, /* 1-month digit register */
28 MSM6242_MONTH10 = 0x9, /* 10-month digit register */
29 MSM6242_YEAR1 = 0xa, /* 1-year digit register */
30 MSM6242_YEAR10 = 0xb, /* 10-year digit register */
31 MSM6242_WEEK = 0xc, /* Week register */
32 MSM6242_CD = 0xd, /* Control Register D */
33 MSM6242_CE = 0xe, /* Control Register E */
34 MSM6242_CF = 0xf, /* Control Register F */
35};
36
37#define MSM6242_HOUR10_AM (0 << 2)
38#define MSM6242_HOUR10_PM (1 << 2)
39#define MSM6242_HOUR10_HR_MASK (3 << 0)
40
41#define MSM6242_WEEK_SUNDAY 0
42#define MSM6242_WEEK_MONDAY 1
43#define MSM6242_WEEK_TUESDAY 2
44#define MSM6242_WEEK_WEDNESDAY 3
45#define MSM6242_WEEK_THURSDAY 4
46#define MSM6242_WEEK_FRIDAY 5
47#define MSM6242_WEEK_SATURDAY 6
48
49#define MSM6242_CD_30_S_ADJ (1 << 3) /* 30-second adjustment */
50#define MSM6242_CD_IRQ_FLAG (1 << 2)
51#define MSM6242_CD_BUSY (1 << 1)
52#define MSM6242_CD_HOLD (1 << 0)
53
54#define MSM6242_CE_T_MASK (3 << 2)
55#define MSM6242_CE_T_64HZ (0 << 2) /* period 1/64 second */
56#define MSM6242_CE_T_1HZ (1 << 2) /* period 1 second */
57#define MSM6242_CE_T_1MINUTE (2 << 2) /* period 1 minute */
58#define MSM6242_CE_T_1HOUR (3 << 2) /* period 1 hour */
59
60#define MSM6242_CE_ITRPT_STND (1 << 1)
61#define MSM6242_CE_MASK (1 << 0) /* STD.P output control */
62
63#define MSM6242_CF_TEST (1 << 3)
64#define MSM6242_CF_12H (0 << 2)
65#define MSM6242_CF_24H (1 << 2)
66#define MSM6242_CF_STOP (1 << 1)
67#define MSM6242_CF_REST (1 << 0) /* reset */
68
69
70struct msm6242_priv {
71 u32 __iomem *regs;
72 struct rtc_device *rtc;
73};
74
75static inline unsigned int msm6242_read(struct msm6242_priv *priv,
76 unsigned int reg)
77{
78 return __raw_readl(&priv->regs[reg]) & 0xf;
79}
80
81static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val,
82 unsigned int reg)
83{
84 return __raw_writel(val, &priv->regs[reg]);
85}
86
87static inline void msm6242_set(struct msm6242_priv *priv, unsigned int val,
88 unsigned int reg)
89{
90 msm6242_write(priv, msm6242_read(priv, reg) | val, reg);
91}
92
93static inline void msm6242_clear(struct msm6242_priv *priv, unsigned int val,
94 unsigned int reg)
95{
96 msm6242_write(priv, msm6242_read(priv, reg) & ~val, reg);
97}
98
99static void msm6242_lock(struct msm6242_priv *priv)
100{
101 int cnt = 5;
102
103 msm6242_set(priv, MSM6242_CD_HOLD, MSM6242_CD);
104
105 while ((msm6242_read(priv, MSM6242_CD) & MSM6242_CD_BUSY) && cnt) {
106 msm6242_clear(priv, MSM6242_CD_HOLD, MSM6242_CD);
107 udelay(70);
108 msm6242_set(priv, MSM6242_CD_HOLD, MSM6242_CD);
109 cnt--;
110 }
111
112 if (!cnt)
113 pr_warning("msm6242: timed out waiting for RTC (0x%x)\n",
114 msm6242_read(priv, MSM6242_CD));
115}
116
117static void msm6242_unlock(struct msm6242_priv *priv)
118{
119 msm6242_clear(priv, MSM6242_CD_HOLD, MSM6242_CD);
120}
121
122static int msm6242_read_time(struct device *dev, struct rtc_time *tm)
123{
124 struct msm6242_priv *priv = dev_get_drvdata(dev);
125
126 msm6242_lock(priv);
127
128 tm->tm_sec = msm6242_read(priv, MSM6242_SECOND10) * 10 +
129 msm6242_read(priv, MSM6242_SECOND1);
130 tm->tm_min = msm6242_read(priv, MSM6242_MINUTE10) * 10 +
131 msm6242_read(priv, MSM6242_MINUTE1);
132 tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10 & 3)) * 10 +
133 msm6242_read(priv, MSM6242_HOUR1);
134 tm->tm_mday = msm6242_read(priv, MSM6242_DAY10) * 10 +
135 msm6242_read(priv, MSM6242_DAY1);
136 tm->tm_wday = msm6242_read(priv, MSM6242_WEEK);
137 tm->tm_mon = msm6242_read(priv, MSM6242_MONTH10) * 10 +
138 msm6242_read(priv, MSM6242_MONTH1) - 1;
139 tm->tm_year = msm6242_read(priv, MSM6242_YEAR10) * 10 +
140 msm6242_read(priv, MSM6242_YEAR1);
141 if (tm->tm_year <= 69)
142 tm->tm_year += 100;
143
144 if (!(msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)) {
145 unsigned int pm = msm6242_read(priv, MSM6242_HOUR10) &
146 MSM6242_HOUR10_PM;
147 if (!pm && tm->tm_hour == 12)
148 tm->tm_hour = 0;
149 else if (pm && tm->tm_hour != 12)
150 tm->tm_hour += 12;
151 }
152
153 msm6242_unlock(priv);
154
155 return rtc_valid_tm(tm);
156}
157
158static int msm6242_set_time(struct device *dev, struct rtc_time *tm)
159{
160 struct msm6242_priv *priv = dev_get_drvdata(dev);
161
162 msm6242_lock(priv);
163
164 msm6242_write(priv, tm->tm_sec / 10, MSM6242_SECOND10);
165 msm6242_write(priv, tm->tm_sec % 10, MSM6242_SECOND1);
166 msm6242_write(priv, tm->tm_min / 10, MSM6242_MINUTE10);
167 msm6242_write(priv, tm->tm_min % 10, MSM6242_MINUTE1);
168 if (msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)
169 msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10);
170 else if (tm->tm_hour >= 12)
171 msm6242_write(priv, MSM6242_HOUR10_PM + (tm->tm_hour - 12) / 10,
172 MSM6242_HOUR10);
173 else
174 msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10);
175 msm6242_write(priv, tm->tm_hour % 10, MSM6242_HOUR1);
176 msm6242_write(priv, tm->tm_mday / 10, MSM6242_DAY10);
177 msm6242_write(priv, tm->tm_mday % 10, MSM6242_DAY1);
178 if (tm->tm_wday != -1)
179 msm6242_write(priv, tm->tm_wday, MSM6242_WEEK);
180 msm6242_write(priv, (tm->tm_mon + 1) / 10, MSM6242_MONTH10);
181 msm6242_write(priv, (tm->tm_mon + 1) % 10, MSM6242_MONTH1);
182 if (tm->tm_year >= 100)
183 tm->tm_year -= 100;
184 msm6242_write(priv, tm->tm_year / 10, MSM6242_YEAR10);
185 msm6242_write(priv, tm->tm_year % 10, MSM6242_YEAR1);
186
187 msm6242_unlock(priv);
188 return 0;
189}
190
191static const struct rtc_class_ops msm6242_rtc_ops = {
192 .read_time = msm6242_read_time,
193 .set_time = msm6242_set_time,
194};
195
196static int __init msm6242_rtc_probe(struct platform_device *dev)
197{
198 struct resource *res;
199 struct msm6242_priv *priv;
200 struct rtc_device *rtc;
201 int error;
202
203 res = platform_get_resource(dev, IORESOURCE_MEM, 0);
204 if (!res)
205 return -ENODEV;
206
207 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
208 if (!priv)
209 return -ENOMEM;
210
211 priv->regs = ioremap(res->start, resource_size(res));
212 if (!priv->regs) {
213 error = -ENOMEM;
214 goto out_free_priv;
215 }
216
217 rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops,
218 THIS_MODULE);
219 if (IS_ERR(rtc)) {
220 error = PTR_ERR(rtc);
221 goto out_unmap;
222 }
223
224 priv->rtc = rtc;
225 platform_set_drvdata(dev, priv);
226 return 0;
227
228out_unmap:
229 iounmap(priv->regs);
230out_free_priv:
231 kfree(priv);
232 return error;
233}
234
235static int __exit msm6242_rtc_remove(struct platform_device *dev)
236{
237 struct msm6242_priv *priv = platform_get_drvdata(dev);
238
239 rtc_device_unregister(priv->rtc);
240 iounmap(priv->regs);
241 kfree(priv);
242 return 0;
243}
244
245static struct platform_driver msm6242_rtc_driver = {
246 .driver = {
247 .name = "rtc-msm6242",
248 .owner = THIS_MODULE,
249 },
250 .remove = __exit_p(msm6242_rtc_remove),
251};
252
253static int __init msm6242_rtc_init(void)
254{
255 return platform_driver_probe(&msm6242_rtc_driver, msm6242_rtc_probe);
256}
257
258static void __exit msm6242_rtc_fini(void)
259{
260 platform_driver_unregister(&msm6242_rtc_driver);
261}
262
263module_init(msm6242_rtc_init);
264module_exit(msm6242_rtc_fini);
265
266MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
267MODULE_LICENSE("GPL");
268MODULE_DESCRIPTION("Oki MSM6242 RTC driver");
269MODULE_ALIAS("platform:rtc-msm6242");
diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c
new file mode 100644
index 000000000000..e1313feb060f
--- /dev/null
+++ b/drivers/rtc/rtc-rp5c01.c
@@ -0,0 +1,222 @@
1/*
2 * Ricoh RP5C01 RTC Driver
3 *
4 * Copyright 2009 Geert Uytterhoeven
5 *
6 * Based on the A3000 TOD code in arch/m68k/amiga/config.c
7 * Copyright (C) 1993 Hamish Macdonald
8 */
9
10#include <linux/io.h>
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/platform_device.h>
14#include <linux/rtc.h>
15
16
17enum {
18 RP5C01_1_SECOND = 0x0, /* MODE 00 */
19 RP5C01_10_SECOND = 0x1, /* MODE 00 */
20 RP5C01_1_MINUTE = 0x2, /* MODE 00 and MODE 01 */
21 RP5C01_10_MINUTE = 0x3, /* MODE 00 and MODE 01 */
22 RP5C01_1_HOUR = 0x4, /* MODE 00 and MODE 01 */
23 RP5C01_10_HOUR = 0x5, /* MODE 00 and MODE 01 */
24 RP5C01_DAY_OF_WEEK = 0x6, /* MODE 00 and MODE 01 */
25 RP5C01_1_DAY = 0x7, /* MODE 00 and MODE 01 */
26 RP5C01_10_DAY = 0x8, /* MODE 00 and MODE 01 */
27 RP5C01_1_MONTH = 0x9, /* MODE 00 */
28 RP5C01_10_MONTH = 0xa, /* MODE 00 */
29 RP5C01_1_YEAR = 0xb, /* MODE 00 */
30 RP5C01_10_YEAR = 0xc, /* MODE 00 */
31
32 RP5C01_12_24_SELECT = 0xa, /* MODE 01 */
33 RP5C01_LEAP_YEAR = 0xb, /* MODE 01 */
34
35 RP5C01_MODE = 0xd, /* all modes */
36 RP5C01_TEST = 0xe, /* all modes */
37 RP5C01_RESET = 0xf, /* all modes */
38};
39
40#define RP5C01_12_24_SELECT_12 (0 << 0)
41#define RP5C01_12_24_SELECT_24 (1 << 0)
42
43#define RP5C01_10_HOUR_AM (0 << 1)
44#define RP5C01_10_HOUR_PM (1 << 1)
45
46#define RP5C01_MODE_TIMER_EN (1 << 3) /* timer enable */
47#define RP5C01_MODE_ALARM_EN (1 << 2) /* alarm enable */
48
49#define RP5C01_MODE_MODE_MASK (3 << 0)
50#define RP5C01_MODE_MODE00 (0 << 0) /* time */
51#define RP5C01_MODE_MODE01 (1 << 0) /* alarm, 12h/24h, leap year */
52#define RP5C01_MODE_RAM_BLOCK10 (2 << 0) /* RAM 4 bits x 13 */
53#define RP5C01_MODE_RAM_BLOCK11 (3 << 0) /* RAM 4 bits x 13 */
54
55#define RP5C01_RESET_1HZ_PULSE (1 << 3)
56#define RP5C01_RESET_16HZ_PULSE (1 << 2)
57#define RP5C01_RESET_SECOND (1 << 1) /* reset divider stages for */
58 /* seconds or smaller units */
59#define RP5C01_RESET_ALARM (1 << 0) /* reset all alarm registers */
60
61
62struct rp5c01_priv {
63 u32 __iomem *regs;
64 struct rtc_device *rtc;
65};
66
67static inline unsigned int rp5c01_read(struct rp5c01_priv *priv,
68 unsigned int reg)
69{
70 return __raw_readl(&priv->regs[reg]) & 0xf;
71}
72
73static inline void rp5c01_write(struct rp5c01_priv *priv, unsigned int val,
74 unsigned int reg)
75{
76 return __raw_writel(val, &priv->regs[reg]);
77}
78
79static void rp5c01_lock(struct rp5c01_priv *priv)
80{
81 rp5c01_write(priv, RP5C01_MODE_MODE00, RP5C01_MODE);
82}
83
84static void rp5c01_unlock(struct rp5c01_priv *priv)
85{
86 rp5c01_write(priv, RP5C01_MODE_TIMER_EN | RP5C01_MODE_MODE01,
87 RP5C01_MODE);
88}
89
90static int rp5c01_read_time(struct device *dev, struct rtc_time *tm)
91{
92 struct rp5c01_priv *priv = dev_get_drvdata(dev);
93
94 rp5c01_lock(priv);
95
96 tm->tm_sec = rp5c01_read(priv, RP5C01_10_SECOND) * 10 +
97 rp5c01_read(priv, RP5C01_1_SECOND);
98 tm->tm_min = rp5c01_read(priv, RP5C01_10_MINUTE) * 10 +
99 rp5c01_read(priv, RP5C01_1_MINUTE);
100 tm->tm_hour = rp5c01_read(priv, RP5C01_10_HOUR) * 10 +
101 rp5c01_read(priv, RP5C01_1_HOUR);
102 tm->tm_mday = rp5c01_read(priv, RP5C01_10_DAY) * 10 +
103 rp5c01_read(priv, RP5C01_1_DAY);
104 tm->tm_wday = rp5c01_read(priv, RP5C01_DAY_OF_WEEK);
105 tm->tm_mon = rp5c01_read(priv, RP5C01_10_MONTH) * 10 +
106 rp5c01_read(priv, RP5C01_1_MONTH) - 1;
107 tm->tm_year = rp5c01_read(priv, RP5C01_10_YEAR) * 10 +
108 rp5c01_read(priv, RP5C01_1_YEAR);
109 if (tm->tm_year <= 69)
110 tm->tm_year += 100;
111
112 rp5c01_unlock(priv);
113
114 return rtc_valid_tm(tm);
115}
116
117static int rp5c01_set_time(struct device *dev, struct rtc_time *tm)
118{
119 struct rp5c01_priv *priv = dev_get_drvdata(dev);
120
121 rp5c01_lock(priv);
122
123 rp5c01_write(priv, tm->tm_sec / 10, RP5C01_10_SECOND);
124 rp5c01_write(priv, tm->tm_sec % 10, RP5C01_1_SECOND);
125 rp5c01_write(priv, tm->tm_min / 10, RP5C01_10_MINUTE);
126 rp5c01_write(priv, tm->tm_min % 10, RP5C01_1_MINUTE);
127 rp5c01_write(priv, tm->tm_hour / 10, RP5C01_10_HOUR);
128 rp5c01_write(priv, tm->tm_hour % 10, RP5C01_1_HOUR);
129 rp5c01_write(priv, tm->tm_mday / 10, RP5C01_10_DAY);
130 rp5c01_write(priv, tm->tm_mday % 10, RP5C01_1_DAY);
131 if (tm->tm_wday != -1)
132 rp5c01_write(priv, tm->tm_wday, RP5C01_DAY_OF_WEEK);
133 rp5c01_write(priv, (tm->tm_mon + 1) / 10, RP5C01_10_MONTH);
134 rp5c01_write(priv, (tm->tm_mon + 1) % 10, RP5C01_1_MONTH);
135 if (tm->tm_year >= 100)
136 tm->tm_year -= 100;
137 rp5c01_write(priv, tm->tm_year / 10, RP5C01_10_YEAR);
138 rp5c01_write(priv, tm->tm_year % 10, RP5C01_1_YEAR);
139
140 rp5c01_unlock(priv);
141 return 0;
142}
143
144static const struct rtc_class_ops rp5c01_rtc_ops = {
145 .read_time = rp5c01_read_time,
146 .set_time = rp5c01_set_time,
147};
148
149static int __init rp5c01_rtc_probe(struct platform_device *dev)
150{
151 struct resource *res;
152 struct rp5c01_priv *priv;
153 struct rtc_device *rtc;
154 int error;
155
156 res = platform_get_resource(dev, IORESOURCE_MEM, 0);
157 if (!res)
158 return -ENODEV;
159
160 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
161 if (!priv)
162 return -ENOMEM;
163
164 priv->regs = ioremap(res->start, resource_size(res));
165 if (!priv->regs) {
166 error = -ENOMEM;
167 goto out_free_priv;
168 }
169
170 rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops,
171 THIS_MODULE);
172 if (IS_ERR(rtc)) {
173 error = PTR_ERR(rtc);
174 goto out_unmap;
175 }
176
177 priv->rtc = rtc;
178 platform_set_drvdata(dev, priv);
179 return 0;
180
181out_unmap:
182 iounmap(priv->regs);
183out_free_priv:
184 kfree(priv);
185 return error;
186}
187
188static int __exit rp5c01_rtc_remove(struct platform_device *dev)
189{
190 struct rp5c01_priv *priv = platform_get_drvdata(dev);
191
192 rtc_device_unregister(priv->rtc);
193 iounmap(priv->regs);
194 kfree(priv);
195 return 0;
196}
197
198static struct platform_driver rp5c01_rtc_driver = {
199 .driver = {
200 .name = "rtc-rp5c01",
201 .owner = THIS_MODULE,
202 },
203 .remove = __exit_p(rp5c01_rtc_remove),
204};
205
206static int __init rp5c01_rtc_init(void)
207{
208 return platform_driver_probe(&rp5c01_rtc_driver, rp5c01_rtc_probe);
209}
210
211static void __exit rp5c01_rtc_fini(void)
212{
213 platform_driver_unregister(&rp5c01_rtc_driver);
214}
215
216module_init(rp5c01_rtc_init);
217module_exit(rp5c01_rtc_fini);
218
219MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
220MODULE_LICENSE("GPL");
221MODULE_DESCRIPTION("Ricoh RP5C01 RTC driver");
222MODULE_ALIAS("platform:rtc-rp5c01");