1 // SPDX-License-Identifier: GPL-2.0-only
3 * Dallas DS1216 RTC driver
5 * Copyright (c) 2007 Thomas Bogendoerfer
9 #include <linux/module.h>
10 #include <linux/rtc.h>
11 #include <linux/platform_device.h>
12 #include <linux/bcd.h>
13 #include <linux/slab.h>
26 #define DS1216_HOUR_1224 (1 << 7)
27 #define DS1216_HOUR_AMPM (1 << 5)
30 struct rtc_device
*rtc
;
34 static const u8 magic
[] = {
35 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c
39 * Read the 64 bit we'd like to have - It a series
40 * of 64 bits showing up in the LSB of the base register.
43 static void ds1216_read(u8 __iomem
*ioaddr
, u8
*buf
)
48 for (i
= 0; i
< 8; i
++) {
50 for (j
= 0; j
< 8; j
++)
51 c
|= (readb(ioaddr
) & 0x1) << j
;
56 static void ds1216_write(u8 __iomem
*ioaddr
, const u8
*buf
)
61 for (i
= 0; i
< 8; i
++) {
63 for (j
= 0; j
< 8; j
++) {
70 static void ds1216_switch_ds_to_clock(u8 __iomem
*ioaddr
)
72 /* Reset magic pointer */
74 /* Write 64 bit magic to DS1216 */
75 ds1216_write(ioaddr
, magic
);
78 static int ds1216_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
80 struct ds1216_priv
*priv
= dev_get_drvdata(dev
);
81 struct ds1216_regs regs
;
83 ds1216_switch_ds_to_clock(priv
->ioaddr
);
84 ds1216_read(priv
->ioaddr
, (u8
*)®s
);
86 tm
->tm_sec
= bcd2bin(regs
.sec
);
87 tm
->tm_min
= bcd2bin(regs
.min
);
88 if (regs
.hour
& DS1216_HOUR_1224
) {
90 tm
->tm_hour
= bcd2bin(regs
.hour
& 0x1f);
91 if (regs
.hour
& DS1216_HOUR_AMPM
)
94 tm
->tm_hour
= bcd2bin(regs
.hour
& 0x3f);
95 tm
->tm_wday
= (regs
.wday
& 7) - 1;
96 tm
->tm_mday
= bcd2bin(regs
.mday
& 0x3f);
97 tm
->tm_mon
= bcd2bin(regs
.month
& 0x1f);
98 tm
->tm_year
= bcd2bin(regs
.year
);
105 static int ds1216_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
107 struct ds1216_priv
*priv
= dev_get_drvdata(dev
);
108 struct ds1216_regs regs
;
110 ds1216_switch_ds_to_clock(priv
->ioaddr
);
111 ds1216_read(priv
->ioaddr
, (u8
*)®s
);
113 regs
.tsec
= 0; /* clear 0.1 and 0.01 seconds */
114 regs
.sec
= bin2bcd(tm
->tm_sec
);
115 regs
.min
= bin2bcd(tm
->tm_min
);
116 regs
.hour
&= DS1216_HOUR_1224
;
117 if (regs
.hour
&& tm
->tm_hour
> 12) {
118 regs
.hour
|= DS1216_HOUR_AMPM
;
121 regs
.hour
|= bin2bcd(tm
->tm_hour
);
123 regs
.wday
|= tm
->tm_wday
;
124 regs
.mday
= bin2bcd(tm
->tm_mday
);
125 regs
.month
= bin2bcd(tm
->tm_mon
);
126 regs
.year
= bin2bcd(tm
->tm_year
% 100);
128 ds1216_switch_ds_to_clock(priv
->ioaddr
);
129 ds1216_write(priv
->ioaddr
, (u8
*)®s
);
133 static const struct rtc_class_ops ds1216_rtc_ops
= {
134 .read_time
= ds1216_rtc_read_time
,
135 .set_time
= ds1216_rtc_set_time
,
138 static int __init
ds1216_rtc_probe(struct platform_device
*pdev
)
140 struct ds1216_priv
*priv
;
143 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
147 platform_set_drvdata(pdev
, priv
);
149 priv
->ioaddr
= devm_platform_ioremap_resource(pdev
, 0);
150 if (IS_ERR(priv
->ioaddr
))
151 return PTR_ERR(priv
->ioaddr
);
153 priv
->rtc
= devm_rtc_device_register(&pdev
->dev
, "ds1216",
154 &ds1216_rtc_ops
, THIS_MODULE
);
155 if (IS_ERR(priv
->rtc
))
156 return PTR_ERR(priv
->rtc
);
158 /* dummy read to get clock into a known state */
159 ds1216_read(priv
->ioaddr
, dummy
);
163 static struct platform_driver ds1216_rtc_platform_driver
= {
165 .name
= "rtc-ds1216",
169 module_platform_driver_probe(ds1216_rtc_platform_driver
, ds1216_rtc_probe
);
171 MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
172 MODULE_DESCRIPTION("DS1216 RTC driver");
173 MODULE_LICENSE("GPL");
174 MODULE_ALIAS("platform:rtc-ds1216");