1 /****************************************************************************/
4 * drivers/rtc/rtc-ds1302.c -- DS1302 RTC code
6 * Copyright (C) 2002 David McCullough <davidm@snapgear.com>
7 * Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org>
8 * Copyright (C) 2006 Greg Ungerer <gerg@snapgear.com>
10 * Support for the DS1302 on some Snapgear SH based boards.
13 /****************************************************************************/
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/init.h>
18 #include <linux/rtc.h>
19 #include <linux/bcd.h>
20 #include <linux/platform_device.h>
22 #include <asm/snapgear.h>
24 /****************************************************************************/
26 * we need to implement a DS1302 driver here that can operate in
27 * conjunction with the builtin rtc driver which is already quite friendly
29 /*****************************************************************************/
31 #define RTC_CMD_READ 0x81 /* Read command */
32 #define RTC_CMD_WRITE 0x80 /* Write command */
34 #define RTC_ADDR_YEAR 0x06 /* Address of year register */
35 #define RTC_ADDR_DAY 0x05 /* Address of day of week register */
36 #define RTC_ADDR_MON 0x04 /* Address of month register */
37 #define RTC_ADDR_DATE 0x03 /* Address of day of month register */
38 #define RTC_ADDR_HOUR 0x02 /* Address of hour register */
39 #define RTC_ADDR_MIN 0x01 /* Address of minute register */
40 #define RTC_ADDR_SEC 0x00 /* Address of second register */
42 #define RTC_RESET 0x1000
43 #define RTC_IODATA 0x0800
44 #define RTC_SCLK 0x0400
48 #define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
49 #define get_dp(x) SECUREEDGE_READ_IOPORT()
51 static void ds1302_sendbits(unsigned int val
)
55 for (i
= 8; (i
); i
--, val
>>= 1) {
56 set_dp((get_dp() & ~RTC_IODATA
) | ((val
& 0x1) ? RTC_IODATA
: 0));
57 set_dp(get_dp() | RTC_SCLK
); // clock high
58 set_dp(get_dp() & ~RTC_SCLK
); // clock low
62 static unsigned int ds1302_recvbits(void)
67 for (i
= 0, val
= 0; (i
< 8); i
++) {
68 val
|= (((get_dp() & RTC_IODATA
) ? 1 : 0) << i
);
69 set_dp(get_dp() | RTC_SCLK
); // clock high
70 set_dp(get_dp() & ~RTC_SCLK
); // clock low
75 static unsigned int ds1302_readbyte(unsigned int addr
)
80 local_irq_save(flags
);
81 set_dirp(get_dirp() | RTC_RESET
| RTC_IODATA
| RTC_SCLK
);
82 set_dp(get_dp() & ~(RTC_RESET
| RTC_IODATA
| RTC_SCLK
));
84 set_dp(get_dp() | RTC_RESET
);
85 ds1302_sendbits(((addr
& 0x3f) << 1) | RTC_CMD_READ
);
86 set_dirp(get_dirp() & ~RTC_IODATA
);
87 val
= ds1302_recvbits();
88 set_dp(get_dp() & ~RTC_RESET
);
89 local_irq_restore(flags
);
94 static void ds1302_writebyte(unsigned int addr
, unsigned int val
)
98 local_irq_save(flags
);
99 set_dirp(get_dirp() | RTC_RESET
| RTC_IODATA
| RTC_SCLK
);
100 set_dp(get_dp() & ~(RTC_RESET
| RTC_IODATA
| RTC_SCLK
));
101 set_dp(get_dp() | RTC_RESET
);
102 ds1302_sendbits(((addr
& 0x3f) << 1) | RTC_CMD_WRITE
);
103 ds1302_sendbits(val
);
104 set_dp(get_dp() & ~RTC_RESET
);
105 local_irq_restore(flags
);
108 static void ds1302_reset(void)
111 /* Hardware dependant reset/init */
112 local_irq_save(flags
);
113 set_dirp(get_dirp() | RTC_RESET
| RTC_IODATA
| RTC_SCLK
);
114 set_dp(get_dp() & ~(RTC_RESET
| RTC_IODATA
| RTC_SCLK
));
115 local_irq_restore(flags
);
118 /****************************************************************************/
120 static inline int bcd2bin(int val
)
125 static int ds1302_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
127 tm
->tm_sec
= bcd2bin(ds1302_readbyte(RTC_ADDR_SEC
) & 0x7f);
128 tm
->tm_min
= bcd2bin(ds1302_readbyte(RTC_ADDR_MIN
) & 0x7f);
129 tm
->tm_hour
= bcd2bin(ds1302_readbyte(RTC_ADDR_HOUR
) & 0x3f);
130 tm
->tm_wday
= bcd2bin(ds1302_readbyte(RTC_ADDR_DAY
) & 0x07) - 1;
131 tm
->tm_mday
= bcd2bin(ds1302_readbyte(RTC_ADDR_DATE
) & 0x3f);
132 tm
->tm_mon
= bcd2bin(ds1302_readbyte(RTC_ADDR_MON
) & 0x1f) - 1;
133 tm
->tm_year
= bcd2bin(ds1302_readbyte(RTC_ADDR_YEAR
)) + 100;
138 static int ds1302_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
141 ds1302_writebyte(RTC_ADDR_SEC
, 0x80);
143 ds1302_writebyte(RTC_ADDR_MIN
, BIN2BCD(tm
->tm_min
));
144 ds1302_writebyte(RTC_ADDR_HOUR
, BIN2BCD(tm
->tm_hour
));
145 ds1302_writebyte(RTC_ADDR_DAY
, BIN2BCD(tm
->tm_wday
+ 1));
146 ds1302_writebyte(RTC_ADDR_DATE
, BIN2BCD(tm
->tm_mday
));
147 ds1302_writebyte(RTC_ADDR_MON
, BIN2BCD(tm
->tm_mon
+ 1));
148 ds1302_writebyte(RTC_ADDR_YEAR
, BIN2BCD(tm
->tm_year
- 100));
151 ds1302_writebyte(RTC_ADDR_SEC
, BIN2BCD(tm
->tm_sec
));
156 /****************************************************************************/
158 static struct rtc_class_ops ds1302_rtc_ops
= {
159 .read_time
= ds1302_rtc_read_time
,
160 .set_time
= ds1302_rtc_set_time
,
163 /****************************************************************************/
165 static int __devinit
ds1302_rtc_probe(struct platform_device
*pdev
)
167 struct rtc_device
*rdev
;
168 unsigned char *test
= "snapgear";
173 for (i
= 0; test
[i
]; i
++)
174 ds1302_writebyte(32 + i
, test
[i
]);
176 for (i
= 0; test
[i
]; i
++) {
177 if (ds1302_readbyte(32 + i
) != test
[i
])
181 rdev
= rtc_device_register("ds1302", &pdev
->dev
, &ds1302_rtc_ops
, THIS_MODULE
);
183 printk("SnapGear RTC: using ds1302 rtc.\n");
185 platform_set_drvdata(pdev
, rdev
);
189 /****************************************************************************/
191 static int __devexit
ds1302_rtc_remove(struct platform_device
*pdev
)
193 struct rtc_device
*rdev
= platform_get_drvdata(pdev
);
196 rtc_device_unregister(rdev
);
200 /****************************************************************************/
202 static struct platform_driver ds1302_rtc_platform_driver
= {
205 .owner
= THIS_MODULE
,
207 .probe
= ds1302_rtc_probe
,
208 .remove
= __devexit_p(ds1302_rtc_remove
),
211 /****************************************************************************/
213 static int __init
ds1302_rtc_init(void)
215 return platform_driver_register(&ds1302_rtc_platform_driver
);
218 static void __exit
ds1302_rtc_exit(void)
220 platform_driver_unregister(&ds1302_rtc_platform_driver
);
223 /****************************************************************************/
225 module_init(ds1302_rtc_init
);
226 module_exit(ds1302_rtc_exit
);
228 /****************************************************************************/
230 MODULE_DESCRIPTION("DS1302 on SnapGear SH hardware platforms");
231 MODULE_AUTHOR("David McCullough <davidm@snapgear.com>, Paul Mundt <lethal@linux-sh.org>, Greg Ungerer <gerg@snapgear.com>");
232 MODULE_LICENSE("GPL");
234 /****************************************************************************/