1 // SPDX-License-Identifier: GPL-2.0-only
3 * Driver for ST M41T94 SPI RTC
5 * Copyright (C) 2008 Kim B. Heino
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/platform_device.h>
11 #include <linux/rtc.h>
12 #include <linux/spi/spi.h>
13 #include <linux/bcd.h>
15 #define M41T94_REG_SECONDS 0x01
16 #define M41T94_REG_MINUTES 0x02
17 #define M41T94_REG_HOURS 0x03
18 #define M41T94_REG_WDAY 0x04
19 #define M41T94_REG_DAY 0x05
20 #define M41T94_REG_MONTH 0x06
21 #define M41T94_REG_YEAR 0x07
22 #define M41T94_REG_HT 0x0c
24 #define M41T94_BIT_HALT 0x40
25 #define M41T94_BIT_STOP 0x80
26 #define M41T94_BIT_CB 0x40
27 #define M41T94_BIT_CEB 0x80
29 static int m41t94_set_time(struct device
*dev
, struct rtc_time
*tm
)
31 struct spi_device
*spi
= to_spi_device(dev
);
32 u8 buf
[8]; /* write cmd + 7 registers */
34 dev_dbg(dev
, "%s secs=%d, mins=%d, "
35 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
36 "write", tm
->tm_sec
, tm
->tm_min
,
37 tm
->tm_hour
, tm
->tm_mday
,
38 tm
->tm_mon
, tm
->tm_year
, tm
->tm_wday
);
40 buf
[0] = 0x80 | M41T94_REG_SECONDS
; /* write time + date */
41 buf
[M41T94_REG_SECONDS
] = bin2bcd(tm
->tm_sec
);
42 buf
[M41T94_REG_MINUTES
] = bin2bcd(tm
->tm_min
);
43 buf
[M41T94_REG_HOURS
] = bin2bcd(tm
->tm_hour
);
44 buf
[M41T94_REG_WDAY
] = bin2bcd(tm
->tm_wday
+ 1);
45 buf
[M41T94_REG_DAY
] = bin2bcd(tm
->tm_mday
);
46 buf
[M41T94_REG_MONTH
] = bin2bcd(tm
->tm_mon
+ 1);
48 buf
[M41T94_REG_HOURS
] |= M41T94_BIT_CEB
;
49 if (tm
->tm_year
>= 100)
50 buf
[M41T94_REG_HOURS
] |= M41T94_BIT_CB
;
51 buf
[M41T94_REG_YEAR
] = bin2bcd(tm
->tm_year
% 100);
53 return spi_write(spi
, buf
, 8);
56 static int m41t94_read_time(struct device
*dev
, struct rtc_time
*tm
)
58 struct spi_device
*spi
= to_spi_device(dev
);
62 /* clear halt update bit */
63 ret
= spi_w8r8(spi
, M41T94_REG_HT
);
66 if (ret
& M41T94_BIT_HALT
) {
67 buf
[0] = 0x80 | M41T94_REG_HT
;
68 buf
[1] = ret
& ~M41T94_BIT_HALT
;
69 spi_write(spi
, buf
, 2);
73 ret
= spi_w8r8(spi
, M41T94_REG_SECONDS
);
76 if (ret
& M41T94_BIT_STOP
) {
77 buf
[0] = 0x80 | M41T94_REG_SECONDS
;
78 buf
[1] = ret
& ~M41T94_BIT_STOP
;
79 spi_write(spi
, buf
, 2);
82 tm
->tm_sec
= bcd2bin(spi_w8r8(spi
, M41T94_REG_SECONDS
));
83 tm
->tm_min
= bcd2bin(spi_w8r8(spi
, M41T94_REG_MINUTES
));
84 hour
= spi_w8r8(spi
, M41T94_REG_HOURS
);
85 tm
->tm_hour
= bcd2bin(hour
& 0x3f);
86 tm
->tm_wday
= bcd2bin(spi_w8r8(spi
, M41T94_REG_WDAY
)) - 1;
87 tm
->tm_mday
= bcd2bin(spi_w8r8(spi
, M41T94_REG_DAY
));
88 tm
->tm_mon
= bcd2bin(spi_w8r8(spi
, M41T94_REG_MONTH
)) - 1;
89 tm
->tm_year
= bcd2bin(spi_w8r8(spi
, M41T94_REG_YEAR
));
90 if ((hour
& M41T94_BIT_CB
) || !(hour
& M41T94_BIT_CEB
))
93 dev_dbg(dev
, "%s secs=%d, mins=%d, "
94 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
95 "read", tm
->tm_sec
, tm
->tm_min
,
96 tm
->tm_hour
, tm
->tm_mday
,
97 tm
->tm_mon
, tm
->tm_year
, tm
->tm_wday
);
102 static const struct rtc_class_ops m41t94_rtc_ops
= {
103 .read_time
= m41t94_read_time
,
104 .set_time
= m41t94_set_time
,
107 static struct spi_driver m41t94_driver
;
109 static int m41t94_probe(struct spi_device
*spi
)
111 struct rtc_device
*rtc
;
114 spi
->bits_per_word
= 8;
117 res
= spi_w8r8(spi
, M41T94_REG_SECONDS
);
119 dev_err(&spi
->dev
, "not found.\n");
123 rtc
= devm_rtc_device_register(&spi
->dev
, m41t94_driver
.driver
.name
,
124 &m41t94_rtc_ops
, THIS_MODULE
);
128 spi_set_drvdata(spi
, rtc
);
133 static struct spi_driver m41t94_driver
= {
135 .name
= "rtc-m41t94",
137 .probe
= m41t94_probe
,
140 module_spi_driver(m41t94_driver
);
142 MODULE_AUTHOR("Kim B. Heino <Kim.Heino@bluegiga.com>");
143 MODULE_DESCRIPTION("Driver for ST M41T94 SPI RTC");
144 MODULE_LICENSE("GPL");
145 MODULE_ALIAS("spi:rtc-m41t94");