2 * Driver for ST M41T94 SPI RTC
4 * Copyright (C) 2008 Kim B. Heino
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/platform_device.h>
14 #include <linux/rtc.h>
15 #include <linux/spi/spi.h>
16 #include <linux/bcd.h>
18 #define M41T94_REG_SECONDS 0x01
19 #define M41T94_REG_MINUTES 0x02
20 #define M41T94_REG_HOURS 0x03
21 #define M41T94_REG_WDAY 0x04
22 #define M41T94_REG_DAY 0x05
23 #define M41T94_REG_MONTH 0x06
24 #define M41T94_REG_YEAR 0x07
25 #define M41T94_REG_HT 0x0c
27 #define M41T94_BIT_HALT 0x40
28 #define M41T94_BIT_STOP 0x80
29 #define M41T94_BIT_CB 0x40
30 #define M41T94_BIT_CEB 0x80
32 static int m41t94_set_time(struct device
*dev
, struct rtc_time
*tm
)
34 struct spi_device
*spi
= to_spi_device(dev
);
35 u8 buf
[8]; /* write cmd + 7 registers */
37 dev_dbg(dev
, "%s secs=%d, mins=%d, "
38 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
39 "write", tm
->tm_sec
, tm
->tm_min
,
40 tm
->tm_hour
, tm
->tm_mday
,
41 tm
->tm_mon
, tm
->tm_year
, tm
->tm_wday
);
43 buf
[0] = 0x80 | M41T94_REG_SECONDS
; /* write time + date */
44 buf
[M41T94_REG_SECONDS
] = bin2bcd(tm
->tm_sec
);
45 buf
[M41T94_REG_MINUTES
] = bin2bcd(tm
->tm_min
);
46 buf
[M41T94_REG_HOURS
] = bin2bcd(tm
->tm_hour
);
47 buf
[M41T94_REG_WDAY
] = bin2bcd(tm
->tm_wday
+ 1);
48 buf
[M41T94_REG_DAY
] = bin2bcd(tm
->tm_mday
);
49 buf
[M41T94_REG_MONTH
] = bin2bcd(tm
->tm_mon
+ 1);
51 buf
[M41T94_REG_HOURS
] |= M41T94_BIT_CEB
;
52 if (tm
->tm_year
>= 100)
53 buf
[M41T94_REG_HOURS
] |= M41T94_BIT_CB
;
54 buf
[M41T94_REG_YEAR
] = bin2bcd(tm
->tm_year
% 100);
56 return spi_write(spi
, buf
, 8);
59 static int m41t94_read_time(struct device
*dev
, struct rtc_time
*tm
)
61 struct spi_device
*spi
= to_spi_device(dev
);
65 /* clear halt update bit */
66 ret
= spi_w8r8(spi
, M41T94_REG_HT
);
69 if (ret
& M41T94_BIT_HALT
) {
70 buf
[0] = 0x80 | M41T94_REG_HT
;
71 buf
[1] = ret
& ~M41T94_BIT_HALT
;
72 spi_write(spi
, buf
, 2);
76 ret
= spi_w8r8(spi
, M41T94_REG_SECONDS
);
79 if (ret
& M41T94_BIT_STOP
) {
80 buf
[0] = 0x80 | M41T94_REG_SECONDS
;
81 buf
[1] = ret
& ~M41T94_BIT_STOP
;
82 spi_write(spi
, buf
, 2);
85 tm
->tm_sec
= bcd2bin(spi_w8r8(spi
, M41T94_REG_SECONDS
));
86 tm
->tm_min
= bcd2bin(spi_w8r8(spi
, M41T94_REG_MINUTES
));
87 hour
= spi_w8r8(spi
, M41T94_REG_HOURS
);
88 tm
->tm_hour
= bcd2bin(hour
& 0x3f);
89 tm
->tm_wday
= bcd2bin(spi_w8r8(spi
, M41T94_REG_WDAY
)) - 1;
90 tm
->tm_mday
= bcd2bin(spi_w8r8(spi
, M41T94_REG_DAY
));
91 tm
->tm_mon
= bcd2bin(spi_w8r8(spi
, M41T94_REG_MONTH
)) - 1;
92 tm
->tm_year
= bcd2bin(spi_w8r8(spi
, M41T94_REG_YEAR
));
93 if ((hour
& M41T94_BIT_CB
) || !(hour
& M41T94_BIT_CEB
))
96 dev_dbg(dev
, "%s secs=%d, mins=%d, "
97 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
98 "read", tm
->tm_sec
, tm
->tm_min
,
99 tm
->tm_hour
, tm
->tm_mday
,
100 tm
->tm_mon
, tm
->tm_year
, tm
->tm_wday
);
102 /* initial clock setting can be undefined */
103 return rtc_valid_tm(tm
);
106 static const struct rtc_class_ops m41t94_rtc_ops
= {
107 .read_time
= m41t94_read_time
,
108 .set_time
= m41t94_set_time
,
111 static struct spi_driver m41t94_driver
;
113 static int __devinit
m41t94_probe(struct spi_device
*spi
)
115 struct rtc_device
*rtc
;
118 spi
->bits_per_word
= 8;
121 res
= spi_w8r8(spi
, M41T94_REG_SECONDS
);
123 dev_err(&spi
->dev
, "not found.\n");
127 rtc
= rtc_device_register(m41t94_driver
.driver
.name
,
128 &spi
->dev
, &m41t94_rtc_ops
, THIS_MODULE
);
132 dev_set_drvdata(&spi
->dev
, rtc
);
137 static int __devexit
m41t94_remove(struct spi_device
*spi
)
139 struct rtc_device
*rtc
= spi_get_drvdata(spi
);
142 rtc_device_unregister(rtc
);
147 static struct spi_driver m41t94_driver
= {
149 .name
= "rtc-m41t94",
150 .owner
= THIS_MODULE
,
152 .probe
= m41t94_probe
,
153 .remove
= __devexit_p(m41t94_remove
),
156 module_spi_driver(m41t94_driver
);
158 MODULE_AUTHOR("Kim B. Heino <Kim.Heino@bluegiga.com>");
159 MODULE_DESCRIPTION("Driver for ST M41T94 SPI RTC");
160 MODULE_LICENSE("GPL");
161 MODULE_ALIAS("spi:rtc-m41t94");