1 // SPDX-License-Identifier: GPL-2.0-only
3 * Driver for Epson RTC-9701JE
5 * Copyright (C) 2008 Magnus Damm
7 * Based on rtc-max6902.c
9 * Copyright (C) 2006 8D Technologies inc.
10 * Copyright (C) 2004 Compulab Ltd.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/platform_device.h>
16 #include <linux/device.h>
17 #include <linux/init.h>
18 #include <linux/rtc.h>
19 #include <linux/spi/spi.h>
20 #include <linux/bcd.h>
21 #include <linux/delay.h>
22 #include <linux/bitops.h>
24 #define RSECCNT 0x00 /* Second Counter */
25 #define RMINCNT 0x01 /* Minute Counter */
26 #define RHRCNT 0x02 /* Hour Counter */
27 #define RWKCNT 0x03 /* Week Counter */
28 #define RDAYCNT 0x04 /* Day Counter */
29 #define RMONCNT 0x05 /* Month Counter */
30 #define RYRCNT 0x06 /* Year Counter */
31 #define R100CNT 0x07 /* Y100 Counter */
32 #define RMINAR 0x08 /* Minute Alarm */
33 #define RHRAR 0x09 /* Hour Alarm */
34 #define RWKAR 0x0a /* Week/Day Alarm */
35 #define RTIMCNT 0x0c /* Interval Timer */
36 #define REXT 0x0d /* Extension Register */
37 #define RFLAG 0x0e /* RTC Flag Register */
38 #define RCR 0x0f /* RTC Control Register */
40 static int write_reg(struct device
*dev
, int address
, unsigned char data
)
42 struct spi_device
*spi
= to_spi_device(dev
);
45 buf
[0] = address
& 0x7f;
48 return spi_write(spi
, buf
, ARRAY_SIZE(buf
));
51 static int read_regs(struct device
*dev
, unsigned char *regs
, int no_regs
)
53 struct spi_device
*spi
= to_spi_device(dev
);
54 u8 txbuf
[1], rxbuf
[1];
59 for (k
= 0; ret
== 0 && k
< no_regs
; k
++) {
60 txbuf
[0] = 0x80 | regs
[k
];
61 ret
= spi_write_then_read(spi
, txbuf
, 1, rxbuf
, 1);
68 static int r9701_get_datetime(struct device
*dev
, struct rtc_time
*dt
)
71 unsigned char buf
[] = { RSECCNT
, RMINCNT
, RHRCNT
,
72 RDAYCNT
, RMONCNT
, RYRCNT
};
74 ret
= read_regs(dev
, buf
, ARRAY_SIZE(buf
));
78 memset(dt
, 0, sizeof(*dt
));
80 dt
->tm_sec
= bcd2bin(buf
[0]); /* RSECCNT */
81 dt
->tm_min
= bcd2bin(buf
[1]); /* RMINCNT */
82 dt
->tm_hour
= bcd2bin(buf
[2]); /* RHRCNT */
84 dt
->tm_mday
= bcd2bin(buf
[3]); /* RDAYCNT */
85 dt
->tm_mon
= bcd2bin(buf
[4]) - 1; /* RMONCNT */
86 dt
->tm_year
= bcd2bin(buf
[5]) + 100; /* RYRCNT */
88 /* the rtc device may contain illegal values on power up
89 * according to the data sheet. make sure they are valid.
95 static int r9701_set_datetime(struct device
*dev
, struct rtc_time
*dt
)
99 year
= dt
->tm_year
+ 1900;
100 if (year
>= 2100 || year
< 2000)
103 ret
= write_reg(dev
, RHRCNT
, bin2bcd(dt
->tm_hour
));
104 ret
= ret
? ret
: write_reg(dev
, RMINCNT
, bin2bcd(dt
->tm_min
));
105 ret
= ret
? ret
: write_reg(dev
, RSECCNT
, bin2bcd(dt
->tm_sec
));
106 ret
= ret
? ret
: write_reg(dev
, RDAYCNT
, bin2bcd(dt
->tm_mday
));
107 ret
= ret
? ret
: write_reg(dev
, RMONCNT
, bin2bcd(dt
->tm_mon
+ 1));
108 ret
= ret
? ret
: write_reg(dev
, RYRCNT
, bin2bcd(dt
->tm_year
- 100));
109 ret
= ret
? ret
: write_reg(dev
, RWKCNT
, 1 << dt
->tm_wday
);
114 static const struct rtc_class_ops r9701_rtc_ops
= {
115 .read_time
= r9701_get_datetime
,
116 .set_time
= r9701_set_datetime
,
119 static int r9701_probe(struct spi_device
*spi
)
121 struct rtc_device
*rtc
;
127 res
= read_regs(&spi
->dev
, &tmp
, 1);
128 if (res
|| tmp
!= 0x20) {
129 dev_err(&spi
->dev
, "cannot read RTC register\n");
134 * The device seems to be present. Now check if the registers
135 * contain invalid values. If so, try to write a default date:
138 if (r9701_get_datetime(&spi
->dev
, &dt
)) {
139 dev_info(&spi
->dev
, "trying to repair invalid date/time\n");
147 if (r9701_set_datetime(&spi
->dev
, &dt
) ||
148 r9701_get_datetime(&spi
->dev
, &dt
)) {
149 dev_err(&spi
->dev
, "cannot repair RTC register\n");
154 rtc
= devm_rtc_device_register(&spi
->dev
, "r9701",
155 &r9701_rtc_ops
, THIS_MODULE
);
159 spi_set_drvdata(spi
, rtc
);
164 static struct spi_driver r9701_driver
= {
168 .probe
= r9701_probe
,
171 module_spi_driver(r9701_driver
);
173 MODULE_DESCRIPTION("r9701 spi RTC driver");
174 MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
175 MODULE_LICENSE("GPL");
176 MODULE_ALIAS("spi:rtc-r9701");