2 * Dallas DS1216 RTC driver
4 * Copyright (c) 2007 Thomas Bogendoerfer
8 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/bcd.h>
12 #include <linux/slab.h>
14 #define DRV_VERSION "0.2"
27 #define DS1216_HOUR_1224 (1 << 7)
28 #define DS1216_HOUR_AMPM (1 << 5)
31 struct rtc_device
*rtc
;
34 unsigned long baseaddr
;
37 static const u8 magic
[] = {
38 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c
42 * Read the 64 bit we'd like to have - It a series
43 * of 64 bits showing up in the LSB of the base register.
46 static void ds1216_read(u8 __iomem
*ioaddr
, u8
*buf
)
51 for (i
= 0; i
< 8; i
++) {
53 for (j
= 0; j
< 8; j
++)
54 c
|= (readb(ioaddr
) & 0x1) << j
;
59 static void ds1216_write(u8 __iomem
*ioaddr
, const u8
*buf
)
64 for (i
= 0; i
< 8; i
++) {
66 for (j
= 0; j
< 8; j
++) {
73 static void ds1216_switch_ds_to_clock(u8 __iomem
*ioaddr
)
75 /* Reset magic pointer */
77 /* Write 64 bit magic to DS1216 */
78 ds1216_write(ioaddr
, magic
);
81 static int ds1216_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
83 struct platform_device
*pdev
= to_platform_device(dev
);
84 struct ds1216_priv
*priv
= platform_get_drvdata(pdev
);
85 struct ds1216_regs regs
;
87 ds1216_switch_ds_to_clock(priv
->ioaddr
);
88 ds1216_read(priv
->ioaddr
, (u8
*)®s
);
90 tm
->tm_sec
= bcd2bin(regs
.sec
);
91 tm
->tm_min
= bcd2bin(regs
.min
);
92 if (regs
.hour
& DS1216_HOUR_1224
) {
94 tm
->tm_hour
= bcd2bin(regs
.hour
& 0x1f);
95 if (regs
.hour
& DS1216_HOUR_AMPM
)
98 tm
->tm_hour
= bcd2bin(regs
.hour
& 0x3f);
99 tm
->tm_wday
= (regs
.wday
& 7) - 1;
100 tm
->tm_mday
= bcd2bin(regs
.mday
& 0x3f);
101 tm
->tm_mon
= bcd2bin(regs
.month
& 0x1f);
102 tm
->tm_year
= bcd2bin(regs
.year
);
103 if (tm
->tm_year
< 70)
106 return rtc_valid_tm(tm
);
109 static int ds1216_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
111 struct platform_device
*pdev
= to_platform_device(dev
);
112 struct ds1216_priv
*priv
= platform_get_drvdata(pdev
);
113 struct ds1216_regs regs
;
115 ds1216_switch_ds_to_clock(priv
->ioaddr
);
116 ds1216_read(priv
->ioaddr
, (u8
*)®s
);
118 regs
.tsec
= 0; /* clear 0.1 and 0.01 seconds */
119 regs
.sec
= bin2bcd(tm
->tm_sec
);
120 regs
.min
= bin2bcd(tm
->tm_min
);
121 regs
.hour
&= DS1216_HOUR_1224
;
122 if (regs
.hour
&& tm
->tm_hour
> 12) {
123 regs
.hour
|= DS1216_HOUR_AMPM
;
126 regs
.hour
|= bin2bcd(tm
->tm_hour
);
128 regs
.wday
|= tm
->tm_wday
;
129 regs
.mday
= bin2bcd(tm
->tm_mday
);
130 regs
.month
= bin2bcd(tm
->tm_mon
);
131 regs
.year
= bin2bcd(tm
->tm_year
% 100);
133 ds1216_switch_ds_to_clock(priv
->ioaddr
);
134 ds1216_write(priv
->ioaddr
, (u8
*)®s
);
138 static const struct rtc_class_ops ds1216_rtc_ops
= {
139 .read_time
= ds1216_rtc_read_time
,
140 .set_time
= ds1216_rtc_set_time
,
143 static int __init
ds1216_rtc_probe(struct platform_device
*pdev
)
145 struct resource
*res
;
146 struct ds1216_priv
*priv
;
150 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
153 priv
= kzalloc(sizeof *priv
, GFP_KERNEL
);
157 platform_set_drvdata(pdev
, priv
);
159 priv
->size
= resource_size(res
);
160 if (!request_mem_region(res
->start
, priv
->size
, pdev
->name
)) {
164 priv
->baseaddr
= res
->start
;
165 priv
->ioaddr
= ioremap(priv
->baseaddr
, priv
->size
);
170 priv
->rtc
= rtc_device_register("ds1216", &pdev
->dev
,
171 &ds1216_rtc_ops
, THIS_MODULE
);
172 if (IS_ERR(priv
->rtc
)) {
173 ret
= PTR_ERR(priv
->rtc
);
177 /* dummy read to get clock into a known state */
178 ds1216_read(priv
->ioaddr
, dummy
);
183 iounmap(priv
->ioaddr
);
185 release_mem_region(priv
->baseaddr
, priv
->size
);
190 static int __exit
ds1216_rtc_remove(struct platform_device
*pdev
)
192 struct ds1216_priv
*priv
= platform_get_drvdata(pdev
);
194 rtc_device_unregister(priv
->rtc
);
195 iounmap(priv
->ioaddr
);
196 release_mem_region(priv
->baseaddr
, priv
->size
);
201 static struct platform_driver ds1216_rtc_platform_driver
= {
203 .name
= "rtc-ds1216",
204 .owner
= THIS_MODULE
,
206 .remove
= __exit_p(ds1216_rtc_remove
),
209 static int __init
ds1216_rtc_init(void)
211 return platform_driver_probe(&ds1216_rtc_platform_driver
, ds1216_rtc_probe
);
214 static void __exit
ds1216_rtc_exit(void)
216 platform_driver_unregister(&ds1216_rtc_platform_driver
);
219 MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
220 MODULE_DESCRIPTION("DS1216 RTC driver");
221 MODULE_LICENSE("GPL");
222 MODULE_VERSION(DRV_VERSION
);
223 MODULE_ALIAS("platform:rtc-ds1216");
225 module_init(ds1216_rtc_init
);
226 module_exit(ds1216_rtc_exit
);